Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add the sqlite3_update_hook() API. (CVS 2820) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
36229018817eebfbfca7a66d2285e4fa |
User & Date: | danielk1977 2005-12-15 15:22:09.000 |
Context
2005-12-15
| ||
22:34 | Fix the utf8 to utf16 conversion routine for short strings. Bug introduced by check-in (2817). (CVS 2821) (check-in: 4fba2db38e user: drh tags: trunk) | |
15:22 | Add the sqlite3_update_hook() API. (CVS 2820) (check-in: 3622901881 user: danielk1977 tags: trunk) | |
10:50 | Move malloc(), free(), realloc() and allocationSize() into the Os vtbl. (CVS 2819) (check-in: 81a41f6637 user: danielk1977 tags: trunk) | |
Changes
Changes to src/delete.c.
︙ | |||
8 9 10 11 12 13 14 | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | - + | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** |
︙ | |||
211 212 213 214 215 216 217 218 219 220 221 222 223 224 | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | + + + | addr = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0); sqlite3VdbeAddOp(v, OP_Next, iCur, addr); sqlite3VdbeResolveLabel(v, endOfLoop); sqlite3VdbeAddOp(v, OP_Close, iCur, 0); } if( !isView ){ sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb); if( !pParse->nested ){ sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC); } for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, pIdx->iDb); } } } /* The usual case: There is a WHERE clause so we have to scan through |
︙ | |||
376 377 378 379 380 381 382 383 384 385 386 387 388 389 | 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 | + + + | int iCur, /* Cursor number for the table */ int count /* Increment the row change counter */ ){ int addr; addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0); sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0); sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0)); if( count ){ sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC); } sqlite3VdbeJumpHere(v, addr); } /* ** This routine generates VDBE code that causes the deletion of all ** index entries associated with a single row of a single table. ** |
︙ |
Changes to src/insert.c.
︙ | |||
8 9 10 11 12 13 14 | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | - + | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** |
︙ | |||
1075 1076 1077 1078 1079 1080 1081 | 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 | - + + + + + | sqlite3VdbeAddOp(v, OP_Dup, 1, 0); sqlite3VdbeAddOp(v, OP_Insert, newIdx, 0); } #endif if( pParse->nested ){ pik_flags = 0; }else{ |
︙ |
Changes to src/main.c.
︙ | |||
10 11 12 13 14 15 16 | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | - + | ** ************************************************************************* ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** |
︙ | |||
543 544 545 546 547 548 549 550 551 552 553 554 555 556 | 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 | + + + + + + + + + + + + + | void *pArg /* Argument to the function */ ){ void *pOld = db->pCommitArg; db->xCommitCallback = xCallback; db->pCommitArg = pArg; return pOld; } /* ** Register a callback to be invoked each time a row is updated, ** inserted or deleted using this database connection. */ 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 */ ){ db->xUpdateCallback = xCallback; db->pUpdateArg = pArg; } /* ** This routine is called to create a connection to a database BTree ** driver. If zFilename is the name of a file, then that file is ** opened and used. If zFilename is the magic name ":memory:" then ** the database is stored in memory (and is thus forgotten as soon as |
︙ |
Changes to src/sqlite.h.in.
︙ | |||
8 9 10 11 12 13 14 | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | - + | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the SQLite library ** presents to client programs. ** |
︙ | |||
1287 1288 1289 1290 1291 1292 1293 | 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 | - - - + + + + + + + + + + + + + + + + + + + + + + + + | ** allocated anyway and the current operation proceeds. ** ** This function is only available if the library was compiled without the ** SQLITE_OMIT_SOFTHEAPLIMIT option set. */ void sqlite3_soft_heap_limit(int); |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | - + | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** |
︙ | |||
437 438 439 440 441 442 443 444 445 446 447 448 449 450 | 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 | + + | int activeVdbeCnt; /* Number of vdbes currently executing */ void (*xTrace)(void*,const char*); /* Trace function */ 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 *pUpdateArg; void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*); void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*); void *pCollNeededArg; sqlite3_value *pErr; /* Most recent error message */ char *zErrMsg; /* Most recent error message (UTF-8 encoded) */ char *zErrMsg16; /* Most recent error message (UTF-16 encoded) */ #ifndef SQLITE_OMIT_AUTHORIZATION |
︙ | |||
1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 | 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 | + | }; /* ** Bitfield flags for P2 value in OP_Insert and OP_Delete */ #define OPFLAG_NCHANGE 1 /* Set to update db->nChange */ #define OPFLAG_LASTROWID 2 /* Set to update db->lastRowid */ #define OPFLAG_ISUPDATE 4 /* This OP_Insert is an sql UPDATE */ /* * Each trigger present in the database schema is stored as an instance of * struct Trigger. * * Pointers to instances of struct Trigger are stored in two ways. * 1. In the "trigHash" hash table (part of the sqlite3* that represents the |
︙ |
Changes to src/tclsqlite.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | - + | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** A TCL Interface to SQLite ** |
︙ | |||
95 96 97 98 99 100 101 102 103 104 105 106 107 108 | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | + | char *zCommit; /* The commit hook callback routine */ char *zTrace; /* The trace callback routine */ char *zProfile; /* The profile callback routine */ char *zProgress; /* The progress callback routine */ char *zAuth; /* The authorization callback routine */ char *zNull; /* Text to substitute for an SQL NULL value */ SqlFunc *pFunc; /* List of SQL functions */ Tcl_Obj *pUpdateHook; /* Update 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 */ SqlPreparedStmt *stmtList; /* List of prepared statements*/ SqlPreparedStmt *stmtLast; /* Last statement in the list */ int maxStmt; /* The next maximum number of stmtList */ int nStmt; /* Number of statements in stmtList */ |
︙ | |||
206 207 208 209 210 211 212 213 214 215 216 217 218 219 | 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | + + + + + + | } if( pDb->zAuth ){ Tcl_Free(pDb->zAuth); } if( pDb->zNull ){ Tcl_Free(pDb->zNull); } if( pDb->pUpdateHook ){ Tcl_DecrRefCount(pDb->pUpdateHook); } if( pDb->pCollateNeeded ){ Tcl_DecrRefCount(pDb->pCollateNeeded); } Tcl_Free((char*)pDb); } /* ** This routine is called when a database file is locked while trying ** to execute SQL. */ |
︙ | |||
292 293 294 295 296 297 298 299 300 301 302 303 304 305 | 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | + + + + + + + + + + + + + + + + + + + + + + + | rc = Tcl_Eval(pDb->interp, pDb->zCommit); if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ return 1; } return 0; } static void DbUpdateHandler( void *p, int op, const char *zDb, const char *zTbl, sqlite_int64 rowid ){ SqliteDb *pDb = (SqliteDb *)p; Tcl_Obj *pCmd; assert( pDb->pUpdateHook ); assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE ); pCmd = Tcl_DuplicateObj(pDb->pUpdateHook); Tcl_IncrRefCount(pCmd); Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj( ( (op==SQLITE_INSERT)?"INSERT":(op==SQLITE_UPDATE)?"UPDATE":"DELETE"), -1)); Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zDb, -1)); Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zTbl, -1)); Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(rowid)); Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); } static void tclCollateNeeded( void *pCtx, sqlite3 *db, int enc, const char *zName ){ |
︙ | |||
621 622 623 624 625 626 627 | 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 | - + + - + | "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", |
︙ | |||
1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 | 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 | + + + + + + + + + + + + + + + + + + + + + + + + + + + | const char *zEnd; if( rc==TCL_ERROR ){ zEnd = "ROLLBACK"; } else { zEnd = "COMMIT"; } sqlite3_exec(pDb->db, zEnd, 0, 0, 0); } break; } /* ** $db update_hook ?script? */ case DB_UPDATE_HOOK: { if( objc!=2 && objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?"); return TCL_ERROR; } if( pDb->pUpdateHook ){ Tcl_SetObjResult(interp, pDb->pUpdateHook); if( objc==3 ){ Tcl_DecrRefCount(pDb->pUpdateHook); pDb->pUpdateHook = 0; } } if( objc==3 ){ 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); } } break; } /* $db version ** ** Return the version string for this database. |
︙ |
Changes to src/vdbe.c.
︙ | |||
39 40 41 42 43 44 45 | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | - + | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** |
︙ | |||
156 157 158 159 160 161 162 | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | - + + + + | *ppTos = pTos; } /* ** Allocate cursor number iCur. Return a pointer to it. Return NULL ** if we run out of memory. */ |
︙ | |||
2521 2522 2523 2524 2525 2526 2527 | 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 | - + | sqlite3VdbeMemIntegerify(pTos); p2 = pTos->i; assert( (pTos->flags & MEM_Dyn)==0 ); pTos--; assert( p2>=2 ); } assert( i>=0 ); |
︙ | |||
2599 2600 2601 2602 2603 2604 2605 | 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 | - + | ** if P3 is not 0. If P3 is not NULL, it points to a KeyInfo structure ** that defines the format of keys in the index. */ case OP_OpenVirtual: { /* no-push */ int i = pOp->p1; Cursor *pCx; assert( i>=0 ); |
︙ | |||
2651 2652 2653 2654 2655 2656 2657 | 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 | - + | ** A pseudo-table created by this opcode is useful for holding the ** NEW or OLD tables in a trigger. */ case OP_OpenPseudo: { /* no-push */ int i = pOp->p1; Cursor *pCx; assert( i>=0 ); |
︙ | |||
3190 3191 3192 3193 3194 3195 3196 | 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 | - + | } pTos++; pTos->i = v; pTos->flags = MEM_Int; break; } |
︙ | |||
3257 3258 3259 3260 3261 3262 3263 | 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 | - + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + | #ifndef SQLITE_OMIT_TRIGGER } #endif pC->rowidIsValid = 0; pC->deferredMoveto = 0; pC->cacheValid = 0; |
︙ | |||
3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 | 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | ** The table being clear is in the main database file if P2==0. If ** P2==1 then the table to be clear is in the auxiliary database file ** that is used to store tables create using CREATE TEMPORARY TABLE. ** ** See also: Destroy */ case OP_Clear: { /* no-push */ Btree *pBt = db->aDb[pOp->p2].pBt; if( db->xUpdateCallback && pOp->p3 ){ const char *zDb = db->aDb[pOp->p2].zName; const char *zTbl = pOp->p3; BtCursor *pCur = 0; int fin = 0; rc = sqlite3BtreeCursor(pBt, pOp->p1, 0, 0, 0, &pCur); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } for( rc=sqlite3BtreeFirst(pCur, &fin); rc==SQLITE_OK && !fin; rc=sqlite3BtreeNext(pCur, &fin) ){ i64 iKey; rc = sqlite3BtreeKeySize(pCur, &iKey); if( rc ){ break; } iKey = keyToInt(iKey); db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, iKey); } sqlite3BtreeCloseCursor(pCur); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } } rc = sqlite3BtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1); break; } /* Opcode: CreateTable P1 * * ** ** Allocate a new table in the main database file if P2==0 or in the |
︙ | |||
4339 4340 4341 4342 4343 4344 4345 | 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 | - | if( !pOp->p1 ){ sqlite3ExpirePreparedStatements(db); }else{ p->expired = 1; } break; } |
︙ |
Changes to src/vdbeInt.h.
︙ | |||
56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | + | ** If the Cursor.isTriggerRow flag is set it means that this cursor is ** really a single row that represents the NEW or OLD pseudo-table of ** a row trigger. The data for the row is stored in Cursor.pData and ** the rowid is in Cursor.iKey. */ struct Cursor { BtCursor *pCursor; /* The cursor structure of the backend */ int iDb; /* Index of cursor database in db->aDb[] (or -1) */ i64 lastRowid; /* Last rowid from a Next or NextIdx operation */ i64 nextRowid; /* Next rowid returned by OP_NewRowid */ Bool zeroed; /* True if zeroed out and ready for reuse */ Bool rowidIsValid; /* True if lastRowid is valid */ Bool atFirst; /* True if pointing to first entry */ Bool useRandomRowid; /* Generate new record numbers semi-randomly */ Bool nullRow; /* True if pointing to a row with no data */ |
︙ |
Changes to test/hook.test.
︙ | |||
10 11 12 13 14 15 16 17 | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | + - + | #*********************************************************************** # This file implements regression tests for TCL interface to the # SQLite library. # # The focus of the tests in this file is the following interface: # # sqlite_commit_hook # sqlite_update_hook (tests hook-4 onwards) # |
︙ | |||
85 86 87 88 89 90 91 92 93 | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | db commit_hook {} set ::commit_cnt {} execsql { INSERT INTO t2 VALUES(7,8); } 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. # do_test hook-4.1 { catchsql { DROP TABLE t1; } execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two'); INSERT INTO t1 VALUES(3, 'three'); } db update_hook [list lappend ::update_hook] } {} do_test hook-4.2 { execsql { INSERT INTO t1 VALUES(4, 'four'); DELETE FROM t1 WHERE b = 'two'; UPDATE t1 SET b = '' WHERE a = 1 OR a = 3; DELETE FROM t1; } set ::update_hook } [list \ INSERT main t1 4 \ DELETE main t1 2 \ UPDATE main t1 1 \ UPDATE main t1 3 \ DELETE main t1 1 \ DELETE main t1 3 \ 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 { catchsql { DROP TABLE t2; } execsql { CREATE TABLE t2(c INTEGER PRIMARY KEY, d); CREATE TRIGGER t1_trigger AFTER INSERT ON t1 BEGIN INSERT INTO t2 VALUES(new.a, new.b); UPDATE t2 SET d = d || ' via trigger' WHERE new.a = c; DELETE FROM t2 WHERE new.a = c; END; } } {} do_test hook-5.2 { execsql { INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two'); } set ::update_hook } [list \ INSERT main t1 1 \ INSERT main t2 1 \ UPDATE main t2 1 \ DELETE main t2 1 \ INSERT main t1 2 \ INSERT main t2 2 \ UPDATE main t2 2 \ DELETE main t2 2 \ ] set ::update_hook {} do_test hook-6.1 { file delete -force test2.db execsql { ATTACH 'test2.db' AS aux; CREATE TABLE aux.t3(a INTEGER PRIMARY KEY, b); INSERT INTO aux.t3 SELECT * FROM t1; UPDATE t3 SET b = 'two or so' WHERE a = 2; DELETE FROM t3; } set ::update_hook } [list \ INSERT aux t3 1 \ INSERT aux t3 2 \ UPDATE aux t3 2 \ DELETE aux t3 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. # set ::update_hook {} do_test hook-7.1 { execsql { DROP TRIGGER t1_trigger; CREATE INDEX t1_i ON t1(b); INSERT INTO t1 VALUES(3, 'three'); UPDATE t1 SET b = ''; DELETE FROM t1 WHERE a > 1; } set ::update_hook } [list \ INSERT main t1 3 \ UPDATE main t1 1 \ UPDATE main t1 2 \ UPDATE main t1 3 \ DELETE main t1 2 \ DELETE main t1 3 \ ] set ::update_hook {} do_test hook-7.2 { execsql { SELECT * FROM t1 UNION SELECT * FROM t3; SELECT * FROM t1 UNION ALL SELECT * FROM t3; SELECT * FROM t1 INTERSECT SELECT * FROM t3; SELECT * FROM t1 EXCEPT SELECT * FROM t3; SELECT * FROM t1 ORDER BY b; SELECT * FROM t1 GROUP BY b; } set ::update_hook } [list] finish_test |