aboutsummaryrefslogtreecommitdiff
path: root/src/tclsqlite.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tclsqlite.c')
-rw-r--r--src/tclsqlite.c155
1 files changed, 132 insertions, 23 deletions
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index 1516728d5..4e7f77dd2 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -12,7 +12,7 @@
** A TCL Interface to SQLite. Append this file to sqlite3.c and
** compile the whole thing to build a TCL-enabled version of SQLite.
**
-** $Id: tclsqlite.c,v 1.235 2009/02/03 16:51:25 danielk1977 Exp $
+** $Id: tclsqlite.c,v 1.236 2009/02/04 22:46:47 drh Exp $
*/
#include "tcl.h"
#include <errno.h>
@@ -983,30 +983,31 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
int choice;
int rc = TCL_OK;
static const char *DB_strs[] = {
- "authorizer", "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", "profile",
- "progress", "rekey", "rollback_hook",
- "status", "timeout", "total_changes",
- "trace", "transaction", "update_hook",
- "version", 0
+ "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",
+ "profile", "progress", "rekey",
+ "restore", "rollback_hook", "status",
+ "timeout", "total_changes", "trace",
+ "transaction", "update_hook", "version",
+ 0
};
enum DB_enum {
- DB_AUTHORIZER, 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_PROFILE,
- DB_PROGRESS, DB_REKEY, DB_ROLLBACK_HOOK,
- DB_STATUS, DB_TIMEOUT, DB_TOTAL_CHANGES,
- DB_TRACE, DB_TRANSACTION, DB_UPDATE_HOOK,
- DB_VERSION
+ 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_PROFILE, DB_PROGRESS, DB_REKEY,
+ DB_RESTORE, DB_ROLLBACK_HOOK, DB_STATUS,
+ DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE,
+ DB_TRANSACTION, DB_UPDATE_HOOK, DB_VERSION,
};
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
@@ -1074,6 +1075,55 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break;
}
+ /* $db backup ?DATABASE? FILENAME
+ **
+ ** Open or create a database file named FILENAME. Transfer the
+ ** content of local database DATABASE (default: "main") into the
+ ** FILENAME database.
+ */
+ case DB_BACKUP: {
+ const char *zDestFile;
+ const char *zSrcDb;
+ sqlite3 *pDest;
+ sqlite3_backup *pBackup;
+
+ if( objc==3 ){
+ zSrcDb = "main";
+ zDestFile = Tcl_GetString(objv[2]);
+ }else if( objc==4 ){
+ zSrcDb = Tcl_GetString(objv[2]);
+ zDestFile = Tcl_GetString(objv[3]);
+ }else{
+ Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? FILENAME");
+ return TCL_ERROR;
+ }
+ rc = sqlite3_open(zDestFile, &pDest);
+ if( rc!=SQLITE_OK ){
+ Tcl_AppendResult(interp, "cannot open target database: ",
+ sqlite3_errmsg(pDest), (char*)0);
+ sqlite3_close(pDest);
+ return TCL_ERROR;
+ }
+ pBackup = sqlite3_backup_init(pDest, "main", pDb->db, zSrcDb);
+ if( pBackup==0 ){
+ Tcl_AppendResult(interp, "backup failed: ",
+ sqlite3_errmsg(pDest), (char*)0);
+ sqlite3_close(pDest);
+ return TCL_ERROR;
+ }
+ while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
+ sqlite3_backup_finish(pBackup);
+ if( rc==SQLITE_DONE ){
+ rc = TCL_OK;
+ }else{
+ Tcl_AppendResult(interp, "backup failed: ",
+ sqlite3_errmsg(pDest), (char*)0);
+ rc = TCL_ERROR;
+ }
+ sqlite3_close(pDest);
+ break;
+ }
+
/* $db busy ?CALLBACK?
**
** Invoke the given callback if an SQL statement attempts to open
@@ -2151,6 +2201,65 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break;
}
+ /* $db restore ?DATABASE? FILENAME
+ **
+ ** Open a database file named FILENAME. Transfer the content
+ ** of FILENAME into the local database DATABASE (default: "main").
+ */
+ case DB_RESTORE: {
+ const char *zSrcFile;
+ const char *zDestDb;
+ sqlite3 *pSrc;
+ sqlite3_backup *pBackup;
+ int nTimeout = 0;
+
+ if( objc==3 ){
+ zDestDb = "main";
+ zSrcFile = Tcl_GetString(objv[2]);
+ }else if( objc==4 ){
+ zDestDb = Tcl_GetString(objv[2]);
+ zSrcFile = Tcl_GetString(objv[3]);
+ }else{
+ Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? FILENAME");
+ return TCL_ERROR;
+ }
+ rc = sqlite3_open_v2(zSrcFile, &pSrc, SQLITE_OPEN_READONLY, 0);
+ if( rc!=SQLITE_OK ){
+ Tcl_AppendResult(interp, "cannot open source database: ",
+ sqlite3_errmsg(pSrc), (char*)0);
+ sqlite3_close(pSrc);
+ return TCL_ERROR;
+ }
+ pBackup = sqlite3_backup_init(pDb->db, zDestDb, pSrc, "main");
+ if( pBackup==0 ){
+ Tcl_AppendResult(interp, "restore failed: ",
+ sqlite3_errmsg(pDb->db), (char*)0);
+ sqlite3_close(pSrc);
+ return TCL_ERROR;
+ }
+ while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
+ || rc==SQLITE_BUSY ){
+ if( rc==SQLITE_BUSY ){
+ if( nTimeout++ >= 3 ) break;
+ sqlite3_sleep(100);
+ }
+ }
+ sqlite3_backup_finish(pBackup);
+ if( rc==SQLITE_DONE ){
+ rc = TCL_OK;
+ }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
+ Tcl_AppendResult(interp, "restore failed: source database busy",
+ (char*)0);
+ rc = TCL_ERROR;
+ }else{
+ Tcl_AppendResult(interp, "restore failed: ",
+ sqlite3_errmsg(pDb->db), (char*)0);
+ rc = TCL_ERROR;
+ }
+ sqlite3_close(pSrc);
+ break;
+ }
+
/*
** $db status (step|sort)
**