]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Replace the sqlite3_memdb_ptr() interface with the more general
authordrh <drh@noemail.net>
Wed, 3 Jan 2018 16:49:52 +0000 (16:49 +0000)
committerdrh <drh@noemail.net>
Wed, 3 Jan 2018 16:49:52 +0000 (16:49 +0000)
sqlite3_serialize() interface.

FossilOrigin-Name: 8cf2ed4eff6d2e0958656e23384b05ead2128b678b0b69a591878af4190cd077

manifest
manifest.uuid
src/memdb.c
src/sqlite.h.in
src/tclsqlite.c
test/memdb1.test
tool/mkopts.tcl

index 9d5dca5c2b6874d1f402b8410600f1d73b9cdd6c..892a7572e4593b22bc2a61a438551beeec967ea5 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Simplify\sthe\s"sqlite3"\scommand\sin\sthe\sTCL\sinterface.\s\sThe\sfilename\sis\snow\noptional.\s\sThere\sis\sa\snew\s--memdb\soption\swith\san\sargument\sthat\sis\sthe\sblob\nto\swhich\sthe\sdatabase\scontent\sshould\sbe\sinitialized.
-D 2018-01-03T13:20:02.897
+C Replace\sthe\ssqlite3_memdb_ptr()\sinterface\swith\sthe\smore\sgeneral\nsqlite3_serialize()\sinterface.
+D 2018-01-03T16:49:52.676
 F Makefile.in 892bf253c48f3d2d8d4e4e89b44b71aa548a0eba11b148c338690cfb99822859
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc 3b7ee2ebaf579fe7d30bece93e61e52782c3ff836455cba3a192f7a8f6f269d6
@@ -450,7 +450,7 @@ F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
 F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3
 F src/mem3.c 8768ac94694f31ffaf8b4d0ea5dc08af7010a35a
 F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944
-F src/memdb.c 13c69aee0185614a25303e2be3802b73416e655e95e1f1c607a9f963b35a1def
+F src/memdb.c 39dd9443f902759b858e598f17afc425c094b0d5f057b7ec988d224d812bd2a3
 F src/memjournal.c 6f3d36a0a8f72f48f6c3c722f04301ac64f2515435fa42924293e46fc7994661
 F src/msvc.h 4942752b6a253116baaa8de75256c51a459a5e81
 F src/mutex.c b021263554c8a3995e9d53193b8194b96d1ed28e06c3b532dd7f7d29cf0c7d53
@@ -481,14 +481,14 @@ F src/resolve.c bbee7e31d369a18a2f4836644769882e9c5d40ef4a3af911db06410b65cb3730
 F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
 F src/select.c 8b22abe193e4d8243befa2038e4ae2405802fed1c446e5e502d11f652e09ba74
 F src/shell.c.in a418ddceef7a2789f18bdc2bcdd481b2562fe4a7754b8009c8dd33d5a67da332
-F src/sqlite.h.in 8b6cd7fd8b286d567bcc1ee3a750686cbb1c0962dc453b2cfa034684fe5808db
+F src/sqlite.h.in 16bbb15a5fc53bfd725305ec9a201a7f57df7770749aa758b33a0636946d1bb4
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h c02d628cca67f3889c689d82d25c3eb45e2c155db08e4c6089b5840d64687d34
 F src/sqliteInt.h 2567341e37050ad542d57f3027b8717cb9b14ff363fdfeecf85421e0d973787f
 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
 F src/status.c 9737ed017279a9e0c5da748701c3c7bf1e8ae0dae459aad20dd64fcff97a7e35
 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
-F src/tclsqlite.c 907133153d3194ddfd728e84f55fa106de696dc644c9508a054c72b9f833972e
+F src/tclsqlite.c 322ad6b4e613aba84eee8cf6239eae668167f8b9891ca9e4aa53b78cd3aaff35
 F src/test1.c 8ef15f7a357f85dfc41c6c748ce9c947b4f676e01bb5ae6a45bee4923dff8b51
 F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
 F src/test3.c b8434949dfb8aff8dfa082c8b592109e77844c2135ed3c492113839b6956255b
@@ -1056,7 +1056,7 @@ F test/malloc_common.tcl aac62499b76be719fac31e7a3e54a7fd53272e7f
 F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e
 F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
 F test/memdb.test c1f2a343ad14398d5d6debda6ea33e80d0dafcc7
-F test/memdb1.test 1d94a4bf153201f16a0a755a5a0a5d7f33b001c972e3086acb1f76ad3fb7e0e5
+F test/memdb1.test 062cdf3b7de2f861878e4275d3a67b80982d9f792f693418c844fade15ec7537
 F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
 F test/memsubsys1.test 9e7555a22173b8f1c96c281ce289b338fcba2abe8b157f8798ca195bbf1d347e
 F test/memsubsys2.test 3e4a8d0c05fd3e5fa92017c64666730a520c7e08
@@ -1624,7 +1624,7 @@ F tool/mkkeywordhash.c 2e852ac0dfdc5af18886dc1ce7e9676d11714ae3df0a282dc7d90b3a0
 F tool/mkmsvcmin.tcl 8baf26690b80d861d0ac341b29880eec6ade39e4f11fe690271ded9cb90563a3
 F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
 F tool/mkopcodeh.tcl 4ee2a30ccbd900dc4d5cdb61bdab87cd2166cd2affcc78c9cc0b8d22a65b2eee
-F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
+F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa
 F tool/mkpragmatab.tcl 2144bc8550a6471a029db262a132d2df4b9e0db61b90398bf64f5b7b3f8d92cd
 F tool/mkshellc.tcl 574307265b49d813301fba91ccd74e6a26d33f65f74b6891c320a0ffbee07895
 F tool/mksourceid.c d458f9004c837bee87a6382228ac20d3eae3c49ea3b0a5aace936f8b60748d3b
@@ -1690,7 +1690,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P e5c6ade8ee596eaffd98d1d7ce9c7c968cd2d45f206603b894026e7ad7ac15b6
-R 66054801a2fc399d3dc7a916643e1819
+P 47398ae77236a92f6b9345aa397361b6df127a9a2895c0771d506b0be10822b9
+R bfc121db68c7d1b10b977a508d74da37
 U drh
-Z 2a01cfd70faa22757159c69df08c3c76
+Z 6064e9ffbc398d82aebface075258c56
index 2905c1c5a62efff32cf831e5f0164cf13b8a15df..a6d77e2b7f873cbe10ce399d0b8cea58a284d76e 100644 (file)
@@ -1 +1 @@
-47398ae77236a92f6b9345aa397361b6df127a9a2895c0771d506b0be10822b9
\ No newline at end of file
+8cf2ed4eff6d2e0958656e23384b05ead2128b678b0b69a591878af4190cd077
\ No newline at end of file
index 215bfbb24a0108a49ba9d6abd08621696c9a475e..0a81978cceb6a1b2009f65f22b9d48210f09c0c4 100644 (file)
@@ -157,6 +157,7 @@ static int memdbRead(
   MemFile *p = (MemFile *)pFile;
   if( iOfst+iAmt>p->sz ){
     memset(zBuf, 0, iAmt);
+    if( iOfst<p->sz ) memcpy(zBuf, p->aData+iOfst, p->sz - iOfst);
     return SQLITE_IOERR_SHORT_READ;
   }
   memcpy(zBuf, p->aData+iOfst, iAmt);
@@ -449,20 +450,6 @@ static MemFile *memdbFromDbSchema(sqlite3 *db, const char *zSchema){
   return p;
 }
 
-/*
-** Return a pointer to the memory used to hold the database.
-** Return NULL if the arguments do not describe a memdb database.
-*/
-void *sqlite3_memdb_ptr(sqlite3 *db, const char *zSchema, sqlite3_int64 *pSz){
-  MemFile *p = memdbFromDbSchema(db, zSchema);
-  if( p==0 ){
-    *pSz = 0;
-    return 0;
-  }
-  *pSz = p->sz;
-  return p->aData;
-}
-
 /*
 ** Reconfigure a memdb database.
 */
@@ -494,6 +481,72 @@ int sqlite3_memdb_config(
   return SQLITE_OK;
 }
 
+/*
+** Return the serialization of a database
+*/
+unsigned char *sqlite3_serialize(
+  sqlite3 *db,              /* The database connection */
+  const char *zSchema,      /* Which database within the connection */
+  sqlite3_int64 *piSize,    /* Write size here, if not NULL */
+  unsigned int mFlags       /* Maybe SQLITE_SERIALIZE_NOCOPY */
+){
+  MemFile *p = memdbFromDbSchema(db, zSchema);
+  int iDb = sqlite3FindDbName(db, zSchema);
+  Btree *pBt;
+  sqlite3_int64 sz;
+  int szPage = 0;
+  sqlite3_stmt *pStmt = 0;
+  unsigned char *pOut;
+  char *zSql;
+  int rc;
+
+  if( piSize ) *piSize = -1;
+  if( iDb<0 ) return 0;
+  if( p ){
+    if( piSize ) *piSize = p->sz;
+    if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
+      pOut = p->aData;
+    }else{
+      pOut = sqlite3_malloc64( p->sz );
+      if( pOut ) memcpy(pOut, p->aData, p->sz);
+    }
+    return pOut;
+  }
+  pBt = db->aDb[iDb].pBt;
+  if( pBt==0 ) return 0;
+  szPage = sqlite3BtreeGetPageSize(pBt);
+  zSql = sqlite3_mprintf("PRAGMA \"%w\".page_count", zSchema);
+  rc = zSql ? sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0) : SQLITE_NOMEM;
+  sqlite3_free(zSql);
+  if( rc ) return 0;
+  sqlite3_step(pStmt);
+  sz = sqlite3_column_int64(pStmt, 0)*szPage;
+  if( piSize ) *piSize = sz;
+  if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
+    pOut = 0;
+  }else{
+    pOut = sqlite3_malloc64( sz );
+    if( pOut ){
+      int nPage = sqlite3_column_int(pStmt, 0);
+      Pager *pPager = sqlite3BtreePager(pBt);
+      int pgno;
+      for(pgno=1; pgno<=nPage; pgno++){
+        DbPage *pPage = 0;
+        unsigned char *pTo = pOut + szPage*(sqlite3_int64)(pgno-1);
+        rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pPage, 0);
+        if( rc==SQLITE_OK ){
+          memcpy(pTo, sqlite3PagerGetData(pPage), szPage);
+        }else{
+          memset(pTo, 0, szPage);
+        }
+        sqlite3PagerUnref(pPage);       
+      }
+    }
+  }
+  sqlite3_finalize(pStmt);
+  return pOut;
+}
+
 /* 
 ** This routine is called when the extension is loaded.
 ** Register the new VFS.
index 1434485532fb3c424906c0d813111b61e8958f7c..6b6a5655b3290ee9ec0a22248b0f432ce9ae74b6 100644 (file)
@@ -8758,22 +8758,6 @@ SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
 */
 SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
 
-/*
-** CAPI3REF: Retrieve the current MEMDB buffer
-** EXPERIMENTAL
-**
-** This interface is only available when SQLite is compiled
-** with SQLITE_ENABLE_MEMDB.
-**
-** The sqlite3_memdb_ptr(D,S,P) interface returns a pointer to the
-** memory buffer that is the database file used for [database connection] D
-** and schema S.  If schema S of database connection D is not a MEMDB
-** database, then this routine returns NULL.  If P is not NULL, then it must
-** be a pointer to a 64-bit signed integer into which the size of the 
-** database file is written.
-*/
-SQLITE_EXPERIMENTAL void *sqlite3_memdb_ptr(sqlite3*,const char*,sqlite3_int64*);
-
 /*
 ** CAPI3REF: Set the current MEMDB buffer
 ** EXPERIMENTAL
@@ -8785,7 +8769,7 @@ SQLITE_EXPERIMENTAL void *sqlite3_memdb_ptr(sqlite3*,const char*,sqlite3_int64*)
 ** The database identified by D and S must not be in active use when this
 ** interface is called, or [SQLITE_BUSY] is returned.
 */
-SQLITE_EXPERIMENTAL int sqlite3_memdb_config(sqlite3*,const char*,void*,sqlite3_int64,sqlite3_int64,unsigned);
+int sqlite3_memdb_config(sqlite3*,const char*,void*,sqlite3_int64,sqlite3_int64,unsigned);
 
 /*
 ** CAPI3REF: Flags for configuring MEMDB databases
@@ -8797,6 +8781,99 @@ SQLITE_EXPERIMENTAL int sqlite3_memdb_config(sqlite3*,const char*,void*,sqlite3_
 #define SQLITE_MEMDB_FREEONCLOSE  0x001   /* Free the memory buffer on close */
 #define SQLITE_MEMDB_RESIZEABLE   0x002   /* Resize using sqlite3_realloc64() */
 
+/*
+** CAPI3REF: Serialize a database
+** EXPERIMENTAL
+**
+** The sqlite3_serialize(D,S,P,F) interface returns a pointer to memory
+** that is a serialization of the S database on [database connection] D.
+** If P is not a NULL pointer, then the size of the database in bytes
+** is written into *P.
+**
+** For an ordinary on-disk database file, the serialization is just a
+** copy of the disk file.  For an in-memory database or a "TEMP" database,
+** the serialization is the same sequence of bytes which would be written
+** to disk if that database where backed up to disk.
+**
+** The usual case is that sqlite3_serialize() copies the serialization of
+** the database into memory obtained from [sqlite3_malloc64()] and returns
+** a pointer to that memory.  The caller is responsible for freeing the
+** returned value to avoid a memory leak.  However, if the F argument
+** contains the SQLITE_SERIALIZE_NOCOPY bit, then no memory allocations
+** are made, and the sqlite3_serialize() function will return a pointer
+** to the contiguous memory representation of the database that SQLite
+** is currently using for that database, or NULL if the no such contiguous
+** memory representation of the database exists.  A contigous memory
+** representation of the database will usually only exist if there has
+** been a prior call to [sqlite3_deserialize(D,S,...)] with the same
+** values of D and S.
+** The size of the database is written into *P even if the 
+** SQLITE_SERIALIZE_NOCOPY bit is set but no contigious copy
+** of the database exists.
+**
+** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the
+** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory
+** allocation error occurs.
+*/
+unsigned char *sqlite3_serialize(
+  sqlite3 *db,           /* The database connection */
+  const char *zSchema,   /* Which DB to serialize. ex: "main", "temp", ... */
+  sqlite3_int64 *piSize, /* Write size of the DB here, if not NULL */
+  unsigned int mFlags    /* Zero or more SQLITE_SERIALIZE_* flags */
+);
+
+/*
+** CAPI3REF: Flags for sqlite3_serialize
+** EXPERIMENTAL
+*/
+#define SQLITE_SERIALIZE_NOCOPY 0x001   /* Do no memory allocations */
+
+/*
+** CAPI3REF: Set the current MEMDB buffer
+** EXPERIMENTAL
+**
+** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the 
+** [database connection] D to disconnection from database S and then
+** reopen S as an in-memory database based on the serialization contained
+** in P.  The serialized database P is N bytes in size.  M is the size of
+** the buffer P, which might be larger than N.  If M is larger than N, and
+** the SQLITE_DESERIALIZE_READONLY bit is not set in F, then SQLite is
+** permitted to add content to the in-memory database as long as the total
+** size does not exceed M bytes.
+**
+** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will
+** invoke sqlite3_free() on the serialization buffer when the database
+** connection closes.  If the SQLITE_DESERIALIZE_RESIZEABLE bit is set, then
+** SQLite will try to increase the buffer size using sqlite3_realloc64()
+** if writes on the database cause it to grow larger than M bytes.
+**
+** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the
+** database is currently in a read transaction or is involved in a backup
+** operation.
+**
+** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the 
+** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then
+** [sqlite3_free()] is invoked on argument P prior to returning.
+*/
+int sqlite3_deserialize(
+  sqlite3 *db,            /* The database connection */
+  const char *zSchema,    /* Which DB to reopen with the deserialization */
+  unsigned char *pData,   /* The serialized database content */
+  sqlite3_int64 szDb,     /* Number bytes in the deserialization */
+  sqlite3_int64 szBuf,    /* Total size of buffer pData[] */
+  unsigned mFlags         /* Zero or more SQLITE_DESERIALIZE_* flags */
+);
+
+/*
+** CAPI3REF: Flags for sqlite3_deserialize()
+** EXPERIMENTAL
+**
+** The following are allowed values for the 6th argument (the "flags" or "F"
+** argument) of the [sqlite3_deserialize()] interface.
+*/
+#define SQLITE_DESERIALIZE_FREEONCLOSE 1 /* Call sqlite3_free() on close */
+#define SQLITE_DESERIALIZE_RESIZEABLE  2 /* Resize using sqlite3_realloc64() */
+#define SQLITE_DESERIALIZE_READONLY    4 /* Database is read-only */
 
 /*
 ** Undo the hack that converts floating point types to integer for
index d02d94baf564aa859853358ad29bcdf32c935b3e..2c6e1bbe27d594e0ba8453867ff24df35d81aa1d 100644 (file)
@@ -1846,34 +1846,36 @@ static int SQLITE_TCLAPI DbObjCmd(
   int choice;
   int rc = TCL_OK;
   static const char *DB_strs[] = {
-    "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",  "memdb",             "nullvalue",
-    "onecolumn",          "preupdate",         "profile",
-    "progress",           "rekey",             "restore",
-    "rollback_hook",      "status",            "timeout",
-    "total_changes",      "trace",             "trace_v2",
-    "transaction",        "unlock_notify",     "update_hook",
-    "version",            "wal_hook",          0
+    "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",     "memdb",
+    "nullvalue",              "onecolumn",             "preupdate",
+    "profile",                "progress",              "rekey",
+    "restore",                "rollback_hook",         "serialize",
+    "status",                 "timeout",               "total_changes",
+    "trace",                  "trace_v2",              "transaction",
+    "unlock_notify",          "update_hook",           "version",
+    "wal_hook",               0                        
   };
   enum DB_enum {
-    DB_AUTHORIZER,        DB_BACKUP,           DB_BUSY,
-    DB_CACHE,             DB_CHANGES,          DB_CLOSE,
-    DB_COLLATE,           DB_COLLATION_NEEDED, DB_COMMIT_HOOK,
-    DB_COMPLETE,          DB_COPY,             DB_ENABLE_LOAD_EXTENSION,
-    DB_ERRORCODE,         DB_EVAL,             DB_EXISTS,
-    DB_FUNCTION,          DB_INCRBLOB,         DB_INTERRUPT,
-    DB_LAST_INSERT_ROWID, DB_MEMDB,            DB_NULLVALUE,
-    DB_ONECOLUMN,         DB_PREUPDATE,        DB_PROFILE,
-    DB_PROGRESS,          DB_REKEY,            DB_RESTORE,
-    DB_ROLLBACK_HOOK,     DB_STATUS,           DB_TIMEOUT,
-    DB_TOTAL_CHANGES,     DB_TRACE,            DB_TRACE_V2,
-    DB_TRANSACTION,       DB_UNLOCK_NOTIFY,    DB_UPDATE_HOOK,
-    DB_VERSION,           DB_WAL_HOOK
+    DB_AUTHORIZER,            DB_BACKUP,               DB_BUSY,
+    DB_CACHE,                 DB_CHANGES,              DB_CLOSE,
+    DB_COLLATE,               DB_COLLATION_NEEDED,     DB_COMMIT_HOOK,
+    DB_COMPLETE,              DB_COPY,                 DB_DESERIALIZE,
+    DB_ENABLE_LOAD_EXTENSION, DB_ERRORCODE,            DB_EVAL,
+    DB_EXISTS,                DB_FUNCTION,             DB_INCRBLOB,
+    DB_INTERRUPT,             DB_LAST_INSERT_ROWID,    DB_MEMDB,
+    DB_NULLVALUE,             DB_ONECOLUMN,            DB_PREUPDATE,
+    DB_PROFILE,               DB_PROGRESS,             DB_REKEY,
+    DB_RESTORE,               DB_ROLLBACK_HOOK,        DB_SERIALIZE,
+    DB_STATUS,                DB_TIMEOUT,              DB_TOTAL_CHANGES,
+    DB_TRACE,                 DB_TRACE_V2,             DB_TRANSACTION,
+    DB_UNLOCK_NOTIFY,         DB_UPDATE_HOOK,          DB_VERSION,
+    DB_WAL_HOOK
   };
   /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
 
@@ -2411,6 +2413,16 @@ static int SQLITE_TCLAPI DbObjCmd(
     break;
   }
 
+  /*
+  **     $db deserialize ?DATABASE? VALUE
+  **
+  ** Reopen DATABASE (default "main") using the content in $VALUE
+  */
+  case DB_DESERIALIZE: {
+    rc = TCL_ERROR;  /* TBD */
+    break; 
+  }
+
   /*
   **    $db enable_load_extension BOOLEAN
   **
@@ -2679,17 +2691,8 @@ static int SQLITE_TCLAPI DbObjCmd(
     rc = TCL_ERROR;
 #else
     const char *zSchema = Tcl_GetString(objv[2]);
-    sqlite3_int64 sz = 0;
     unsigned char *pData;
-    if( objc==3 ){
-      pData = sqlite3_memdb_ptr(pDb->db, zSchema, &sz);
-      if( pData==0 ){
-        Tcl_AppendResult(interp, "not a MEMDB database", (char*)0);
-        rc = TCL_ERROR;
-      }else{
-        Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pData,sz));
-      }
-    }else if( objc==4 ){
+    if( objc==4 ){
       int len = 0, xrc;
       unsigned char *pBA = Tcl_GetByteArrayFromObj(objv[3], &len);
       pData = sqlite3_malloc64( len );
@@ -2933,6 +2936,39 @@ static int SQLITE_TCLAPI DbObjCmd(
     break;
   }
 
+  /*
+  **     $db serialize ?DATABASE?
+  **
+  ** Return a serialization of a database.  
+  */
+  case DB_SERIALIZE: {
+#ifndef SQLITE_ENABLE_MEMDB
+    Tcl_AppendResult(interp, "MEMDB not available in this build",
+                     (char*)0);
+    rc = TCL_ERROR;
+#else
+    const char *zSchema = objc>=3 ? Tcl_GetString(objv[2]) : "main";
+    sqlite3_int64 sz = 0;
+    unsigned char *pData;
+    if( objc!=2 && objc!=3 ){
+      Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE?");
+      rc = TCL_ERROR;
+    }else{
+      int needFree;
+      pData = sqlite3_serialize(pDb->db, zSchema, &sz, SQLITE_SERIALIZE_NOCOPY);
+      if( pData ){
+        needFree = 0;
+      }else{
+        pData = sqlite3_serialize(pDb->db, zSchema, &sz, 0);
+        needFree = 1;
+      }
+      Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pData,sz));
+      if( needFree ) sqlite3_free(pData);
+    }
+#endif
+    break;
+  }
+
   /*
   **     $db status (step|sort|autoindex|vmstep)
   **
index 13ef57ace458f17aa41a9d9c075e3d002c973247..36184e2e4e9053653e8f2d677ec53132436fb9f1 100644 (file)
@@ -27,8 +27,6 @@ ifcapable !memdb {
 # Verify that the size of $::db1 is the same as the size of
 # the database.
 #
-db close
-sqlite3 db dummy -vfs memdb
 unset -nocomplain db1
 unset -nocomplain sz1
 unset -nocomplain pgsz
@@ -39,9 +37,12 @@ do_test 100 {
   }
   set ::pgsz [db one {PRAGMA page_size}]
   set ::sz1 [expr {$::pgsz*[db one {PRAGMA page_count}]}]
-  set ::db1 [db memdb main]
+  set ::db1 [db serialize]
   expr {[string length $::db1]==$::sz1}
 } 1
+set fd [open db1.db wb]
+puts -nonewline $fd $db1
+close $fd
 
 # Create a new MEMDB and initialize it to the content of $::db1
 # Verify that the content is the same.
index e3ddcb9eeb378667d3ca11e1487f66d438f1487f..88f645bbe3016391c1b9323c39433fdf1a357abe 100644 (file)
@@ -11,7 +11,7 @@ while {![eof stdin]} {
   if {$line==""} continue
   regsub -all "\[ \t\n,\]+" [string trim $line] { } line
   foreach token [split $line { }] {
-    if {![regexp {(([a-zA-Z]+)_)?([_a-zA-Z]+)} $token all px p2 name]} continue
+    if {![regexp {(([a-zA-Z]+)_)?([_a-zA-Z0-9]+)} $token all px p2 name]} continue
     lappend namelist [string tolower $name]
     if {$px!=""} {set prefix $p2}
   }
@@ -23,7 +23,7 @@ proc put_item x {
   global col
   if {$col==0} {puts -nonewline "   "}
   if {$col<2} {
-    puts -nonewline [format " %-21s" $x]
+    puts -nonewline [format " %-25s" $x]
     incr col
   } else {
     puts $x