blob: a48980aa341736fd918fa14ecf7f860a3e15ee44 [file] [log] [blame]
drhac442f42018-01-03 01:28:46 +00001/*
2** 2016-09-07
3**
4** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
6**
7** May you do good and not evil.
8** May you find forgiveness for yourself and forgive others.
9** May you share freely, never taking more than you give.
10**
11******************************************************************************
12**
drh840fda42018-03-28 15:06:39 +000013** This file implements an in-memory VFS. A database is held as a contiguous
drh99abe5c2018-01-03 22:48:38 +000014** block of memory.
15**
16** This file also implements interface sqlite3_serialize() and
17** sqlite3_deserialize().
drhac442f42018-01-03 01:28:46 +000018*/
drhac442f42018-01-03 01:28:46 +000019#include "sqliteInt.h"
mistachkined008ec2018-09-12 01:05:26 +000020#ifdef SQLITE_ENABLE_DESERIALIZE
drhac442f42018-01-03 01:28:46 +000021
22/*
23** Forward declaration of objects used by this utility
24*/
25typedef struct sqlite3_vfs MemVfs;
26typedef struct MemFile MemFile;
27
28/* Access to a lower-level VFS that (might) implement dynamic loading,
29** access to randomness, etc.
30*/
31#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
32
33/* An open file */
34struct MemFile {
35 sqlite3_file base; /* IO methods */
36 sqlite3_int64 sz; /* Size of the file */
drh6ca64482019-01-22 16:06:20 +000037 sqlite3_int64 szAlloc; /* Space allocated to aData */
38 sqlite3_int64 szMax; /* Maximum allowed size of the file */
drhac442f42018-01-03 01:28:46 +000039 unsigned char *aData; /* content of the file */
40 int nMmap; /* Number of memory mapped pages */
41 unsigned mFlags; /* Flags */
42 int eLock; /* Most recent lock against this file */
43};
44
45/*
46** Methods for MemFile
47*/
48static int memdbClose(sqlite3_file*);
49static int memdbRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
50static int memdbWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
51static int memdbTruncate(sqlite3_file*, sqlite3_int64 size);
52static int memdbSync(sqlite3_file*, int flags);
53static int memdbFileSize(sqlite3_file*, sqlite3_int64 *pSize);
54static int memdbLock(sqlite3_file*, int);
drh14714162018-03-06 19:14:32 +000055/* static int memdbCheckReservedLock(sqlite3_file*, int *pResOut);// not used */
drhac442f42018-01-03 01:28:46 +000056static int memdbFileControl(sqlite3_file*, int op, void *pArg);
drh5f9d1922018-03-06 04:01:08 +000057/* static int memdbSectorSize(sqlite3_file*); // not used */
drhac442f42018-01-03 01:28:46 +000058static int memdbDeviceCharacteristics(sqlite3_file*);
drhac442f42018-01-03 01:28:46 +000059static int memdbFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
60static int memdbUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
61
62/*
63** Methods for MemVfs
64*/
65static int memdbOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
drh14714162018-03-06 19:14:32 +000066/* static int memdbDelete(sqlite3_vfs*, const char *zName, int syncDir); */
drhac442f42018-01-03 01:28:46 +000067static int memdbAccess(sqlite3_vfs*, const char *zName, int flags, int *);
68static int memdbFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
69static void *memdbDlOpen(sqlite3_vfs*, const char *zFilename);
70static void memdbDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
71static void (*memdbDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
72static void memdbDlClose(sqlite3_vfs*, void*);
73static int memdbRandomness(sqlite3_vfs*, int nByte, char *zOut);
74static int memdbSleep(sqlite3_vfs*, int microseconds);
drh14714162018-03-06 19:14:32 +000075/* static int memdbCurrentTime(sqlite3_vfs*, double*); */
drhac442f42018-01-03 01:28:46 +000076static int memdbGetLastError(sqlite3_vfs*, int, char *);
77static int memdbCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
78
79static sqlite3_vfs memdb_vfs = {
80 2, /* iVersion */
81 0, /* szOsFile (set when registered) */
82 1024, /* mxPathname */
83 0, /* pNext */
84 "memdb", /* zName */
85 0, /* pAppData (set when registered) */
86 memdbOpen, /* xOpen */
drh14714162018-03-06 19:14:32 +000087 0, /* memdbDelete, */ /* xDelete */
drhac442f42018-01-03 01:28:46 +000088 memdbAccess, /* xAccess */
89 memdbFullPathname, /* xFullPathname */
90 memdbDlOpen, /* xDlOpen */
91 memdbDlError, /* xDlError */
92 memdbDlSym, /* xDlSym */
93 memdbDlClose, /* xDlClose */
94 memdbRandomness, /* xRandomness */
95 memdbSleep, /* xSleep */
drh14714162018-03-06 19:14:32 +000096 0, /* memdbCurrentTime, */ /* xCurrentTime */
drhac442f42018-01-03 01:28:46 +000097 memdbGetLastError, /* xGetLastError */
98 memdbCurrentTimeInt64 /* xCurrentTimeInt64 */
99};
100
101static const sqlite3_io_methods memdb_io_methods = {
102 3, /* iVersion */
103 memdbClose, /* xClose */
104 memdbRead, /* xRead */
105 memdbWrite, /* xWrite */
106 memdbTruncate, /* xTruncate */
107 memdbSync, /* xSync */
108 memdbFileSize, /* xFileSize */
109 memdbLock, /* xLock */
110 memdbLock, /* xUnlock - same as xLock in this case */
drh14714162018-03-06 19:14:32 +0000111 0, /* memdbCheckReservedLock, */ /* xCheckReservedLock */
drhac442f42018-01-03 01:28:46 +0000112 memdbFileControl, /* xFileControl */
drh5f9d1922018-03-06 04:01:08 +0000113 0, /* memdbSectorSize,*/ /* xSectorSize */
drhac442f42018-01-03 01:28:46 +0000114 memdbDeviceCharacteristics, /* xDeviceCharacteristics */
drh99abe5c2018-01-03 22:48:38 +0000115 0, /* xShmMap */
116 0, /* xShmLock */
117 0, /* xShmBarrier */
118 0, /* xShmUnmap */
drhac442f42018-01-03 01:28:46 +0000119 memdbFetch, /* xFetch */
120 memdbUnfetch /* xUnfetch */
121};
122
123
124
125/*
126** Close an memdb-file.
127**
128** The pData pointer is owned by the application, so there is nothing
drhff01ee32020-10-17 22:13:16 +0000129** to free. Unless the SQLITE_DESERIALIZE_FREEONCLOSE flag is set,
130** in which case we own the pData pointer and need to free it.
drhac442f42018-01-03 01:28:46 +0000131*/
132static int memdbClose(sqlite3_file *pFile){
133 MemFile *p = (MemFile *)pFile;
drhff01ee32020-10-17 22:13:16 +0000134 if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ){
135 sqlite3_free(p->aData);
136 }
drhac442f42018-01-03 01:28:46 +0000137 return SQLITE_OK;
138}
139
140/*
141** Read data from an memdb-file.
142*/
143static int memdbRead(
144 sqlite3_file *pFile,
145 void *zBuf,
146 int iAmt,
147 sqlite_int64 iOfst
148){
149 MemFile *p = (MemFile *)pFile;
150 if( iOfst+iAmt>p->sz ){
151 memset(zBuf, 0, iAmt);
drhcb7d5412018-01-03 16:49:52 +0000152 if( iOfst<p->sz ) memcpy(zBuf, p->aData+iOfst, p->sz - iOfst);
drhac442f42018-01-03 01:28:46 +0000153 return SQLITE_IOERR_SHORT_READ;
154 }
155 memcpy(zBuf, p->aData+iOfst, iAmt);
156 return SQLITE_OK;
157}
158
159/*
160** Try to enlarge the memory allocation to hold at least sz bytes
161*/
162static int memdbEnlarge(MemFile *p, sqlite3_int64 newSz){
163 unsigned char *pNew;
drh5f9d1922018-03-06 04:01:08 +0000164 if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || p->nMmap>0 ){
165 return SQLITE_FULL;
166 }
drh6ca64482019-01-22 16:06:20 +0000167 if( newSz>p->szMax ){
168 return SQLITE_FULL;
169 }
170 newSz *= 2;
171 if( newSz>p->szMax ) newSz = p->szMax;
drhd924e7b2020-05-17 00:26:44 +0000172 pNew = sqlite3Realloc(p->aData, newSz);
drh5f9d1922018-03-06 04:01:08 +0000173 if( pNew==0 ) return SQLITE_NOMEM;
drhac442f42018-01-03 01:28:46 +0000174 p->aData = pNew;
drh6ca64482019-01-22 16:06:20 +0000175 p->szAlloc = newSz;
drhac442f42018-01-03 01:28:46 +0000176 return SQLITE_OK;
177}
178
179/*
180** Write data to an memdb-file.
181*/
182static int memdbWrite(
183 sqlite3_file *pFile,
184 const void *z,
185 int iAmt,
186 sqlite_int64 iOfst
187){
188 MemFile *p = (MemFile *)pFile;
drhf186f0b2019-01-22 16:43:47 +0000189 if( NEVER(p->mFlags & SQLITE_DESERIALIZE_READONLY) ) return SQLITE_READONLY;
drhac442f42018-01-03 01:28:46 +0000190 if( iOfst+iAmt>p->sz ){
drh5f9d1922018-03-06 04:01:08 +0000191 int rc;
drh6ca64482019-01-22 16:06:20 +0000192 if( iOfst+iAmt>p->szAlloc
193 && (rc = memdbEnlarge(p, iOfst+iAmt))!=SQLITE_OK
drh5f9d1922018-03-06 04:01:08 +0000194 ){
195 return rc;
drhac442f42018-01-03 01:28:46 +0000196 }
197 if( iOfst>p->sz ) memset(p->aData+p->sz, 0, iOfst-p->sz);
198 p->sz = iOfst+iAmt;
199 }
200 memcpy(p->aData+iOfst, z, iAmt);
201 return SQLITE_OK;
202}
203
204/*
205** Truncate an memdb-file.
drh14714162018-03-06 19:14:32 +0000206**
207** In rollback mode (which is always the case for memdb, as it does not
208** support WAL mode) the truncate() method is only used to reduce
209** the size of a file, never to increase the size.
drhac442f42018-01-03 01:28:46 +0000210*/
211static int memdbTruncate(sqlite3_file *pFile, sqlite_int64 size){
212 MemFile *p = (MemFile *)pFile;
drh14714162018-03-06 19:14:32 +0000213 if( NEVER(size>p->sz) ) return SQLITE_FULL;
drhac442f42018-01-03 01:28:46 +0000214 p->sz = size;
215 return SQLITE_OK;
216}
217
218/*
219** Sync an memdb-file.
220*/
221static int memdbSync(sqlite3_file *pFile, int flags){
222 return SQLITE_OK;
223}
224
225/*
226** Return the current file-size of an memdb-file.
227*/
228static int memdbFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
229 MemFile *p = (MemFile *)pFile;
230 *pSize = p->sz;
231 return SQLITE_OK;
232}
233
234/*
235** Lock an memdb-file.
236*/
237static int memdbLock(sqlite3_file *pFile, int eLock){
238 MemFile *p = (MemFile *)pFile;
drhf186f0b2019-01-22 16:43:47 +0000239 if( eLock>SQLITE_LOCK_SHARED
240 && (p->mFlags & SQLITE_DESERIALIZE_READONLY)!=0
241 ){
242 return SQLITE_READONLY;
243 }
drhac442f42018-01-03 01:28:46 +0000244 p->eLock = eLock;
245 return SQLITE_OK;
246}
247
drh14714162018-03-06 19:14:32 +0000248#if 0 /* Never used because memdbAccess() always returns false */
drhac442f42018-01-03 01:28:46 +0000249/*
250** Check if another file-handle holds a RESERVED lock on an memdb-file.
251*/
252static int memdbCheckReservedLock(sqlite3_file *pFile, int *pResOut){
253 *pResOut = 0;
254 return SQLITE_OK;
255}
drh14714162018-03-06 19:14:32 +0000256#endif
drhac442f42018-01-03 01:28:46 +0000257
258/*
259** File control method. For custom operations on an memdb-file.
260*/
261static int memdbFileControl(sqlite3_file *pFile, int op, void *pArg){
262 MemFile *p = (MemFile *)pFile;
263 int rc = SQLITE_NOTFOUND;
264 if( op==SQLITE_FCNTL_VFSNAME ){
265 *(char**)pArg = sqlite3_mprintf("memdb(%p,%lld)", p->aData, p->sz);
266 rc = SQLITE_OK;
267 }
drh6ca64482019-01-22 16:06:20 +0000268 if( op==SQLITE_FCNTL_SIZE_LIMIT ){
269 sqlite3_int64 iLimit = *(sqlite3_int64*)pArg;
270 if( iLimit<p->sz ){
271 if( iLimit<0 ){
272 iLimit = p->szMax;
273 }else{
274 iLimit = p->sz;
275 }
276 }
277 p->szMax = iLimit;
278 *(sqlite3_int64*)pArg = iLimit;
279 rc = SQLITE_OK;
280 }
drhac442f42018-01-03 01:28:46 +0000281 return rc;
282}
283
drh5f9d1922018-03-06 04:01:08 +0000284#if 0 /* Not used because of SQLITE_IOCAP_POWERSAFE_OVERWRITE */
drhac442f42018-01-03 01:28:46 +0000285/*
286** Return the sector-size in bytes for an memdb-file.
287*/
288static int memdbSectorSize(sqlite3_file *pFile){
289 return 1024;
290}
drh5f9d1922018-03-06 04:01:08 +0000291#endif
drhac442f42018-01-03 01:28:46 +0000292
293/*
294** Return the device characteristic flags supported by an memdb-file.
295*/
296static int memdbDeviceCharacteristics(sqlite3_file *pFile){
297 return SQLITE_IOCAP_ATOMIC |
298 SQLITE_IOCAP_POWERSAFE_OVERWRITE |
299 SQLITE_IOCAP_SAFE_APPEND |
300 SQLITE_IOCAP_SEQUENTIAL;
301}
302
drhac442f42018-01-03 01:28:46 +0000303/* Fetch a page of a memory-mapped file */
304static int memdbFetch(
305 sqlite3_file *pFile,
306 sqlite3_int64 iOfst,
307 int iAmt,
308 void **pp
309){
310 MemFile *p = (MemFile *)pFile;
drh94f0a832019-01-25 14:16:01 +0000311 if( iOfst+iAmt>p->sz ){
drh94f0a832019-01-25 14:16:01 +0000312 *pp = 0;
313 }else{
314 p->nMmap++;
315 *pp = (void*)(p->aData + iOfst);
316 }
drhac442f42018-01-03 01:28:46 +0000317 return SQLITE_OK;
318}
319
320/* Release a memory-mapped page */
321static int memdbUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
322 MemFile *p = (MemFile *)pFile;
323 p->nMmap--;
324 return SQLITE_OK;
325}
326
327/*
328** Open an mem file handle.
329*/
330static int memdbOpen(
331 sqlite3_vfs *pVfs,
332 const char *zName,
333 sqlite3_file *pFile,
334 int flags,
335 int *pOutFlags
336){
337 MemFile *p = (MemFile*)pFile;
drh5f9d1922018-03-06 04:01:08 +0000338 if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){
339 return ORIGVFS(pVfs)->xOpen(ORIGVFS(pVfs), zName, pFile, flags, pOutFlags);
340 }
drhac442f42018-01-03 01:28:46 +0000341 memset(p, 0, sizeof(*p));
drh3ec86652018-01-03 19:03:31 +0000342 p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE;
drh14714162018-03-06 19:14:32 +0000343 assert( pOutFlags!=0 ); /* True because flags==SQLITE_OPEN_MAIN_DB */
344 *pOutFlags = flags | SQLITE_OPEN_MEMORY;
drh0c52f5a2020-07-24 09:17:42 +0000345 pFile->pMethods = &memdb_io_methods;
drh23a88592019-01-31 15:38:53 +0000346 p->szMax = sqlite3GlobalConfig.mxMemdbSize;
drhac442f42018-01-03 01:28:46 +0000347 return SQLITE_OK;
348}
349
drh067b92b2020-06-19 15:24:12 +0000350#if 0 /* Only used to delete rollback journals, super-journals, and WAL
drh14714162018-03-06 19:14:32 +0000351 ** files, none of which exist in memdb. So this routine is never used */
drhac442f42018-01-03 01:28:46 +0000352/*
353** Delete the file located at zPath. If the dirSync argument is true,
354** ensure the file-system modifications are synced to disk before
355** returning.
356*/
357static int memdbDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
358 return SQLITE_IOERR_DELETE;
359}
drh14714162018-03-06 19:14:32 +0000360#endif
drhac442f42018-01-03 01:28:46 +0000361
362/*
363** Test for access permissions. Return true if the requested permission
364** is available, or false otherwise.
drh14714162018-03-06 19:14:32 +0000365**
366** With memdb, no files ever exist on disk. So always return false.
drhac442f42018-01-03 01:28:46 +0000367*/
368static int memdbAccess(
369 sqlite3_vfs *pVfs,
370 const char *zPath,
371 int flags,
372 int *pResOut
373){
374 *pResOut = 0;
375 return SQLITE_OK;
376}
377
378/*
379** Populate buffer zOut with the full canonical pathname corresponding
380** to the pathname in zPath. zOut is guaranteed to point to a buffer
381** of at least (INST_MAX_PATHNAME+1) bytes.
382*/
383static int memdbFullPathname(
384 sqlite3_vfs *pVfs,
385 const char *zPath,
386 int nOut,
387 char *zOut
388){
389 sqlite3_snprintf(nOut, zOut, "%s", zPath);
390 return SQLITE_OK;
391}
392
393/*
394** Open the dynamic library located at zPath and return a handle.
395*/
396static void *memdbDlOpen(sqlite3_vfs *pVfs, const char *zPath){
397 return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
398}
399
400/*
401** Populate the buffer zErrMsg (size nByte bytes) with a human readable
402** utf-8 string describing the most recent error encountered associated
403** with dynamic libraries.
404*/
405static void memdbDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
406 ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
407}
408
409/*
410** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
411*/
412static void (*memdbDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
413 return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
414}
415
416/*
417** Close the dynamic library handle pHandle.
418*/
419static void memdbDlClose(sqlite3_vfs *pVfs, void *pHandle){
420 ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
421}
422
423/*
424** Populate the buffer pointed to by zBufOut with nByte bytes of
425** random data.
426*/
427static int memdbRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
428 return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
429}
430
431/*
432** Sleep for nMicro microseconds. Return the number of microseconds
433** actually slept.
434*/
435static int memdbSleep(sqlite3_vfs *pVfs, int nMicro){
436 return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
437}
438
drh14714162018-03-06 19:14:32 +0000439#if 0 /* Never used. Modern cores only call xCurrentTimeInt64() */
drhac442f42018-01-03 01:28:46 +0000440/*
441** Return the current time as a Julian Day number in *pTimeOut.
442*/
443static int memdbCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
444 return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
445}
drh14714162018-03-06 19:14:32 +0000446#endif
drhac442f42018-01-03 01:28:46 +0000447
448static int memdbGetLastError(sqlite3_vfs *pVfs, int a, char *b){
449 return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
450}
451static int memdbCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
452 return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);
453}
454
455/*
456** Translate a database connection pointer and schema name into a
457** MemFile pointer.
458*/
459static MemFile *memdbFromDbSchema(sqlite3 *db, const char *zSchema){
460 MemFile *p = 0;
461 int rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p);
462 if( rc ) return 0;
463 if( p->base.pMethods!=&memdb_io_methods ) return 0;
464 return p;
465}
466
467/*
drhcb7d5412018-01-03 16:49:52 +0000468** Return the serialization of a database
469*/
470unsigned char *sqlite3_serialize(
471 sqlite3 *db, /* The database connection */
472 const char *zSchema, /* Which database within the connection */
473 sqlite3_int64 *piSize, /* Write size here, if not NULL */
474 unsigned int mFlags /* Maybe SQLITE_SERIALIZE_NOCOPY */
475){
drhb2194ce2018-03-01 22:18:26 +0000476 MemFile *p;
477 int iDb;
drhcb7d5412018-01-03 16:49:52 +0000478 Btree *pBt;
479 sqlite3_int64 sz;
480 int szPage = 0;
481 sqlite3_stmt *pStmt = 0;
482 unsigned char *pOut;
483 char *zSql;
484 int rc;
485
mistachkin6630f942018-03-08 19:56:52 +0000486#ifdef SQLITE_ENABLE_API_ARMOR
487 if( !sqlite3SafetyCheckOk(db) ){
488 (void)SQLITE_MISUSE_BKPT;
489 return 0;
490 }
491#endif
492
drhb2194ce2018-03-01 22:18:26 +0000493 if( zSchema==0 ) zSchema = db->aDb[0].zDbSName;
494 p = memdbFromDbSchema(db, zSchema);
495 iDb = sqlite3FindDbName(db, zSchema);
drhcb7d5412018-01-03 16:49:52 +0000496 if( piSize ) *piSize = -1;
497 if( iDb<0 ) return 0;
498 if( p ){
499 if( piSize ) *piSize = p->sz;
500 if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
501 pOut = p->aData;
502 }else{
503 pOut = sqlite3_malloc64( p->sz );
504 if( pOut ) memcpy(pOut, p->aData, p->sz);
505 }
506 return pOut;
507 }
508 pBt = db->aDb[iDb].pBt;
509 if( pBt==0 ) return 0;
510 szPage = sqlite3BtreeGetPageSize(pBt);
511 zSql = sqlite3_mprintf("PRAGMA \"%w\".page_count", zSchema);
512 rc = zSql ? sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0) : SQLITE_NOMEM;
513 sqlite3_free(zSql);
514 if( rc ) return 0;
drh8784efa2018-03-06 20:54:27 +0000515 rc = sqlite3_step(pStmt);
516 if( rc!=SQLITE_ROW ){
drhcb7d5412018-01-03 16:49:52 +0000517 pOut = 0;
518 }else{
drh8784efa2018-03-06 20:54:27 +0000519 sz = sqlite3_column_int64(pStmt, 0)*szPage;
520 if( piSize ) *piSize = sz;
521 if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
522 pOut = 0;
523 }else{
524 pOut = sqlite3_malloc64( sz );
525 if( pOut ){
526 int nPage = sqlite3_column_int(pStmt, 0);
527 Pager *pPager = sqlite3BtreePager(pBt);
528 int pgno;
529 for(pgno=1; pgno<=nPage; pgno++){
530 DbPage *pPage = 0;
531 unsigned char *pTo = pOut + szPage*(sqlite3_int64)(pgno-1);
532 rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pPage, 0);
533 if( rc==SQLITE_OK ){
534 memcpy(pTo, sqlite3PagerGetData(pPage), szPage);
535 }else{
536 memset(pTo, 0, szPage);
537 }
538 sqlite3PagerUnref(pPage);
drhcb7d5412018-01-03 16:49:52 +0000539 }
drhcb7d5412018-01-03 16:49:52 +0000540 }
541 }
542 }
543 sqlite3_finalize(pStmt);
544 return pOut;
545}
546
drh3ec86652018-01-03 19:03:31 +0000547/* Convert zSchema to a MemDB and initialize its content.
548*/
549int sqlite3_deserialize(
550 sqlite3 *db, /* The database connection */
551 const char *zSchema, /* Which DB to reopen with the deserialization */
552 unsigned char *pData, /* The serialized database content */
553 sqlite3_int64 szDb, /* Number bytes in the deserialization */
554 sqlite3_int64 szBuf, /* Total size of buffer pData[] */
555 unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */
556){
557 MemFile *p;
558 char *zSql;
559 sqlite3_stmt *pStmt = 0;
560 int rc;
561 int iDb;
562
mistachkin6630f942018-03-08 19:56:52 +0000563#ifdef SQLITE_ENABLE_API_ARMOR
564 if( !sqlite3SafetyCheckOk(db) ){
565 return SQLITE_MISUSE_BKPT;
566 }
567 if( szDb<0 ) return SQLITE_MISUSE_BKPT;
568 if( szBuf<0 ) return SQLITE_MISUSE_BKPT;
569#endif
570
drh3ec86652018-01-03 19:03:31 +0000571 sqlite3_mutex_enter(db->mutex);
572 if( zSchema==0 ) zSchema = db->aDb[0].zDbSName;
573 iDb = sqlite3FindDbName(db, zSchema);
574 if( iDb<0 ){
575 rc = SQLITE_ERROR;
576 goto end_deserialize;
577 }
578 zSql = sqlite3_mprintf("ATTACH x AS %Q", zSchema);
drh672f07c2020-10-20 14:40:53 +0000579 if( zSql==0 ){
580 rc = SQLITE_NOMEM;
581 }else{
582 rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
583 sqlite3_free(zSql);
584 }
drh3ec86652018-01-03 19:03:31 +0000585 if( rc ) goto end_deserialize;
586 db->init.iDb = (u8)iDb;
587 db->init.reopenMemdb = 1;
588 rc = sqlite3_step(pStmt);
589 db->init.reopenMemdb = 0;
590 if( rc!=SQLITE_DONE ){
591 rc = SQLITE_ERROR;
592 goto end_deserialize;
593 }
594 p = memdbFromDbSchema(db, zSchema);
drh8784efa2018-03-06 20:54:27 +0000595 if( p==0 ){
596 rc = SQLITE_ERROR;
597 }else{
598 p->aData = pData;
drhff01ee32020-10-17 22:13:16 +0000599 pData = 0;
drh8784efa2018-03-06 20:54:27 +0000600 p->sz = szDb;
drh6ca64482019-01-22 16:06:20 +0000601 p->szAlloc = szBuf;
drh8784efa2018-03-06 20:54:27 +0000602 p->szMax = szBuf;
drh23a88592019-01-31 15:38:53 +0000603 if( p->szMax<sqlite3GlobalConfig.mxMemdbSize ){
604 p->szMax = sqlite3GlobalConfig.mxMemdbSize;
drh6ca64482019-01-22 16:06:20 +0000605 }
drh8784efa2018-03-06 20:54:27 +0000606 p->mFlags = mFlags;
607 rc = SQLITE_OK;
608 }
609
drh3ec86652018-01-03 19:03:31 +0000610end_deserialize:
611 sqlite3_finalize(pStmt);
drhff01ee32020-10-17 22:13:16 +0000612 if( pData && (mFlags & SQLITE_DESERIALIZE_FREEONCLOSE)!=0 ){
613 sqlite3_free(pData);
614 }
drh3ec86652018-01-03 19:03:31 +0000615 sqlite3_mutex_leave(db->mutex);
616 return rc;
617}
618
drhac442f42018-01-03 01:28:46 +0000619/*
620** This routine is called when the extension is loaded.
621** Register the new VFS.
622*/
623int sqlite3MemdbInit(void){
drh5f9d1922018-03-06 04:01:08 +0000624 sqlite3_vfs *pLower = sqlite3_vfs_find(0);
625 int sz = pLower->szOsFile;
626 memdb_vfs.pAppData = pLower;
drhf25f8d52020-05-21 20:38:39 +0000627 /* The following conditional can only be true when compiled for
628 ** Windows x86 and SQLITE_MAX_MMAP_SIZE=0. We always leave
629 ** it in, to be safe, but it is marked as NO_TEST since there
630 ** is no way to reach it under most builds. */
631 if( sz<sizeof(MemFile) ) sz = sizeof(MemFile); /*NO_TEST*/
drh5f9d1922018-03-06 04:01:08 +0000632 memdb_vfs.szOsFile = sz;
drhac442f42018-01-03 01:28:46 +0000633 return sqlite3_vfs_register(&memdb_vfs, 0);
634}
drh9c6396e2018-03-06 21:43:19 +0000635#endif /* SQLITE_ENABLE_DESERIALIZE */