diff options
author | danielk1977 <danielk1977@noemail.net> | 2005-12-16 06:54:01 +0000 |
---|---|---|
committer | danielk1977 <danielk1977@noemail.net> | 2005-12-16 06:54:01 +0000 |
commit | 71fd80bf5ca3027464eb233c36bd928f2249edc4 (patch) | |
tree | 73a7df6795d4af33ca58d20cbcaf87294cae236e /src | |
parent | fdd6e85a34cc4f1fcb49639519f3673627ecacbf (diff) | |
download | sqlite-71fd80bf5ca3027464eb233c36bd928f2249edc4.tar.gz sqlite-71fd80bf5ca3027464eb233c36bd928f2249edc4.zip |
Add the sqlite3_rollback_hook() API. Still requires further testing. (CVS 2823)
FossilOrigin-Name: 3baa3ff32435b64e7ae7646b17a98fef9296aaa0
Diffstat (limited to 'src')
-rw-r--r-- | src/btree.c | 4 | ||||
-rw-r--r-- | src/main.c | 31 | ||||
-rw-r--r-- | src/sqlite.h.in | 9 | ||||
-rw-r--r-- | src/sqliteInt.h | 8 | ||||
-rw-r--r-- | src/tclsqlite.c | 66 | ||||
-rw-r--r-- | src/vdbeaux.c | 24 |
6 files changed, 106 insertions, 36 deletions
diff --git a/src/btree.c b/src/btree.c index ba5e6c492..65b5594dd 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.273 2005/12/09 20:02:05 drh Exp $ +** $Id: btree.c,v 1.274 2005/12/16 06:54:02 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -4906,9 +4906,11 @@ int sqlite3BtreeClearTable(Btree *pBt, int iTable){ } } rc = clearDatabasePage(pBt, (Pgno)iTable, 0, 0); +#if 0 if( rc ){ sqlite3BtreeRollback(pBt); } +#endif return rc; } diff --git a/src/main.c b/src/main.c index 8bc6bb885..ba0bb5feb 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.310 2005/12/15 15:22:09 danielk1977 Exp $ +** $Id: main.c,v 1.311 2005/12/16 06:54:02 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -210,7 +210,14 @@ void sqlite3RollbackAll(sqlite3 *db){ db->aDb[i].inTrans = 0; } } - sqlite3ResetInternalSchema(db, 0); + if( db->flags&SQLITE_InternChanges ){ + sqlite3ResetInternalSchema(db, 0); + } + + /* If one has been configured, invoke the rollback-hook callback */ + if( db->xRollbackCallback ){ + db->xRollbackCallback(db->pRollbackArg); + } } /* @@ -534,7 +541,7 @@ void *sqlite3_profile( /*** EXPERIMENTAL *** ** ** Register a function to be invoked when a transaction comments. -** If either function returns non-zero, then the commit becomes a +** If the invoked function returns non-zero, then the commit becomes a ** rollback. */ void *sqlite3_commit_hook( @@ -552,15 +559,31 @@ void *sqlite3_commit_hook( ** Register a callback to be invoked each time a row is updated, ** inserted or deleted using this database connection. */ -void sqlite3_update_hook( +void *sqlite3_update_hook( sqlite3 *db, /* Attach the hook to this database */ void (*xCallback)(void*,int,char const *,char const *,sqlite_int64), void *pArg /* Argument to the function */ ){ + void *pRet = db->pUpdateArg; db->xUpdateCallback = xCallback; db->pUpdateArg = pArg; + return pRet; } +/* +** Register a callback to be invoked each time a transaction is rolled +** back by this database connection. +*/ +void *sqlite3_rollback_hook( + sqlite3 *db, /* Attach the hook to this database */ + void (*xCallback)(void*), /* Callback function */ + void *pArg /* Argument to the function */ +){ + void *pRet = db->pRollbackArg; + db->xRollbackCallback = xCallback; + db->pRollbackArg = pArg; + return pRet; +} /* ** This routine is called to create a connection to a database BTree diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 86d75d26d..966b38a20 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -12,7 +12,7 @@ ** This header file defines the interface that the SQLite library ** presents to client programs. ** -** @(#) $Id: sqlite.h.in,v 1.146 2005/12/15 15:22:09 danielk1977 Exp $ +** @(#) $Id: sqlite.h.in,v 1.147 2005/12/16 06:54:02 danielk1977 Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ @@ -1309,13 +1309,18 @@ void sqlite3_soft_heap_limit(int); ** ** The update hook is not invoked when internal system tables are ** modified (i.e. sqlite_master and sqlite_sequence). +** +** If another function was previously registered, its pArg value is returned. +** Otherwise NULL is returned. */ -void sqlite3_update_hook( +void *sqlite3_update_hook( sqlite3*, void(*)(void *,int ,char const *,char const *,sqlite_int64), void* ); +void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); + /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 0285677f8..11624cab9 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.438 2005/12/16 01:06:17 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.439 2005/12/16 06:54:02 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -440,8 +440,10 @@ struct sqlite3 { void *pTraceArg; /* Argument to the trace function */ void (*xProfile)(void*,const char*,u64); /* Profiling function */ void *pProfileArg; /* Argument to profile function */ - void *pCommitArg; /* Argument to xCommitCallback() */ - int (*xCommitCallback)(void*);/* Invoked at every commit. */ + void *pCommitArg; /* Argument to xCommitCallback() */ + int (*xCommitCallback)(void*); /* Invoked at every commit. */ + void *pRollbackArg; /* Argument to xRollbackCallback() */ + void (*xRollbackCallback)(void*); /* Invoked at every commit. */ void *pUpdateArg; void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*); diff --git a/src/tclsqlite.c b/src/tclsqlite.c index b862df3f0..337cdefb4 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -11,7 +11,7 @@ ************************************************************************* ** A TCL Interface to SQLite ** -** $Id: tclsqlite.c,v 1.139 2005/12/15 15:22:10 danielk1977 Exp $ +** $Id: tclsqlite.c,v 1.140 2005/12/16 06:54:03 danielk1977 Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ @@ -100,6 +100,7 @@ struct SqliteDb { char *zNull; /* Text to substitute for an SQL NULL value */ SqlFunc *pFunc; /* List of SQL functions */ Tcl_Obj *pUpdateHook; /* Update hook script (if any) */ + Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */ SqlCollate *pCollate; /* List of SQL collation functions */ int rc; /* Return code of most recent sqlite3_exec() */ Tcl_Obj *pCollateNeeded; /* Collation needed script */ @@ -214,6 +215,9 @@ static void DbDeleteCmd(void *db){ if( pDb->pUpdateHook ){ Tcl_DecrRefCount(pDb->pUpdateHook); } + if( pDb->pRollbackHook ){ + Tcl_DecrRefCount(pDb->pRollbackHook); + } if( pDb->pCollateNeeded ){ Tcl_DecrRefCount(pDb->pCollateNeeded); } @@ -304,6 +308,14 @@ static int DbCommitHandler(void *cd){ return 0; } +static void DbRollbackHandler(void *clientData){ + SqliteDb *pDb = (SqliteDb*)clientData; + assert(pDb->pRollbackHook); + if( TCL_OK!=Tcl_EvalObjEx(pDb->interp, pDb->pRollbackHook, 0) ){ + Tcl_BackgroundError(pDb->interp); + } +} + static void DbUpdateHandler( void *p, int op, @@ -653,10 +665,10 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ "copy", "errorcode", "eval", "exists", "function", "last_insert_rowid", "nullvalue", "onecolumn", "profile", - "progress", "rekey", "soft_heap_limit", - "timeout", "total_changes", "trace", - "transaction", "update_hook", "version", - 0 + "progress", "rekey", "rollback_hook", + "soft_heap_limit", "timeout", "total_changes", + "trace", "transaction", "update_hook", + "version", 0 }; enum DB_enum { DB_AUTHORIZER, DB_BUSY, DB_CACHE, @@ -665,9 +677,10 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ DB_COPY, DB_ERRORCODE, DB_EVAL, DB_EXISTS, DB_FUNCTION, DB_LAST_INSERT_ROWID, DB_NULLVALUE, DB_ONECOLUMN, DB_PROFILE, - DB_PROGRESS, DB_REKEY, DB_SOFT_HEAP_LIMIT, - DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE, - DB_TRANSACTION, DB_UPDATE_HOOK, DB_VERSION + DB_PROGRESS, DB_REKEY, DB_ROLLBACK_HOOK, + DB_SOFT_HEAP_LIMIT, 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 */ @@ -1872,28 +1885,43 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ /* ** $db update_hook ?script? + ** $db rollback_hook ?script? */ - case DB_UPDATE_HOOK: { + case DB_UPDATE_HOOK: + case DB_ROLLBACK_HOOK: { + + /* set ppHook to point at pUpdateHook or pRollbackHook, depending on + ** whether [$db update_hook] or [$db rollback_hook] was invoked. + */ + Tcl_Obj **ppHook; + if( choice==DB_UPDATE_HOOK ){ + ppHook = &pDb->pUpdateHook; + }else{ + ppHook = &pDb->pRollbackHook; + } + if( objc!=2 && objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?"); return TCL_ERROR; } - if( pDb->pUpdateHook ){ - Tcl_SetObjResult(interp, pDb->pUpdateHook); + if( *ppHook ){ + Tcl_SetObjResult(interp, *ppHook); if( objc==3 ){ - Tcl_DecrRefCount(pDb->pUpdateHook); - pDb->pUpdateHook = 0; + Tcl_DecrRefCount(*ppHook); + *ppHook = 0; } } if( objc==3 ){ + assert( !(*ppHook) ); if( Tcl_GetCharLength(objv[2])>0 ){ - pDb->pUpdateHook = objv[2]; - Tcl_IncrRefCount(pDb->pUpdateHook); - sqlite3_update_hook(pDb->db, DbUpdateHandler, pDb); - }else{ - sqlite3_update_hook(pDb->db, 0, 0); + *ppHook = objv[2]; + Tcl_IncrRefCount(*ppHook); } } + + sqlite3_update_hook(pDb->db, (pDb->pUpdateHook?DbUpdateHandler:0), pDb); + sqlite3_rollback_hook(pDb->db,(pDb->pRollbackHook?DbRollbackHandler:0),pDb); + break; } @@ -2160,7 +2188,7 @@ int TCLSH_MAIN(int argc, char **argv){ Sqlitetest4_Init(interp); Sqlitetest5_Init(interp); Sqlitetest6_Init(interp); - Sqlitetestasync_Init(interp); + /* Sqlitetestasync_Init(interp); */ Md5_Init(interp); #ifdef SQLITE_SSE Sqlitetestsse_Init(interp); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 6949f8c35..a99dc4643 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1233,17 +1233,27 @@ int sqlite3VdbeHalt(Vdbe *p){ } } - /* If xFunc is not NULL, then it is one of sqlite3BtreeRollback, + /* If xFunc is not NULL, then it is one of ** sqlite3BtreeRollbackStmt or sqlite3BtreeCommitStmt. Call it once on ** each backend. If an error occurs and the return code is still ** SQLITE_OK, set the return code to the new error value. */ - for(i=0; xFunc && i<db->nDb; i++){ - int rc; - Btree *pBt = db->aDb[i].pBt; - if( pBt ){ - rc = xFunc(pBt); - if( p->rc==SQLITE_OK ) p->rc = rc; + assert(!xFunc || + xFunc==sqlite3BtreeCommitStmt || + xFunc==sqlite3BtreeRollbackStmt || + xFunc==sqlite3BtreeRollback + ); + if( xFunc==sqlite3BtreeRollback ){ + assert( p->rc!=SQLITE_OK ); + sqlite3RollbackAll(db); + }else{ + for(i=0; xFunc && i<db->nDb; i++){ + int rc; + Btree *pBt = db->aDb[i].pBt; + if( pBt ){ + rc = xFunc(pBt); + if( p->rc==SQLITE_OK ) p->rc = rc; + } } } |