1 : /******************************************************************************
2 : * $Id: ogrsqlitevfs.cpp 24807 2012-08-19 20:14:37Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements SQLite VFS
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 :
8 : ******************************************************************************
9 : * Copyright (c) 2011, Even Rouault, <even dot rouault at mines dash paris dot org>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_atomic_ops.h"
31 : #include "ogr_sqlite.h"
32 :
33 : CPL_CVSID("$Id: ogrsqlitevfs.cpp 24807 2012-08-19 20:14:37Z rouault $");
34 :
35 : //#define DEBUG_IO 1
36 :
37 : #ifdef HAVE_SQLITE_VFS
38 :
39 : typedef struct
40 : {
41 : char szVFSName[64];
42 : sqlite3_vfs *pDefaultVFS;
43 : pfnNotifyFileOpenedType pfn;
44 : void *pfnUserData;
45 : int nCounter;
46 : } OGRSQLiteVFSAppDataStruct;
47 :
48 : #define GET_UNDERLYING_VFS(pVFS) ((OGRSQLiteVFSAppDataStruct* )pVFS->pAppData)->pDefaultVFS
49 :
50 : typedef struct
51 : {
52 : const struct sqlite3_io_methods *pMethods;
53 : VSILFILE *fp;
54 : int bDeleteOnClose;
55 : char *pszFilename;
56 : } OGRSQLiteFileStruct;
57 :
58 1157 : static int OGRSQLiteIOClose(sqlite3_file* pFile)
59 : {
60 1157 : OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
61 : #ifdef DEBUG_IO
62 : CPLDebug("SQLITE", "OGRSQLiteIOClose(%p (%s))", pMyFile->fp, pMyFile->pszFilename);
63 : #endif
64 1157 : VSIFCloseL(pMyFile->fp);
65 1157 : if (pMyFile->bDeleteOnClose)
66 25 : VSIUnlink(pMyFile->pszFilename);
67 1157 : CPLFree(pMyFile->pszFilename);
68 1157 : return SQLITE_OK;
69 : }
70 :
71 30282 : static int OGRSQLiteIORead(sqlite3_file* pFile, void* pBuffer, int iAmt, sqlite3_int64 iOfst)
72 : {
73 30282 : OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
74 30282 : VSIFSeekL(pMyFile->fp, (vsi_l_offset) iOfst, SEEK_SET);
75 30282 : int nRead = (int)VSIFReadL(pBuffer, 1, iAmt, pMyFile->fp);
76 : #ifdef DEBUG_IO
77 : CPLDebug("SQLITE", "OGRSQLiteIORead(%p, %d, %d) = %d", pMyFile->fp, iAmt, (int)iOfst, nRead);
78 : #endif
79 30282 : if (nRead < iAmt)
80 : {
81 118 : memset(((char*)pBuffer) + nRead, 0, iAmt - nRead);
82 118 : return SQLITE_IOERR_SHORT_READ;
83 : }
84 30164 : return SQLITE_OK;
85 : }
86 :
87 12822 : static int OGRSQLiteIOWrite(sqlite3_file* pFile, const void* pBuffer, int iAmt, sqlite3_int64 iOfst)
88 : {
89 12822 : OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
90 12822 : VSIFSeekL(pMyFile->fp, (vsi_l_offset) iOfst, SEEK_SET);
91 12822 : int nWritten = (int)VSIFWriteL(pBuffer, 1, iAmt, pMyFile->fp);
92 : #ifdef DEBUG_IO
93 : CPLDebug("SQLITE", "OGRSQLiteIOWrite(%p, %d, %d) = %d", pMyFile->fp, iAmt, (int)iOfst, nWritten);
94 : #endif
95 12822 : if (nWritten < iAmt)
96 : {
97 0 : return SQLITE_IOERR_WRITE;
98 : }
99 12822 : return SQLITE_OK;
100 : }
101 :
102 46 : static int OGRSQLiteIOTruncate(sqlite3_file* pFile, sqlite3_int64 size)
103 : {
104 46 : OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
105 : #ifdef DEBUG_IO
106 : CPLDebug("SQLITE", "OGRSQLiteIOTruncate(%p, " CPL_FRMT_GIB ")", pMyFile->fp, size);
107 : #endif
108 46 : int nRet = VSIFTruncateL(pMyFile->fp, size);
109 46 : return (nRet == 0) ? SQLITE_OK : SQLITE_IOERR_TRUNCATE;
110 : }
111 :
112 0 : static int OGRSQLiteIOSync(sqlite3_file* pFile, int flags)
113 : {
114 : #ifdef DEBUG_IO
115 : OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
116 : CPLDebug("SQLITE", "OGRSQLiteIOSync(%p, %d)", pMyFile->fp, flags);
117 : #endif
118 0 : return SQLITE_OK;
119 : }
120 :
121 2822 : static int OGRSQLiteIOFileSize(sqlite3_file* pFile, sqlite3_int64 *pSize)
122 : {
123 2822 : OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
124 2822 : vsi_l_offset nCurOffset = VSIFTellL(pMyFile->fp);
125 2822 : VSIFSeekL(pMyFile->fp, 0, SEEK_END);
126 2822 : *pSize = VSIFTellL(pMyFile->fp);
127 2822 : VSIFSeekL(pMyFile->fp, nCurOffset, SEEK_SET);
128 : #ifdef DEBUG_IO
129 : CPLDebug("SQLITE", "OGRSQLiteIOFileSize(%p) = " CPL_FRMT_GIB, pMyFile->fp, *pSize);
130 : #endif
131 2822 : return SQLITE_OK;
132 : }
133 :
134 4116 : static int OGRSQLiteIOLock(sqlite3_file* pFile, int flags)
135 : {
136 : #ifdef DEBUG_IO
137 : OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
138 : CPLDebug("SQLITE", "OGRSQLiteIOLock(%p)", pMyFile->fp);
139 : #endif
140 4116 : return SQLITE_OK;
141 : }
142 :
143 3931 : static int OGRSQLiteIOUnlock(sqlite3_file* pFile, int flags)
144 : {
145 : #ifdef DEBUG_IO
146 : OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
147 : CPLDebug("SQLITE", "OGRSQLiteIOUnlock(%p)", pMyFile->fp);
148 : #endif
149 3931 : return SQLITE_OK;
150 : }
151 :
152 0 : static int OGRSQLiteIOCheckReservedLock(sqlite3_file* pFile, int *pResOut)
153 : {
154 : #ifdef DEBUG_IO
155 : OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
156 : CPLDebug("SQLITE", "OGRSQLiteIOCheckReservedLock(%p)", pMyFile->fp);
157 : #endif
158 0 : *pResOut = 0;
159 0 : return SQLITE_OK;
160 : }
161 :
162 0 : static int OGRSQLiteIOFileControl(sqlite3_file* pFile, int op, void *pArg)
163 : {
164 : #ifdef DEBUG_IO
165 : OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
166 : CPLDebug("SQLITE", "OGRSQLiteIOFileControl(%p, %d)", pMyFile->fp, op);
167 : #endif
168 0 : return SQLITE_NOTFOUND;
169 : }
170 :
171 928 : static int OGRSQLiteIOSectorSize(sqlite3_file* pFile)
172 : {
173 : #ifdef DEBUG_IO
174 : OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
175 : CPLDebug("SQLITE", "OGRSQLiteIOSectorSize(%p)", pMyFile->fp);
176 : #endif
177 928 : return 0;
178 : }
179 :
180 0 : static int OGRSQLiteIODeviceCharacteristics(sqlite3_file* pFile)
181 : {
182 : #ifdef DEBUG_IO
183 : OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
184 : CPLDebug("SQLITE", "OGRSQLiteIODeviceCharacteristics(%p)", pMyFile->fp);
185 : #endif
186 0 : return 0;
187 : }
188 :
189 : static const sqlite3_io_methods OGRSQLiteIOMethods =
190 : {
191 : 1,
192 : OGRSQLiteIOClose,
193 : OGRSQLiteIORead,
194 : OGRSQLiteIOWrite,
195 : OGRSQLiteIOTruncate,
196 : OGRSQLiteIOSync,
197 : OGRSQLiteIOFileSize,
198 : OGRSQLiteIOLock,
199 : OGRSQLiteIOUnlock,
200 : OGRSQLiteIOCheckReservedLock,
201 : OGRSQLiteIOFileControl,
202 : OGRSQLiteIOSectorSize,
203 : OGRSQLiteIODeviceCharacteristics
204 : };
205 :
206 1157 : static int OGRSQLiteVFSOpen(sqlite3_vfs* pVFS,
207 : const char *zName,
208 : sqlite3_file* pFile,
209 : int flags,
210 : int *pOutFlags)
211 : {
212 : #ifdef DEBUG_IO
213 : CPLDebug("SQLITE", "OGRSQLiteVFSOpen(%s, %d)", zName ? zName : "(null)", flags);
214 : #endif
215 :
216 1157 : OGRSQLiteVFSAppDataStruct* pAppData = (OGRSQLiteVFSAppDataStruct* )pVFS->pAppData;
217 :
218 1157 : if (zName == NULL)
219 : {
220 : zName = CPLSPrintf("/vsimem/sqlite/%p_%d",
221 25 : pVFS, CPLAtomicInc(&(pAppData->nCounter)));
222 : }
223 :
224 1157 : OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
225 1157 : pMyFile->pMethods = NULL;
226 1157 : pMyFile->bDeleteOnClose = FALSE;
227 1157 : pMyFile->pszFilename = NULL;
228 1157 : if ( flags & SQLITE_OPEN_READONLY )
229 5 : pMyFile->fp = VSIFOpenL(zName, "rb");
230 1152 : else if ( flags & SQLITE_OPEN_CREATE )
231 808 : pMyFile->fp = VSIFOpenL(zName, "wb+");
232 344 : else if ( flags & SQLITE_OPEN_READWRITE )
233 344 : pMyFile->fp = VSIFOpenL(zName, "rb+");
234 : else
235 0 : pMyFile->fp = NULL;
236 :
237 1157 : if (pMyFile->fp == NULL)
238 0 : return SQLITE_CANTOPEN;
239 :
240 : #ifdef DEBUG_IO
241 : CPLDebug("SQLITE", "OGRSQLiteVFSOpen() = %p", pMyFile->fp);
242 : #endif
243 :
244 1157 : pfnNotifyFileOpenedType pfn = pAppData->pfn;
245 1157 : if (pfn)
246 : {
247 1147 : pfn(pAppData->pfnUserData, zName, pMyFile->fp);
248 : }
249 :
250 1157 : pMyFile->pMethods = &OGRSQLiteIOMethods;
251 1157 : pMyFile->bDeleteOnClose = ( flags & SQLITE_OPEN_DELETEONCLOSE );
252 1157 : pMyFile->pszFilename = CPLStrdup(zName);
253 :
254 1157 : if (pOutFlags != NULL)
255 466 : *pOutFlags = flags;
256 :
257 1157 : return SQLITE_OK;
258 : }
259 :
260 666 : static int OGRSQLiteVFSDelete(sqlite3_vfs* pVFS, const char *zName, int syncDir)
261 : {
262 : #ifdef DEBUG_IO
263 : CPLDebug("SQLITE", "OGRSQLiteVFSDelete(%s)", zName);
264 : #endif
265 666 : VSIUnlink(zName);
266 666 : return SQLITE_OK;
267 : }
268 :
269 2789 : static int OGRSQLiteVFSAccess (sqlite3_vfs* pVFS, const char *zName, int flags, int *pResOut)
270 : {
271 : #ifdef DEBUG_IO
272 : CPLDebug("SQLITE", "OGRSQLiteVFSAccess(%s, %d)", zName, flags);
273 : #endif
274 : VSIStatBufL sStatBufL;
275 : int nRet;
276 2789 : if (flags == SQLITE_ACCESS_EXISTS)
277 : {
278 : /* Do not try to check the presence of a journal on /vsicurl ! */
279 2812 : if ( strncmp(zName, "/vsicurl/", 9) == 0 &&
280 : strlen(zName) > strlen("-journal") &&
281 : strcmp(zName + strlen(zName) - strlen("-journal"), "-journal") == 0 )
282 23 : nRet = -1;
283 : else
284 2766 : nRet = VSIStatExL(zName, &sStatBufL, VSI_STAT_EXISTS_FLAG);
285 : }
286 0 : else if (flags == SQLITE_ACCESS_READ)
287 : {
288 0 : VSILFILE* fp = VSIFOpenL(zName, "rb");
289 0 : nRet = fp ? 0 : -1;
290 0 : if (fp)
291 0 : VSIFCloseL(fp);
292 : }
293 0 : else if (flags == SQLITE_ACCESS_READWRITE)
294 : {
295 0 : VSILFILE* fp = VSIFOpenL(zName, "rb+");
296 0 : nRet = fp ? 0 : -1;
297 0 : if (fp)
298 0 : VSIFCloseL(fp);
299 : }
300 : else
301 0 : nRet = -1;
302 2789 : *pResOut = (nRet == 0);
303 2789 : return SQLITE_OK;
304 : }
305 :
306 466 : static int OGRSQLiteVFSFullPathname (sqlite3_vfs* pVFS, const char *zName, int nOut, char *zOut)
307 : {
308 466 : sqlite3_vfs* pUnderlyingVFS = GET_UNDERLYING_VFS(pVFS);
309 : #ifdef DEBUG_IO
310 : CPLDebug("SQLITE", "OGRSQLiteVFSFullPathname(%s)", zName);
311 : #endif
312 466 : if (zName[0] == '/')
313 : {
314 466 : strncpy(zOut, zName, nOut);
315 466 : zOut[nOut-1] = '\0';
316 466 : return SQLITE_OK;
317 : }
318 0 : return pUnderlyingVFS->xFullPathname(pUnderlyingVFS, zName, nOut, zOut);
319 : }
320 :
321 0 : static void* OGRSQLiteVFSDlOpen (sqlite3_vfs* pVFS, const char *zFilename)
322 : {
323 0 : sqlite3_vfs* pUnderlyingVFS = GET_UNDERLYING_VFS(pVFS);
324 : //CPLDebug("SQLITE", "OGRSQLiteVFSDlOpen(%s)", zFilename);
325 0 : return pUnderlyingVFS->xDlOpen(pUnderlyingVFS, zFilename);
326 : }
327 :
328 0 : static void OGRSQLiteVFSDlError (sqlite3_vfs* pVFS, int nByte, char *zErrMsg)
329 : {
330 0 : sqlite3_vfs* pUnderlyingVFS = GET_UNDERLYING_VFS(pVFS);
331 : //CPLDebug("SQLITE", "OGRSQLiteVFSDlError()");
332 0 : pUnderlyingVFS->xDlError(pUnderlyingVFS, nByte, zErrMsg);
333 0 : }
334 :
335 : /* xDlSym member signature changed in sqlite 3.6.7 (http://www.sqlite.org/changes.html) */
336 : /* This was supposed to be done "in a way that is backwards compatible but which might cause compiler warnings" */
337 : /* Perhaps in C, but definitely not in C++ ( #4515 ) */
338 : #if SQLITE_VERSION_NUMBER >= 3006007
339 0 : static void (*OGRSQLiteVFSDlSym (sqlite3_vfs* pVFS,void* pHandle, const char *zSymbol))(void)
340 : #else
341 : static void (*OGRSQLiteVFSDlSym (sqlite3_vfs* pVFS,void* pHandle, const char *zSymbol))
342 : #endif
343 : {
344 0 : sqlite3_vfs* pUnderlyingVFS = GET_UNDERLYING_VFS(pVFS);
345 : //CPLDebug("SQLITE", "OGRSQLiteVFSDlSym(%s)", zSymbol);
346 0 : return pUnderlyingVFS->xDlSym(pUnderlyingVFS, pHandle, zSymbol);
347 : }
348 :
349 0 : static void OGRSQLiteVFSDlClose (sqlite3_vfs* pVFS, void* pHandle)
350 : {
351 0 : sqlite3_vfs* pUnderlyingVFS = GET_UNDERLYING_VFS(pVFS);
352 : //CPLDebug("SQLITE", "OGRSQLiteVFSDlClose(%p)", pHandle);
353 0 : pUnderlyingVFS->xDlClose(pUnderlyingVFS, pHandle);
354 0 : }
355 :
356 0 : static int OGRSQLiteVFSRandomness (sqlite3_vfs* pVFS, int nByte, char *zOut)
357 : {
358 0 : sqlite3_vfs* pUnderlyingVFS = GET_UNDERLYING_VFS(pVFS);
359 : //CPLDebug("SQLITE", "OGRSQLiteVFSRandomness()");
360 0 : return pUnderlyingVFS->xRandomness(pUnderlyingVFS, nByte, zOut);
361 : }
362 :
363 0 : static int OGRSQLiteVFSSleep (sqlite3_vfs* pVFS, int microseconds)
364 : {
365 0 : sqlite3_vfs* pUnderlyingVFS = GET_UNDERLYING_VFS(pVFS);
366 : //CPLDebug("SQLITE", "OGRSQLiteVFSSleep()");
367 0 : return pUnderlyingVFS->xSleep(pUnderlyingVFS, microseconds);
368 : }
369 :
370 6 : static int OGRSQLiteVFSCurrentTime (sqlite3_vfs* pVFS, double* p1)
371 : {
372 6 : sqlite3_vfs* pUnderlyingVFS = GET_UNDERLYING_VFS(pVFS);
373 : //CPLDebug("SQLITE", "OGRSQLiteVFSCurrentTime()");
374 6 : return pUnderlyingVFS->xCurrentTime(pUnderlyingVFS, p1);
375 : }
376 :
377 0 : static int OGRSQLiteVFSGetLastError (sqlite3_vfs* pVFS, int p1, char *p2)
378 : {
379 0 : sqlite3_vfs* pUnderlyingVFS = GET_UNDERLYING_VFS(pVFS);
380 : //CPLDebug("SQLITE", "OGRSQLiteVFSGetLastError()");
381 0 : return pUnderlyingVFS->xGetLastError(pUnderlyingVFS, p1, p2);
382 : }
383 :
384 466 : sqlite3_vfs* OGRSQLiteCreateVFS(pfnNotifyFileOpenedType pfn, void* pfnUserData)
385 : {
386 466 : sqlite3_vfs* pDefaultVFS = sqlite3_vfs_find(NULL);
387 466 : sqlite3_vfs* pMyVFS = (sqlite3_vfs*) CPLCalloc(1, sizeof(sqlite3_vfs));
388 :
389 : OGRSQLiteVFSAppDataStruct* pVFSAppData =
390 466 : (OGRSQLiteVFSAppDataStruct*) CPLCalloc(1, sizeof(OGRSQLiteVFSAppDataStruct));
391 466 : sprintf(pVFSAppData->szVFSName, "OGRSQLITEVFS_%p", pVFSAppData);
392 466 : pVFSAppData->pDefaultVFS = pDefaultVFS;
393 466 : pVFSAppData->pfn = pfn;
394 466 : pVFSAppData->pfnUserData = pfnUserData;
395 466 : pVFSAppData->nCounter = 0;
396 :
397 466 : pMyVFS->iVersion = 1;
398 466 : pMyVFS->szOsFile = sizeof(OGRSQLiteFileStruct);
399 466 : pMyVFS->mxPathname = pDefaultVFS->mxPathname;
400 466 : pMyVFS->zName = pVFSAppData->szVFSName;
401 466 : pMyVFS->pAppData = pVFSAppData;
402 466 : pMyVFS->xOpen = OGRSQLiteVFSOpen;
403 466 : pMyVFS->xDelete = OGRSQLiteVFSDelete;
404 466 : pMyVFS->xAccess = OGRSQLiteVFSAccess;
405 466 : pMyVFS->xFullPathname = OGRSQLiteVFSFullPathname;
406 466 : pMyVFS->xDlOpen = OGRSQLiteVFSDlOpen;
407 466 : pMyVFS->xDlError = OGRSQLiteVFSDlError;
408 466 : pMyVFS->xDlSym = OGRSQLiteVFSDlSym;
409 466 : pMyVFS->xDlClose = OGRSQLiteVFSDlClose;
410 466 : pMyVFS->xRandomness = OGRSQLiteVFSRandomness;
411 466 : pMyVFS->xSleep = OGRSQLiteVFSSleep;
412 466 : pMyVFS->xCurrentTime = OGRSQLiteVFSCurrentTime;
413 466 : pMyVFS->xGetLastError = OGRSQLiteVFSGetLastError;
414 466 : return pMyVFS;
415 : }
416 :
417 : #endif // HAVE_SQLITE_VFS
|