xref: /sqlite-3.40.0/ext/misc/memvfs.c (revision a959bf53)
1d609bdb9Sdrh /*
2d609bdb9Sdrh ** 2016-09-07
3d609bdb9Sdrh **
4d609bdb9Sdrh ** The author disclaims copyright to this source code.  In place of
5d609bdb9Sdrh ** a legal notice, here is a blessing:
6d609bdb9Sdrh **
7d609bdb9Sdrh **    May you do good and not evil.
8d609bdb9Sdrh **    May you find forgiveness for yourself and forgive others.
9d609bdb9Sdrh **    May you share freely, never taking more than you give.
10d609bdb9Sdrh **
11d609bdb9Sdrh ******************************************************************************
12d609bdb9Sdrh **
13595a0e2aSdrh ** This is an in-memory VFS implementation.  The application supplies
14595a0e2aSdrh ** a chunk of memory to hold the database file.
15d609bdb9Sdrh **
16595a0e2aSdrh ** Because there is place to store a rollback or wal journal, the database
17595a0e2aSdrh ** must use one of journal_mode=MEMORY or journal_mode=NONE.
18d609bdb9Sdrh **
19d609bdb9Sdrh ** USAGE:
20d609bdb9Sdrh **
21595a0e2aSdrh **    sqlite3_open_v2("file:/whatever?ptr=0xf05538&sz=14336&max=65536", &db,
22595a0e2aSdrh **                    SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI,
23d609bdb9Sdrh **                    "memvfs");
24d609bdb9Sdrh **
25595a0e2aSdrh ** These are the query parameters:
26595a0e2aSdrh **
27595a0e2aSdrh **    ptr=          The address of the memory buffer that holds the database.
28595a0e2aSdrh **
29595a0e2aSdrh **    sz=           The current size the database file
30595a0e2aSdrh **
31595a0e2aSdrh **    maxsz=        The maximum size of the database.  In other words, the
32595a0e2aSdrh **                  amount of space allocated for the ptr= buffer.
33595a0e2aSdrh **
34595a0e2aSdrh **    freeonclose=  If true, then sqlite3_free() is called on the ptr=
35595a0e2aSdrh **                  value when the connection closes.
36595a0e2aSdrh **
37595a0e2aSdrh ** The ptr= and sz= query parameters are required.  If maxsz= is omitted,
38595a0e2aSdrh ** then it defaults to the sz= value.  Parameter values can be in either
39595a0e2aSdrh ** decimal or hexadecimal.  The filename in the URI is ignored.
40d609bdb9Sdrh */
41d609bdb9Sdrh #include <sqlite3ext.h>
42d609bdb9Sdrh SQLITE_EXTENSION_INIT1
43d609bdb9Sdrh #include <string.h>
44d609bdb9Sdrh #include <assert.h>
45d609bdb9Sdrh 
46d609bdb9Sdrh 
47d609bdb9Sdrh /*
48d609bdb9Sdrh ** Forward declaration of objects used by this utility
49d609bdb9Sdrh */
50d609bdb9Sdrh typedef struct sqlite3_vfs MemVfs;
51d609bdb9Sdrh typedef struct MemFile MemFile;
52d609bdb9Sdrh 
53d609bdb9Sdrh /* Access to a lower-level VFS that (might) implement dynamic loading,
54d609bdb9Sdrh ** access to randomness, etc.
55d609bdb9Sdrh */
56d609bdb9Sdrh #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
57d609bdb9Sdrh 
58d609bdb9Sdrh /* An open file */
59d609bdb9Sdrh struct MemFile {
60d609bdb9Sdrh   sqlite3_file base;              /* IO methods */
61d609bdb9Sdrh   sqlite3_int64 sz;               /* Size of the file */
62595a0e2aSdrh   sqlite3_int64 szMax;            /* Space allocated to aData */
63d609bdb9Sdrh   unsigned char *aData;           /* content of the file */
64595a0e2aSdrh   int bFreeOnClose;               /* Invoke sqlite3_free() on aData at close */
65d609bdb9Sdrh };
66d609bdb9Sdrh 
67d609bdb9Sdrh /*
68d609bdb9Sdrh ** Methods for MemFile
69d609bdb9Sdrh */
70d609bdb9Sdrh static int memClose(sqlite3_file*);
71d609bdb9Sdrh static int memRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
72d609bdb9Sdrh static int memWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
73d609bdb9Sdrh static int memTruncate(sqlite3_file*, sqlite3_int64 size);
74d609bdb9Sdrh static int memSync(sqlite3_file*, int flags);
75d609bdb9Sdrh static int memFileSize(sqlite3_file*, sqlite3_int64 *pSize);
76d609bdb9Sdrh static int memLock(sqlite3_file*, int);
77d609bdb9Sdrh static int memUnlock(sqlite3_file*, int);
78d609bdb9Sdrh static int memCheckReservedLock(sqlite3_file*, int *pResOut);
79d609bdb9Sdrh static int memFileControl(sqlite3_file*, int op, void *pArg);
80d609bdb9Sdrh static int memSectorSize(sqlite3_file*);
81d609bdb9Sdrh static int memDeviceCharacteristics(sqlite3_file*);
82d609bdb9Sdrh static int memShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
83d609bdb9Sdrh static int memShmLock(sqlite3_file*, int offset, int n, int flags);
84d609bdb9Sdrh static void memShmBarrier(sqlite3_file*);
85d609bdb9Sdrh static int memShmUnmap(sqlite3_file*, int deleteFlag);
86d609bdb9Sdrh static int memFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
87d609bdb9Sdrh static int memUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
88d609bdb9Sdrh 
89d609bdb9Sdrh /*
90d609bdb9Sdrh ** Methods for MemVfs
91d609bdb9Sdrh */
92d609bdb9Sdrh static int memOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
93d609bdb9Sdrh static int memDelete(sqlite3_vfs*, const char *zName, int syncDir);
94d609bdb9Sdrh static int memAccess(sqlite3_vfs*, const char *zName, int flags, int *);
95d609bdb9Sdrh static int memFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
96d609bdb9Sdrh static void *memDlOpen(sqlite3_vfs*, const char *zFilename);
97d609bdb9Sdrh static void memDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
98d609bdb9Sdrh static void (*memDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
99d609bdb9Sdrh static void memDlClose(sqlite3_vfs*, void*);
100d609bdb9Sdrh static int memRandomness(sqlite3_vfs*, int nByte, char *zOut);
101d609bdb9Sdrh static int memSleep(sqlite3_vfs*, int microseconds);
102d609bdb9Sdrh static int memCurrentTime(sqlite3_vfs*, double*);
103d609bdb9Sdrh static int memGetLastError(sqlite3_vfs*, int, char *);
104d609bdb9Sdrh static int memCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
105d609bdb9Sdrh 
106d609bdb9Sdrh static sqlite3_vfs mem_vfs = {
107d609bdb9Sdrh   2,                           /* iVersion */
108d609bdb9Sdrh   0,                           /* szOsFile (set when registered) */
109d609bdb9Sdrh   1024,                        /* mxPathname */
110d609bdb9Sdrh   0,                           /* pNext */
111d609bdb9Sdrh   "memvfs",                    /* zName */
112d609bdb9Sdrh   0,                           /* pAppData (set when registered) */
113d609bdb9Sdrh   memOpen,                     /* xOpen */
114d609bdb9Sdrh   memDelete,                   /* xDelete */
115d609bdb9Sdrh   memAccess,                   /* xAccess */
116d609bdb9Sdrh   memFullPathname,             /* xFullPathname */
117d609bdb9Sdrh   memDlOpen,                   /* xDlOpen */
118d609bdb9Sdrh   memDlError,                  /* xDlError */
119d609bdb9Sdrh   memDlSym,                    /* xDlSym */
120d609bdb9Sdrh   memDlClose,                  /* xDlClose */
121d609bdb9Sdrh   memRandomness,               /* xRandomness */
122d609bdb9Sdrh   memSleep,                    /* xSleep */
123d609bdb9Sdrh   memCurrentTime,              /* xCurrentTime */
124d609bdb9Sdrh   memGetLastError,             /* xGetLastError */
125d609bdb9Sdrh   memCurrentTimeInt64          /* xCurrentTimeInt64 */
126d609bdb9Sdrh };
127d609bdb9Sdrh 
128d609bdb9Sdrh static const sqlite3_io_methods mem_io_methods = {
129d609bdb9Sdrh   3,                              /* iVersion */
130d609bdb9Sdrh   memClose,                      /* xClose */
131d609bdb9Sdrh   memRead,                       /* xRead */
132d609bdb9Sdrh   memWrite,                      /* xWrite */
133d609bdb9Sdrh   memTruncate,                   /* xTruncate */
134d609bdb9Sdrh   memSync,                       /* xSync */
135d609bdb9Sdrh   memFileSize,                   /* xFileSize */
136d609bdb9Sdrh   memLock,                       /* xLock */
137d609bdb9Sdrh   memUnlock,                     /* xUnlock */
138d609bdb9Sdrh   memCheckReservedLock,          /* xCheckReservedLock */
139d609bdb9Sdrh   memFileControl,                /* xFileControl */
140d609bdb9Sdrh   memSectorSize,                 /* xSectorSize */
141d609bdb9Sdrh   memDeviceCharacteristics,      /* xDeviceCharacteristics */
142d609bdb9Sdrh   memShmMap,                     /* xShmMap */
143d609bdb9Sdrh   memShmLock,                    /* xShmLock */
144d609bdb9Sdrh   memShmBarrier,                 /* xShmBarrier */
145d609bdb9Sdrh   memShmUnmap,                   /* xShmUnmap */
146d609bdb9Sdrh   memFetch,                      /* xFetch */
147d609bdb9Sdrh   memUnfetch                     /* xUnfetch */
148d609bdb9Sdrh };
149d609bdb9Sdrh 
150d609bdb9Sdrh 
151d609bdb9Sdrh 
152d609bdb9Sdrh /*
153d609bdb9Sdrh ** Close an mem-file.
154d609bdb9Sdrh **
155d609bdb9Sdrh ** The pData pointer is owned by the application, so there is nothing
156d609bdb9Sdrh ** to free.
157d609bdb9Sdrh */
memClose(sqlite3_file * pFile)158d609bdb9Sdrh static int memClose(sqlite3_file *pFile){
159595a0e2aSdrh   MemFile *p = (MemFile *)pFile;
160595a0e2aSdrh   if( p->bFreeOnClose ) sqlite3_free(p->aData);
161d609bdb9Sdrh   return SQLITE_OK;
162d609bdb9Sdrh }
163d609bdb9Sdrh 
164d609bdb9Sdrh /*
165d609bdb9Sdrh ** Read data from an mem-file.
166d609bdb9Sdrh */
memRead(sqlite3_file * pFile,void * zBuf,int iAmt,sqlite_int64 iOfst)167d609bdb9Sdrh static int memRead(
168d609bdb9Sdrh   sqlite3_file *pFile,
169d609bdb9Sdrh   void *zBuf,
170d609bdb9Sdrh   int iAmt,
171d609bdb9Sdrh   sqlite_int64 iOfst
172d609bdb9Sdrh ){
173d609bdb9Sdrh   MemFile *p = (MemFile *)pFile;
174d609bdb9Sdrh   memcpy(zBuf, p->aData+iOfst, iAmt);
175d609bdb9Sdrh   return SQLITE_OK;
176d609bdb9Sdrh }
177d609bdb9Sdrh 
178d609bdb9Sdrh /*
179d609bdb9Sdrh ** Write data to an mem-file.
180d609bdb9Sdrh */
memWrite(sqlite3_file * pFile,const void * z,int iAmt,sqlite_int64 iOfst)181d609bdb9Sdrh static int memWrite(
182d609bdb9Sdrh   sqlite3_file *pFile,
183d609bdb9Sdrh   const void *z,
184d609bdb9Sdrh   int iAmt,
185d609bdb9Sdrh   sqlite_int64 iOfst
186d609bdb9Sdrh ){
187595a0e2aSdrh   MemFile *p = (MemFile *)pFile;
188595a0e2aSdrh   if( iOfst+iAmt>p->sz ){
189595a0e2aSdrh     if( iOfst+iAmt>p->szMax ) return SQLITE_FULL;
190595a0e2aSdrh     if( iOfst>p->sz ) memset(p->aData+p->sz, 0, iOfst-p->sz);
191595a0e2aSdrh     p->sz = iOfst+iAmt;
192595a0e2aSdrh   }
193595a0e2aSdrh   memcpy(p->aData+iOfst, z, iAmt);
194595a0e2aSdrh   return SQLITE_OK;
195d609bdb9Sdrh }
196d609bdb9Sdrh 
197d609bdb9Sdrh /*
198d609bdb9Sdrh ** Truncate an mem-file.
199d609bdb9Sdrh */
memTruncate(sqlite3_file * pFile,sqlite_int64 size)200d609bdb9Sdrh static int memTruncate(sqlite3_file *pFile, sqlite_int64 size){
201595a0e2aSdrh   MemFile *p = (MemFile *)pFile;
202595a0e2aSdrh   if( size>p->sz ){
203595a0e2aSdrh     if( size>p->szMax ) return SQLITE_FULL;
204595a0e2aSdrh     memset(p->aData+p->sz, 0, size-p->sz);
205595a0e2aSdrh   }
206595a0e2aSdrh   p->sz = size;
207595a0e2aSdrh   return SQLITE_OK;
208d609bdb9Sdrh }
209d609bdb9Sdrh 
210d609bdb9Sdrh /*
211d609bdb9Sdrh ** Sync an mem-file.
212d609bdb9Sdrh */
memSync(sqlite3_file * pFile,int flags)213d609bdb9Sdrh static int memSync(sqlite3_file *pFile, int flags){
214595a0e2aSdrh   return SQLITE_OK;
215d609bdb9Sdrh }
216d609bdb9Sdrh 
217d609bdb9Sdrh /*
218d609bdb9Sdrh ** Return the current file-size of an mem-file.
219d609bdb9Sdrh */
memFileSize(sqlite3_file * pFile,sqlite_int64 * pSize)220d609bdb9Sdrh static int memFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
221d609bdb9Sdrh   MemFile *p = (MemFile *)pFile;
222d609bdb9Sdrh   *pSize = p->sz;
223d609bdb9Sdrh   return SQLITE_OK;
224d609bdb9Sdrh }
225d609bdb9Sdrh 
226d609bdb9Sdrh /*
227d609bdb9Sdrh ** Lock an mem-file.
228d609bdb9Sdrh */
memLock(sqlite3_file * pFile,int eLock)229d609bdb9Sdrh static int memLock(sqlite3_file *pFile, int eLock){
230595a0e2aSdrh   return SQLITE_OK;
231d609bdb9Sdrh }
232d609bdb9Sdrh 
233d609bdb9Sdrh /*
234d609bdb9Sdrh ** Unlock an mem-file.
235d609bdb9Sdrh */
memUnlock(sqlite3_file * pFile,int eLock)236d609bdb9Sdrh static int memUnlock(sqlite3_file *pFile, int eLock){
237d609bdb9Sdrh   return SQLITE_OK;
238d609bdb9Sdrh }
239d609bdb9Sdrh 
240d609bdb9Sdrh /*
241d609bdb9Sdrh ** Check if another file-handle holds a RESERVED lock on an mem-file.
242d609bdb9Sdrh */
memCheckReservedLock(sqlite3_file * pFile,int * pResOut)243d609bdb9Sdrh static int memCheckReservedLock(sqlite3_file *pFile, int *pResOut){
244d609bdb9Sdrh   *pResOut = 0;
245d609bdb9Sdrh   return SQLITE_OK;
246d609bdb9Sdrh }
247d609bdb9Sdrh 
248d609bdb9Sdrh /*
249d609bdb9Sdrh ** File control method. For custom operations on an mem-file.
250d609bdb9Sdrh */
memFileControl(sqlite3_file * pFile,int op,void * pArg)251d609bdb9Sdrh static int memFileControl(sqlite3_file *pFile, int op, void *pArg){
252d609bdb9Sdrh   MemFile *p = (MemFile *)pFile;
253d609bdb9Sdrh   int rc = SQLITE_NOTFOUND;
254d609bdb9Sdrh   if( op==SQLITE_FCNTL_VFSNAME ){
255d609bdb9Sdrh     *(char**)pArg = sqlite3_mprintf("mem(%p,%lld)", p->aData, p->sz);
256d609bdb9Sdrh     rc = SQLITE_OK;
257d609bdb9Sdrh   }
258d609bdb9Sdrh   return rc;
259d609bdb9Sdrh }
260d609bdb9Sdrh 
261d609bdb9Sdrh /*
262d609bdb9Sdrh ** Return the sector-size in bytes for an mem-file.
263d609bdb9Sdrh */
memSectorSize(sqlite3_file * pFile)264d609bdb9Sdrh static int memSectorSize(sqlite3_file *pFile){
265d609bdb9Sdrh   return 1024;
266d609bdb9Sdrh }
267d609bdb9Sdrh 
268d609bdb9Sdrh /*
269d609bdb9Sdrh ** Return the device characteristic flags supported by an mem-file.
270d609bdb9Sdrh */
memDeviceCharacteristics(sqlite3_file * pFile)271d609bdb9Sdrh static int memDeviceCharacteristics(sqlite3_file *pFile){
272595a0e2aSdrh   return SQLITE_IOCAP_ATOMIC |
273595a0e2aSdrh          SQLITE_IOCAP_POWERSAFE_OVERWRITE |
274595a0e2aSdrh          SQLITE_IOCAP_SAFE_APPEND |
275595a0e2aSdrh          SQLITE_IOCAP_SEQUENTIAL;
276d609bdb9Sdrh }
277d609bdb9Sdrh 
278d609bdb9Sdrh /* Create a shared memory file mapping */
memShmMap(sqlite3_file * pFile,int iPg,int pgsz,int bExtend,void volatile ** pp)279d609bdb9Sdrh static int memShmMap(
280d609bdb9Sdrh   sqlite3_file *pFile,
281d609bdb9Sdrh   int iPg,
282d609bdb9Sdrh   int pgsz,
283d609bdb9Sdrh   int bExtend,
284d609bdb9Sdrh   void volatile **pp
285d609bdb9Sdrh ){
286595a0e2aSdrh   return SQLITE_IOERR_SHMMAP;
287d609bdb9Sdrh }
288d609bdb9Sdrh 
289d609bdb9Sdrh /* Perform locking on a shared-memory segment */
memShmLock(sqlite3_file * pFile,int offset,int n,int flags)290d609bdb9Sdrh static int memShmLock(sqlite3_file *pFile, int offset, int n, int flags){
291595a0e2aSdrh   return SQLITE_IOERR_SHMLOCK;
292d609bdb9Sdrh }
293d609bdb9Sdrh 
294d609bdb9Sdrh /* Memory barrier operation on shared memory */
memShmBarrier(sqlite3_file * pFile)295d609bdb9Sdrh static void memShmBarrier(sqlite3_file *pFile){
296d609bdb9Sdrh   return;
297d609bdb9Sdrh }
298d609bdb9Sdrh 
299d609bdb9Sdrh /* Unmap a shared memory segment */
memShmUnmap(sqlite3_file * pFile,int deleteFlag)300d609bdb9Sdrh static int memShmUnmap(sqlite3_file *pFile, int deleteFlag){
301d609bdb9Sdrh   return SQLITE_OK;
302d609bdb9Sdrh }
303d609bdb9Sdrh 
304d609bdb9Sdrh /* Fetch a page of a memory-mapped file */
memFetch(sqlite3_file * pFile,sqlite3_int64 iOfst,int iAmt,void ** pp)305d609bdb9Sdrh static int memFetch(
306d609bdb9Sdrh   sqlite3_file *pFile,
307d609bdb9Sdrh   sqlite3_int64 iOfst,
308d609bdb9Sdrh   int iAmt,
309d609bdb9Sdrh   void **pp
310d609bdb9Sdrh ){
311d609bdb9Sdrh   MemFile *p = (MemFile *)pFile;
312d609bdb9Sdrh   *pp = (void*)(p->aData + iOfst);
313d609bdb9Sdrh   return SQLITE_OK;
314d609bdb9Sdrh }
315d609bdb9Sdrh 
316d609bdb9Sdrh /* Release a memory-mapped page */
memUnfetch(sqlite3_file * pFile,sqlite3_int64 iOfst,void * pPage)317d609bdb9Sdrh static int memUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
318d609bdb9Sdrh   return SQLITE_OK;
319d609bdb9Sdrh }
320d609bdb9Sdrh 
321d609bdb9Sdrh /*
322d609bdb9Sdrh ** Open an mem file handle.
323d609bdb9Sdrh */
memOpen(sqlite3_vfs * pVfs,const char * zName,sqlite3_file * pFile,int flags,int * pOutFlags)324d609bdb9Sdrh static int memOpen(
325d609bdb9Sdrh   sqlite3_vfs *pVfs,
326d609bdb9Sdrh   const char *zName,
327d609bdb9Sdrh   sqlite3_file *pFile,
328d609bdb9Sdrh   int flags,
329d609bdb9Sdrh   int *pOutFlags
330d609bdb9Sdrh ){
331d609bdb9Sdrh   MemFile *p = (MemFile*)pFile;
332d609bdb9Sdrh   memset(p, 0, sizeof(*p));
333d609bdb9Sdrh   if( (flags & SQLITE_OPEN_MAIN_DB)==0 ) return SQLITE_CANTOPEN;
334d609bdb9Sdrh   p->aData = (unsigned char*)sqlite3_uri_int64(zName,"ptr",0);
335d609bdb9Sdrh   if( p->aData==0 ) return SQLITE_CANTOPEN;
336d609bdb9Sdrh   p->sz = sqlite3_uri_int64(zName,"sz",0);
337d609bdb9Sdrh   if( p->sz<0 ) return SQLITE_CANTOPEN;
338595a0e2aSdrh   p->szMax = sqlite3_uri_int64(zName,"max",p->sz);
339595a0e2aSdrh   if( p->szMax<p->sz ) return SQLITE_CANTOPEN;
340595a0e2aSdrh   p->bFreeOnClose = sqlite3_uri_boolean(zName,"freeonclose",0);
341d609bdb9Sdrh   pFile->pMethods = &mem_io_methods;
342d609bdb9Sdrh   return SQLITE_OK;
343d609bdb9Sdrh }
344d609bdb9Sdrh 
345d609bdb9Sdrh /*
346d609bdb9Sdrh ** Delete the file located at zPath. If the dirSync argument is true,
347d609bdb9Sdrh ** ensure the file-system modifications are synced to disk before
348d609bdb9Sdrh ** returning.
349d609bdb9Sdrh */
memDelete(sqlite3_vfs * pVfs,const char * zPath,int dirSync)350d609bdb9Sdrh static int memDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
351595a0e2aSdrh   return SQLITE_IOERR_DELETE;
352d609bdb9Sdrh }
353d609bdb9Sdrh 
354d609bdb9Sdrh /*
355d609bdb9Sdrh ** Test for access permissions. Return true if the requested permission
356d609bdb9Sdrh ** is available, or false otherwise.
357d609bdb9Sdrh */
memAccess(sqlite3_vfs * pVfs,const char * zPath,int flags,int * pResOut)358d609bdb9Sdrh static int memAccess(
359d609bdb9Sdrh   sqlite3_vfs *pVfs,
360d609bdb9Sdrh   const char *zPath,
361d609bdb9Sdrh   int flags,
362d609bdb9Sdrh   int *pResOut
363d609bdb9Sdrh ){
364d609bdb9Sdrh   *pResOut = 0;
365d609bdb9Sdrh   return SQLITE_OK;
366d609bdb9Sdrh }
367d609bdb9Sdrh 
368d609bdb9Sdrh /*
369d609bdb9Sdrh ** Populate buffer zOut with the full canonical pathname corresponding
370d609bdb9Sdrh ** to the pathname in zPath. zOut is guaranteed to point to a buffer
371d609bdb9Sdrh ** of at least (INST_MAX_PATHNAME+1) bytes.
372d609bdb9Sdrh */
memFullPathname(sqlite3_vfs * pVfs,const char * zPath,int nOut,char * zOut)373d609bdb9Sdrh static int memFullPathname(
374d609bdb9Sdrh   sqlite3_vfs *pVfs,
375d609bdb9Sdrh   const char *zPath,
376d609bdb9Sdrh   int nOut,
377d609bdb9Sdrh   char *zOut
378d609bdb9Sdrh ){
379d609bdb9Sdrh   sqlite3_snprintf(nOut, zOut, "%s", zPath);
380d609bdb9Sdrh   return SQLITE_OK;
381d609bdb9Sdrh }
382d609bdb9Sdrh 
383d609bdb9Sdrh /*
384d609bdb9Sdrh ** Open the dynamic library located at zPath and return a handle.
385d609bdb9Sdrh */
memDlOpen(sqlite3_vfs * pVfs,const char * zPath)386d609bdb9Sdrh static void *memDlOpen(sqlite3_vfs *pVfs, const char *zPath){
387d609bdb9Sdrh   return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
388d609bdb9Sdrh }
389d609bdb9Sdrh 
390d609bdb9Sdrh /*
391d609bdb9Sdrh ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
392d609bdb9Sdrh ** utf-8 string describing the most recent error encountered associated
393d609bdb9Sdrh ** with dynamic libraries.
394d609bdb9Sdrh */
memDlError(sqlite3_vfs * pVfs,int nByte,char * zErrMsg)395d609bdb9Sdrh static void memDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
396d609bdb9Sdrh   ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
397d609bdb9Sdrh }
398d609bdb9Sdrh 
399d609bdb9Sdrh /*
400d609bdb9Sdrh ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
401d609bdb9Sdrh */
memDlSym(sqlite3_vfs * pVfs,void * p,const char * zSym)402d609bdb9Sdrh static void (*memDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
403d609bdb9Sdrh   return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
404d609bdb9Sdrh }
405d609bdb9Sdrh 
406d609bdb9Sdrh /*
407d609bdb9Sdrh ** Close the dynamic library handle pHandle.
408d609bdb9Sdrh */
memDlClose(sqlite3_vfs * pVfs,void * pHandle)409d609bdb9Sdrh static void memDlClose(sqlite3_vfs *pVfs, void *pHandle){
410d609bdb9Sdrh   ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
411d609bdb9Sdrh }
412d609bdb9Sdrh 
413d609bdb9Sdrh /*
414d609bdb9Sdrh ** Populate the buffer pointed to by zBufOut with nByte bytes of
415d609bdb9Sdrh ** random data.
416d609bdb9Sdrh */
memRandomness(sqlite3_vfs * pVfs,int nByte,char * zBufOut)417d609bdb9Sdrh static int memRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
418d609bdb9Sdrh   return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
419d609bdb9Sdrh }
420d609bdb9Sdrh 
421d609bdb9Sdrh /*
422d609bdb9Sdrh ** Sleep for nMicro microseconds. Return the number of microseconds
423d609bdb9Sdrh ** actually slept.
424d609bdb9Sdrh */
memSleep(sqlite3_vfs * pVfs,int nMicro)425d609bdb9Sdrh static int memSleep(sqlite3_vfs *pVfs, int nMicro){
426d609bdb9Sdrh   return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
427d609bdb9Sdrh }
428d609bdb9Sdrh 
429d609bdb9Sdrh /*
430d609bdb9Sdrh ** Return the current time as a Julian Day number in *pTimeOut.
431d609bdb9Sdrh */
memCurrentTime(sqlite3_vfs * pVfs,double * pTimeOut)432d609bdb9Sdrh static int memCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
433d609bdb9Sdrh   return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
434d609bdb9Sdrh }
435d609bdb9Sdrh 
memGetLastError(sqlite3_vfs * pVfs,int a,char * b)436d609bdb9Sdrh static int memGetLastError(sqlite3_vfs *pVfs, int a, char *b){
437d609bdb9Sdrh   return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
438d609bdb9Sdrh }
memCurrentTimeInt64(sqlite3_vfs * pVfs,sqlite3_int64 * p)439d609bdb9Sdrh static int memCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
440d609bdb9Sdrh   return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);
441d609bdb9Sdrh }
442d609bdb9Sdrh 
443d609bdb9Sdrh #ifdef MEMVFS_TEST
444d609bdb9Sdrh /*
445595a0e2aSdrh **       memvfs_from_file(FILENAME, MAXSIZE)
446d609bdb9Sdrh **
447d609bdb9Sdrh ** This an SQL function used to help in testing the memvfs VFS.  The
448d609bdb9Sdrh ** function reads the content of a file into memory and then returns
449595a0e2aSdrh ** a URI that can be handed to ATTACH to attach the memory buffer as
450595a0e2aSdrh ** a database.  Example:
451595a0e2aSdrh **
452595a0e2aSdrh **       ATTACH memvfs_from_file('test.db',1048576) AS inmem;
453595a0e2aSdrh **
454595a0e2aSdrh ** The optional MAXSIZE argument gives the size of the memory allocation
455595a0e2aSdrh ** used to hold the database.  If omitted, it defaults to the size of the
456595a0e2aSdrh ** file on disk.
457d609bdb9Sdrh */
458d609bdb9Sdrh #include <stdio.h>
memvfsFromFileFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)459595a0e2aSdrh static void memvfsFromFileFunc(
460d609bdb9Sdrh   sqlite3_context *context,
461d609bdb9Sdrh   int argc,
462d609bdb9Sdrh   sqlite3_value **argv
463d609bdb9Sdrh ){
464d609bdb9Sdrh   unsigned char *p;
465d609bdb9Sdrh   sqlite3_int64 sz;
466595a0e2aSdrh   sqlite3_int64 szMax;
467d609bdb9Sdrh   FILE *in;
468d609bdb9Sdrh   const char *zFilename = (const char*)sqlite3_value_text(argv[0]);
469595a0e2aSdrh   char *zUri;
470d609bdb9Sdrh 
471d609bdb9Sdrh   if( zFilename==0 ) return;
472d609bdb9Sdrh   in = fopen(zFilename, "rb");
473d609bdb9Sdrh   if( in==0 ) return;
474d609bdb9Sdrh   fseek(in, 0, SEEK_END);
475595a0e2aSdrh   szMax = sz = ftell(in);
476d609bdb9Sdrh   rewind(in);
477595a0e2aSdrh   if( argc>=2 ){
478595a0e2aSdrh     szMax = sqlite3_value_int64(argv[1]);
479595a0e2aSdrh     if( szMax<sz ) szMax = sz;
480595a0e2aSdrh   }
481595a0e2aSdrh   p = sqlite3_malloc64( szMax );
482d609bdb9Sdrh   if( p==0 ){
483d609bdb9Sdrh     fclose(in);
484d609bdb9Sdrh     sqlite3_result_error_nomem(context);
485d609bdb9Sdrh     return;
486d609bdb9Sdrh   }
487d609bdb9Sdrh   fread(p, sz, 1, in);
488d609bdb9Sdrh   fclose(in);
489595a0e2aSdrh   zUri = sqlite3_mprintf(
490595a0e2aSdrh            "file:/mem?vfs=memvfs&ptr=%lld&sz=%lld&max=%lld&freeonclose=1",
491595a0e2aSdrh                          (sqlite3_int64)p, sz, szMax);
492595a0e2aSdrh   sqlite3_result_text(context, zUri, -1, sqlite3_free);
493d609bdb9Sdrh }
494595a0e2aSdrh #endif /* MEMVFS_TEST */
495595a0e2aSdrh 
496595a0e2aSdrh #ifdef MEMVFS_TEST
497595a0e2aSdrh /*
498595a0e2aSdrh **       memvfs_to_file(SCHEMA, FILENAME)
499595a0e2aSdrh **
500595a0e2aSdrh ** The schema identified by SCHEMA must be a memvfs database.  Write
501595a0e2aSdrh ** the content of this database into FILENAME.
502595a0e2aSdrh */
memvfsToFileFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)503595a0e2aSdrh static void memvfsToFileFunc(
504595a0e2aSdrh   sqlite3_context *context,
505595a0e2aSdrh   int argc,
506595a0e2aSdrh   sqlite3_value **argv
507595a0e2aSdrh ){
508595a0e2aSdrh   MemFile *p = 0;
509595a0e2aSdrh   FILE *out;
510595a0e2aSdrh   int rc;
511595a0e2aSdrh   sqlite3 *db = sqlite3_context_db_handle(context);
512595a0e2aSdrh   sqlite3_vfs *pVfs = 0;
513595a0e2aSdrh   const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
514595a0e2aSdrh   const char *zFilename = (const char*)sqlite3_value_text(argv[1]);
515595a0e2aSdrh 
516595a0e2aSdrh   if( zFilename==0 ) return;
517595a0e2aSdrh   out = fopen(zFilename, "wb");
518595a0e2aSdrh   if( out==0 ) return;
519595a0e2aSdrh   rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_VFS_POINTER, &pVfs);
520595a0e2aSdrh   if( rc || pVfs==0 ) return;
521595a0e2aSdrh   if( strcmp(pVfs->zName,"memvfs")!=0 ) return;
522595a0e2aSdrh   rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p);
523595a0e2aSdrh   if( rc ) return;
524595a0e2aSdrh   fwrite(p->aData, 1, (size_t)p->sz, out);
525595a0e2aSdrh   fclose(out);
526595a0e2aSdrh }
527595a0e2aSdrh #endif /* MEMVFS_TEST */
528595a0e2aSdrh 
529595a0e2aSdrh #ifdef MEMVFS_TEST
530d609bdb9Sdrh /* Called for each new database connection */
memvfsRegister(sqlite3 * db,char ** pzErrMsg,const struct sqlite3_api_routines * pThunk)531d609bdb9Sdrh static int memvfsRegister(
532d609bdb9Sdrh   sqlite3 *db,
533595a0e2aSdrh   char **pzErrMsg,
534d609bdb9Sdrh   const struct sqlite3_api_routines *pThunk
535d609bdb9Sdrh ){
536595a0e2aSdrh   sqlite3_create_function(db, "memvfs_from_file", 1, SQLITE_UTF8, 0,
537595a0e2aSdrh                           memvfsFromFileFunc, 0, 0);
538595a0e2aSdrh   sqlite3_create_function(db, "memvfs_from_file", 2, SQLITE_UTF8, 0,
539595a0e2aSdrh                           memvfsFromFileFunc, 0, 0);
540595a0e2aSdrh   sqlite3_create_function(db, "memvfs_to_file", 2, SQLITE_UTF8, 0,
541595a0e2aSdrh                           memvfsToFileFunc, 0, 0);
542595a0e2aSdrh   return SQLITE_OK;
543d609bdb9Sdrh }
544d609bdb9Sdrh #endif /* MEMVFS_TEST */
545d609bdb9Sdrh 
546d609bdb9Sdrh 
547d609bdb9Sdrh #ifdef _WIN32
548d609bdb9Sdrh __declspec(dllexport)
549d609bdb9Sdrh #endif
550d609bdb9Sdrh /*
551d609bdb9Sdrh ** This routine is called when the extension is loaded.
552d609bdb9Sdrh ** Register the new VFS.
553d609bdb9Sdrh */
sqlite3_memvfs_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)554d609bdb9Sdrh int sqlite3_memvfs_init(
555d609bdb9Sdrh   sqlite3 *db,
556d609bdb9Sdrh   char **pzErrMsg,
557d609bdb9Sdrh   const sqlite3_api_routines *pApi
558d609bdb9Sdrh ){
559d609bdb9Sdrh   int rc = SQLITE_OK;
560d609bdb9Sdrh   SQLITE_EXTENSION_INIT2(pApi);
561d609bdb9Sdrh   mem_vfs.pAppData = sqlite3_vfs_find(0);
562*a959bf53Sdrh   if( mem_vfs.pAppData==0 ) return SQLITE_ERROR;
563d609bdb9Sdrh   mem_vfs.szOsFile = sizeof(MemFile);
564d609bdb9Sdrh   rc = sqlite3_vfs_register(&mem_vfs, 1);
565d609bdb9Sdrh #ifdef MEMVFS_TEST
566d609bdb9Sdrh   if( rc==SQLITE_OK ){
567d609bdb9Sdrh     rc = sqlite3_auto_extension((void(*)(void))memvfsRegister);
568d609bdb9Sdrh   }
569595a0e2aSdrh   if( rc==SQLITE_OK ){
570595a0e2aSdrh     rc = memvfsRegister(db, pzErrMsg, pApi);
571595a0e2aSdrh   }
572d609bdb9Sdrh #endif
573d609bdb9Sdrh   if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
574d609bdb9Sdrh   return rc;
575d609bdb9Sdrh }
576