/ Changes On Branch memdb
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch memdb Excluding Merge-Ins

This is equivalent to a diff from e5ce256a to fadbc5e2

2018-03-07
13:01
Add the sqlite3_serialize() and sqlite3_deserialize() interfaces, enabled when the -DSQLITE_ENABLE_DESERIALIZE compile-time option is used. check-in: fc42d31d user: drh tags: trunk
01:37
Mark an unreachable branch using NEVER(). Closed-Leaf check-in: fadbc5e2 user: drh tags: memdb
2018-03-06
21:43
Improved documentation for sqlite3_serialize() and sqlite3_deserialize(). Change the name of the compile-time option to enable these interfaces from SQLITE_ENABLE_MEMDB to SQLITE_ENABLE_DESERIALIZE. check-in: f07e97ae user: drh tags: memdb
11:46
Avoid running a couple of tests in crash8.test that depend on the presence of the journal file if running on an F2FS file-system that does not require a journal file. check-in: 797e02e0 user: dan tags: trunk
02:00
Merge the walIteratorInit() fix from trunk. check-in: 6399e101 user: drh tags: memdb
2018-03-05
23:23
Fix walIteratorInit() so that it always leaves the iterator as a NULL pointer if an OOM occurs. This fixes an assertion fault introduced by check-in [044b0b65e716bff]. check-in: e5ce256a user: drh tags: trunk
21:17
Fix another crash in the sessions module triggered by malformed input. check-in: 7e70c9b8 user: dan tags: trunk

Changes to Makefile.in.

   176    176            fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \
   177    177            fts3_tokenize_vtab.lo \
   178    178            fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \
   179    179   	 fts5.lo \
   180    180            func.lo global.lo hash.lo \
   181    181            icu.lo insert.lo json1.lo legacy.lo loadext.lo \
   182    182            main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \
   183         -         memjournal.lo \
          183  +         memdb.lo memjournal.lo \
   184    184            mutex.lo mutex_noop.lo mutex_unix.lo mutex_w32.lo \
   185    185            notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \
   186    186            pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
   187    187            random.lo resolve.lo rowset.lo rtree.lo \
   188    188            sqlite3session.lo select.lo sqlite3rbu.lo status.lo stmt.lo \
   189    189            table.lo threads.lo tokenize.lo treeview.lo trigger.lo \
   190    190            update.lo util.lo vacuum.lo \
................................................................................
   236    236     $(TOP)/src/main.c \
   237    237     $(TOP)/src/malloc.c \
   238    238     $(TOP)/src/mem0.c \
   239    239     $(TOP)/src/mem1.c \
   240    240     $(TOP)/src/mem2.c \
   241    241     $(TOP)/src/mem3.c \
   242    242     $(TOP)/src/mem5.c \
          243  +  $(TOP)/src/memdb.c \
   243    244     $(TOP)/src/memjournal.c \
   244    245     $(TOP)/src/msvc.h \
   245    246     $(TOP)/src/mutex.c \
   246    247     $(TOP)/src/mutex.h \
   247    248     $(TOP)/src/mutex_noop.c \
   248    249     $(TOP)/src/mutex_unix.c \
   249    250     $(TOP)/src/mutex_w32.c \
................................................................................
   825    826   
   826    827   mem3.lo:	$(TOP)/src/mem3.c $(HDR)
   827    828   	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mem3.c
   828    829   
   829    830   mem5.lo:	$(TOP)/src/mem5.c $(HDR)
   830    831   	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mem5.c
   831    832   
          833  +memdb.lo:	$(TOP)/src/memdb.c $(HDR)
          834  +	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/memdb.c
          835  +
   832    836   memjournal.lo:	$(TOP)/src/memjournal.c $(HDR)
   833    837   	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/memjournal.c
   834    838   
   835    839   mutex.lo:	$(TOP)/src/mutex.c $(HDR)
   836    840   	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mutex.c
   837    841   
   838    842   mutex_noop.lo:	$(TOP)/src/mutex_noop.c $(HDR)

Changes to Makefile.msc.

  1182   1182            fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \
  1183   1183            fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \
  1184   1184            fts3_tokenize_vtab.lo fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \
  1185   1185            fts5.lo \
  1186   1186            func.lo global.lo hash.lo \
  1187   1187            icu.lo insert.lo legacy.lo loadext.lo \
  1188   1188            main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \
  1189         -         memjournal.lo \
         1189  +         memdb.lo memjournal.lo \
  1190   1190            mutex.lo mutex_noop.lo mutex_unix.lo mutex_w32.lo \
  1191   1191            notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \
  1192   1192            pager.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
  1193   1193            random.lo resolve.lo rowset.lo rtree.lo \
  1194   1194            sqlite3session.lo select.lo sqlite3rbu.lo status.lo \
  1195   1195            table.lo threads.lo tokenize.lo treeview.lo trigger.lo \
  1196   1196            update.lo util.lo vacuum.lo \
................................................................................
  1255   1255     $(TOP)\src\main.c \
  1256   1256     $(TOP)\src\malloc.c \
  1257   1257     $(TOP)\src\mem0.c \
  1258   1258     $(TOP)\src\mem1.c \
  1259   1259     $(TOP)\src\mem2.c \
  1260   1260     $(TOP)\src\mem3.c \
  1261   1261     $(TOP)\src\mem5.c \
         1262  +  $(TOP)\src\memdb.c \
  1262   1263     $(TOP)\src\memjournal.c \
  1263   1264     $(TOP)\src\mutex.c \
  1264   1265     $(TOP)\src\mutex_noop.c \
  1265   1266     $(TOP)\src\mutex_unix.c \
  1266   1267     $(TOP)\src\mutex_w32.c \
  1267   1268     $(TOP)\src\notify.c \
  1268   1269     $(TOP)\src\os.c \
................................................................................
  1905   1906   
  1906   1907   mem3.lo:	$(TOP)\src\mem3.c $(HDR)
  1907   1908   	$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\mem3.c
  1908   1909   
  1909   1910   mem5.lo:	$(TOP)\src\mem5.c $(HDR)
  1910   1911   	$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\mem5.c
  1911   1912   
         1913  +memdb.lo:	$(TOP)\src\memdb.c $(HDR)
         1914  +	$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\memdb.c
         1915  +
  1912   1916   memjournal.lo:	$(TOP)\src\memjournal.c $(HDR)
  1913   1917   	$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\memjournal.c
  1914   1918   
  1915   1919   mutex.lo:	$(TOP)\src\mutex.c $(HDR)
  1916   1920   	$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\mutex.c
  1917   1921   
  1918   1922   mutex_noop.lo:	$(TOP)\src\mutex_noop.c $(HDR)

Changes to main.mk.

    61     61            fts3.o fts3_aux.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \
    62     62            fts3_snippet.o fts3_tokenizer.o fts3_tokenizer1.o \
    63     63            fts3_tokenize_vtab.o \
    64     64   	 fts3_unicode.o fts3_unicode2.o \
    65     65            fts3_write.o fts5.o func.o global.o hash.o \
    66     66            icu.o insert.o json1.o legacy.o loadext.o \
    67     67            main.o malloc.o mem0.o mem1.o mem2.o mem3.o mem5.o \
    68         -         memjournal.o \
           68  +         memdb.o memjournal.o \
    69     69            mutex.o mutex_noop.o mutex_unix.o mutex_w32.o \
    70     70            notify.o opcodes.o os.o os_unix.o os_win.o \
    71     71            pager.o pcache.o pcache1.o pragma.o prepare.o printf.o \
    72     72            random.o resolve.o rowset.o rtree.o \
    73     73            select.o sqlite3rbu.o status.o stmt.o \
    74     74            table.o threads.o tokenize.o treeview.o trigger.o \
    75     75            update.o userauth.o util.o vacuum.o \
................................................................................
   114    114     $(TOP)/src/main.c \
   115    115     $(TOP)/src/malloc.c \
   116    116     $(TOP)/src/mem0.c \
   117    117     $(TOP)/src/mem1.c \
   118    118     $(TOP)/src/mem2.c \
   119    119     $(TOP)/src/mem3.c \
   120    120     $(TOP)/src/mem5.c \
          121  +  $(TOP)/src/memdb.c \
   121    122     $(TOP)/src/memjournal.c \
   122    123     $(TOP)/src/msvc.h \
   123    124     $(TOP)/src/mutex.c \
   124    125     $(TOP)/src/mutex.h \
   125    126     $(TOP)/src/mutex_noop.c \
   126    127     $(TOP)/src/mutex_unix.c \
   127    128     $(TOP)/src/mutex_w32.c \

Changes to src/attach.c.

    51     51   **
    52     52   **     ATTACH DATABASE x AS y KEY z
    53     53   **
    54     54   **     SELECT sqlite_attach(x, y, z)
    55     55   **
    56     56   ** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the
    57     57   ** third argument.
           58  +**
           59  +** If the db->init.reopenMemdb flags is set, then instead of attaching a
           60  +** new database, close the database on db->init.iDb and reopen it as an
           61  +** empty MemDB.
    58     62   */
    59     63   static void attachFunc(
    60     64     sqlite3_context *context,
    61     65     int NotUsed,
    62     66     sqlite3_value **argv
    63     67   ){
    64     68     int i;
................................................................................
    71     75     unsigned int flags;
    72     76     Db *aNew;                 /* New array of Db pointers */
    73     77     Db *pNew;                 /* Db object for the newly attached database */
    74     78     char *zErrDyn = 0;
    75     79     sqlite3_vfs *pVfs;
    76     80   
    77     81     UNUSED_PARAMETER(NotUsed);
    78         -
    79     82     zFile = (const char *)sqlite3_value_text(argv[0]);
    80     83     zName = (const char *)sqlite3_value_text(argv[1]);
    81     84     if( zFile==0 ) zFile = "";
    82     85     if( zName==0 ) zName = "";
    83     86   
    84         -  /* Check for the following errors:
    85         -  **
    86         -  **     * Too many attached databases,
    87         -  **     * Transaction currently open
    88         -  **     * Specified database name already being used.
    89         -  */
    90         -  if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){
    91         -    zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d", 
    92         -      db->aLimit[SQLITE_LIMIT_ATTACHED]
    93         -    );
    94         -    goto attach_error;
    95         -  }
    96         -  for(i=0; i<db->nDb; i++){
    97         -    char *z = db->aDb[i].zDbSName;
    98         -    assert( z && zName );
    99         -    if( sqlite3StrICmp(z, zName)==0 ){
   100         -      zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName);
           87  +#ifdef SQLITE_ENABLE_DESERIALIZE
           88  +# define REOPEN_AS_MEMDB(db)  (db->init.reopenMemdb)
           89  +#else
           90  +# define REOPEN_AS_MEMDB(db)  (0)
           91  +#endif
           92  +
           93  +  if( REOPEN_AS_MEMDB(db) ){
           94  +    /* This is not a real ATTACH.  Instead, this routine is being called
           95  +    ** from sqlite3_deserialize() to close database db->init.iDb and
           96  +    ** reopen it as a MemDB */
           97  +    pVfs = sqlite3_vfs_find("memdb");
           98  +    if( pVfs==0 ) return;
           99  +    pNew = &db->aDb[db->init.iDb];
          100  +    if( pNew->pBt ) sqlite3BtreeClose(pNew->pBt);
          101  +    pNew->pBt = 0;
          102  +    pNew->pSchema = 0;
          103  +    rc = sqlite3BtreeOpen(pVfs, "x", db, &pNew->pBt, 0, SQLITE_OPEN_MAIN_DB);
          104  +  }else{
          105  +    /* This is a real ATTACH
          106  +    **
          107  +    ** Check for the following errors:
          108  +    **
          109  +    **     * Too many attached databases,
          110  +    **     * Transaction currently open
          111  +    **     * Specified database name already being used.
          112  +    */
          113  +    if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){
          114  +      zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d", 
          115  +        db->aLimit[SQLITE_LIMIT_ATTACHED]
          116  +      );
   101    117         goto attach_error;
   102    118       }
   103         -  }
   104         -
   105         -  /* Allocate the new entry in the db->aDb[] array and initialize the schema
   106         -  ** hash tables.
   107         -  */
   108         -  if( db->aDb==db->aDbStatic ){
   109         -    aNew = sqlite3DbMallocRawNN(db, sizeof(db->aDb[0])*3 );
   110         -    if( aNew==0 ) return;
   111         -    memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
   112         -  }else{
   113         -    aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
   114         -    if( aNew==0 ) return;
   115         -  }
   116         -  db->aDb = aNew;
   117         -  pNew = &db->aDb[db->nDb];
   118         -  memset(pNew, 0, sizeof(*pNew));
   119         -
   120         -  /* Open the database file. If the btree is successfully opened, use
   121         -  ** it to obtain the database schema. At this point the schema may
   122         -  ** or may not be initialized.
   123         -  */
   124         -  flags = db->openFlags;
   125         -  rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr);
   126         -  if( rc!=SQLITE_OK ){
   127         -    if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
   128         -    sqlite3_result_error(context, zErr, -1);
   129         -    sqlite3_free(zErr);
   130         -    return;
   131         -  }
   132         -  assert( pVfs );
   133         -  flags |= SQLITE_OPEN_MAIN_DB;
   134         -  rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags);
   135         -  sqlite3_free( zPath );
   136         -  db->nDb++;
          119  +    for(i=0; i<db->nDb; i++){
          120  +      char *z = db->aDb[i].zDbSName;
          121  +      assert( z && zName );
          122  +      if( sqlite3StrICmp(z, zName)==0 ){
          123  +        zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName);
          124  +        goto attach_error;
          125  +      }
          126  +    }
          127  +  
          128  +    /* Allocate the new entry in the db->aDb[] array and initialize the schema
          129  +    ** hash tables.
          130  +    */
          131  +    if( db->aDb==db->aDbStatic ){
          132  +      aNew = sqlite3DbMallocRawNN(db, sizeof(db->aDb[0])*3 );
          133  +      if( aNew==0 ) return;
          134  +      memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
          135  +    }else{
          136  +      aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
          137  +      if( aNew==0 ) return;
          138  +    }
          139  +    db->aDb = aNew;
          140  +    pNew = &db->aDb[db->nDb];
          141  +    memset(pNew, 0, sizeof(*pNew));
          142  +  
          143  +    /* Open the database file. If the btree is successfully opened, use
          144  +    ** it to obtain the database schema. At this point the schema may
          145  +    ** or may not be initialized.
          146  +    */
          147  +    flags = db->openFlags;
          148  +    rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr);
          149  +    if( rc!=SQLITE_OK ){
          150  +      if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
          151  +      sqlite3_result_error(context, zErr, -1);
          152  +      sqlite3_free(zErr);
          153  +      return;
          154  +    }
          155  +    assert( pVfs );
          156  +    flags |= SQLITE_OPEN_MAIN_DB;
          157  +    rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags);
          158  +    sqlite3_free( zPath );
          159  +    db->nDb++;
          160  +  }
   137    161     db->skipBtreeMutex = 0;
   138    162     if( rc==SQLITE_CONSTRAINT ){
   139    163       rc = SQLITE_ERROR;
   140    164       zErrDyn = sqlite3MPrintf(db, "database is already attached");
   141    165     }else if( rc==SQLITE_OK ){
   142    166       Pager *pPager;
   143    167       pNew->pSchema = sqlite3SchemaGet(db, pNew->pBt);
................................................................................
   156    180   #ifndef SQLITE_OMIT_PAGER_PRAGMAS
   157    181       sqlite3BtreeSetPagerFlags(pNew->pBt,
   158    182                         PAGER_SYNCHRONOUS_FULL | (db->flags & PAGER_FLAGS_MASK));
   159    183   #endif
   160    184       sqlite3BtreeLeave(pNew->pBt);
   161    185     }
   162    186     pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
   163         -  pNew->zDbSName = sqlite3DbStrDup(db, zName);
          187  +  if( !REOPEN_AS_MEMDB(db) ) pNew->zDbSName = sqlite3DbStrDup(db, zName);
   164    188     if( rc==SQLITE_OK && pNew->zDbSName==0 ){
   165    189       rc = SQLITE_NOMEM_BKPT;
   166    190     }
   167    191   
   168    192   
   169    193   #ifdef SQLITE_HAS_CODEC
   170    194     if( rc==SQLITE_OK ){
................................................................................
   196    220           break;
   197    221       }
   198    222     }
   199    223   #endif
   200    224   
   201    225     /* If the file was opened successfully, read the schema for the new database.
   202    226     ** If this fails, or if opening the file failed, then close the file and 
   203         -  ** remove the entry from the db->aDb[] array. i.e. put everything back the way
   204         -  ** we found it.
          227  +  ** remove the entry from the db->aDb[] array. i.e. put everything back the
          228  +  ** way we found it.
   205    229     */
   206    230     if( rc==SQLITE_OK ){
   207    231       sqlite3BtreeEnterAll(db);
          232  +    db->init.iDb = 0;
   208    233       rc = sqlite3Init(db, &zErrDyn);
   209    234       sqlite3BtreeLeaveAll(db);
          235  +    assert( zErrDyn==0 || rc!=SQLITE_OK );
   210    236     }
   211    237   #ifdef SQLITE_USER_AUTHENTICATION
   212    238     if( rc==SQLITE_OK ){
   213    239       u8 newAuth = 0;
   214    240       rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth);
   215    241       if( newAuth<db->auth.authLevel ){
   216    242         rc = SQLITE_AUTH_USER;
   217    243       }
   218    244     }
   219    245   #endif
   220    246     if( rc ){
   221         -    int iDb = db->nDb - 1;
   222         -    assert( iDb>=2 );
   223         -    if( db->aDb[iDb].pBt ){
   224         -      sqlite3BtreeClose(db->aDb[iDb].pBt);
   225         -      db->aDb[iDb].pBt = 0;
   226         -      db->aDb[iDb].pSchema = 0;
   227         -    }
   228         -    sqlite3ResetAllSchemasOfConnection(db);
   229         -    db->nDb = iDb;
   230         -    if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
   231         -      sqlite3OomFault(db);
   232         -      sqlite3DbFree(db, zErrDyn);
   233         -      zErrDyn = sqlite3MPrintf(db, "out of memory");
   234         -    }else if( zErrDyn==0 ){
   235         -      zErrDyn = sqlite3MPrintf(db, "unable to open database: %s", zFile);
          247  +    if( !REOPEN_AS_MEMDB(db) ){
          248  +      int iDb = db->nDb - 1;
          249  +      assert( iDb>=2 );
          250  +      if( db->aDb[iDb].pBt ){
          251  +        sqlite3BtreeClose(db->aDb[iDb].pBt);
          252  +        db->aDb[iDb].pBt = 0;
          253  +        db->aDb[iDb].pSchema = 0;
          254  +      }
          255  +      sqlite3ResetAllSchemasOfConnection(db);
          256  +      db->nDb = iDb;
          257  +      if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
          258  +        sqlite3OomFault(db);
          259  +        sqlite3DbFree(db, zErrDyn);
          260  +        zErrDyn = sqlite3MPrintf(db, "out of memory");
          261  +      }else if( zErrDyn==0 ){
          262  +        zErrDyn = sqlite3MPrintf(db, "unable to open database: %s", zFile);
          263  +      }
   236    264       }
   237    265       goto attach_error;
   238    266     }
   239    267     
   240    268     return;
   241    269   
   242    270   attach_error:

Changes to src/main.c.

   235    235       if( sqlite3GlobalConfig.isPCacheInit==0 ){
   236    236         rc = sqlite3PcacheInitialize();
   237    237       }
   238    238       if( rc==SQLITE_OK ){
   239    239         sqlite3GlobalConfig.isPCacheInit = 1;
   240    240         rc = sqlite3OsInit();
   241    241       }
          242  +#ifdef SQLITE_ENABLE_DESERIALIZE
          243  +    if( rc==SQLITE_OK ){
          244  +      rc = sqlite3MemdbInit();
          245  +    }
          246  +#endif
   242    247       if( rc==SQLITE_OK ){
   243    248         sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage, 
   244    249             sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);
   245    250         sqlite3GlobalConfig.isInit = 1;
   246    251   #ifdef SQLITE_EXTRA_INIT
   247    252         bRunExtraInit = 1;
   248    253   #endif
................................................................................
   267    272     ** been compiled correctly.  It is important to run this code, but
   268    273     ** we don't want to run it too often and soak up CPU cycles for no
   269    274     ** reason.  So we run it once during initialization.
   270    275     */
   271    276   #ifndef NDEBUG
   272    277   #ifndef SQLITE_OMIT_FLOATING_POINT
   273    278     /* This section of code's only "output" is via assert() statements. */
   274         -  if ( rc==SQLITE_OK ){
          279  +  if( rc==SQLITE_OK ){
   275    280       u64 x = (((u64)1)<<63)-1;
   276    281       double y;
   277    282       assert(sizeof(x)==8);
   278    283       assert(sizeof(x)==sizeof(y));
   279    284       memcpy(&y, &x, 8);
   280    285       assert( sqlite3IsNaN(y) );
   281    286     }

Added src/memdb.c.

            1  +/*
            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  +**
           13  +** This file implements in-memory VFS.  A database is held as a contiguous
           14  +** block of memory.
           15  +**
           16  +** This file also implements interface sqlite3_serialize() and
           17  +** sqlite3_deserialize().
           18  +*/
           19  +#ifdef SQLITE_ENABLE_DESERIALIZE
           20  +#include "sqliteInt.h"
           21  +
           22  +/*
           23  +** Forward declaration of objects used by this utility
           24  +*/
           25  +typedef struct sqlite3_vfs MemVfs;
           26  +typedef 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 */
           34  +struct MemFile {
           35  +  sqlite3_file base;              /* IO methods */
           36  +  sqlite3_int64 sz;               /* Size of the file */
           37  +  sqlite3_int64 szMax;            /* Space allocated to aData */
           38  +  unsigned char *aData;           /* content of the file */
           39  +  int nMmap;                      /* Number of memory mapped pages */
           40  +  unsigned mFlags;                /* Flags */
           41  +  int eLock;                      /* Most recent lock against this file */
           42  +};
           43  +
           44  +/*
           45  +** Methods for MemFile
           46  +*/
           47  +static int memdbClose(sqlite3_file*);
           48  +static int memdbRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
           49  +static int memdbWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
           50  +static int memdbTruncate(sqlite3_file*, sqlite3_int64 size);
           51  +static int memdbSync(sqlite3_file*, int flags);
           52  +static int memdbFileSize(sqlite3_file*, sqlite3_int64 *pSize);
           53  +static int memdbLock(sqlite3_file*, int);
           54  +/* static int memdbCheckReservedLock(sqlite3_file*, int *pResOut);// not used */
           55  +static int memdbFileControl(sqlite3_file*, int op, void *pArg);
           56  +/* static int memdbSectorSize(sqlite3_file*); // not used */
           57  +static int memdbDeviceCharacteristics(sqlite3_file*);
           58  +static int memdbFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
           59  +static int memdbUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
           60  +
           61  +/*
           62  +** Methods for MemVfs
           63  +*/
           64  +static int memdbOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
           65  +/* static int memdbDelete(sqlite3_vfs*, const char *zName, int syncDir); */
           66  +static int memdbAccess(sqlite3_vfs*, const char *zName, int flags, int *);
           67  +static int memdbFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
           68  +static void *memdbDlOpen(sqlite3_vfs*, const char *zFilename);
           69  +static void memdbDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
           70  +static void (*memdbDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
           71  +static void memdbDlClose(sqlite3_vfs*, void*);
           72  +static int memdbRandomness(sqlite3_vfs*, int nByte, char *zOut);
           73  +static int memdbSleep(sqlite3_vfs*, int microseconds);
           74  +/* static int memdbCurrentTime(sqlite3_vfs*, double*); */
           75  +static int memdbGetLastError(sqlite3_vfs*, int, char *);
           76  +static int memdbCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
           77  +
           78  +static sqlite3_vfs memdb_vfs = {
           79  +  2,                           /* iVersion */
           80  +  0,                           /* szOsFile (set when registered) */
           81  +  1024,                        /* mxPathname */
           82  +  0,                           /* pNext */
           83  +  "memdb",                     /* zName */
           84  +  0,                           /* pAppData (set when registered) */ 
           85  +  memdbOpen,                   /* xOpen */
           86  +  0, /* memdbDelete, */        /* xDelete */
           87  +  memdbAccess,                 /* xAccess */
           88  +  memdbFullPathname,           /* xFullPathname */
           89  +  memdbDlOpen,                 /* xDlOpen */
           90  +  memdbDlError,                /* xDlError */
           91  +  memdbDlSym,                  /* xDlSym */
           92  +  memdbDlClose,                /* xDlClose */
           93  +  memdbRandomness,             /* xRandomness */
           94  +  memdbSleep,                  /* xSleep */
           95  +  0, /* memdbCurrentTime, */   /* xCurrentTime */
           96  +  memdbGetLastError,           /* xGetLastError */
           97  +  memdbCurrentTimeInt64        /* xCurrentTimeInt64 */
           98  +};
           99  +
          100  +static const sqlite3_io_methods memdb_io_methods = {
          101  +  3,                              /* iVersion */
          102  +  memdbClose,                      /* xClose */
          103  +  memdbRead,                       /* xRead */
          104  +  memdbWrite,                      /* xWrite */
          105  +  memdbTruncate,                   /* xTruncate */
          106  +  memdbSync,                       /* xSync */
          107  +  memdbFileSize,                   /* xFileSize */
          108  +  memdbLock,                       /* xLock */
          109  +  memdbLock,                       /* xUnlock - same as xLock in this case */ 
          110  +  0, /* memdbCheckReservedLock, */ /* xCheckReservedLock */
          111  +  memdbFileControl,                /* xFileControl */
          112  +  0, /* memdbSectorSize,*/         /* xSectorSize */
          113  +  memdbDeviceCharacteristics,      /* xDeviceCharacteristics */
          114  +  0,                               /* xShmMap */
          115  +  0,                               /* xShmLock */
          116  +  0,                               /* xShmBarrier */
          117  +  0,                               /* xShmUnmap */
          118  +  memdbFetch,                      /* xFetch */
          119  +  memdbUnfetch                     /* xUnfetch */
          120  +};
          121  +
          122  +
          123  +
          124  +/*
          125  +** Close an memdb-file.
          126  +**
          127  +** The pData pointer is owned by the application, so there is nothing
          128  +** to free.
          129  +*/
          130  +static int memdbClose(sqlite3_file *pFile){
          131  +  MemFile *p = (MemFile *)pFile;
          132  +  if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ) sqlite3_free(p->aData);
          133  +  return SQLITE_OK;
          134  +}
          135  +
          136  +/*
          137  +** Read data from an memdb-file.
          138  +*/
          139  +static int memdbRead(
          140  +  sqlite3_file *pFile, 
          141  +  void *zBuf, 
          142  +  int iAmt, 
          143  +  sqlite_int64 iOfst
          144  +){
          145  +  MemFile *p = (MemFile *)pFile;
          146  +  if( iOfst+iAmt>p->sz ){
          147  +    memset(zBuf, 0, iAmt);
          148  +    if( iOfst<p->sz ) memcpy(zBuf, p->aData+iOfst, p->sz - iOfst);
          149  +    return SQLITE_IOERR_SHORT_READ;
          150  +  }
          151  +  memcpy(zBuf, p->aData+iOfst, iAmt);
          152  +  return SQLITE_OK;
          153  +}
          154  +
          155  +/*
          156  +** Try to enlarge the memory allocation to hold at least sz bytes
          157  +*/
          158  +static int memdbEnlarge(MemFile *p, sqlite3_int64 newSz){
          159  +  unsigned char *pNew;
          160  +  if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || p->nMmap>0 ){
          161  +    return SQLITE_FULL;
          162  +  }
          163  +  pNew = sqlite3_realloc64(p->aData, newSz);
          164  +  if( pNew==0 ) return SQLITE_NOMEM;
          165  +  p->aData = pNew;
          166  +  p->szMax = newSz;
          167  +  return SQLITE_OK;
          168  +}
          169  +
          170  +/*
          171  +** Write data to an memdb-file.
          172  +*/
          173  +static int memdbWrite(
          174  +  sqlite3_file *pFile,
          175  +  const void *z,
          176  +  int iAmt,
          177  +  sqlite_int64 iOfst
          178  +){
          179  +  MemFile *p = (MemFile *)pFile;
          180  +  if( iOfst+iAmt>p->sz ){
          181  +    int rc;
          182  +    if( iOfst+iAmt>p->szMax
          183  +     && (rc = memdbEnlarge(p, (iOfst+iAmt)*2))!=SQLITE_OK
          184  +    ){
          185  +      return rc;
          186  +    }
          187  +    if( iOfst>p->sz ) memset(p->aData+p->sz, 0, iOfst-p->sz);
          188  +    p->sz = iOfst+iAmt;
          189  +  }
          190  +  memcpy(p->aData+iOfst, z, iAmt);
          191  +  return SQLITE_OK;
          192  +}
          193  +
          194  +/*
          195  +** Truncate an memdb-file.
          196  +**
          197  +** In rollback mode (which is always the case for memdb, as it does not
          198  +** support WAL mode) the truncate() method is only used to reduce
          199  +** the size of a file, never to increase the size.
          200  +*/
          201  +static int memdbTruncate(sqlite3_file *pFile, sqlite_int64 size){
          202  +  MemFile *p = (MemFile *)pFile;
          203  +  if( NEVER(size>p->sz) ) return SQLITE_FULL;
          204  +  p->sz = size; 
          205  +  return SQLITE_OK;
          206  +}
          207  +
          208  +/*
          209  +** Sync an memdb-file.
          210  +*/
          211  +static int memdbSync(sqlite3_file *pFile, int flags){
          212  +  return SQLITE_OK;
          213  +}
          214  +
          215  +/*
          216  +** Return the current file-size of an memdb-file.
          217  +*/
          218  +static int memdbFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
          219  +  MemFile *p = (MemFile *)pFile;
          220  +  *pSize = p->sz;
          221  +  return SQLITE_OK;
          222  +}
          223  +
          224  +/*
          225  +** Lock an memdb-file.
          226  +*/
          227  +static int memdbLock(sqlite3_file *pFile, int eLock){
          228  +  MemFile *p = (MemFile *)pFile;
          229  +  p->eLock = eLock;
          230  +  return SQLITE_OK;
          231  +}
          232  +
          233  +#if 0 /* Never used because memdbAccess() always returns false */
          234  +/*
          235  +** Check if another file-handle holds a RESERVED lock on an memdb-file.
          236  +*/
          237  +static int memdbCheckReservedLock(sqlite3_file *pFile, int *pResOut){
          238  +  *pResOut = 0;
          239  +  return SQLITE_OK;
          240  +}
          241  +#endif
          242  +
          243  +/*
          244  +** File control method. For custom operations on an memdb-file.
          245  +*/
          246  +static int memdbFileControl(sqlite3_file *pFile, int op, void *pArg){
          247  +  MemFile *p = (MemFile *)pFile;
          248  +  int rc = SQLITE_NOTFOUND;
          249  +  if( op==SQLITE_FCNTL_VFSNAME ){
          250  +    *(char**)pArg = sqlite3_mprintf("memdb(%p,%lld)", p->aData, p->sz);
          251  +    rc = SQLITE_OK;
          252  +  }
          253  +  return rc;
          254  +}
          255  +
          256  +#if 0  /* Not used because of SQLITE_IOCAP_POWERSAFE_OVERWRITE */
          257  +/*
          258  +** Return the sector-size in bytes for an memdb-file.
          259  +*/
          260  +static int memdbSectorSize(sqlite3_file *pFile){
          261  +  return 1024;
          262  +}
          263  +#endif
          264  +
          265  +/*
          266  +** Return the device characteristic flags supported by an memdb-file.
          267  +*/
          268  +static int memdbDeviceCharacteristics(sqlite3_file *pFile){
          269  +  return SQLITE_IOCAP_ATOMIC | 
          270  +         SQLITE_IOCAP_POWERSAFE_OVERWRITE |
          271  +         SQLITE_IOCAP_SAFE_APPEND |
          272  +         SQLITE_IOCAP_SEQUENTIAL;
          273  +}
          274  +
          275  +/* Fetch a page of a memory-mapped file */
          276  +static int memdbFetch(
          277  +  sqlite3_file *pFile,
          278  +  sqlite3_int64 iOfst,
          279  +  int iAmt,
          280  +  void **pp
          281  +){
          282  +  MemFile *p = (MemFile *)pFile;
          283  +  p->nMmap++;
          284  +  *pp = (void*)(p->aData + iOfst);
          285  +  return SQLITE_OK;
          286  +}
          287  +
          288  +/* Release a memory-mapped page */
          289  +static int memdbUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
          290  +  MemFile *p = (MemFile *)pFile;
          291  +  p->nMmap--;
          292  +  return SQLITE_OK;
          293  +}
          294  +
          295  +/*
          296  +** Open an mem file handle.
          297  +*/
          298  +static int memdbOpen(
          299  +  sqlite3_vfs *pVfs,
          300  +  const char *zName,
          301  +  sqlite3_file *pFile,
          302  +  int flags,
          303  +  int *pOutFlags
          304  +){
          305  +  MemFile *p = (MemFile*)pFile;
          306  +  if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){
          307  +    return ORIGVFS(pVfs)->xOpen(ORIGVFS(pVfs), zName, pFile, flags, pOutFlags);
          308  +  }
          309  +  memset(p, 0, sizeof(*p));
          310  +  p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE;
          311  +  assert( pOutFlags!=0 );  /* True because flags==SQLITE_OPEN_MAIN_DB */
          312  +  *pOutFlags = flags | SQLITE_OPEN_MEMORY;
          313  +  p->base.pMethods = &memdb_io_methods;
          314  +  return SQLITE_OK;
          315  +}
          316  +
          317  +#if 0 /* Only used to delete rollback journals, master journals, and WAL
          318  +      ** files, none of which exist in memdb.  So this routine is never used */
          319  +/*
          320  +** Delete the file located at zPath. If the dirSync argument is true,
          321  +** ensure the file-system modifications are synced to disk before
          322  +** returning.
          323  +*/
          324  +static int memdbDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
          325  +  return SQLITE_IOERR_DELETE;
          326  +}
          327  +#endif
          328  +
          329  +/*
          330  +** Test for access permissions. Return true if the requested permission
          331  +** is available, or false otherwise.
          332  +**
          333  +** With memdb, no files ever exist on disk.  So always return false.
          334  +*/
          335  +static int memdbAccess(
          336  +  sqlite3_vfs *pVfs, 
          337  +  const char *zPath, 
          338  +  int flags, 
          339  +  int *pResOut
          340  +){
          341  +  *pResOut = 0;
          342  +  return SQLITE_OK;
          343  +}
          344  +
          345  +/*
          346  +** Populate buffer zOut with the full canonical pathname corresponding
          347  +** to the pathname in zPath. zOut is guaranteed to point to a buffer
          348  +** of at least (INST_MAX_PATHNAME+1) bytes.
          349  +*/
          350  +static int memdbFullPathname(
          351  +  sqlite3_vfs *pVfs, 
          352  +  const char *zPath, 
          353  +  int nOut, 
          354  +  char *zOut
          355  +){
          356  +  sqlite3_snprintf(nOut, zOut, "%s", zPath);
          357  +  return SQLITE_OK;
          358  +}
          359  +
          360  +/*
          361  +** Open the dynamic library located at zPath and return a handle.
          362  +*/
          363  +static void *memdbDlOpen(sqlite3_vfs *pVfs, const char *zPath){
          364  +  return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
          365  +}
          366  +
          367  +/*
          368  +** Populate the buffer zErrMsg (size nByte bytes) with a human readable
          369  +** utf-8 string describing the most recent error encountered associated 
          370  +** with dynamic libraries.
          371  +*/
          372  +static void memdbDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
          373  +  ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
          374  +}
          375  +
          376  +/*
          377  +** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
          378  +*/
          379  +static void (*memdbDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
          380  +  return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
          381  +}
          382  +
          383  +/*
          384  +** Close the dynamic library handle pHandle.
          385  +*/
          386  +static void memdbDlClose(sqlite3_vfs *pVfs, void *pHandle){
          387  +  ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
          388  +}
          389  +
          390  +/*
          391  +** Populate the buffer pointed to by zBufOut with nByte bytes of 
          392  +** random data.
          393  +*/
          394  +static int memdbRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
          395  +  return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
          396  +}
          397  +
          398  +/*
          399  +** Sleep for nMicro microseconds. Return the number of microseconds 
          400  +** actually slept.
          401  +*/
          402  +static int memdbSleep(sqlite3_vfs *pVfs, int nMicro){
          403  +  return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
          404  +}
          405  +
          406  +#if 0  /* Never used.  Modern cores only call xCurrentTimeInt64() */
          407  +/*
          408  +** Return the current time as a Julian Day number in *pTimeOut.
          409  +*/
          410  +static int memdbCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
          411  +  return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
          412  +}
          413  +#endif
          414  +
          415  +static int memdbGetLastError(sqlite3_vfs *pVfs, int a, char *b){
          416  +  return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
          417  +}
          418  +static int memdbCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
          419  +  return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);
          420  +}
          421  +
          422  +/*
          423  +** Translate a database connection pointer and schema name into a
          424  +** MemFile pointer.
          425  +*/
          426  +static MemFile *memdbFromDbSchema(sqlite3 *db, const char *zSchema){
          427  +  MemFile *p = 0;
          428  +  int rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p);
          429  +  if( rc ) return 0;
          430  +  if( p->base.pMethods!=&memdb_io_methods ) return 0;
          431  +  return p;
          432  +}
          433  +
          434  +/*
          435  +** Return the serialization of a database
          436  +*/
          437  +unsigned char *sqlite3_serialize(
          438  +  sqlite3 *db,              /* The database connection */
          439  +  const char *zSchema,      /* Which database within the connection */
          440  +  sqlite3_int64 *piSize,    /* Write size here, if not NULL */
          441  +  unsigned int mFlags       /* Maybe SQLITE_SERIALIZE_NOCOPY */
          442  +){
          443  +  MemFile *p;
          444  +  int iDb;
          445  +  Btree *pBt;
          446  +  sqlite3_int64 sz;
          447  +  int szPage = 0;
          448  +  sqlite3_stmt *pStmt = 0;
          449  +  unsigned char *pOut;
          450  +  char *zSql;
          451  +  int rc;
          452  +
          453  +  if( zSchema==0 ) zSchema = db->aDb[0].zDbSName;
          454  +  p = memdbFromDbSchema(db, zSchema);
          455  +  iDb = sqlite3FindDbName(db, zSchema);
          456  +  if( piSize ) *piSize = -1;
          457  +  if( iDb<0 ) return 0;
          458  +  if( p ){
          459  +    if( piSize ) *piSize = p->sz;
          460  +    if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
          461  +      pOut = p->aData;
          462  +    }else{
          463  +      pOut = sqlite3_malloc64( p->sz );
          464  +      if( pOut ) memcpy(pOut, p->aData, p->sz);
          465  +    }
          466  +    return pOut;
          467  +  }
          468  +  pBt = db->aDb[iDb].pBt;
          469  +  if( pBt==0 ) return 0;
          470  +  szPage = sqlite3BtreeGetPageSize(pBt);
          471  +  zSql = sqlite3_mprintf("PRAGMA \"%w\".page_count", zSchema);
          472  +  rc = zSql ? sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0) : SQLITE_NOMEM;
          473  +  sqlite3_free(zSql);
          474  +  if( rc ) return 0;
          475  +  rc = sqlite3_step(pStmt);
          476  +  if( rc!=SQLITE_ROW ){
          477  +    pOut = 0;
          478  +  }else{
          479  +    sz = sqlite3_column_int64(pStmt, 0)*szPage;
          480  +    if( piSize ) *piSize = sz;
          481  +    if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
          482  +      pOut = 0;
          483  +    }else{
          484  +      pOut = sqlite3_malloc64( sz );
          485  +      if( pOut ){
          486  +        int nPage = sqlite3_column_int(pStmt, 0);
          487  +        Pager *pPager = sqlite3BtreePager(pBt);
          488  +        int pgno;
          489  +        for(pgno=1; pgno<=nPage; pgno++){
          490  +          DbPage *pPage = 0;
          491  +          unsigned char *pTo = pOut + szPage*(sqlite3_int64)(pgno-1);
          492  +          rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pPage, 0);
          493  +          if( rc==SQLITE_OK ){
          494  +            memcpy(pTo, sqlite3PagerGetData(pPage), szPage);
          495  +          }else{
          496  +            memset(pTo, 0, szPage);
          497  +          }
          498  +          sqlite3PagerUnref(pPage);       
          499  +        }
          500  +      }
          501  +    }
          502  +  }
          503  +  sqlite3_finalize(pStmt);
          504  +  return pOut;
          505  +}
          506  +
          507  +/* Convert zSchema to a MemDB and initialize its content.
          508  +*/
          509  +int sqlite3_deserialize(
          510  +  sqlite3 *db,            /* The database connection */
          511  +  const char *zSchema,    /* Which DB to reopen with the deserialization */
          512  +  unsigned char *pData,   /* The serialized database content */
          513  +  sqlite3_int64 szDb,     /* Number bytes in the deserialization */
          514  +  sqlite3_int64 szBuf,    /* Total size of buffer pData[] */
          515  +  unsigned mFlags         /* Zero or more SQLITE_DESERIALIZE_* flags */
          516  +){
          517  +  MemFile *p;
          518  +  char *zSql;
          519  +  sqlite3_stmt *pStmt = 0;
          520  +  int rc;
          521  +  int iDb;
          522  +
          523  +  sqlite3_mutex_enter(db->mutex);
          524  +  if( zSchema==0 ) zSchema = db->aDb[0].zDbSName;
          525  +  iDb = sqlite3FindDbName(db, zSchema);
          526  +  if( iDb<0 ){
          527  +    rc = SQLITE_ERROR;
          528  +    goto end_deserialize;
          529  +  }    
          530  +  zSql = sqlite3_mprintf("ATTACH x AS %Q", zSchema);
          531  +  rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
          532  +  sqlite3_free(zSql);
          533  +  if( rc ) goto end_deserialize;
          534  +  db->init.iDb = (u8)iDb;
          535  +  db->init.reopenMemdb = 1;
          536  +  rc = sqlite3_step(pStmt);
          537  +  db->init.reopenMemdb = 0;
          538  +  if( rc!=SQLITE_DONE ){
          539  +    rc = SQLITE_ERROR;
          540  +    goto end_deserialize;
          541  +  }
          542  +  p = memdbFromDbSchema(db, zSchema);
          543  +  if( p==0 ){
          544  +    rc = SQLITE_ERROR;
          545  +  }else{
          546  +    p->aData = pData;
          547  +    p->sz = szDb;
          548  +    p->szMax = szBuf;
          549  +    p->mFlags = mFlags;
          550  +    rc = SQLITE_OK;
          551  +  }
          552  +
          553  +end_deserialize:
          554  +  sqlite3_finalize(pStmt);
          555  +  sqlite3_mutex_leave(db->mutex);
          556  +  return rc;
          557  +}
          558  +
          559  +/* 
          560  +** This routine is called when the extension is loaded.
          561  +** Register the new VFS.
          562  +*/
          563  +int sqlite3MemdbInit(void){
          564  +  sqlite3_vfs *pLower = sqlite3_vfs_find(0);
          565  +  int sz = pLower->szOsFile;
          566  +  memdb_vfs.pAppData = pLower;
          567  +  /* In all known configurations of SQLite, the size of a default
          568  +  ** sqlite3_file is greater than the size of a memdb sqlite3_file.
          569  +  ** Should that ever change, remove the following NEVER() */
          570  +  if( NEVER(sz<sizeof(MemFile)) ) sz = sizeof(MemFile);
          571  +  memdb_vfs.szOsFile = sz;
          572  +  return sqlite3_vfs_register(&memdb_vfs, 0);
          573  +}
          574  +#endif /* SQLITE_ENABLE_DESERIALIZE */

Changes to src/pager.c.

  4719   4719     void (*xReinit)(DbPage*) /* Function to reinitialize pages */
  4720   4720   ){
  4721   4721     u8 *pPtr;
  4722   4722     Pager *pPager = 0;       /* Pager object to allocate and return */
  4723   4723     int rc = SQLITE_OK;      /* Return code */
  4724   4724     int tempFile = 0;        /* True for temp files (incl. in-memory files) */
  4725   4725     int memDb = 0;           /* True if this is an in-memory file */
         4726  +#ifdef SQLITE_ENABLE_DESERIALIZE
         4727  +  int memJM = 0;           /* Memory journal mode */
         4728  +#else
         4729  +# define memJM 0
         4730  +#endif
  4726   4731     int readOnly = 0;        /* True if this is a read-only file */
  4727   4732     int journalFileSize;     /* Bytes to allocate for each journal fd */
  4728   4733     char *zPathname = 0;     /* Full path to database file */
  4729   4734     int nPathname = 0;       /* Number of bytes in zPathname */
  4730   4735     int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; /* False to omit journal */
  4731   4736     int pcacheSize = sqlite3PcacheSize();       /* Bytes to allocate for PCache */
  4732   4737     u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE;  /* Default page size */
................................................................................
  4846   4851   
  4847   4852     /* Open the pager file.
  4848   4853     */
  4849   4854     if( zFilename && zFilename[0] ){
  4850   4855       int fout = 0;                    /* VFS flags returned by xOpen() */
  4851   4856       rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout);
  4852   4857       assert( !memDb );
  4853         -    readOnly = (fout&SQLITE_OPEN_READONLY);
         4858  +#ifdef SQLITE_ENABLE_DESERIALIZE
         4859  +    memJM = (fout&SQLITE_OPEN_MEMORY)!=0;
         4860  +#endif
         4861  +    readOnly = (fout&SQLITE_OPEN_READONLY)!=0;
  4854   4862   
  4855   4863       /* If the file was successfully opened for read/write access,
  4856   4864       ** choose a default page size in case we have to create the
  4857   4865       ** database file. The default page size is the maximum of:
  4858   4866       **
  4859   4867       **    + SQLITE_DEFAULT_PAGE_SIZE,
  4860   4868       **    + The value returned by sqlite3OsSectorSize()
................................................................................
  4977   4985     /* pPager->pLast = 0; */
  4978   4986     pPager->nExtra = (u16)nExtra;
  4979   4987     pPager->journalSizeLimit = SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT;
  4980   4988     assert( isOpen(pPager->fd) || tempFile );
  4981   4989     setSectorSize(pPager);
  4982   4990     if( !useJournal ){
  4983   4991       pPager->journalMode = PAGER_JOURNALMODE_OFF;
  4984         -  }else if( memDb ){
         4992  +  }else if( memDb || memJM ){
  4985   4993       pPager->journalMode = PAGER_JOURNALMODE_MEMORY;
  4986   4994     }
  4987   4995     /* pPager->xBusyHandler = 0; */
  4988   4996     /* pPager->pBusyHandlerArg = 0; */
  4989   4997     pPager->xReiniter = xReinit;
  4990   4998     setGetterMethod(pPager);
  4991   4999     /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */

Changes to src/sqlite.h.in.

  8725   8725   ** transaction open on the database, or if the database is not a wal mode
  8726   8726   ** database.
  8727   8727   **
  8728   8728   ** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
  8729   8729   */
  8730   8730   SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
  8731   8731   
         8732  +/*
         8733  +** CAPI3REF: Serialize a database
         8734  +** EXPERIMENTAL
         8735  +**
         8736  +** The sqlite3_serialize(D,S,P,F) interface returns a pointer to memory
         8737  +** that is a serialization of the S database on [database connection] D.
         8738  +** If P is not a NULL pointer, then the size of the database in bytes
         8739  +** is written into *P.
         8740  +**
         8741  +** For an ordinary on-disk database file, the serialization is just a
         8742  +** copy of the disk file.  For an in-memory database or a "TEMP" database,
         8743  +** the serialization is the same sequence of bytes which would be written
         8744  +** to disk if that database where backed up to disk.
         8745  +**
         8746  +** The usual case is that sqlite3_serialize() copies the serialization of
         8747  +** the database into memory obtained from [sqlite3_malloc64()] and returns
         8748  +** a pointer to that memory.  The caller is responsible for freeing the
         8749  +** returned value to avoid a memory leak.  However, if the F argument
         8750  +** contains the SQLITE_SERIALIZE_NOCOPY bit, then no memory allocations
         8751  +** are made, and the sqlite3_serialize() function will return a pointer
         8752  +** to the contiguous memory representation of the database that SQLite
         8753  +** is currently using for that database, or NULL if the no such contiguous
         8754  +** memory representation of the database exists.  A contigous memory
         8755  +** representation of the database will usually only exist if there has
         8756  +** been a prior call to [sqlite3_deserialize(D,S,...)] with the same
         8757  +** values of D and S.
         8758  +** The size of the database is written into *P even if the 
         8759  +** SQLITE_SERIALIZE_NOCOPY bit is set but no contigious copy
         8760  +** of the database exists.
         8761  +**
         8762  +** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the
         8763  +** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory
         8764  +** allocation error occurs.
         8765  +**
         8766  +** This interface is only available if SQLite is compiled with the
         8767  +** [SQLITE_ENABLE_DESERIALIZE] option.
         8768  +*/
         8769  +unsigned char *sqlite3_serialize(
         8770  +  sqlite3 *db,           /* The database connection */
         8771  +  const char *zSchema,   /* Which DB to serialize. ex: "main", "temp", ... */
         8772  +  sqlite3_int64 *piSize, /* Write size of the DB here, if not NULL */
         8773  +  unsigned int mFlags    /* Zero or more SQLITE_SERIALIZE_* flags */
         8774  +);
         8775  +
         8776  +/*
         8777  +** CAPI3REF: Flags for sqlite3_serialize
         8778  +** EXPERIMENTAL
         8779  +**
         8780  +** Zero or more of the following constants can be OR-ed together for
         8781  +** the F argument to [sqlite3_serialize(D,S,P,F)].
         8782  +**
         8783  +** SQLITE_SERIALIZE_NOCOPY means that [sqlite3_serialize()] will return
         8784  +** a pointer to contiguous in-memory database that it is currently using,
         8785  +** without making a copy of the database.  If SQLite is not currently using
         8786  +** a contiguous in-memory database, then this option causes
         8787  +** [sqlite3_serialize()] to return a NULL pointer.  SQLite will only be
         8788  +** using a contiguous in-memory database if it has been initialized by a
         8789  +** prior call to [sqlite3_deserialize()].
         8790  +*/
         8791  +#define SQLITE_SERIALIZE_NOCOPY 0x001   /* Do no memory allocations */
         8792  +
         8793  +/*
         8794  +** CAPI3REF: Deserialize a database
         8795  +** EXPERIMENTAL
         8796  +**
         8797  +** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the 
         8798  +** [database connection] D to disconnection from database S and then
         8799  +** reopen S as an in-memory database based on the serialization contained
         8800  +** in P.  The serialized database P is N bytes in size.  M is the size of
         8801  +** the buffer P, which might be larger than N.  If M is larger than N, and
         8802  +** the SQLITE_DESERIALIZE_READONLY bit is not set in F, then SQLite is
         8803  +** permitted to add content to the in-memory database as long as the total
         8804  +** size does not exceed M bytes.
         8805  +**
         8806  +** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will
         8807  +** invoke sqlite3_free() on the serialization buffer when the database
         8808  +** connection closes.  If the SQLITE_DESERIALIZE_RESIZEABLE bit is set, then
         8809  +** SQLite will try to increase the buffer size using sqlite3_realloc64()
         8810  +** if writes on the database cause it to grow larger than M bytes.
         8811  +**
         8812  +** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the
         8813  +** database is currently in a read transaction or is involved in a backup
         8814  +** operation.
         8815  +**
         8816  +** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the 
         8817  +** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then
         8818  +** [sqlite3_free()] is invoked on argument P prior to returning.
         8819  +**
         8820  +** This interface is only available if SQLite is compiled with the
         8821  +** [SQLITE_ENABLE_DESERIALIZE] option.
         8822  +*/
         8823  +int sqlite3_deserialize(
         8824  +  sqlite3 *db,            /* The database connection */
         8825  +  const char *zSchema,    /* Which DB to reopen with the deserialization */
         8826  +  unsigned char *pData,   /* The serialized database content */
         8827  +  sqlite3_int64 szDb,     /* Number bytes in the deserialization */
         8828  +  sqlite3_int64 szBuf,    /* Total size of buffer pData[] */
         8829  +  unsigned mFlags         /* Zero or more SQLITE_DESERIALIZE_* flags */
         8830  +);
         8831  +
         8832  +/*
         8833  +** CAPI3REF: Flags for sqlite3_deserialize()
         8834  +** EXPERIMENTAL
         8835  +**
         8836  +** The following are allowed values for 6th argument (the F argument) to
         8837  +** the [sqlite3_deserialize(D,S,P,N,M,F)] interface.
         8838  +**
         8839  +** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization
         8840  +** in the P argument is held in memory obtained from [sqlite3_malloc64()]
         8841  +** and that SQLite should take ownership of this memory and automatically
         8842  +** free it when it has finished using it.  Without this flag, the caller
         8843  +** is resposible for freeing any dynamically allocated memory.
         8844  +**
         8845  +** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to
         8846  +** grow the size of the database usign calls to [sqlite3_realloc64()].  This
         8847  +** flag should only be used if SQLITE_DESERIALIZE_FREEONCLOSE is also used.
         8848  +** Without this flag, the deserialized database cannot increase in size beyond
         8849  +** the number of bytes specified by the M parameter.
         8850  +**
         8851  +** The SQLITE_DESERIALIZE_READONLY flag means that the deserialized database
         8852  +** should be treated as read-only.
         8853  +*/
         8854  +#define SQLITE_DESERIALIZE_FREEONCLOSE 1 /* Call sqlite3_free() on close */
         8855  +#define SQLITE_DESERIALIZE_RESIZEABLE  2 /* Resize using sqlite3_realloc64() */
         8856  +#define SQLITE_DESERIALIZE_READONLY    4 /* Database is read-only */
         8857  +
  8732   8858   /*
  8733   8859   ** Undo the hack that converts floating point types to integer for
  8734   8860   ** builds on processors without floating point support.
  8735   8861   */
  8736   8862   #ifdef SQLITE_OMIT_FLOATING_POINT
  8737   8863   # undef double
  8738   8864   #endif
  8739   8865   
  8740   8866   #ifdef __cplusplus
  8741   8867   }  /* End of the 'extern "C"' block */
  8742   8868   #endif
  8743   8869   #endif /* SQLITE3_H */

Changes to src/sqliteInt.h.

  1361   1361     int nTotalChange;             /* Value returned by sqlite3_total_changes() */
  1362   1362     int aLimit[SQLITE_N_LIMIT];   /* Limits */
  1363   1363     int nMaxSorterMmap;           /* Maximum size of regions mapped by sorter */
  1364   1364     struct sqlite3InitInfo {      /* Information used during initialization */
  1365   1365       int newTnum;                /* Rootpage of table being initialized */
  1366   1366       u8 iDb;                     /* Which db file is being initialized */
  1367   1367       u8 busy;                    /* TRUE if currently initializing */
  1368         -    u8 orphanTrigger;           /* Last statement is orphaned TEMP trigger */
  1369         -    u8 imposterTable;           /* Building an imposter table */
         1368  +    unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */
         1369  +    unsigned imposterTable : 1; /* Building an imposter table */
         1370  +    unsigned reopenMemdb : 1;   /* ATTACH is really a reopen using MemDB */
  1370   1371     } init;
  1371   1372     int nVdbeActive;              /* Number of VDBEs currently running */
  1372   1373     int nVdbeRead;                /* Number of active VDBEs that read or write */
  1373   1374     int nVdbeWrite;               /* Number of active VDBEs that read and write */
  1374   1375     int nVdbeExec;                /* Number of nested calls to VdbeExec() */
  1375   1376     int nVDestroy;                /* Number of active OP_VDestroy operations */
  1376   1377     int nExtension;               /* Number of loaded extensions */
................................................................................
  4018   4019   void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
  4019   4020   u8 sqlite3HexToInt(int h);
  4020   4021   int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
  4021   4022   
  4022   4023   #if defined(SQLITE_NEED_ERR_NAME)
  4023   4024   const char *sqlite3ErrName(int);
  4024   4025   #endif
         4026  +
         4027  +#ifdef SQLITE_ENABLE_DESERIALIZE
         4028  +int sqlite3MemdbInit(void);
         4029  +#endif
  4025   4030   
  4026   4031   const char *sqlite3ErrStr(int);
  4027   4032   int sqlite3ReadSchema(Parse *pParse);
  4028   4033   CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
  4029   4034   CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
  4030   4035   CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
  4031   4036   CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr);

Changes to src/tclsqlite.c.

  1844   1844     int objc,
  1845   1845     Tcl_Obj *const*objv
  1846   1846   ){
  1847   1847     SqliteDb *pDb = (SqliteDb*)cd;
  1848   1848     int choice;
  1849   1849     int rc = TCL_OK;
  1850   1850     static const char *DB_strs[] = {
  1851         -    "authorizer",         "backup",            "busy",
  1852         -    "cache",              "changes",           "close",
  1853         -    "collate",            "collation_needed",  "commit_hook",
  1854         -    "complete",           "copy",              "enable_load_extension",
  1855         -    "errorcode",          "eval",              "exists",
  1856         -    "function",           "incrblob",          "interrupt",
  1857         -    "last_insert_rowid",  "nullvalue",         "onecolumn",
  1858         -    "preupdate",          "profile",           "progress",
  1859         -    "rekey",              "restore",           "rollback_hook",
  1860         -    "status",             "timeout",           "total_changes",
  1861         -    "trace",              "trace_v2",          "transaction",
  1862         -    "unlock_notify",      "update_hook",       "version",
  1863         -    "wal_hook",
  1864         -    0
         1851  +    "authorizer",             "backup",                "busy",
         1852  +    "cache",                  "changes",               "close",
         1853  +    "collate",                "collation_needed",      "commit_hook",
         1854  +    "complete",               "copy",                  "deserialize",
         1855  +    "enable_load_extension",  "errorcode",             "eval",
         1856  +    "exists",                 "function",              "incrblob",
         1857  +    "interrupt",              "last_insert_rowid",     "nullvalue",
         1858  +    "onecolumn",              "preupdate",             "profile",
         1859  +    "progress",               "rekey",                 "restore",
         1860  +    "rollback_hook",          "serialize",             "status",
         1861  +    "timeout",                "total_changes",         "trace",
         1862  +    "trace_v2",               "transaction",           "unlock_notify",
         1863  +    "update_hook",            "version",               "wal_hook",
         1864  +    0                        
  1865   1865     };
  1866   1866     enum DB_enum {
  1867         -    DB_AUTHORIZER,        DB_BACKUP,           DB_BUSY,
  1868         -    DB_CACHE,             DB_CHANGES,          DB_CLOSE,
  1869         -    DB_COLLATE,           DB_COLLATION_NEEDED, DB_COMMIT_HOOK,
  1870         -    DB_COMPLETE,          DB_COPY,             DB_ENABLE_LOAD_EXTENSION,
  1871         -    DB_ERRORCODE,         DB_EVAL,             DB_EXISTS,
  1872         -    DB_FUNCTION,          DB_INCRBLOB,         DB_INTERRUPT,
  1873         -    DB_LAST_INSERT_ROWID, DB_NULLVALUE,        DB_ONECOLUMN,
  1874         -    DB_PREUPDATE,         DB_PROFILE,          DB_PROGRESS,
  1875         -    DB_REKEY,             DB_RESTORE,          DB_ROLLBACK_HOOK,
  1876         -    DB_STATUS,            DB_TIMEOUT,          DB_TOTAL_CHANGES,
  1877         -    DB_TRACE,             DB_TRACE_V2,         DB_TRANSACTION,
  1878         -    DB_UNLOCK_NOTIFY,     DB_UPDATE_HOOK,      DB_VERSION,
  1879         -    DB_WAL_HOOK,
         1867  +    DB_AUTHORIZER,            DB_BACKUP,               DB_BUSY,
         1868  +    DB_CACHE,                 DB_CHANGES,              DB_CLOSE,
         1869  +    DB_COLLATE,               DB_COLLATION_NEEDED,     DB_COMMIT_HOOK,
         1870  +    DB_COMPLETE,              DB_COPY,                 DB_DESERIALIZE,
         1871  +    DB_ENABLE_LOAD_EXTENSION, DB_ERRORCODE,            DB_EVAL,
         1872  +    DB_EXISTS,                DB_FUNCTION,             DB_INCRBLOB,
         1873  +    DB_INTERRUPT,             DB_LAST_INSERT_ROWID,    DB_NULLVALUE,
         1874  +    DB_ONECOLUMN,             DB_PREUPDATE,            DB_PROFILE,
         1875  +    DB_PROGRESS,              DB_REKEY,                DB_RESTORE,
         1876  +    DB_ROLLBACK_HOOK,         DB_SERIALIZE,            DB_STATUS,
         1877  +    DB_TIMEOUT,               DB_TOTAL_CHANGES,        DB_TRACE,
         1878  +    DB_TRACE_V2,              DB_TRANSACTION,          DB_UNLOCK_NOTIFY,
         1879  +    DB_UPDATE_HOOK,           DB_VERSION,              DB_WAL_HOOK
  1880   1880     };
  1881   1881     /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
  1882   1882   
  1883   1883     if( objc<2 ){
  1884   1884       Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
  1885   1885       return TCL_ERROR;
  1886   1886     }
................................................................................
  2409   2409         sqlite3_snprintf(sizeof(zLineNum), zLineNum,"%d",lineno);
  2410   2410         Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,
  2411   2411                          (char*)0);
  2412   2412         rc = TCL_ERROR;
  2413   2413       }
  2414   2414       break;
  2415   2415     }
         2416  +
         2417  +  /*
         2418  +  **     $db deserialize ?DATABASE? VALUE
         2419  +  **
         2420  +  ** Reopen DATABASE (default "main") using the content in $VALUE
         2421  +  */
         2422  +  case DB_DESERIALIZE: {
         2423  +#ifndef SQLITE_ENABLE_DESERIALIZE
         2424  +    Tcl_AppendResult(interp, "MEMDB not available in this build",
         2425  +                     (char*)0);
         2426  +    rc = TCL_ERROR;
         2427  +#else
         2428  +    const char *zSchema;
         2429  +    Tcl_Obj *pValue;
         2430  +    unsigned char *pBA;
         2431  +    unsigned char *pData;
         2432  +    int len, xrc;
         2433  +    
         2434  +    if( objc==3 ){
         2435  +      zSchema = 0;
         2436  +      pValue = objv[2];
         2437  +    }else if( objc==4 ){
         2438  +      zSchema = Tcl_GetString(objv[2]);
         2439  +      pValue = objv[3];
         2440  +    }else{
         2441  +      Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? VALUE");
         2442  +      rc = TCL_ERROR;
         2443  +      break;
         2444  +    }
         2445  +    pBA = Tcl_GetByteArrayFromObj(pValue, &len);
         2446  +    pData = sqlite3_malloc64( len );
         2447  +    if( pData==0 && len>0 ){
         2448  +      Tcl_AppendResult(interp, "out of memory", (char*)0);
         2449  +      rc = TCL_ERROR;
         2450  +    }else{
         2451  +      if( len>0 ) memcpy(pData, pBA, len);
         2452  +      xrc = sqlite3_deserialize(pDb->db, zSchema, pData, len, len,
         2453  +                SQLITE_DESERIALIZE_FREEONCLOSE |
         2454  +                SQLITE_DESERIALIZE_RESIZEABLE);
         2455  +      if( xrc ){
         2456  +        Tcl_AppendResult(interp, "unable to set MEMDB content", (char*)0);
         2457  +        rc = TCL_ERROR;
         2458  +      }
         2459  +    }
         2460  +#endif
         2461  +    break; 
         2462  +  }
  2416   2463   
  2417   2464     /*
  2418   2465     **    $db enable_load_extension BOOLEAN
  2419   2466     **
  2420   2467     ** Turn the extension loading feature on or off.  It if off by
  2421   2468     ** default.
  2422   2469     */
................................................................................
  2884   2931         Tcl_AppendResult(interp, "restore failed: ",
  2885   2932              sqlite3_errmsg(pDb->db), (char*)0);
  2886   2933         rc = TCL_ERROR;
  2887   2934       }
  2888   2935       sqlite3_close(pSrc);
  2889   2936       break;
  2890   2937     }
         2938  +
         2939  +  /*
         2940  +  **     $db serialize ?DATABASE?
         2941  +  **
         2942  +  ** Return a serialization of a database.  
         2943  +  */
         2944  +  case DB_SERIALIZE: {
         2945  +#ifndef SQLITE_ENABLE_DESERIALIZE
         2946  +    Tcl_AppendResult(interp, "MEMDB not available in this build",
         2947  +                     (char*)0);
         2948  +    rc = TCL_ERROR;
         2949  +#else
         2950  +    const char *zSchema = objc>=3 ? Tcl_GetString(objv[2]) : "main";
         2951  +    sqlite3_int64 sz = 0;
         2952  +    unsigned char *pData;
         2953  +    if( objc!=2 && objc!=3 ){
         2954  +      Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE?");
         2955  +      rc = TCL_ERROR;
         2956  +    }else{
         2957  +      int needFree;
         2958  +      pData = sqlite3_serialize(pDb->db, zSchema, &sz, SQLITE_SERIALIZE_NOCOPY);
         2959  +      if( pData ){
         2960  +        needFree = 0;
         2961  +      }else{
         2962  +        pData = sqlite3_serialize(pDb->db, zSchema, &sz, 0);
         2963  +        needFree = 1;
         2964  +      }
         2965  +      Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pData,sz));
         2966  +      if( needFree ) sqlite3_free(pData);
         2967  +    }
         2968  +#endif
         2969  +    break;
         2970  +  }
  2891   2971   
  2892   2972     /*
  2893   2973     **     $db status (step|sort|autoindex|vmstep)
  2894   2974     **
  2895   2975     ** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or
  2896   2976     ** SQLITE_STMTSTATUS_SORT for the most recent eval.
  2897   2977     */
................................................................................
  3344   3424     Tcl_Interp *interp,
  3345   3425     int objc,
  3346   3426     Tcl_Obj *const*objv
  3347   3427   ){
  3348   3428     return Tcl_NRCallObjProc(interp, DbObjCmd, cd, objc, objv);
  3349   3429   }
  3350   3430   #endif /* SQLITE_TCL_NRE */
         3431  +
         3432  +/*
         3433  +** Issue the usage message when the "sqlite3" command arguments are
         3434  +** incorrect.
         3435  +*/
         3436  +static int sqliteCmdUsage(
         3437  +  Tcl_Interp *interp,
         3438  +  Tcl_Obj *const*objv
         3439  +){
         3440  +  Tcl_WrongNumArgs(interp, 1, objv,
         3441  +    "HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
         3442  +    " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
         3443  +#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
         3444  +    " ?-key CODECKEY?"
         3445  +#endif
         3446  +  );
         3447  +  return TCL_ERROR;
         3448  +}
  3351   3449   
  3352   3450   /*
  3353   3451   **   sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN?
  3354   3452   **                           ?-create BOOLEAN? ?-nomutex BOOLEAN?
  3355   3453   **
  3356   3454   ** This is the main Tcl command.  When the "sqlite" Tcl command is
  3357   3455   ** invoked, this routine runs to process that command.
................................................................................
  3370   3468     int objc,
  3371   3469     Tcl_Obj *const*objv
  3372   3470   ){
  3373   3471     SqliteDb *p;
  3374   3472     const char *zArg;
  3375   3473     char *zErrMsg;
  3376   3474     int i;
  3377         -  const char *zFile;
         3475  +  const char *zFile = 0;
  3378   3476     const char *zVfs = 0;
  3379   3477     int flags;
  3380   3478     Tcl_DString translatedFilename;
  3381   3479   #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
  3382   3480     void *pKey = 0;
  3383   3481     int nKey = 0;
  3384   3482   #endif
  3385   3483     int rc;
  3386   3484   
  3387   3485     /* In normal use, each TCL interpreter runs in a single thread.  So
  3388         -  ** by default, we can turn of mutexing on SQLite database connections.
         3486  +  ** by default, we can turn off mutexing on SQLite database connections.
  3389   3487     ** However, for testing purposes it is useful to have mutexes turned
  3390   3488     ** on.  So, by default, mutexes default off.  But if compiled with
  3391   3489     ** SQLITE_TCL_DEFAULT_FULLMUTEX then mutexes default on.
  3392   3490     */
  3393   3491   #ifdef SQLITE_TCL_DEFAULT_FULLMUTEX
  3394   3492     flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
  3395   3493   #else
................................................................................
  3410   3508   #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
  3411   3509         Tcl_AppendResult(interp,"1",(char*)0);
  3412   3510   #else
  3413   3511         Tcl_AppendResult(interp,"0",(char*)0);
  3414   3512   #endif
  3415   3513         return TCL_OK;
  3416   3514       }
         3515  +    if( zArg[0]=='-' ) return sqliteCmdUsage(interp, objv);
  3417   3516     }
  3418         -  for(i=3; i+1<objc; i+=2){
         3517  +  for(i=2; i<objc; i++){
  3419   3518       zArg = Tcl_GetString(objv[i]);
         3519  +    if( zArg[0]!='-' ){
         3520  +      if( zFile!=0 ) return sqliteCmdUsage(interp, objv);
         3521  +      zFile = zArg;
         3522  +      continue;
         3523  +    }
         3524  +    if( i==objc-1 ) return sqliteCmdUsage(interp, objv);
         3525  +    i++;
  3420   3526       if( strcmp(zArg,"-key")==0 ){
  3421   3527   #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
  3422         -      pKey = Tcl_GetByteArrayFromObj(objv[i+1], &nKey);
         3528  +      pKey = Tcl_GetByteArrayFromObj(objv[i], &nKey);
  3423   3529   #endif
  3424   3530       }else if( strcmp(zArg, "-vfs")==0 ){
  3425         -      zVfs = Tcl_GetString(objv[i+1]);
         3531  +      zVfs = Tcl_GetString(objv[i]);
  3426   3532       }else if( strcmp(zArg, "-readonly")==0 ){
  3427   3533         int b;
  3428         -      if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
         3534  +      if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
  3429   3535         if( b ){
  3430   3536           flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
  3431   3537           flags |= SQLITE_OPEN_READONLY;
  3432   3538         }else{
  3433   3539           flags &= ~SQLITE_OPEN_READONLY;
  3434   3540           flags |= SQLITE_OPEN_READWRITE;
  3435   3541         }
  3436   3542       }else if( strcmp(zArg, "-create")==0 ){
  3437   3543         int b;
  3438         -      if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
         3544  +      if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
  3439   3545         if( b && (flags & SQLITE_OPEN_READONLY)==0 ){
  3440   3546           flags |= SQLITE_OPEN_CREATE;
  3441   3547         }else{
  3442   3548           flags &= ~SQLITE_OPEN_CREATE;
  3443   3549         }
  3444   3550       }else if( strcmp(zArg, "-nomutex")==0 ){
  3445   3551         int b;
  3446         -      if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
         3552  +      if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
  3447   3553         if( b ){
  3448   3554           flags |= SQLITE_OPEN_NOMUTEX;
  3449   3555           flags &= ~SQLITE_OPEN_FULLMUTEX;
  3450   3556         }else{
  3451   3557           flags &= ~SQLITE_OPEN_NOMUTEX;
  3452   3558         }
  3453   3559       }else if( strcmp(zArg, "-fullmutex")==0 ){
  3454   3560         int b;
  3455         -      if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
         3561  +      if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
  3456   3562         if( b ){
  3457   3563           flags |= SQLITE_OPEN_FULLMUTEX;
  3458   3564           flags &= ~SQLITE_OPEN_NOMUTEX;
  3459   3565         }else{
  3460   3566           flags &= ~SQLITE_OPEN_FULLMUTEX;
  3461   3567         }
  3462   3568       }else if( strcmp(zArg, "-uri")==0 ){
  3463   3569         int b;
  3464         -      if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
         3570  +      if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
  3465   3571         if( b ){
  3466   3572           flags |= SQLITE_OPEN_URI;
  3467   3573         }else{
  3468   3574           flags &= ~SQLITE_OPEN_URI;
  3469   3575         }
  3470   3576       }else{
  3471   3577         Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0);
  3472   3578         return TCL_ERROR;
  3473   3579       }
  3474   3580     }
  3475         -  if( objc<3 || (objc&1)!=1 ){
  3476         -    Tcl_WrongNumArgs(interp, 1, objv,
  3477         -      "HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
  3478         -      " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
  3479         -#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
  3480         -      " ?-key CODECKEY?"
  3481         -#endif
  3482         -    );
  3483         -    return TCL_ERROR;
  3484         -  }
  3485   3581     zErrMsg = 0;
  3486   3582     p = (SqliteDb*)Tcl_Alloc( sizeof(*p) );
  3487   3583     memset(p, 0, sizeof(*p));
  3488         -  zFile = Tcl_GetStringFromObj(objv[2], 0);
         3584  +  if( zFile==0 ) zFile = "";
  3489   3585     zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename);
  3490   3586     rc = sqlite3_open_v2(zFile, &p->db, flags, zVfs);
  3491   3587     Tcl_DStringFree(&translatedFilename);
  3492   3588     if( p->db ){
  3493   3589       if( SQLITE_OK!=sqlite3_errcode(p->db) ){
  3494   3590         zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
  3495   3591         sqlite3_close(p->db);

Changes to src/test_config.c.

   143    143   #endif
   144    144   
   145    145   #ifdef SQLITE_ENABLE_HIDDEN_COLUMNS
   146    146     Tcl_SetVar2(interp, "sqlite_options", "hiddencolumns", "1", TCL_GLOBAL_ONLY);
   147    147   #else
   148    148     Tcl_SetVar2(interp, "sqlite_options", "hiddencolumns", "0", TCL_GLOBAL_ONLY);
   149    149   #endif
          150  +
          151  +#ifdef SQLITE_ENABLE_DESERIALIZE
          152  +  Tcl_SetVar2(interp, "sqlite_options", "deserialize", "1", TCL_GLOBAL_ONLY);
          153  +#else
          154  +  Tcl_SetVar2(interp, "sqlite_options", "deserialize", "0", TCL_GLOBAL_ONLY);
          155  +#endif
   150    156   
   151    157   #ifdef SQLITE_ENABLE_MEMSYS3
   152    158     Tcl_SetVar2(interp, "sqlite_options", "mem3", "1", TCL_GLOBAL_ONLY);
   153    159   #else
   154    160     Tcl_SetVar2(interp, "sqlite_options", "mem3", "0", TCL_GLOBAL_ONLY);
   155    161   #endif
   156    162   

Added test/memdb1.test.

            1  +# 2018-01-02
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library.  The
           12  +# focus of this file is the "memdb" VFS
           13  +#
           14  +
           15  +set testdir [file dirname $argv0]
           16  +source $testdir/tester.tcl
           17  +set testprefix memdb1
           18  +do_not_use_codec
           19  +
           20  +ifcapable !deserialize {
           21  +  finish_test
           22  +  return
           23  +}
           24  +
           25  +# Create a MEMDB and populate it with some dummy data.
           26  +# Then extract the database into the $::db1 variable.
           27  +# Verify that the size of $::db1 is the same as the size of
           28  +# the database.
           29  +#
           30  +unset -nocomplain db1
           31  +unset -nocomplain sz1
           32  +unset -nocomplain pgsz
           33  +do_test 100 {
           34  +  db eval {
           35  +    CREATE TABLE t1(a,b);
           36  +    INSERT INTO t1 VALUES(1,2);
           37  +  }
           38  +  set ::pgsz [db one {PRAGMA page_size}]
           39  +  set ::sz1 [expr {$::pgsz*[db one {PRAGMA page_count}]}]
           40  +  set ::db1 [db serialize]
           41  +  expr {[string length $::db1]==$::sz1}
           42  +} 1
           43  +set fd [open db1.db wb]
           44  +puts -nonewline $fd $db1
           45  +close $fd
           46  +
           47  +# Create a new MEMDB and initialize it to the content of $::db1
           48  +# Verify that the content is the same.
           49  +#
           50  +db close
           51  +sqlite3 db
           52  +db deserialize $db1
           53  +do_execsql_test 110 {
           54  +  SELECT * FROM t1;
           55  +} {1 2}
           56  +
           57  +# What happens when we try to VACUUM a MEMDB database?
           58  +#
           59  +do_execsql_test 120 {
           60  +  VACUUM;
           61  +} {}
           62  +do_execsql_test 130 {
           63  +  CREATE TABLE t2(x, y);
           64  +  WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
           65  +   INSERT INTO t2(x, y) SELECT x, randomblob(1000) FROM c;
           66  +  DROP TABLE t2;
           67  +  PRAGMA page_count;
           68  +} {116}
           69  +do_execsql_test 140 {
           70  +  VACUUM;
           71  +  PRAGMA page_count;
           72  +} {2}
           73  +
           74  +# Build a largish on-disk database and serialize it.  Verify that the
           75  +# serialization works.
           76  +#
           77  +db close
           78  +forcedelete test.db
           79  +sqlite3 db test.db
           80  +do_execsql_test 200 {
           81  +  CREATE TABLE t3(x, y);
           82  +  WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<400)
           83  +   INSERT INTO t3(x, y) SELECT x, randomblob(1000) FROM c;
           84  +  PRAGMA quick_check;
           85  +} {ok}
           86  +set fd [open test.db rb]
           87  +unset -nocomplain direct
           88  +set direct [read $fd]
           89  +close $fd
           90  +do_test 210 {
           91  +  string length [db serialize]
           92  +} [string length $direct]
           93  +do_test 220 {
           94  +  db eval {ATTACH ':memory:' AS aux1}
           95  +  db deserialize aux1 $::direct
           96  +  db eval {
           97  +     SELECT x, y FROM main.t3 EXCEPT SELECT x, y FROM aux1.t3;
           98  +  }
           99  +} {}
          100  +unset -nocomplain direct
          101  +
          102  +# Do the same with a :memory: database.
          103  +#
          104  +db close
          105  +sqlite3 db :memory:
          106  +do_execsql_test 300 {
          107  +  CREATE TABLE t3(x, y);
          108  +  WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<400)
          109  +   INSERT INTO t3(x, y) SELECT x, randomblob(1000) FROM c;
          110  +  PRAGMA quick_check;
          111  +} {ok}
          112  +do_test 310 {
          113  +  db eval {ATTACH ':memory:' AS aux1}
          114  +  db deserialize aux1 [db serialize main]
          115  +  db eval {
          116  +     SELECT x, y FROM main.t3 EXCEPT SELECT x, y FROM aux1.t3;
          117  +  }
          118  +} {}
          119  +
          120  +# Deserialize an empty database
          121  +#
          122  +db close
          123  +sqlite3 db
          124  +db deserialize {}
          125  +do_execsql_test 400 {
          126  +  PRAGMA integrity_check;
          127  +} {ok}
          128  +do_execsql_test 410 {
          129  +  CREATE TABLE t4(a,b);
          130  +  INSERT INTO t4 VALUES('hello','world!');
          131  +  PRAGMA integrity_check;
          132  +  SELECT * FROM t4;
          133  +} {ok hello world!}
          134  +
          135  +# Deserialize something that is not a database.
          136  +#
          137  +db close
          138  +sqlite3 db
          139  +do_test 500 {
          140  +  set rc [catch {db deserialize not-a-database} msg]
          141  +  lappend rc $msg
          142  +} {0 {}}
          143  +do_catchsql_test 510 {
          144  +  PRAGMA integrity_check;
          145  +} {1 {file is not a database}}
          146  +
          147  +# Abuse the serialize and deserialize commands.  Make sure errors are caught.
          148  +#
          149  +do_test 600 {
          150  +  set rc [catch {db deserialize} msg]
          151  +  lappend rc $msg
          152  +} {1 {wrong # args: should be "db deserialize ?DATABASE? VALUE"}}
          153  +do_test 610 {
          154  +  set rc [catch {db deserialize a b c} msg]
          155  +  lappend rc $msg
          156  +} {1 {wrong # args: should be "db deserialize ?DATABASE? VALUE"}}
          157  +do_test 620 {
          158  +  set rc [catch {db serialize a b} msg]
          159  +  lappend rc $msg
          160  +} {1 {wrong # args: should be "db serialize ?DATABASE?"}}
          161  +
          162  +finish_test

Changes to test/tclsqlite.test.

    18     18   # $Id: tclsqlite.test,v 1.73 2009/03/16 13:19:36 danielk1977 Exp $
    19     19   
    20     20   set testdir [file dirname $argv0]
    21     21   source $testdir/tester.tcl
    22     22   
    23     23   # Check the error messages generated by tclsqlite
    24     24   #
    25         -set r "sqlite_orig HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
           25  +set r "sqlite_orig HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
    26     26   if {[sqlite3 -has-codec]} {
    27     27     append r " ?-key CODECKEY?"
    28     28   }
    29     29   do_test tcl-1.1 {
    30         -  set v [catch {sqlite3 bogus} msg]
           30  +  set v [catch {sqlite3 -bogus} msg]
    31     31     regsub {really_sqlite3} $msg {sqlite3} msg
    32     32     lappend v $msg
    33     33   } [list 1 "wrong # args: should be \"$r\""]
    34     34   do_test tcl-1.2 {
    35     35     set v [catch {db bogus} msg]
    36     36     lappend v $msg
    37         -} {1 {bad option "bogus": must be authorizer, backup, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, copy, enable_load_extension, errorcode, eval, exists, function, incrblob, interrupt, last_insert_rowid, nullvalue, onecolumn, preupdate, profile, progress, rekey, restore, rollback_hook, status, timeout, total_changes, trace, trace_v2, transaction, unlock_notify, update_hook, version, or wal_hook}}
           37  +} {1 {bad option "bogus": must be authorizer, backup, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, copy, deserialize, enable_load_extension, errorcode, eval, exists, function, incrblob, interrupt, last_insert_rowid, nullvalue, onecolumn, preupdate, profile, progress, rekey, restore, rollback_hook, serialize, status, timeout, total_changes, trace, trace_v2, transaction, unlock_notify, update_hook, version, or wal_hook}}
    38     38   do_test tcl-1.2.1 {
    39     39     set v [catch {db cache bogus} msg]
    40     40     lappend v $msg
    41     41   } {1 {bad option "bogus": must be flush or size}}
    42     42   do_test tcl-1.2.2 {
    43     43     set v [catch {db cache} msg]
    44     44     lappend v $msg

Changes to tool/mkopts.tcl.

     7      7   
     8      8   set prefix {}
     9      9   while {![eof stdin]} {
    10     10     set line [gets stdin]
    11     11     if {$line==""} continue
    12     12     regsub -all "\[ \t\n,\]+" [string trim $line] { } line
    13     13     foreach token [split $line { }] {
    14         -    if {![regexp {(([a-zA-Z]+)_)?([_a-zA-Z]+)} $token all px p2 name]} continue
           14  +    if {![regexp {(([a-zA-Z]+)_)?([_a-zA-Z0-9]+)} $token all px p2 name]} continue
    15     15       lappend namelist [string tolower $name]
    16     16       if {$px!=""} {set prefix $p2}
    17     17     }
    18     18   }
    19     19   
    20     20   puts "  static const char *${prefix}_strs\[\] = \173"
    21     21   set col 0
    22     22   proc put_item x {
    23     23     global col
    24     24     if {$col==0} {puts -nonewline "   "}
    25     25     if {$col<2} {
    26         -    puts -nonewline [format " %-21s" $x]
           26  +    puts -nonewline [format " %-25s" $x]
    27     27       incr col
    28     28     } else {
    29     29       puts $x
    30     30       set col 0
    31     31     }
    32     32   }
    33     33   proc finalize {} {

Changes to tool/mksqlite3c.tcl.

   316    316      utf.c
   317    317      util.c
   318    318      hash.c
   319    319      opcodes.c
   320    320   
   321    321      os_unix.c
   322    322      os_win.c
          323  +   memdb.c
   323    324   
   324    325      bitvec.c
   325    326      pcache.c
   326    327      pcache1.c
   327    328      rowset.c
   328    329      pager.c
   329    330      wal.c