diff --git a/manifest b/manifest index 2608f60580..132ab8f068 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sexperimental\ssqlite3_preupdate_hook()\sAPI. -D 2011-03-01T18:42:07 +C Add\sthe\sexperimental\ssqlite3_transaction_hook()\sAPI. +D 2011-03-03T20:06:00 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -142,7 +142,7 @@ F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e F src/loadext.c 8af9fcc75708d60b88636ccba38b4a7b3c155c3e -F src/main.c 9ab948225b8c362cdd6902c447abbf218607e0f3 +F src/main.c 1a5cafdc1bee11f4322c837487bf6fa8e54b2f50 F src/malloc.c 92d59a007d7a42857d4e9454aa25b6b703286be1 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206 @@ -177,13 +177,13 @@ F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/select.c d24406c45dd2442eb2eeaac413439066b149c944 F src/shell.c 649c51979812f77f97507024a4cea480c6862b8b -F src/sqlite.h.in 3a8a9f25a45735879cec195a2c129b48e34ebf8e +F src/sqlite.h.in 992688609e9a0274b56c156d4800be96364b3590 F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754 -F src/sqliteInt.h 3a262a299fa5b1f6916157ec2302e8987e50bac9 +F src/sqliteInt.h 85e635183013e806069320ffa6080a77183f9225 F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44 F src/status.c 4997380fbb915426fef9e500b4872e79c99267fc F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e -F src/tclsqlite.c 20a3bf120f3bba1914f0e5132dbe937dee135f36 +F src/tclsqlite.c 64aeb4109ee2b38fd820b8e8de45b02377fcddc0 F src/test1.c 9020310c7617234b33fd1c3064f89524db25f290 F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31 F src/test3.c 056093cfef69ff4227a6bdb9108564dc7f45e4bc @@ -229,11 +229,11 @@ F src/update.c 1b9a82ede7df15e76ed86c6a3cbe4ce0f21eaa9b F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685 F src/util.c ab1c92426494f499f42b9e307537b03e923d75c1 F src/vacuum.c 924bd1bcee2dfb05376f79845bd3b4cec7b54b2f -F src/vdbe.c 4330cc94597b9c95853c5e8ff87776f1e6ceaa3f +F src/vdbe.c 2c523bc17f915329f3db3745fc76ed9bfc5c26bb F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2 F src/vdbeInt.h 41b8e337332f279228196039ab86acd353ad0c6c -F src/vdbeapi.c c407f3f0e21d5de68b1269bfa12315ef7ed6e3fd -F src/vdbeaux.c 874e16966eb6e58183ee2746abb4e4c5238f2350 +F src/vdbeapi.c ea741433042d95c392b29397ac6c2b08f6106317 +F src/vdbeaux.c cc817d8597307a2be361c24f3b436a7e41fa67dc F src/vdbeblob.c 18955f0ee6b133cd08e1592010cb9a6b11e9984c F src/vdbemem.c 0fa2ed786cd207d5b988afef3562a8e663a75b50 F src/vdbetrace.c 3ba13bc32bdf16d2bdea523245fd16736bed67b5 @@ -471,7 +471,7 @@ F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167 F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5 F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b F test/fuzz_malloc.test dd7001ac86d09c154a7dff064f4739c60e2b312c -F test/hook.test 5fd01c30f47896d88bed8a09bf7773cff218e8ff +F test/hook.test a90748e44c7ca53da46f857616fc7ce18bf7be13 F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4 F test/in.test 19b642bb134308980a92249750ea4ce3f6c75c2d F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75 @@ -667,7 +667,7 @@ F test/superlock.test 5d7a4954b0059c903f82c7b67867bc5451a7c082 F test/sync.test ded6b39d8d8ca3c0c5518516c6371b3316d3e3a3 F test/table.test 04ba066432430657712d167ebf28080fe878d305 F test/tableapi.test 7262a8cbaa9965d429f1cbd2747edc185fa56516 -F test/tclsqlite.test 1ce9b6340d6d412420634e129a2e3722c651056a +F test/tclsqlite.test 550f2268281d186b767b3ee14dd0be5f9e3ff25d F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05 @@ -909,10 +909,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 4e50b0362ab6604a4b6c9f4ad849ec1733d6ce1a -R 0e3c3fa7441b432fef74ccddd445caf6 -T *branch * experimental -T *sym-experimental * -T -sym-trunk * +P 6145d7b89f83500318713779c60f79a7ab2098ba +R 2617e052d0e8716cc0b428f99022eddb U dan -Z 1b63beda3df1a2343540c0064b366df4 +Z 24e44e929785c6b1d1f35eb2447fe0e7 diff --git a/manifest.uuid b/manifest.uuid index c59fca196c..e0c1dabe5a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6145d7b89f83500318713779c60f79a7ab2098ba \ No newline at end of file +093d8cd8e2f3a6af5d40cf810e396f4919eb5cef \ No newline at end of file diff --git a/src/main.c b/src/main.c index 3976f7ebc3..a8ac80039e 100644 --- a/src/main.c +++ b/src/main.c @@ -764,6 +764,26 @@ int sqlite3_close(sqlite3 *db){ return SQLITE_OK; } + +/* +** Invoke the transaction-hook. +*/ +void sqlite3TransactionHook(sqlite3 *db, int op, int iLevel){ + assert( op==SQLITE_BEGIN || op==SQLITE_COMMIT || op==SQLITE_ROLLBACK ); + assert( op==SQLITE_BEGIN || iLeveliOpenTrans || iLevel==0 ); + assert( op==SQLITE_BEGIN || iLeveliOpenTrans || db->iOpenTrans==0 ); + assert( op!=SQLITE_BEGIN || iLevel==db->iOpenTrans || iLevel==0 ); + assert( op!=SQLITE_BEGIN || iLevel==db->iOpenTrans || db->iOpenTrans==1 ); + + if( op==SQLITE_BEGIN && iLevel!=db->iOpenTrans ) return; + if( op!=SQLITE_BEGIN && iLevel>=db->iOpenTrans ) return; + + if( db->xTransCallback ){ + db->xTransCallback(db->pTransArg, op, iLevel); + } + db->iOpenTrans = iLevel + (op==SQLITE_BEGIN); +} + /* ** Rollback all database files. */ @@ -796,6 +816,10 @@ void sqlite3RollbackAll(sqlite3 *db){ if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ db->xRollbackCallback(db->pRollbackArg); } + + /* If a transaction-hook is configured, invoke it now to report on + ** the rollback operation. */ + sqlite3TransactionHook(db, SQLITE_ROLLBACK, 0); } /* @@ -1290,6 +1314,24 @@ void *sqlite3_preupdate_hook( return pRet; } +/* +** Register a callback to be invoked each time a transaction or savepoint +** is opened, committed or rolled back. +*/ +void *sqlite3_transaction_hook( + sqlite3 *db, /* Database handle */ + void(*xCallback)(void *, int, int), /* Callback function */ + void *pArg /* First callback argument */ +){ + void *pRet; + sqlite3_mutex_enter(db->mutex); + pRet = db->pTransArg; + db->xTransCallback = xCallback; + db->pTransArg = pArg; + sqlite3_mutex_leave(db->mutex); + return pRet; +} + #ifndef SQLITE_OMIT_WAL /* ** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint(). diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 413031ecfa..137be57b89 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6344,7 +6344,15 @@ int sqlite3_wal_checkpoint_v2( #define SQLITE_CHECKPOINT_FULL 1 #define SQLITE_CHECKPOINT_RESTART 2 -void *sqlite3_preupdate_hook( + +/* +** CAPI3REF: The pre-update hook. +** +** The preupdate_old() API may only be used from within an SQLITE_UPDATE or +** SQLITE_DELETE pre-update callback. The preupdate_modified() API may only +** be used from within an SQLITE_UPDATE pre-update callback. +*/ +SQLITE_EXPERIMENTAL void *sqlite3_preupdate_hook( sqlite3 *db, void(*xPreUpdate)( void *pCtx, /* Copy of third arg to preupdate_hook() */ @@ -6357,16 +6365,19 @@ void *sqlite3_preupdate_hook( ), void* ); +SQLITE_EXPERIMENTAL int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **); +SQLITE_EXPERIMENTAL int sqlite3_preupdate_modified(sqlite3 *, int, int *); +SQLITE_EXPERIMENTAL int sqlite3_preupdate_count(sqlite3 *); /* -** The following APIs may only be used from within a pre-update callback. More -** specifically, the preupdate_old() API may only be used from within an -** SQLITE_UPDATE or SQLITE_DELETE pre-update callback. The preupdate_modified() -** API may only be used from within an SQLITE_UPDATE pre-update callback. +** CAPI3REF: The transaction hook. */ -int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **); -int sqlite3_preupdate_modified(sqlite3 *, int, int *); -int sqlite3_preupdate_count(sqlite3 *); +SQLITE_EXPERIMENTAL +void *sqlite3_transaction_hook(sqlite3 *, void(*)(void *, int, int), void *); + +#define SQLITE_BEGIN 1 +#define SQLITE_COMMIT 2 +#define SQLITE_ROLLBACK 3 /* diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 2541936848..1414fb68b5 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -833,6 +833,9 @@ struct sqlite3 { void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64 ); PreUpdate *pPreUpdate; /* Context for active pre-update callback */ + void *pTransArg; /* First argument to xTransCallback */ + void (*xTransCallback)(void*,int,int); + int iOpenTrans; /* Open transaction (xTransCallback) plus 1 */ #ifndef SQLITE_OMIT_WAL int (*xWalCallback)(void *, sqlite3 *, const char *, int); void *pWalArg; @@ -2748,6 +2751,7 @@ void sqlite3PrngSaveState(void); void sqlite3PrngRestoreState(void); void sqlite3PrngResetState(void); void sqlite3RollbackAll(sqlite3*); +void sqlite3TransactionHook(sqlite3 *, int, int); void sqlite3CodeVerifySchema(Parse*, int); void sqlite3BeginTransaction(Parse*, int); void sqlite3CommitTransaction(Parse*); diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 91c6094fa9..c7e6fda068 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -124,6 +124,7 @@ struct SqliteDb { Tcl_Obj *pUpdateHook; /* Update hook script (if any) */ Tcl_Obj *pPreUpdateHook; /* Pre-update hook script (if any) */ Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */ + Tcl_Obj *pTransHook; /* Transaction hook script (if any) */ Tcl_Obj *pWalHook; /* WAL hook script (if any) */ Tcl_Obj *pUnlockNotify; /* Unlock notify script (if any) */ SqlCollate *pCollate; /* List of SQL collation functions */ @@ -597,6 +598,30 @@ static void DbRollbackHandler(void *clientData){ } } +/* +** sqlite3_transaction_hook() callback. +*/ +static void DbTransHandler(void *clientData, int op, int iLevel){ + static const char *azStr[] = { "BEGIN", "COMMIT", "ROLLBACK" }; + SqliteDb *pDb = (SqliteDb*)clientData; + Tcl_Interp *interp = pDb->interp; + Tcl_Obj *pScript; + + assert(pDb->pTransHook); + assert( SQLITE_BEGIN==1 ); + assert( SQLITE_COMMIT==2 ); + assert( SQLITE_ROLLBACK==3 ); + + pScript = Tcl_DuplicateObj(pDb->pTransHook); + Tcl_IncrRefCount(pScript); + Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(azStr[op-1], -1)); + Tcl_ListObjAppendElement(interp, pScript, Tcl_NewIntObj(iLevel)); + if( TCL_OK!=Tcl_EvalObjEx(interp, pScript, 0) ){ + Tcl_BackgroundError(interp); + } + Tcl_DecrRefCount(pScript); +} + /* ** This procedure handles wal_hook callbacks. */ @@ -1628,6 +1653,7 @@ static void DbHookCmd( sqlite3_update_hook(db, (pDb->pUpdateHook?DbUpdateHandler:0), pDb); sqlite3_rollback_hook(db, (pDb->pRollbackHook?DbRollbackHandler:0), pDb); sqlite3_wal_hook(db, (pDb->pWalHook?DbWalHandler:0), pDb); + sqlite3_transaction_hook(db, (pDb->pTransHook?DbTransHandler:0), pDb); } /* @@ -1659,7 +1685,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ "profile", "progress", "rekey", "restore", "rollback_hook", "status", "timeout", "total_changes", "trace", - "transaction", "unlock_notify", "update_hook", + "transaction", "transaction_hook", + "unlock_notify", "update_hook", "version", "wal_hook", 0 }; enum DB_enum { @@ -1674,7 +1701,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ DB_PROFILE, DB_PROGRESS, DB_REKEY, DB_RESTORE, DB_ROLLBACK_HOOK, DB_STATUS, DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE, - DB_TRANSACTION, DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK, + DB_TRANSACTION, DB_TRANSACTION_HOOK, + 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 */ @@ -2914,10 +2942,12 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ ** $db wal_hook ?script? ** $db update_hook ?script? ** $db rollback_hook ?script? + ** $db transaction_hook ?script? */ case DB_WAL_HOOK: case DB_UPDATE_HOOK: - case DB_ROLLBACK_HOOK: { + case DB_ROLLBACK_HOOK: + case DB_TRANSACTION_HOOK: { sqlite3 *db = pDb->db; /* set ppHook to point at pUpdateHook or pRollbackHook, depending on @@ -2927,6 +2957,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ if( choice==DB_WAL_HOOK ) ppHook = &pDb->pWalHook; if( choice==DB_UPDATE_HOOK ) ppHook = &pDb->pUpdateHook; if( choice==DB_ROLLBACK_HOOK ) ppHook = &pDb->pRollbackHook; + if( choice==DB_TRANSACTION_HOOK ) ppHook = &pDb->pTransHook; if( objc>3 ){ Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?"); return TCL_ERROR; diff --git a/src/vdbe.c b/src/vdbe.c index c5492eedc8..252c53cb63 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2568,6 +2568,8 @@ case OP_Savepoint: { }else{ db->nSavepoint++; } + + sqlite3TransactionHook(db, SQLITE_BEGIN, db->nSavepoint); /* Link the new savepoint into the database handle's list. */ pNew->pNext = db->pSavepoint; @@ -2635,6 +2637,13 @@ case OP_Savepoint: { sqlite3ResetInternalSchema(db, 0); db->flags = (db->flags | SQLITE_InternChanges); } + + assert( SAVEPOINT_ROLLBACK+1==SQLITE_ROLLBACK ); + assert( SAVEPOINT_RELEASE+1==SQLITE_COMMIT ); + sqlite3TransactionHook(db, p1+1, iSavepoint+1); + if( p1==SAVEPOINT_ROLLBACK ){ + sqlite3TransactionHook(db, SQLITE_BEGIN, iSavepoint+1); + } } /* Regardless of whether this is a RELEASE or ROLLBACK, destroy all @@ -2710,6 +2719,9 @@ case OP_AutoCommit: { }else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){ goto vdbe_return; }else{ + if( desiredAutoCommit==0 ){ + sqlite3TransactionHook(db, SQLITE_BEGIN, 0); + } db->autoCommit = (u8)desiredAutoCommit; if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ p->pc = pc; @@ -2796,6 +2808,7 @@ case OP_Transaction: { p->iStatement = db->nSavepoint + db->nStatement; } rc = sqlite3BtreeBeginStmt(pBt, p->iStatement); + sqlite3TransactionHook(db, SQLITE_BEGIN, p->iStatement); /* Store the current value of the database handles deferred constraint ** counter. If the statement transaction needs to be rolled back, diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 8b1f2e21bb..cefca02a24 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -401,7 +401,15 @@ static int sqlite3Step(Vdbe *p){ #endif db->activeVdbeCnt++; - if( p->readOnly==0 ) db->writeVdbeCnt++; + if( p->readOnly==0 ){ + /* If this statement will open an implicit transaction, invoke the + ** transaction-hook here. */ + if( db->autoCommit && db->writeVdbeCnt==0 ){ + assert( db->nSavepoint==0 ); + sqlite3TransactionHook(db, SQLITE_BEGIN, 0); + } + db->writeVdbeCnt++; + } p->pc = 0; } #ifndef SQLITE_OMIT_EXPLAIN diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 31cf669144..937c2a1998 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1845,6 +1845,12 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ } #endif + /* If a transaction-hook is configured, invoke it now to report on the + ** successful commit operation. */ + if( rc==SQLITE_OK ){ + sqlite3TransactionHook(db, SQLITE_COMMIT, 0); + } + return rc; } @@ -1946,6 +1952,9 @@ int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){ } } db->nStatement--; + assert( SAVEPOINT_ROLLBACK+1==SQLITE_ROLLBACK ); + assert( SAVEPOINT_RELEASE+1==SQLITE_COMMIT ); + sqlite3TransactionHook(db, eOp+1, p->iStatement); p->iStatement = 0; /* If the statement transaction is being rolled back, also restore the diff --git a/test/hook.test b/test/hook.test index 827ce08b3d..b2e0988828 100644 --- a/test/hook.test +++ b/test/hook.test @@ -616,16 +616,151 @@ do_execsql_test 7.5.2.0 { ALTER TABLE t8 ADD COLUMN c DEFAULT 'xxx'; } +# At time of writing, these two are broken. They demonstraight that the +# sqlite3_preupdate_old() method does not handle the case where ALTER TABLE +# has been used to add a column with a default value other than NULL. +# do_preupdate_test 7.5.2.1 { DELETE FROM t8 WHERE a = 'one' } { DELETE main t8 1 1 one two xxx } - do_preupdate_test 7.5.2.2 { UPDATE t8 SET b = 'five' } { UPDATE main t8 2 2 three four xxx } +#---------------------------------------------------------------------------- +# The following tests - hook-8.* - test the transaction hook. +# +db close +forcedelete test.db +sqlite3 db test.db + +proc transaction_hook {op iLevel} { + lappend ::transaction_hook $op $iLevel +} +db transaction_hook transaction_hook + +proc do_transaction_test {tn sql x} { + set X [list] + foreach elem $x {lappend X $elem} + + uplevel do_test $tn [list " + set ::transaction_hook \[list\] + catchsql { $sql } + set ::transaction_hook + "] [list $X] +} + +do_transaction_test 8.1.1 "CREATE TABLE t1(x)" {BEGIN 0 COMMIT 0} +do_transaction_test 8.1.2 "BEGIN" {BEGIN 0} +do_transaction_test 8.1.3 "COMMIT" {COMMIT 0} +do_transaction_test 8.1.4 "BEGIN ; ROLLBACK" {BEGIN 0 ROLLBACK 0} + +do_execsql_test 8.2.0 { + CREATE TABLE t2(a PRIMARY KEY, b); + INSERT INTO t2 VALUES(1, 'one'); + INSERT INTO t2 VALUES(2, 'two'); + INSERT INTO t2 VALUES(3, 'three'); +} +do_transaction_test 8.2.1 { + INSERT INTO t2 VALUES(2, 'xxx') +} {BEGIN 0 ROLLBACK 0} + +do_transaction_test 8.2.2 { + BEGIN; INSERT INTO t2 SELECT a-2, b FROM t2; +} {BEGIN 0 BEGIN 1 ROLLBACK 1} + +do_transaction_test 8.2.3 { + INSERT OR ROLLBACK INTO t2 SELECT a-2, b FROM t2; +} {ROLLBACK 0} + +do_transaction_test 8.2.4 { + BEGIN; INSERT INTO t2 SELECT a+3, b FROM t2; +} {BEGIN 0 BEGIN 1 COMMIT 1} + +do_transaction_test 8.2.5 "COMMIT" {COMMIT 0} + +do_transaction_test 8.3.1 {SELECT * FROM t2} {} + +do_transaction_test 8.4.1 { + SAVEPOINT top; + RELEASE top; +} {BEGIN 0 COMMIT 0} + +do_transaction_test 8.4.2 { + SAVEPOINT top; + ROLLBACK TO top; + RELEASE top; +} {BEGIN 0 ROLLBACK 0 BEGIN 0 COMMIT 0} + +do_transaction_test 8.4.3 { + SAVEPOINT zero; + SAVEPOINT one; + SAVEPOINT two; + SAVEPOINT three; + ROLLBACK TO zero; + SAVEPOINT one; + SAVEPOINT two; + SAVEPOINT three; + ROLLBACK TO one; + SAVEPOINT two; + RELEASE zero; + + SAVEPOINT zero; + SAVEPOINT one; + SAVEPOINT two; + RELEASE two; + SAVEPOINT two; + SAVEPOINT three; + RELEASE one; + ROLLBACK TO zero; + RELEASE zero; +} { + BEGIN 0 BEGIN 1 BEGIN 2 BEGIN 3 ROLLBACK 0 BEGIN 0 + BEGIN 1 BEGIN 2 BEGIN 3 ROLLBACK 1 BEGIN 1 BEGIN 2 + COMMIT 0 + + BEGIN 0 BEGIN 1 BEGIN 2 COMMIT 2 BEGIN 2 BEGIN 3 COMMIT 1 + ROLLBACK 0 BEGIN 0 COMMIT 0 +} + +do_transaction_test 8.4.4 { + BEGIN; + SAVEPOINT zero; + SAVEPOINT one; + SAVEPOINT two; + SAVEPOINT three; + ROLLBACK TO zero; + SAVEPOINT one; + SAVEPOINT two; + SAVEPOINT three; + ROLLBACK TO one; + SAVEPOINT two; + RELEASE zero; + + SAVEPOINT zero; + SAVEPOINT one; + SAVEPOINT two; + RELEASE two; + SAVEPOINT two; + SAVEPOINT three; + RELEASE one; + ROLLBACK TO zero; + RELEASE zero; + COMMIT; +} { + BEGIN 0 + BEGIN 1 BEGIN 2 BEGIN 3 BEGIN 4 ROLLBACK 1 BEGIN 1 + BEGIN 2 BEGIN 3 BEGIN 4 ROLLBACK 2 BEGIN 2 BEGIN 3 + COMMIT 1 + + BEGIN 1 BEGIN 2 BEGIN 3 COMMIT 3 BEGIN 3 BEGIN 4 COMMIT 2 + ROLLBACK 1 BEGIN 1 COMMIT 1 + COMMIT 0 +} + finish_test + diff --git a/test/tclsqlite.test b/test/tclsqlite.test index c9d562beb5..efc3e53ab6 100644 --- a/test/tclsqlite.test +++ b/test/tclsqlite.test @@ -35,7 +35,7 @@ do_test tcl-1.1 { do_test tcl-1.2 { set v [catch {db bogus} msg] lappend v $msg -} {1 {bad option "bogus": must be 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, transaction, unlock_notify, update_hook, version, or wal_hook}} +} {1 {bad option "bogus": must be 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, transaction, transaction_hook, unlock_notify, update_hook, version, or wal_hook}} do_test tcl-1.2.1 { set v [catch {db cache bogus} msg] lappend v $msg