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