2016-09-07 18:11:11 +00:00
/*
* * 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 .
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
2018-01-02 16:02:50 +00:00
* * This is an in - memory VFS implementation . The application supplies
* * a chunk of memory to hold the database file .
2016-09-07 18:11:11 +00:00
* *
2018-01-02 16:02:50 +00:00
* * Because there is place to store a rollback or wal journal , the database
* * must use one of journal_mode = MEMORY or journal_mode = NONE .
2016-09-07 18:11:11 +00:00
* *
* * USAGE :
* *
2018-01-02 16:02:50 +00:00
* * sqlite3_open_v2 ( " file:/whatever?ptr=0xf05538&sz=14336&max=65536 " , & db ,
* * SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI ,
2016-09-07 18:11:11 +00:00
* * " memvfs " ) ;
* *
2018-01-02 16:02:50 +00:00
* * These are the query parameters :
* *
* * ptr = The address of the memory buffer that holds the database .
* *
* * sz = The current size the database file
* *
* * maxsz = The maximum size of the database . In other words , the
* * amount of space allocated for the ptr = buffer .
* *
* * freeonclose = If true , then sqlite3_free ( ) is called on the ptr =
* * value when the connection closes .
* *
* * The ptr = and sz = query parameters are required . If maxsz = is omitted ,
* * then it defaults to the sz = value . Parameter values can be in either
* * decimal or hexadecimal . The filename in the URI is ignored .
2016-09-07 18:11:11 +00:00
*/
# include <sqlite3ext.h>
SQLITE_EXTENSION_INIT1
# include <string.h>
# include <assert.h>
/*
* * Forward declaration of objects used by this utility
*/
typedef struct sqlite3_vfs MemVfs ;
typedef struct MemFile MemFile ;
/* Access to a lower-level VFS that (might) implement dynamic loading,
* * access to randomness , etc .
*/
# define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
/* An open file */
struct MemFile {
sqlite3_file base ; /* IO methods */
sqlite3_int64 sz ; /* Size of the file */
2018-01-02 16:02:50 +00:00
sqlite3_int64 szMax ; /* Space allocated to aData */
2016-09-07 18:11:11 +00:00
unsigned char * aData ; /* content of the file */
2018-01-02 16:02:50 +00:00
int bFreeOnClose ; /* Invoke sqlite3_free() on aData at close */
2016-09-07 18:11:11 +00:00
} ;
/*
* * Methods for MemFile
*/
static int memClose ( sqlite3_file * ) ;
static int memRead ( sqlite3_file * , void * , int iAmt , sqlite3_int64 iOfst ) ;
static int memWrite ( sqlite3_file * , const void * , int iAmt , sqlite3_int64 iOfst ) ;
static int memTruncate ( sqlite3_file * , sqlite3_int64 size ) ;
static int memSync ( sqlite3_file * , int flags ) ;
static int memFileSize ( sqlite3_file * , sqlite3_int64 * pSize ) ;
static int memLock ( sqlite3_file * , int ) ;
static int memUnlock ( sqlite3_file * , int ) ;
static int memCheckReservedLock ( sqlite3_file * , int * pResOut ) ;
static int memFileControl ( sqlite3_file * , int op , void * pArg ) ;
static int memSectorSize ( sqlite3_file * ) ;
static int memDeviceCharacteristics ( sqlite3_file * ) ;
static int memShmMap ( sqlite3_file * , int iPg , int pgsz , int , void volatile * * ) ;
static int memShmLock ( sqlite3_file * , int offset , int n , int flags ) ;
static void memShmBarrier ( sqlite3_file * ) ;
static int memShmUnmap ( sqlite3_file * , int deleteFlag ) ;
static int memFetch ( sqlite3_file * , sqlite3_int64 iOfst , int iAmt , void * * pp ) ;
static int memUnfetch ( sqlite3_file * , sqlite3_int64 iOfst , void * p ) ;
/*
* * Methods for MemVfs
*/
static int memOpen ( sqlite3_vfs * , const char * , sqlite3_file * , int , int * ) ;
static int memDelete ( sqlite3_vfs * , const char * zName , int syncDir ) ;
static int memAccess ( sqlite3_vfs * , const char * zName , int flags , int * ) ;
static int memFullPathname ( sqlite3_vfs * , const char * zName , int , char * zOut ) ;
static void * memDlOpen ( sqlite3_vfs * , const char * zFilename ) ;
static void memDlError ( sqlite3_vfs * , int nByte , char * zErrMsg ) ;
static void ( * memDlSym ( sqlite3_vfs * pVfs , void * p , const char * zSym ) ) ( void ) ;
static void memDlClose ( sqlite3_vfs * , void * ) ;
static int memRandomness ( sqlite3_vfs * , int nByte , char * zOut ) ;
static int memSleep ( sqlite3_vfs * , int microseconds ) ;
static int memCurrentTime ( sqlite3_vfs * , double * ) ;
static int memGetLastError ( sqlite3_vfs * , int , char * ) ;
static int memCurrentTimeInt64 ( sqlite3_vfs * , sqlite3_int64 * ) ;
static sqlite3_vfs mem_vfs = {
2 , /* iVersion */
0 , /* szOsFile (set when registered) */
1024 , /* mxPathname */
0 , /* pNext */
" memvfs " , /* zName */
0 , /* pAppData (set when registered) */
memOpen , /* xOpen */
memDelete , /* xDelete */
memAccess , /* xAccess */
memFullPathname , /* xFullPathname */
memDlOpen , /* xDlOpen */
memDlError , /* xDlError */
memDlSym , /* xDlSym */
memDlClose , /* xDlClose */
memRandomness , /* xRandomness */
memSleep , /* xSleep */
memCurrentTime , /* xCurrentTime */
memGetLastError , /* xGetLastError */
memCurrentTimeInt64 /* xCurrentTimeInt64 */
} ;
static const sqlite3_io_methods mem_io_methods = {
3 , /* iVersion */
memClose , /* xClose */
memRead , /* xRead */
memWrite , /* xWrite */
memTruncate , /* xTruncate */
memSync , /* xSync */
memFileSize , /* xFileSize */
memLock , /* xLock */
memUnlock , /* xUnlock */
memCheckReservedLock , /* xCheckReservedLock */
memFileControl , /* xFileControl */
memSectorSize , /* xSectorSize */
memDeviceCharacteristics , /* xDeviceCharacteristics */
memShmMap , /* xShmMap */
memShmLock , /* xShmLock */
memShmBarrier , /* xShmBarrier */
memShmUnmap , /* xShmUnmap */
memFetch , /* xFetch */
memUnfetch /* xUnfetch */
} ;
/*
* * Close an mem - file .
* *
* * The pData pointer is owned by the application , so there is nothing
* * to free .
*/
static int memClose ( sqlite3_file * pFile ) {
2018-01-02 16:02:50 +00:00
MemFile * p = ( MemFile * ) pFile ;
if ( p - > bFreeOnClose ) sqlite3_free ( p - > aData ) ;
2016-09-07 18:11:11 +00:00
return SQLITE_OK ;
}
/*
* * Read data from an mem - file .
*/
static int memRead (
sqlite3_file * pFile ,
void * zBuf ,
int iAmt ,
sqlite_int64 iOfst
) {
MemFile * p = ( MemFile * ) pFile ;
memcpy ( zBuf , p - > aData + iOfst , iAmt ) ;
return SQLITE_OK ;
}
/*
* * Write data to an mem - file .
*/
static int memWrite (
sqlite3_file * pFile ,
const void * z ,
int iAmt ,
sqlite_int64 iOfst
) {
2018-01-02 16:02:50 +00:00
MemFile * p = ( MemFile * ) pFile ;
if ( iOfst + iAmt > p - > sz ) {
if ( iOfst + iAmt > p - > szMax ) return SQLITE_FULL ;
if ( iOfst > p - > sz ) memset ( p - > aData + p - > sz , 0 , iOfst - p - > sz ) ;
p - > sz = iOfst + iAmt ;
}
memcpy ( p - > aData + iOfst , z , iAmt ) ;
return SQLITE_OK ;
2016-09-07 18:11:11 +00:00
}
/*
* * Truncate an mem - file .
*/
static int memTruncate ( sqlite3_file * pFile , sqlite_int64 size ) {
2018-01-02 16:02:50 +00:00
MemFile * p = ( MemFile * ) pFile ;
if ( size > p - > sz ) {
if ( size > p - > szMax ) return SQLITE_FULL ;
memset ( p - > aData + p - > sz , 0 , size - p - > sz ) ;
}
p - > sz = size ;
return SQLITE_OK ;
2016-09-07 18:11:11 +00:00
}
/*
* * Sync an mem - file .
*/
static int memSync ( sqlite3_file * pFile , int flags ) {
2018-01-02 16:02:50 +00:00
return SQLITE_OK ;
2016-09-07 18:11:11 +00:00
}
/*
* * Return the current file - size of an mem - file .
*/
static int memFileSize ( sqlite3_file * pFile , sqlite_int64 * pSize ) {
MemFile * p = ( MemFile * ) pFile ;
* pSize = p - > sz ;
return SQLITE_OK ;
}
/*
* * Lock an mem - file .
*/
static int memLock ( sqlite3_file * pFile , int eLock ) {
2018-01-02 16:02:50 +00:00
return SQLITE_OK ;
2016-09-07 18:11:11 +00:00
}
/*
* * Unlock an mem - file .
*/
static int memUnlock ( sqlite3_file * pFile , int eLock ) {
return SQLITE_OK ;
}
/*
* * Check if another file - handle holds a RESERVED lock on an mem - file .
*/
static int memCheckReservedLock ( sqlite3_file * pFile , int * pResOut ) {
* pResOut = 0 ;
return SQLITE_OK ;
}
/*
* * File control method . For custom operations on an mem - file .
*/
static int memFileControl ( sqlite3_file * pFile , int op , void * pArg ) {
MemFile * p = ( MemFile * ) pFile ;
int rc = SQLITE_NOTFOUND ;
if ( op = = SQLITE_FCNTL_VFSNAME ) {
* ( char * * ) pArg = sqlite3_mprintf ( " mem(%p,%lld) " , p - > aData , p - > sz ) ;
rc = SQLITE_OK ;
}
return rc ;
}
/*
* * Return the sector - size in bytes for an mem - file .
*/
static int memSectorSize ( sqlite3_file * pFile ) {
return 1024 ;
}
/*
* * Return the device characteristic flags supported by an mem - file .
*/
static int memDeviceCharacteristics ( sqlite3_file * pFile ) {
2018-01-02 16:02:50 +00:00
return SQLITE_IOCAP_ATOMIC |
SQLITE_IOCAP_POWERSAFE_OVERWRITE |
SQLITE_IOCAP_SAFE_APPEND |
SQLITE_IOCAP_SEQUENTIAL ;
2016-09-07 18:11:11 +00:00
}
/* Create a shared memory file mapping */
static int memShmMap (
sqlite3_file * pFile ,
int iPg ,
int pgsz ,
int bExtend ,
void volatile * * pp
) {
2018-01-02 16:02:50 +00:00
return SQLITE_IOERR_SHMMAP ;
2016-09-07 18:11:11 +00:00
}
/* Perform locking on a shared-memory segment */
static int memShmLock ( sqlite3_file * pFile , int offset , int n , int flags ) {
2018-01-02 16:02:50 +00:00
return SQLITE_IOERR_SHMLOCK ;
2016-09-07 18:11:11 +00:00
}
/* Memory barrier operation on shared memory */
static void memShmBarrier ( sqlite3_file * pFile ) {
return ;
}
/* Unmap a shared memory segment */
static int memShmUnmap ( sqlite3_file * pFile , int deleteFlag ) {
return SQLITE_OK ;
}
/* Fetch a page of a memory-mapped file */
static int memFetch (
sqlite3_file * pFile ,
sqlite3_int64 iOfst ,
int iAmt ,
void * * pp
) {
MemFile * p = ( MemFile * ) pFile ;
* pp = ( void * ) ( p - > aData + iOfst ) ;
return SQLITE_OK ;
}
/* Release a memory-mapped page */
static int memUnfetch ( sqlite3_file * pFile , sqlite3_int64 iOfst , void * pPage ) {
return SQLITE_OK ;
}
/*
* * Open an mem file handle .
*/
static int memOpen (
sqlite3_vfs * pVfs ,
const char * zName ,
sqlite3_file * pFile ,
int flags ,
int * pOutFlags
) {
MemFile * p = ( MemFile * ) pFile ;
memset ( p , 0 , sizeof ( * p ) ) ;
if ( ( flags & SQLITE_OPEN_MAIN_DB ) = = 0 ) return SQLITE_CANTOPEN ;
p - > aData = ( unsigned char * ) sqlite3_uri_int64 ( zName , " ptr " , 0 ) ;
if ( p - > aData = = 0 ) return SQLITE_CANTOPEN ;
p - > sz = sqlite3_uri_int64 ( zName , " sz " , 0 ) ;
if ( p - > sz < 0 ) return SQLITE_CANTOPEN ;
2018-01-02 16:02:50 +00:00
p - > szMax = sqlite3_uri_int64 ( zName , " max " , p - > sz ) ;
if ( p - > szMax < p - > sz ) return SQLITE_CANTOPEN ;
p - > bFreeOnClose = sqlite3_uri_boolean ( zName , " freeonclose " , 0 ) ;
2016-09-07 18:11:11 +00:00
pFile - > pMethods = & mem_io_methods ;
return SQLITE_OK ;
}
/*
* * 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 memDelete ( sqlite3_vfs * pVfs , const char * zPath , int dirSync ) {
2018-01-02 16:02:50 +00:00
return SQLITE_IOERR_DELETE ;
2016-09-07 18:11:11 +00:00
}
/*
* * Test for access permissions . Return true if the requested permission
* * is available , or false otherwise .
*/
static int memAccess (
sqlite3_vfs * pVfs ,
const char * zPath ,
int flags ,
int * pResOut
) {
2018-01-02 16:02:50 +00:00
* pResOut = 0 ;
2016-09-07 18:11:11 +00:00
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 memFullPathname (
sqlite3_vfs * pVfs ,
const char * zPath ,
int nOut ,
char * zOut
) {
sqlite3_snprintf ( nOut , zOut , " %s " , zPath ) ;
return SQLITE_OK ;
}
/*
* * Open the dynamic library located at zPath and return a handle .
*/
static void * memDlOpen ( 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 memDlError ( 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 ( * memDlSym ( 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 memDlClose ( 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 memRandomness ( 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 memSleep ( sqlite3_vfs * pVfs , int nMicro ) {
return ORIGVFS ( pVfs ) - > xSleep ( ORIGVFS ( pVfs ) , nMicro ) ;
}
/*
* * Return the current time as a Julian Day number in * pTimeOut .
*/
static int memCurrentTime ( sqlite3_vfs * pVfs , double * pTimeOut ) {
return ORIGVFS ( pVfs ) - > xCurrentTime ( ORIGVFS ( pVfs ) , pTimeOut ) ;
}
static int memGetLastError ( sqlite3_vfs * pVfs , int a , char * b ) {
return ORIGVFS ( pVfs ) - > xGetLastError ( ORIGVFS ( pVfs ) , a , b ) ;
}
static int memCurrentTimeInt64 ( sqlite3_vfs * pVfs , sqlite3_int64 * p ) {
return ORIGVFS ( pVfs ) - > xCurrentTimeInt64 ( ORIGVFS ( pVfs ) , p ) ;
}
# ifdef MEMVFS_TEST
/*
2018-01-02 16:02:50 +00:00
* * memvfs_from_file ( FILENAME , MAXSIZE )
2016-09-07 18:11:11 +00:00
* *
* * This an SQL function used to help in testing the memvfs VFS . The
* * function reads the content of a file into memory and then returns
2018-01-02 16:02:50 +00:00
* * a URI that can be handed to ATTACH to attach the memory buffer as
* * a database . Example :
* *
* * ATTACH memvfs_from_file ( ' test . db ' , 1048576 ) AS inmem ;
* *
* * The optional MAXSIZE argument gives the size of the memory allocation
* * used to hold the database . If omitted , it defaults to the size of the
* * file on disk .
2016-09-07 18:11:11 +00:00
*/
# include <stdio.h>
2018-01-02 16:02:50 +00:00
static void memvfsFromFileFunc (
2016-09-07 18:11:11 +00:00
sqlite3_context * context ,
int argc ,
sqlite3_value * * argv
) {
unsigned char * p ;
sqlite3_int64 sz ;
2018-01-02 16:02:50 +00:00
sqlite3_int64 szMax ;
2016-09-07 18:11:11 +00:00
FILE * in ;
const char * zFilename = ( const char * ) sqlite3_value_text ( argv [ 0 ] ) ;
2018-01-02 16:02:50 +00:00
char * zUri ;
2016-09-07 18:11:11 +00:00
if ( zFilename = = 0 ) return ;
in = fopen ( zFilename , " rb " ) ;
if ( in = = 0 ) return ;
fseek ( in , 0 , SEEK_END ) ;
2018-01-02 16:02:50 +00:00
szMax = sz = ftell ( in ) ;
2016-09-07 18:11:11 +00:00
rewind ( in ) ;
2018-01-02 16:02:50 +00:00
if ( argc > = 2 ) {
szMax = sqlite3_value_int64 ( argv [ 1 ] ) ;
if ( szMax < sz ) szMax = sz ;
}
p = sqlite3_malloc64 ( szMax ) ;
2016-09-07 18:11:11 +00:00
if ( p = = 0 ) {
fclose ( in ) ;
sqlite3_result_error_nomem ( context ) ;
return ;
}
fread ( p , sz , 1 , in ) ;
fclose ( in ) ;
2018-01-02 16:02:50 +00:00
zUri = sqlite3_mprintf (
" file:/mem?vfs=memvfs&ptr=%lld&sz=%lld&max=%lld&freeonclose=1 " ,
( sqlite3_int64 ) p , sz , szMax ) ;
sqlite3_result_text ( context , zUri , - 1 , sqlite3_free ) ;
2016-09-07 18:11:11 +00:00
}
2018-01-02 16:02:50 +00:00
# endif /* MEMVFS_TEST */
# ifdef MEMVFS_TEST
/*
* * memvfs_to_file ( SCHEMA , FILENAME )
* *
* * The schema identified by SCHEMA must be a memvfs database . Write
* * the content of this database into FILENAME .
*/
static void memvfsToFileFunc (
sqlite3_context * context ,
int argc ,
sqlite3_value * * argv
) {
MemFile * p = 0 ;
FILE * out ;
int rc ;
sqlite3 * db = sqlite3_context_db_handle ( context ) ;
sqlite3_vfs * pVfs = 0 ;
const char * zSchema = ( const char * ) sqlite3_value_text ( argv [ 0 ] ) ;
const char * zFilename = ( const char * ) sqlite3_value_text ( argv [ 1 ] ) ;
if ( zFilename = = 0 ) return ;
out = fopen ( zFilename , " wb " ) ;
if ( out = = 0 ) return ;
rc = sqlite3_file_control ( db , zSchema , SQLITE_FCNTL_VFS_POINTER , & pVfs ) ;
if ( rc | | pVfs = = 0 ) return ;
if ( strcmp ( pVfs - > zName , " memvfs " ) ! = 0 ) return ;
rc = sqlite3_file_control ( db , zSchema , SQLITE_FCNTL_FILE_POINTER , & p ) ;
if ( rc ) return ;
fwrite ( p - > aData , 1 , ( size_t ) p - > sz , out ) ;
fclose ( out ) ;
}
# endif /* MEMVFS_TEST */
# ifdef MEMVFS_TEST
2016-09-07 18:11:11 +00:00
/* Called for each new database connection */
static int memvfsRegister (
sqlite3 * db ,
2018-01-02 16:02:50 +00:00
char * * pzErrMsg ,
2016-09-07 18:11:11 +00:00
const struct sqlite3_api_routines * pThunk
) {
2018-01-02 16:02:50 +00:00
sqlite3_create_function ( db , " memvfs_from_file " , 1 , SQLITE_UTF8 , 0 ,
memvfsFromFileFunc , 0 , 0 ) ;
sqlite3_create_function ( db , " memvfs_from_file " , 2 , SQLITE_UTF8 , 0 ,
memvfsFromFileFunc , 0 , 0 ) ;
sqlite3_create_function ( db , " memvfs_to_file " , 2 , SQLITE_UTF8 , 0 ,
memvfsToFileFunc , 0 , 0 ) ;
return SQLITE_OK ;
2016-09-07 18:11:11 +00:00
}
# endif /* MEMVFS_TEST */
# ifdef _WIN32
__declspec ( dllexport )
# endif
/*
* * This routine is called when the extension is loaded .
* * Register the new VFS .
*/
int sqlite3_memvfs_init (
sqlite3 * db ,
char * * pzErrMsg ,
const sqlite3_api_routines * pApi
) {
int rc = SQLITE_OK ;
SQLITE_EXTENSION_INIT2 ( pApi ) ;
mem_vfs . pAppData = sqlite3_vfs_find ( 0 ) ;
2021-06-15 15:15:40 +00:00
if ( mem_vfs . pAppData = = 0 ) return SQLITE_ERROR ;
2016-09-07 18:11:11 +00:00
mem_vfs . szOsFile = sizeof ( MemFile ) ;
rc = sqlite3_vfs_register ( & mem_vfs , 1 ) ;
# ifdef MEMVFS_TEST
if ( rc = = SQLITE_OK ) {
rc = sqlite3_auto_extension ( ( void ( * ) ( void ) ) memvfsRegister ) ;
}
2018-01-02 16:02:50 +00:00
if ( rc = = SQLITE_OK ) {
rc = memvfsRegister ( db , pzErrMsg , pApi ) ;
}
2016-09-07 18:11:11 +00:00
# endif
if ( rc = = SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY ;
return rc ;
}