]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the sqlite3_rollback_hook() API. Still requires further testing. (CVS 2823)
authordanielk1977 <danielk1977@noemail.net>
Fri, 16 Dec 2005 06:54:01 +0000 (06:54 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Fri, 16 Dec 2005 06:54:01 +0000 (06:54 +0000)
FossilOrigin-Name: 3baa3ff32435b64e7ae7646b17a98fef9296aaa0

main.mk
manifest
manifest.uuid
src/btree.c
src/main.c
src/sqlite.h.in
src/sqliteInt.h
src/tclsqlite.c
src/vdbeaux.c
test/hook.test
test/tclsqlite.test

diff --git a/main.mk b/main.mk
index 32ccb77ca2cf0d7b7fb0727073571d6199ea0b32..ff6b843b25a719250d3d2cd8fd24283920f5229b 100644 (file)
--- a/main.mk
+++ b/main.mk
@@ -133,13 +133,14 @@ TESTSRC = \
   $(TOP)/src/test4.c \
   $(TOP)/src/test5.c \
   $(TOP)/src/test6.c \
-  $(TOP)/src/test_async.c \
   $(TOP)/src/utf.c \
   $(TOP)/src/util.c \
   $(TOP)/src/vdbe.c \
   $(TOP)/src/md5.c \
   $(TOP)/src/where.c
 
+#  $(TOP)/src/test_async.c 
+
 # Header files used by all library source files.
 #
 HDR = \
index fa524f5373b9d10a1f15d87a8451370726122bc0..01a4d601e607e5034c468cd61f49e2fec57030d7 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Initial\sinfrastructure\sfor\srecognizing\sDESC\sindices\sand\sbeing\sable\sto\sread\r\nand\swrite\solder\sdatabases\sthat\sspecify\sDESC\sindices\sbut\sdo\snot\sreally\suse\r\nthem.\s\sNothing\sis\sclose\sto\sworking\syet.\s(CVS\s2822)
-D 2005-12-16T01:06:17
+C Add\sthe\ssqlite3_rollback_hook()\sAPI.\sStill\srequires\sfurther\stesting.\s(CVS\s2823)
+D 2005-12-16T06:54:02
 F Makefile.in e3c6b3a38d734d41574c04f2fc90d18de2b87102
 F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -19,7 +19,7 @@ F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538
 F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac
 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
 F ltmain.sh f6b283068efa69f06eb8aa1fe4bddfdbdeb35826
-F main.mk 1376cec5c19b087d00d679527cfab9fa6598c2c3
+F main.mk c5c5087f957210233fd6ecb5e7c161c2c90038b9
 F mkdll.sh 5ec23622515d5bf8969404e80cfb5e220ddf0512
 F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d
 F mkopcodeh.awk 071dbba4eaf56c8d643baf4604a043af35683316
@@ -34,7 +34,7 @@ F src/alter.c 7bc737c689044fa00ff2f445139c61f5c9ee0ad8
 F src/analyze.c ea42005eed52c382fcc7ef66969e7f1858597633
 F src/attach.c ee70131f128d31a9c6dcb8824e8471c91b18601a
 F src/auth.c 31e2304bef67f44d635655f44234387ea7d21454
-F src/btree.c de0fc1a0f6a4631001ffb6070d1b7588cdebcbc5
+F src/btree.c f880db4dc6339e279e982a342cbd1ff7c1f0d388
 F src/btree.h 1ed561263ca0e335bc3e81d761c9d5ff8c22f61e
 F src/build.c 178a5c36365b5ec89a4a29a74186583f503c10fa
 F src/callback.c 62066afd516f220575e81b1a1239ab92a2eae252
@@ -48,7 +48,7 @@ F src/hash.c 8747cf51d12de46512880dfcf1b68b4e24072863
 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
 F src/insert.c a5629e462560d6aa9be7e0dafb6ed1518bb623bb
 F src/legacy.c 59757d857ab95fcbb0ac27692d3201e35f093dd7
-F src/main.c 066356cdc7f7fbef389c1849b1ccbeec96a5b348
+F src/main.c cbab4a1b056eddf03f671f0e9d76f69f48e6bff2
 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217
 F src/os.c 7b4a002d9c9421580276db55d2329636a604e8ef
 F src/os.h e941992043b127fdb1bd114f0b4319ae1c4562a7
@@ -68,10 +68,10 @@ F src/printf.c f47a2f4b5387cd2ebb12e9117a1a5d6bd9a2b812
 F src/random.c ff5e9a8cad790e2a51cd4d2e7737dc8540e09d1d
 F src/select.c 2292b065bc6be61e01aad39a2e1b93e332fb7e57
 F src/shell.c 4872acee1d2a826c73c914961e469e563204b7f9
-F src/sqlite.h.in 31ab5ef5268c7f1ee909151a0fc45c659290ec15
-F src/sqliteInt.h 853a868ee69e841b9eba078f359932cddd3cf264
+F src/sqlite.h.in 6b9ec2fee44d5a2da19e72f2890f802a9efe8e7c
+F src/sqliteInt.h e6063bc65e02682ee923f795b74afa85d9823f9a
 F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316
-F src/tclsqlite.c c2303e1b1e6602b8cfef4dad00e4d76a47868c5e
+F src/tclsqlite.c b21dd96ffab1625c986513e003a1945a6ae112ae
 F src/test1.c d6924b182773b2ad3b22e435e4d3bfd5a846da9e
 F src/test2.c 36390cdfc70c08e5ee0b466d0654a117f398bbff
 F src/test3.c 7c97833e33496c2b69f4fe6b9882ac60a481da97
@@ -88,7 +88,7 @@ F src/vdbe.c a9acffc91d3e06af24dc1dcf5bf7d5e77460b1c5
 F src/vdbe.h 8729a4ee16ff9aeab2af9667df3cf300ff978e13
 F src/vdbeInt.h 7b8b8c5dcb203243e4a9a4414c9e488473f67741
 F src/vdbeapi.c b270b680cbc5d20b5a1abfdb08339667985df94e
-F src/vdbeaux.c 722736cd433f06942bc5c7b7915e6561be0b400c
+F src/vdbeaux.c c878807fd0f5829c9a02fa069db2ec69692b0ff6
 F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5
 F src/vdbemem.c deba8d6e3727643924b210a8c531a496c2b8d386
 F src/where.c 269569f380ddc018518f67765fe2f0d3c8760e28
@@ -153,7 +153,7 @@ F test/enc3.test f6a5f0b7b7f3a88f030d3143729b87cd5c86d837
 F test/expr.test 06381174d8c25fbbfd9ed335fe0cde835d39123d
 F test/fkey1.test 153004438d51e6769fb1ce165f6313972d6263ce
 F test/func.test e891bebf5a939fd45c9453ad35e2280f41a30687
-F test/hook.test 4a5e598af0dd2436f757706e1650be3e4bbe30a6
+F test/hook.test 2b771652ae4f27e95fc3e6992c618af7954ce785
 F test/in.test cead6165aebbe0d451bb2263a307173acfeb6240
 F test/index.test 3871c47ec475f779f0b99dc36a3d177951995712
 F test/index2.test 9ad98243fd7fe833795a9cc662f371f0eed4ff4f
@@ -221,7 +221,7 @@ F test/subselect.test 2d13fb7f450db3595adcdd24079a0dd1d2d6abc2
 F test/sync.test 6e8b885cec5ccba2090e92c90f747a7142f53c88
 F test/table.test ec0e6c2186bb8f6824f470caa118524dfd8fe057
 F test/tableapi.test 6a66d58b37d46dc0f2b3c7d4bd2617d209399bd1
-F test/tclsqlite.test 9890d58c6c2a72b6a57daf88e2e7aa9c4a141213
+F test/tclsqlite.test 26ee144ca70738ee0f3d8b5c1113b2f13652658b
 F test/temptable.test 7927261befdbc7b0a7ffebb85ecc70a74fa7b15b
 F test/tester.tcl a06c798a653daefb5bce2c85fc3a7d06450a1875
 F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35
@@ -327,7 +327,7 @@ F www/tclsqlite.tcl ddcf912ea48695603c8ed7efb29f0812ef8d1b49
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
 F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P 4fba2db38e0693be52ca7251e4958bd836607f05
-R cf0e0e36b0268dddfac27efc891f1d3b
-U drh
-Z e31baf15a60fd5885441bd2ca28e4cd9
+P cd110aa225b09591064405dd8952b3df37278c52
+R 3161ff073c4e4c2688e57ee8d03a85ab
+U danielk1977
+Z 7173f459f67aead630a0b046899d180b
index cc851b73f41ac4d72e33766ba246e94c965ba593..d22ff498431514a5833b92ad49b0d35ada4182fb 100644 (file)
@@ -1 +1 @@
-cd110aa225b09591064405dd8952b3df37278c52
\ No newline at end of file
+3baa3ff32435b64e7ae7646b17a98fef9296aaa0
\ No newline at end of file
index ba5e6c492654ff445850f96667f113ea0e3e05ea..65b5594dd64b5efe4ebfd5e16d9e7c569451b44e 100644 (file)
@@ -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;
 }
 
index 8bc6bb885b1ed3f51f4938ce47e9011e42022b76..ba0bb5feb3dc1527b31447d3d9aa110e59499e7c 100644 (file)
@@ -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
index 86d75d26d0772f33f2da616134ae121c58a2433c..966b38a206de50e957843cee6ce6d4f8aa010b79 100644 (file)
@@ -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.
index 0285677f8768b87d15ad96b7354018436385fa20..11624cab9d1d73154c270a8b11a7541e8078a98c 100644 (file)
@@ -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*);
index b862df3f0a3b32e9f4d7bc9e8d6df88531af3ea3..337cdefb47ffecd58682ac404cbc5388c47a092a 100644 (file)
@@ -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);
index 6949f8c35cc08f2c222f3f312fc61cf8a07cd080..a99dc464342115cccc703d1d62f3a121968ba4de 100644 (file)
@@ -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;
+      }
     }
   }
 
index 7060366bdec2c795bbef2d166057e08ae3413306..dcffd7053ccf04f405be36e9a45f11f578a52602 100644 (file)
 #
 # The focus of the tests in this file is the  following interface:
 #
-#      sqlite_commit_hook
-#      sqlite_update_hook (tests hook-4 onwards)
+#      sqlite_commit_hook    (tests hook-1..hook-3 inclusive)
+#      sqlite_update_hook    (tests hook-4-*)
+#      sqlite_rollback_hook  (tests hook-5.*)
 #
-# $Id: hook.test,v 1.6 2005/12/15 15:22:10 danielk1977 Exp $
+# $Id: hook.test,v 1.7 2005/12/16 06:54:03 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -91,11 +92,22 @@ do_test hook-3.9 {
   set ::commit_cnt
 } {}
 
-# Very simple tests. Test that the update hook is invoked correctly for INSERT,
-# DELETE and UPDATE statements, including DELETE statements with no WHERE
-# clause.
+#----------------------------------------------------------------------------
+# Tests for the update-hook.
 #
-do_test hook-4.1 {
+# 4.1.* - Very simple tests. Test that the update hook is invoked correctly 
+#         for INSERT, DELETE and UPDATE statements, including DELETE 
+#         statements with no WHERE clause.
+# 4.2.* - Check that the update-hook is invoked for rows modified by trigger
+#         bodies. Also that the database name is correctly reported when 
+#         an attached database is modified.
+# 4.3.* - Do some sorting, grouping, compound queries, population and 
+#         depopulation of indices, to make sure the update-hook is not 
+#         invoked incorrectly.
+#
+
+# Simple tests
+do_test hook-4.1.1 {
   catchsql {
     DROP TABLE t1;
   }
@@ -107,7 +119,7 @@ do_test hook-4.1 {
   }
   db update_hook [list lappend ::update_hook]
 } {}
-do_test hook-4.2 {
+do_test hook-4.1.2 {
   execsql {
     INSERT INTO t1 VALUES(4, 'four');
     DELETE FROM t1 WHERE b = 'two';
@@ -125,11 +137,8 @@ do_test hook-4.2 {
     DELETE main t1 4 \
 ]
 
-# Check that the update-hook is invoked for rows modified by trigger
-# bodies.
-#
 set ::update_hook {}
-do_test hook-5.1 {
+do_test hook-4.2.1 {
   catchsql {
     DROP TABLE t2;
   }
@@ -142,7 +151,7 @@ do_test hook-5.1 {
     END;
   }
 } {}
-do_test hook-5.2 {
+do_test hook-4.2.2 {
   execsql {
     INSERT INTO t1 VALUES(1, 'one');
     INSERT INTO t1 VALUES(2, 'two');
@@ -159,8 +168,9 @@ do_test hook-5.2 {
     DELETE main t2 2 \
 ]
 
+# Triggers + ATTACH
 set ::update_hook {}
-do_test hook-6.1 {
+do_test hook-4.2.3 {
   file delete -force test2.db
   execsql {
     ATTACH 'test2.db' AS aux;
@@ -178,11 +188,10 @@ do_test hook-6.1 {
     DELETE aux t3 2 \
 ]
 
-# Do some sorting, grouping, compound queries, population and depopulation 
-# of indices, to make sure the update-hook is not invoked incorrectly.
-#
+# Test that other vdbe operations involving btree structures do not 
+# incorrectly invoke the update-hook.
 set ::update_hook {}
-do_test hook-7.1 {
+do_test hook-4.3.1 {
   execsql {
     DROP TRIGGER t1_trigger;
     CREATE INDEX t1_i ON t1(b);
@@ -200,7 +209,7 @@ do_test hook-7.1 {
     DELETE main t1 3 \
 ]
 set ::update_hook {}
-do_test hook-7.2 {
+do_test hook-4.3.2 {
   execsql {
     SELECT * FROM t1 UNION SELECT * FROM t3;
     SELECT * FROM t1 UNION ALL SELECT * FROM t3;
@@ -211,6 +220,58 @@ do_test hook-7.2 {
   }
   set ::update_hook
 } [list]
+db update_hook {}
+#
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Test the rollback-hook. The rollback-hook is a bit more complicated than
+# either the commit or update hooks because a rollback can happen 
+# explicitly (an sql ROLLBACK statement) or implicitly (a constraint or 
+# error condition).
+#
+# hook-5.1.* - Test explicit rollbacks.
+# hook-5.2.* - Test implicit rollbacks.
+# hook-5.3.* - Test hot-journal rollbacks.
+#
+
+do_test hook-5.0 {
+  # Configure the rollback hook to increment global variable 
+  # $::rollback_hook each time it is invoked.
+  set ::rollback_hook 0
+  db rollback_hook [list incr ::rollback_hook]
+} {}
+
+# Test explicit rollbacks. Not much can really go wrong here.
+do_test hook-5.1.1 {
+  set ::rollback_hook 0
+  execsql {
+    BEGIN;
+    ROLLBACK;
+  }
+  set ::rollback_hook
+} {1}
+
+# Test implicit rollbacks caused by constraints.
+do_test hook-5.2.1 {
+  set ::rollback_hook 0
+  catchsql {
+    DROP TABLE t1;
+    CREATE TABLE t1(a PRIMARY KEY, b);
+    INSERT INTO t1 VALUES('one', 'I');
+    INSERT INTO t1 VALUES('one', 'I');
+  }
+  set ::rollback_hook
+} {1}
+do_test hook-5.2.2 {
+  # Check that the INSERT transaction above really was rolled back.
+  execsql {
+    SELECT count(*) FROM t1;
+  }
+} {1}
+
+#
+#----------------------------------------------------------------------------
 
 finish_test
 
index 083d42377f4acd1cf21c44467ffce9cfb2385ba9..239fcbbd594a878152ad1ea5269d941c5341da37 100644 (file)
@@ -15,7 +15,7 @@
 # interface is pretty well tested.  This file contains some addition
 # tests for fringe issues that the main test suite does not cover.
 #
-# $Id: tclsqlite.test,v 1.46 2005/12/12 06:53:05 danielk1977 Exp $
+# $Id: tclsqlite.test,v 1.47 2005/12/16 06:54:03 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -34,7 +34,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, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, copy, errorcode, eval, exists, function, last_insert_rowid, nullvalue, onecolumn, profile, progress, rekey, soft_heap_limit, timeout, total_changes, trace, transaction, or version}}
+} {1 {bad option "bogus": must be authorizer, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, copy, errorcode, eval, exists, function, last_insert_rowid, nullvalue, onecolumn, profile, progress, rekey, rollback_hook, soft_heap_limit, timeout, total_changes, trace, transaction, update_hook, or version}}
 do_test tcl-1.3 {
   execsql {CREATE TABLE t1(a int, b int)}
   execsql {INSERT INTO t1 VALUES(10,20)}