aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2018-01-03 16:49:52 +0000
committerdrh <drh@noemail.net>2018-01-03 16:49:52 +0000
commitcb7d541d3ae005e24bb0d36bb138d84a3ca3d415 (patch)
treec594ecd7b9f257a531db3fc9b8712527814d68dc
parent4dcac40e3d4cf02513c84c95ccd4198ef35f2320 (diff)
downloadsqlite-cb7d541d3ae005e24bb0d36bb138d84a3ca3d415.tar.gz
sqlite-cb7d541d3ae005e24bb0d36bb138d84a3ca3d415.zip
Replace the sqlite3_memdb_ptr() interface with the more general
sqlite3_serialize() interface. FossilOrigin-Name: 8cf2ed4eff6d2e0958656e23384b05ead2128b678b0b69a591878af4190cd077
-rw-r--r--manifest20
-rw-r--r--manifest.uuid2
-rw-r--r--src/memdb.c81
-rw-r--r--src/sqlite.h.in111
-rw-r--r--src/tclsqlite.c108
-rw-r--r--test/memdb1.test7
-rw-r--r--tool/mkopts.tcl4
7 files changed, 250 insertions, 83 deletions
diff --git a/manifest b/manifest
index 9d5dca5c2..892a7572e 100644
--- 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
diff --git a/manifest.uuid b/manifest.uuid
index 2905c1c5a..a6d77e2b7 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-47398ae77236a92f6b9345aa397361b6df127a9a2895c0771d506b0be10822b9 \ No newline at end of file
+8cf2ed4eff6d2e0958656e23384b05ead2128b678b0b69a591878af4190cd077 \ No newline at end of file
diff --git a/src/memdb.c b/src/memdb.c
index 215bfbb24..0a81978cc 100644
--- a/src/memdb.c
+++ b/src/memdb.c
@@ -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);
@@ -450,20 +451,6 @@ static MemFile *memdbFromDbSchema(sqlite3 *db, const char *zSchema){
}
/*
-** 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.
*/
int sqlite3_memdb_config(
@@ -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.
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 143448553..6b6a5655b 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -8759,22 +8759,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
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index d02d94baf..2c6e1bbe2 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -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 */
@@ -2412,6 +2414,16 @@ static int SQLITE_TCLAPI DbObjCmd(
}
/*
+ ** $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
**
** Turn the extension loading feature on or off. It if off by
@@ -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 );
@@ -2934,6 +2937,39 @@ static int SQLITE_TCLAPI DbObjCmd(
}
/*
+ ** $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)
**
** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or
diff --git a/test/memdb1.test b/test/memdb1.test
index 13ef57ace..36184e2e4 100644
--- a/test/memdb1.test
+++ b/test/memdb1.test
@@ -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.
diff --git a/tool/mkopts.tcl b/tool/mkopts.tcl
index e3ddcb9ee..88f645bbe 100644
--- a/tool/mkopts.tcl
+++ b/tool/mkopts.tcl
@@ -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