/*** 2016年09月07日**** The author disclaims copyright to this source code. In place of** a legal notice, here is a blessing:**** May you do good and not evil.** May you find forgiveness for yourself and forgive others.** May you share freely, never taking more than you give.************************************************************************************ This file implements an in-memory VFS. A database is held as a contiguous** block of memory.**** This file also implements interface sqlite3_serialize() and** sqlite3_deserialize().*/#include "sqliteInt.h"#ifndef SQLITE_OMIT_DESERIALIZE/*** Forward declaration of objects used by this utility*/typedef struct sqlite3_vfs MemVfs;typedef struct MemFile MemFile;typedef struct MemStore MemStore;/* Access to a lower-level VFS that (might) implement dynamic loading,** access to randomness, etc.*/#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))/* Storage for a memdb file.**** An memdb object can be shared or separate. Shared memdb objects can be** used by more than one database connection. Mutexes are used by shared** memdb objects to coordinate access. Separate memdb objects are only** connected to a single database connection and do not require additional** mutexes.**** Shared memdb objects have .zFName!=0 and .pMutex!=0. They are created** using "file:/name?vfs=memdb". The first character of the name must be** "/" or else the object will be a separate memdb object. All shared** memdb objects are stored in memdb_g.apMemStore[] in an arbitrary order.**** Separate memdb objects are created using a name that does not begin** with "/" or using sqlite3_deserialize().**** Access rules for shared MemStore objects:**** * .zFName is initialized when the object is created and afterwards** is unchanged until the object is destroyed. So it can be accessed** at any time as long as we know the object is not being destroyed,** which means while either the SQLITE_MUTEX_STATIC_VFS1 or** .pMutex is held or the object is not part of memdb_g.apMemStore[].**** * Can .pMutex can only be changed while holding the** SQLITE_MUTEX_STATIC_VFS1 mutex or while the object is not part** of memdb_g.apMemStore[].**** * Other fields can only be changed while holding the .pMutex mutex** or when the .nRef is less than zero and the object is not part of** memdb_g.apMemStore[].**** * The .aData pointer has the added requirement that it can can only** be changed (for resizing) when nMmap is zero.***/struct MemStore {sqlite3_int64 sz; /* Size of the file */sqlite3_int64 szAlloc; /* Space allocated to aData */sqlite3_int64 szMax; /* Maximum allowed size of the file */unsigned char *aData; /* content of the file */sqlite3_mutex *pMutex; /* Used by shared stores only */int nMmap; /* Number of memory mapped pages */unsigned mFlags; /* Flags */int nRdLock; /* Number of readers */int nWrLock; /* Number of writers. (Always 0 or 1) */int nRef; /* Number of users of this MemStore */char *zFName; /* The filename for shared stores */};/* An open file */struct MemFile {sqlite3_file base; /* IO methods */MemStore *pStore; /* The storage */int eLock; /* Most recent lock against this file */};/*** File-scope variables for holding the memdb files that are accessible** to multiple database connections in separate threads.**** Must hold SQLITE_MUTEX_STATIC_VFS1 to access any part of this object.*/static struct MemFS {int nMemStore; /* Number of shared MemStore objects */MemStore **apMemStore; /* Array of all shared MemStore objects */} memdb_g;/*** Methods for MemFile*/static int memdbClose(sqlite3_file*);static int memdbRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);static int memdbWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);static int memdbTruncate(sqlite3_file*, sqlite3_int64 size);static int memdbSync(sqlite3_file*, int flags);static int memdbFileSize(sqlite3_file*, sqlite3_int64 *pSize);static int memdbLock(sqlite3_file*, int);static int memdbUnlock(sqlite3_file*, int);/* static int memdbCheckReservedLock(sqlite3_file*, int *pResOut);// not used */static int memdbFileControl(sqlite3_file*, int op, void *pArg);/* static int memdbSectorSize(sqlite3_file*); // not used */static int memdbDeviceCharacteristics(sqlite3_file*);static int memdbFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);static int memdbUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);/*** Methods for MemVfs*/static int memdbOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);/* static int memdbDelete(sqlite3_vfs*, const char *zName, int syncDir); */static int memdbAccess(sqlite3_vfs*, const char *zName, int flags, int *);static int memdbFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);static void *memdbDlOpen(sqlite3_vfs*, const char *zFilename);static void memdbDlError(sqlite3_vfs*, int nByte, char *zErrMsg);static void (*memdbDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);static void memdbDlClose(sqlite3_vfs*, void*);static int memdbRandomness(sqlite3_vfs*, int nByte, char *zOut);static int memdbSleep(sqlite3_vfs*, int microseconds);/* static int memdbCurrentTime(sqlite3_vfs*, double*); */static int memdbGetLastError(sqlite3_vfs*, int, char *);static int memdbCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);static sqlite3_vfs memdb_vfs = {2, /* iVersion */0, /* szOsFile (set when registered) */1024, /* mxPathname */0, /* pNext */"memdb", /* zName */0, /* pAppData (set when registered) */memdbOpen, /* xOpen */0, /* memdbDelete, */ /* xDelete */memdbAccess, /* xAccess */memdbFullPathname, /* xFullPathname */memdbDlOpen, /* xDlOpen */memdbDlError, /* xDlError */memdbDlSym, /* xDlSym */memdbDlClose, /* xDlClose */memdbRandomness, /* xRandomness */memdbSleep, /* xSleep */0, /* memdbCurrentTime, */ /* xCurrentTime */memdbGetLastError, /* xGetLastError */memdbCurrentTimeInt64, /* xCurrentTimeInt64 */0, /* xSetSystemCall */0, /* xGetSystemCall */0, /* xNextSystemCall */};static const sqlite3_io_methods memdb_io_methods = {3, /* iVersion */memdbClose, /* xClose */memdbRead, /* xRead */memdbWrite, /* xWrite */memdbTruncate, /* xTruncate */memdbSync, /* xSync */memdbFileSize, /* xFileSize */memdbLock, /* xLock */memdbUnlock, /* xUnlock */0, /* memdbCheckReservedLock, */ /* xCheckReservedLock */memdbFileControl, /* xFileControl */0, /* memdbSectorSize,*/ /* xSectorSize */memdbDeviceCharacteristics, /* xDeviceCharacteristics */0, /* xShmMap */0, /* xShmLock */0, /* xShmBarrier */0, /* xShmUnmap */memdbFetch, /* xFetch */memdbUnfetch /* xUnfetch */};/*** Enter/leave the mutex on a MemStore*/#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE==0static void memdbEnter(MemStore *p){UNUSED_PARAMETER(p);}static void memdbLeave(MemStore *p){UNUSED_PARAMETER(p);}#elsestatic void memdbEnter(MemStore *p){sqlite3_mutex_enter(p->pMutex);}static void memdbLeave(MemStore *p){sqlite3_mutex_leave(p->pMutex);}#endif/*** Close an memdb-file.** Free the underlying MemStore object when its refcount drops to zero** or less.*/static int memdbClose(sqlite3_file *pFile){MemStore *p = ((MemFile*)pFile)->pStore;if( p->zFName ){int i;#ifndef SQLITE_MUTEX_OMITsqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);#endifsqlite3_mutex_enter(pVfsMutex);for(i=0; ALWAYS(i<memdb_g.nMemStore); i++){if( memdb_g.apMemStore[i]==p ){memdbEnter(p);if( p->nRef==1 ){memdb_g.apMemStore[i] = memdb_g.apMemStore[--memdb_g.nMemStore];if( memdb_g.nMemStore==0 ){sqlite3_free(memdb_g.apMemStore);memdb_g.apMemStore = 0;}}break;}}sqlite3_mutex_leave(pVfsMutex);}else{memdbEnter(p);}p->nRef--;if( p->nRef<=0 ){if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ){sqlite3_free(p->aData);}memdbLeave(p);sqlite3_mutex_free(p->pMutex);sqlite3_free(p);}else{memdbLeave(p);}return SQLITE_OK;}/*** Read data from an memdb-file.*/static int memdbRead(sqlite3_file *pFile,void *zBuf,int iAmt,sqlite_int64 iOfst){MemStore *p = ((MemFile*)pFile)->pStore;memdbEnter(p);if( iOfst+iAmt>p->sz ){memset(zBuf, 0, iAmt);if( iOfst<p->sz ) memcpy(zBuf, p->aData+iOfst, p->sz - iOfst);memdbLeave(p);return SQLITE_IOERR_SHORT_READ;}memcpy(zBuf, p->aData+iOfst, iAmt);memdbLeave(p);return SQLITE_OK;}/*** Try to enlarge the memory allocation to hold at least sz bytes*/static int memdbEnlarge(MemStore *p, sqlite3_int64 newSz){unsigned char *pNew;if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || NEVER(p->nMmap>0) ){return SQLITE_FULL;}if( newSz>p->szMax ){return SQLITE_FULL;}newSz *= 2;if( newSz>p->szMax ) newSz = p->szMax;pNew = sqlite3Realloc(p->aData, newSz);if( pNew==0 ) return SQLITE_IOERR_NOMEM;p->aData = pNew;p->szAlloc = newSz;return SQLITE_OK;}/*** Write data to an memdb-file.*/static int memdbWrite(sqlite3_file *pFile,const void *z,int iAmt,sqlite_int64 iOfst){MemStore *p = ((MemFile*)pFile)->pStore;memdbEnter(p);if( NEVER(p->mFlags & SQLITE_DESERIALIZE_READONLY) ){/* Can't happen: memdbLock() will return SQLITE_READONLY before** reaching this point */memdbLeave(p);return SQLITE_IOERR_WRITE;}if( iOfst+iAmt>p->sz ){int rc;if( iOfst+iAmt>p->szAlloc&& (rc = memdbEnlarge(p, iOfst+iAmt))!=SQLITE_OK){memdbLeave(p);return rc;}if( iOfst>p->sz ) memset(p->aData+p->sz, 0, iOfst-p->sz);p->sz = iOfst+iAmt;}memcpy(p->aData+iOfst, z, iAmt);memdbLeave(p);return SQLITE_OK;}/*** Truncate an memdb-file.**** In rollback mode (which is always the case for memdb, as it does not** support WAL mode) the truncate() method is only used to reduce** the size of a file, never to increase the size.*/static int memdbTruncate(sqlite3_file *pFile, sqlite_int64 size){MemStore *p = ((MemFile*)pFile)->pStore;int rc = SQLITE_OK;memdbEnter(p);if( size>p->sz ){/* This can only happen with a corrupt wal mode db */rc = SQLITE_CORRUPT;}else{p->sz = size;}memdbLeave(p);return rc;}/*** Sync an memdb-file.*/static int memdbSync(sqlite3_file *pFile, int flags){UNUSED_PARAMETER(pFile);UNUSED_PARAMETER(flags);return SQLITE_OK;}/*** Return the current file-size of an memdb-file.*/static int memdbFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){MemStore *p = ((MemFile*)pFile)->pStore;memdbEnter(p);*pSize = p->sz;memdbLeave(p);return SQLITE_OK;}/*** Lock an memdb-file.*/static int memdbLock(sqlite3_file *pFile, int eLock){MemFile *pThis = (MemFile*)pFile;MemStore *p = pThis->pStore;int rc = SQLITE_OK;if( eLock<=pThis->eLock ) return SQLITE_OK;memdbEnter(p);assert( p->nWrLock==0 || p->nWrLock==1 );assert( pThis->eLock<=SQLITE_LOCK_SHARED || p->nWrLock==1 );assert( pThis->eLock==SQLITE_LOCK_NONE || p->nRdLock>=1 );if( eLock>SQLITE_LOCK_SHARED && (p->mFlags & SQLITE_DESERIALIZE_READONLY) ){rc = SQLITE_READONLY;}else{switch( eLock ){case SQLITE_LOCK_SHARED: {assert( pThis->eLock==SQLITE_LOCK_NONE );if( p->nWrLock>0 ){rc = SQLITE_BUSY;}else{p->nRdLock++;}break;};case SQLITE_LOCK_RESERVED:case SQLITE_LOCK_PENDING: {assert( pThis->eLock>=SQLITE_LOCK_SHARED );if( ALWAYS(pThis->eLock==SQLITE_LOCK_SHARED) ){if( p->nWrLock>0 ){rc = SQLITE_BUSY;}else{p->nWrLock = 1;}}break;}default: {assert( eLock==SQLITE_LOCK_EXCLUSIVE );assert( pThis->eLock>=SQLITE_LOCK_SHARED );if( p->nRdLock>1 ){rc = SQLITE_BUSY;}else if( pThis->eLock==SQLITE_LOCK_SHARED ){p->nWrLock = 1;}break;}}}if( rc==SQLITE_OK ) pThis->eLock = eLock;memdbLeave(p);return rc;}/*** Unlock an memdb-file.*/static int memdbUnlock(sqlite3_file *pFile, int eLock){MemFile *pThis = (MemFile*)pFile;MemStore *p = pThis->pStore;if( eLock>=pThis->eLock ) return SQLITE_OK;memdbEnter(p);assert( eLock==SQLITE_LOCK_SHARED || eLock==SQLITE_LOCK_NONE );if( eLock==SQLITE_LOCK_SHARED ){if( ALWAYS(pThis->eLock>SQLITE_LOCK_SHARED) ){p->nWrLock--;}}else{if( pThis->eLock>SQLITE_LOCK_SHARED ){p->nWrLock--;}p->nRdLock--;}pThis->eLock = eLock;memdbLeave(p);return SQLITE_OK;}#if 0/*** This interface is only used for crash recovery, which does not** occur on an in-memory database.*/static int memdbCheckReservedLock(sqlite3_file *pFile, int *pResOut){*pResOut = 0;return SQLITE_OK;}#endif/*** File control method. For custom operations on an memdb-file.*/static int memdbFileControl(sqlite3_file *pFile, int op, void *pArg){MemStore *p = ((MemFile*)pFile)->pStore;int rc = SQLITE_NOTFOUND;memdbEnter(p);if( op==SQLITE_FCNTL_VFSNAME ){*(char**)pArg = sqlite3_mprintf("memdb(%p,%lld)", p->aData, p->sz);rc = SQLITE_OK;}if( op==SQLITE_FCNTL_SIZE_LIMIT ){sqlite3_int64 iLimit = *(sqlite3_int64*)pArg;if( iLimit<p->sz ){if( iLimit<0 ){iLimit = p->szMax;}else{iLimit = p->sz;}}p->szMax = iLimit;*(sqlite3_int64*)pArg = iLimit;rc = SQLITE_OK;}memdbLeave(p);return rc;}#if 0 /* Not used because of SQLITE_IOCAP_POWERSAFE_OVERWRITE *//*** Return the sector-size in bytes for an memdb-file.*/static int memdbSectorSize(sqlite3_file *pFile){return 1024;}#endif/*** Return the device characteristic flags supported by an memdb-file.*/static int memdbDeviceCharacteristics(sqlite3_file *pFile){UNUSED_PARAMETER(pFile);return SQLITE_IOCAP_ATOMIC |SQLITE_IOCAP_POWERSAFE_OVERWRITE |SQLITE_IOCAP_SAFE_APPEND |SQLITE_IOCAP_SEQUENTIAL;}/* Fetch a page of a memory-mapped file */static int memdbFetch(sqlite3_file *pFile,sqlite3_int64 iOfst,int iAmt,void **pp){MemStore *p = ((MemFile*)pFile)->pStore;memdbEnter(p);if( iOfst+iAmt>p->sz || (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)!=0 ){*pp = 0;}else{p->nMmap++;*pp = (void*)(p->aData + iOfst);}memdbLeave(p);return SQLITE_OK;}/* Release a memory-mapped page */static int memdbUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){MemStore *p = ((MemFile*)pFile)->pStore;UNUSED_PARAMETER(iOfst);UNUSED_PARAMETER(pPage);memdbEnter(p);p->nMmap--;memdbLeave(p);return SQLITE_OK;}/*** Open an mem file handle.*/static int memdbOpen(sqlite3_vfs *pVfs,const char *zName,sqlite3_file *pFd,int flags,int *pOutFlags){MemFile *pFile = (MemFile*)pFd;MemStore *p = 0;int szName;UNUSED_PARAMETER(pVfs);memset(pFile, 0, sizeof(*pFile));szName = sqlite3Strlen30(zName);if( szName>1 && (zName[0]=='/' || zName[0]=='\\') ){int i;#ifndef SQLITE_MUTEX_OMITsqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);#endifsqlite3_mutex_enter(pVfsMutex);for(i=0; i<memdb_g.nMemStore; i++){if( strcmp(memdb_g.apMemStore[i]->zFName,zName)==0 ){p = memdb_g.apMemStore[i];break;}}if( p==0 ){MemStore **apNew;p = sqlite3Malloc( sizeof(*p) + szName + 3 );if( p==0 ){sqlite3_mutex_leave(pVfsMutex);return SQLITE_NOMEM;}apNew = sqlite3Realloc(memdb_g.apMemStore,sizeof(apNew[0])*(memdb_g.nMemStore+1) );if( apNew==0 ){sqlite3_free(p);sqlite3_mutex_leave(pVfsMutex);return SQLITE_NOMEM;}apNew[memdb_g.nMemStore++] = p;memdb_g.apMemStore = apNew;memset(p, 0, sizeof(*p));p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE|SQLITE_DESERIALIZE_FREEONCLOSE;p->szMax = sqlite3GlobalConfig.mxMemdbSize;p->zFName = (char*)&p[1];memcpy(p->zFName, zName, szName+1);p->pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);if( p->pMutex==0 ){memdb_g.nMemStore--;sqlite3_free(p);sqlite3_mutex_leave(pVfsMutex);return SQLITE_NOMEM;}p->nRef = 1;memdbEnter(p);}else{memdbEnter(p);p->nRef++;}sqlite3_mutex_leave(pVfsMutex);}else{p = sqlite3Malloc( sizeof(*p) );if( p==0 ){return SQLITE_NOMEM;}memset(p, 0, sizeof(*p));p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE;p->szMax = sqlite3GlobalConfig.mxMemdbSize;}pFile->pStore = p;if( pOutFlags!=0 ){*pOutFlags = flags | SQLITE_OPEN_MEMORY;}pFd->pMethods = &memdb_io_methods;memdbLeave(p);return SQLITE_OK;}#if 0 /* Only used to delete rollback journals, super-journals, and WAL** files, none of which exist in memdb. So this routine is never used *//*** Delete the file located at zPath. If the dirSync argument is true,** ensure the file-system modifications are synced to disk before** returning.*/static int memdbDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){return SQLITE_IOERR_DELETE;}#endif/*** Test for access permissions. Return true if the requested permission** is available, or false otherwise.**** With memdb, no files ever exist on disk. So always return false.*/static int memdbAccess(sqlite3_vfs *pVfs,const char *zPath,int flags,int *pResOut){UNUSED_PARAMETER(pVfs);UNUSED_PARAMETER(zPath);UNUSED_PARAMETER(flags);*pResOut = 0;return SQLITE_OK;}/*** Populate buffer zOut with the full canonical pathname corresponding** to the pathname in zPath. zOut is guaranteed to point to a buffer** of at least (INST_MAX_PATHNAME+1) bytes.*/static int memdbFullPathname(sqlite3_vfs *pVfs,const char *zPath,int nOut,char *zOut){UNUSED_PARAMETER(pVfs);sqlite3_snprintf(nOut, zOut, "%s", zPath);return SQLITE_OK;}/*** Open the dynamic library located at zPath and return a handle.*/static void *memdbDlOpen(sqlite3_vfs *pVfs, const char *zPath){return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);}/*** Populate the buffer zErrMsg (size nByte bytes) with a human readable** utf-8 string describing the most recent error encountered associated** with dynamic libraries.*/static void memdbDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);}/*** Return a pointer to the symbol zSymbol in the dynamic library pHandle.*/static void (*memdbDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);}/*** Close the dynamic library handle pHandle.*/static void memdbDlClose(sqlite3_vfs *pVfs, void *pHandle){ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);}/*** Populate the buffer pointed to by zBufOut with nByte bytes of** random data.*/static int memdbRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);}/*** Sleep for nMicro microseconds. Return the number of microseconds** actually slept.*/static int memdbSleep(sqlite3_vfs *pVfs, int nMicro){return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);}#if 0 /* Never used. Modern cores only call xCurrentTimeInt64() *//*** Return the current time as a Julian Day number in *pTimeOut.*/static int memdbCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);}#endifstatic int memdbGetLastError(sqlite3_vfs *pVfs, int a, char *b){return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);}static int memdbCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);}/*** Translate a database connection pointer and schema name into a** MemFile pointer.*/static MemFile *memdbFromDbSchema(sqlite3 *db, const char *zSchema){MemFile *p = 0;MemStore *pStore;int rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p);if( rc ) return 0;if( p->base.pMethods!=&memdb_io_methods ) return 0;pStore = p->pStore;memdbEnter(pStore);if( pStore->zFName!=0 ) p = 0;memdbLeave(pStore);return p;}/*** Return the serialization of a database*/unsigned char *sqlite3_serialize(sqlite3 *db, /* The database connection */const char *zSchema, /* Which database within the connection */sqlite3_int64 *piSize, /* Write size here, if not NULL */unsigned int mFlags /* Maybe SQLITE_SERIALIZE_NOCOPY */){MemFile *p;int iDb;Btree *pBt;sqlite3_int64 sz;int szPage = 0;sqlite3_stmt *pStmt = 0;unsigned char *pOut;char *zSql;int rc;#ifdef SQLITE_ENABLE_API_ARMORif( !sqlite3SafetyCheckOk(db) ){(void)SQLITE_MISUSE_BKPT;return 0;}#endifif( zSchema==0 ) zSchema = db->aDb[0].zDbSName;p = memdbFromDbSchema(db, zSchema);iDb = sqlite3FindDbName(db, zSchema);if( piSize ) *piSize = -1;if( iDb<0 ) return 0;if( p ){MemStore *pStore = p->pStore;assert( pStore->pMutex==0 );if( piSize ) *piSize = pStore->sz;if( mFlags & SQLITE_SERIALIZE_NOCOPY ){pOut = pStore->aData;}else{pOut = sqlite3_malloc64( pStore->sz );if( pOut ) memcpy(pOut, pStore->aData, pStore->sz);}return pOut;}pBt = db->aDb[iDb].pBt;if( pBt==0 ) return 0;szPage = sqlite3BtreeGetPageSize(pBt);zSql = sqlite3_mprintf("PRAGMA \"%w\".page_count", zSchema);rc = zSql ? sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0) : SQLITE_NOMEM;sqlite3_free(zSql);if( rc ) return 0;rc = sqlite3_step(pStmt);if( rc!=SQLITE_ROW ){pOut = 0;}else{sz = sqlite3_column_int64(pStmt, 0)*szPage;if( sz==0 ){sqlite3_reset(pStmt);sqlite3_exec(db, "BEGIN IMMEDIATE; COMMIT;", 0, 0, 0);rc = sqlite3_step(pStmt);if( rc==SQLITE_ROW ){sz = sqlite3_column_int64(pStmt, 0)*szPage;}}if( piSize ) *piSize = sz;if( mFlags & SQLITE_SERIALIZE_NOCOPY ){pOut = 0;}else{pOut = sqlite3_malloc64( sz );if( pOut ){int nPage = sqlite3_column_int(pStmt, 0);Pager *pPager = sqlite3BtreePager(pBt);int pgno;for(pgno=1; pgno<=nPage; pgno++){DbPage *pPage = 0;unsigned char *pTo = pOut + szPage*(sqlite3_int64)(pgno-1);rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pPage, 0);if( rc==SQLITE_OK ){memcpy(pTo, sqlite3PagerGetData(pPage), szPage);}else{memset(pTo, 0, szPage);}sqlite3PagerUnref(pPage);}}}}sqlite3_finalize(pStmt);return pOut;}/* Convert zSchema to a MemDB and initialize its content.*/int sqlite3_deserialize(sqlite3 *db, /* The database connection */const char *zSchema, /* Which DB to reopen with the deserialization */unsigned char *pData, /* The serialized database content */sqlite3_int64 szDb, /* Number bytes in the deserialization */sqlite3_int64 szBuf, /* Total size of buffer pData[] */unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */){MemFile *p;char *zSql;sqlite3_stmt *pStmt = 0;int rc;int iDb;#ifdef SQLITE_ENABLE_API_ARMORif( !sqlite3SafetyCheckOk(db) ){return SQLITE_MISUSE_BKPT;}if( szDb<0 ) return SQLITE_MISUSE_BKPT;if( szBuf<0 ) return SQLITE_MISUSE_BKPT;#endifsqlite3_mutex_enter(db->mutex);if( zSchema==0 ) zSchema = db->aDb[0].zDbSName;iDb = sqlite3FindDbName(db, zSchema);testcase( iDb==1 );if( iDb<2 && iDb!=0 ){rc = SQLITE_ERROR;goto end_deserialize;}zSql = sqlite3_mprintf("ATTACH x AS %Q", zSchema);if( zSql==0 ){rc = SQLITE_NOMEM;}else{rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);sqlite3_free(zSql);}if( rc ) goto end_deserialize;db->init.iDb = (u8)iDb;db->init.reopenMemdb = 1;rc = sqlite3_step(pStmt);db->init.reopenMemdb = 0;if( rc!=SQLITE_DONE ){rc = SQLITE_ERROR;goto end_deserialize;}p = memdbFromDbSchema(db, zSchema);if( p==0 ){rc = SQLITE_ERROR;}else{MemStore *pStore = p->pStore;pStore->aData = pData;pData = 0;pStore->sz = szDb;pStore->szAlloc = szBuf;pStore->szMax = szBuf;if( pStore->szMax<sqlite3GlobalConfig.mxMemdbSize ){pStore->szMax = sqlite3GlobalConfig.mxMemdbSize;}pStore->mFlags = mFlags;rc = SQLITE_OK;}end_deserialize:sqlite3_finalize(pStmt);if( pData && (mFlags & SQLITE_DESERIALIZE_FREEONCLOSE)!=0 ){sqlite3_free(pData);}sqlite3_mutex_leave(db->mutex);return rc;}/*** Return true if the VFS is the memvfs.*/int sqlite3IsMemdb(const sqlite3_vfs *pVfs){return pVfs==&memdb_vfs;}/*** This routine is called when the extension is loaded.** Register the new VFS.*/int sqlite3MemdbInit(void){sqlite3_vfs *pLower = sqlite3_vfs_find(0);unsigned int sz;if( NEVER(pLower==0) ) return SQLITE_ERROR;sz = pLower->szOsFile;memdb_vfs.pAppData = pLower;/* The following conditional can only be true when compiled for** Windows x86 and SQLITE_MAX_MMAP_SIZE=0. We always leave** it in, to be safe, but it is marked as NO_TEST since there** is no way to reach it under most builds. */if( sz<sizeof(MemFile) ) sz = sizeof(MemFile); /*NO_TEST*/memdb_vfs.szOsFile = sz;return sqlite3_vfs_register(&memdb_vfs, 0);}#endif /* SQLITE_OMIT_DESERIALIZE */
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。