aboutsummaryrefslogtreecommitdiff
path: root/src/tclsqlite.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tclsqlite.c')
-rw-r--r--src/tclsqlite.c192
1 files changed, 144 insertions, 48 deletions
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index 252b246e6..878cdd961 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -1848,35 +1848,35 @@ 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", "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", "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_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_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 */
@@ -2415,6 +2415,53 @@ static int SQLITE_TCLAPI DbObjCmd(
}
/*
+ ** $db deserialize ?DATABASE? VALUE
+ **
+ ** Reopen DATABASE (default "main") using the content in $VALUE
+ */
+ case DB_DESERIALIZE: {
+#ifndef SQLITE_ENABLE_MEMDB
+ Tcl_AppendResult(interp, "MEMDB not available in this build",
+ (char*)0);
+ rc = TCL_ERROR;
+#else
+ const char *zSchema;
+ Tcl_Obj *pValue;
+ unsigned char *pBA;
+ unsigned char *pData;
+ int len, xrc;
+
+ if( objc==3 ){
+ zSchema = 0;
+ pValue = objv[2];
+ }else if( objc==4 ){
+ zSchema = Tcl_GetString(objv[2]);
+ pValue = objv[3];
+ }else{
+ Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? VALUE");
+ rc = TCL_ERROR;
+ break;
+ }
+ pBA = Tcl_GetByteArrayFromObj(pValue, &len);
+ pData = sqlite3_malloc64( len );
+ if( pData==0 && len>0 ){
+ Tcl_AppendResult(interp, "out of memory", (char*)0);
+ rc = TCL_ERROR;
+ }else{
+ if( len>0 ) memcpy(pData, pBA, len);
+ xrc = sqlite3_deserialize(pDb->db, zSchema, pData, len, len,
+ SQLITE_DESERIALIZE_FREEONCLOSE |
+ SQLITE_DESERIALIZE_RESIZEABLE);
+ if( xrc ){
+ Tcl_AppendResult(interp, "unable to set MEMDB content", (char*)0);
+ rc = TCL_ERROR;
+ }
+ }
+#endif
+ break;
+ }
+
+ /*
** $db enable_load_extension BOOLEAN
**
** Turn the extension loading feature on or off. It if off by
@@ -2890,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
@@ -3350,6 +3430,24 @@ static int SQLITE_TCLAPI DbObjCmdAdaptor(
#endif /* SQLITE_TCL_NRE */
/*
+** Issue the usage message when the "sqlite3" command arguments are
+** incorrect.
+*/
+static int sqliteCmdUsage(
+ Tcl_Interp *interp,
+ Tcl_Obj *const*objv
+){
+ Tcl_WrongNumArgs(interp, 1, objv,
+ "HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
+ " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
+ " ?-key CODECKEY?"
+#endif
+ );
+ return TCL_ERROR;
+}
+
+/*
** sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN?
** ?-create BOOLEAN? ?-nomutex BOOLEAN?
**
@@ -3374,7 +3472,7 @@ static int SQLITE_TCLAPI DbMain(
const char *zArg;
char *zErrMsg;
int i;
- const char *zFile;
+ const char *zFile = 0;
const char *zVfs = 0;
int flags;
Tcl_DString translatedFilename;
@@ -3385,7 +3483,7 @@ static int SQLITE_TCLAPI DbMain(
int rc;
/* In normal use, each TCL interpreter runs in a single thread. So
- ** by default, we can turn of mutexing on SQLite database connections.
+ ** by default, we can turn off mutexing on SQLite database connections.
** However, for testing purposes it is useful to have mutexes turned
** on. So, by default, mutexes default off. But if compiled with
** SQLITE_TCL_DEFAULT_FULLMUTEX then mutexes default on.
@@ -3414,18 +3512,26 @@ static int SQLITE_TCLAPI DbMain(
#endif
return TCL_OK;
}
+ if( zArg[0]=='-' ) return sqliteCmdUsage(interp, objv);
}
- for(i=3; i+1<objc; i+=2){
+ for(i=2; i<objc; i++){
zArg = Tcl_GetString(objv[i]);
+ if( zArg[0]!='-' ){
+ if( zFile!=0 ) return sqliteCmdUsage(interp, objv);
+ zFile = zArg;
+ continue;
+ }
+ if( i==objc-1 ) return sqliteCmdUsage(interp, objv);
+ i++;
if( strcmp(zArg,"-key")==0 ){
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
- pKey = Tcl_GetByteArrayFromObj(objv[i+1], &nKey);
+ pKey = Tcl_GetByteArrayFromObj(objv[i], &nKey);
#endif
}else if( strcmp(zArg, "-vfs")==0 ){
- zVfs = Tcl_GetString(objv[i+1]);
+ zVfs = Tcl_GetString(objv[i]);
}else if( strcmp(zArg, "-readonly")==0 ){
int b;
- if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
+ if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
if( b ){
flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
flags |= SQLITE_OPEN_READONLY;
@@ -3435,7 +3541,7 @@ static int SQLITE_TCLAPI DbMain(
}
}else if( strcmp(zArg, "-create")==0 ){
int b;
- if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
+ if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
if( b && (flags & SQLITE_OPEN_READONLY)==0 ){
flags |= SQLITE_OPEN_CREATE;
}else{
@@ -3443,7 +3549,7 @@ static int SQLITE_TCLAPI DbMain(
}
}else if( strcmp(zArg, "-nomutex")==0 ){
int b;
- if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
+ if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
if( b ){
flags |= SQLITE_OPEN_NOMUTEX;
flags &= ~SQLITE_OPEN_FULLMUTEX;
@@ -3452,7 +3558,7 @@ static int SQLITE_TCLAPI DbMain(
}
}else if( strcmp(zArg, "-fullmutex")==0 ){
int b;
- if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
+ if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
if( b ){
flags |= SQLITE_OPEN_FULLMUTEX;
flags &= ~SQLITE_OPEN_NOMUTEX;
@@ -3461,7 +3567,7 @@ static int SQLITE_TCLAPI DbMain(
}
}else if( strcmp(zArg, "-uri")==0 ){
int b;
- if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
+ if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
if( b ){
flags |= SQLITE_OPEN_URI;
}else{
@@ -3472,20 +3578,10 @@ static int SQLITE_TCLAPI DbMain(
return TCL_ERROR;
}
}
- if( objc<3 || (objc&1)!=1 ){
- Tcl_WrongNumArgs(interp, 1, objv,
- "HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
- " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
-#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
- " ?-key CODECKEY?"
-#endif
- );
- return TCL_ERROR;
- }
zErrMsg = 0;
p = (SqliteDb*)Tcl_Alloc( sizeof(*p) );
memset(p, 0, sizeof(*p));
- zFile = Tcl_GetStringFromObj(objv[2], 0);
+ if( zFile==0 ) zFile = "";
zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename);
rc = sqlite3_open_v2(zFile, &p->db, flags, zVfs);
Tcl_DStringFree(&translatedFilename);