Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add the experimental sqlite3_transaction_hook() API. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | sessions |
Files: | files | file ages | folders |
SHA1: |
093d8cd8e2f3a6af5d40cf810e396f49 |
User & Date: | dan 2011-03-03 20:06:00.000 |
Context
2011-03-08
| ||
19:22 | Add start of sessions feature. (check-in: 269a81a37d user: dan tags: sessions) | |
2011-03-03
| ||
20:06 | Add the experimental sqlite3_transaction_hook() API. (check-in: 093d8cd8e2 user: dan tags: sessions) | |
2011-03-01
| ||
18:42 | Add the experimental sqlite3_preupdate_hook() API. (check-in: 6145d7b89f user: dan tags: sessions) | |
Changes
Changes to src/main.c.
︙ | ︙ | |||
760 761 762 763 764 765 766 767 768 769 770 771 772 773 | if( db->lookaside.bMalloced ){ sqlite3_free(db->lookaside.pStart); } sqlite3_free(db); return SQLITE_OK; } /* ** Rollback all database files. */ void sqlite3RollbackAll(sqlite3 *db){ int i; int inTrans = 0; assert( sqlite3_mutex_held(db->mutex) ); | > > > > > > > > > > > > > > > > > > > > | 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 | if( db->lookaside.bMalloced ){ sqlite3_free(db->lookaside.pStart); } sqlite3_free(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 || iLevel<db->iOpenTrans || iLevel==0 ); assert( op==SQLITE_BEGIN || iLevel<db->iOpenTrans || 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. */ void sqlite3RollbackAll(sqlite3 *db){ int i; int inTrans = 0; assert( sqlite3_mutex_held(db->mutex) ); |
︙ | ︙ | |||
792 793 794 795 796 797 798 799 800 801 802 803 804 805 | /* Any deferred constraint violations have now been resolved. */ db->nDeferredCons = 0; /* If one has been configured, invoke the rollback-hook callback */ if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ db->xRollbackCallback(db->pRollbackArg); } } /* ** Return a static string that describes the kind of error specified in the ** argument. */ const char *sqlite3ErrStr(int rc){ | > > > > | 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 | /* Any deferred constraint violations have now been resolved. */ db->nDeferredCons = 0; /* If one has been configured, invoke the rollback-hook callback */ 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); } /* ** Return a static string that describes the kind of error specified in the ** argument. */ const char *sqlite3ErrStr(int rc){ |
︙ | ︙ | |||
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 | sqlite3_mutex_enter(db->mutex); pRet = db->pPreUpdateArg; db->xPreUpdateCallback = xCallback; db->pPreUpdateArg = pArg; sqlite3_mutex_leave(db->mutex); return pRet; } #ifndef SQLITE_OMIT_WAL /* ** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint(). ** Invoke sqlite3_wal_checkpoint if the number of frames in the log file ** is greater than sqlite3.pWalArg cast to an integer (the value configured by ** wal_autocheckpoint()). | > > > > > > > > > > > > > > > > > > | 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 | sqlite3_mutex_enter(db->mutex); pRet = db->pPreUpdateArg; db->xPreUpdateCallback = xCallback; db->pPreUpdateArg = pArg; sqlite3_mutex_leave(db->mutex); 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(). ** Invoke sqlite3_wal_checkpoint if the number of frames in the log file ** is greater than sqlite3.pWalArg cast to an integer (the value configured by ** wal_autocheckpoint()). |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
6340 6341 6342 6343 6344 6345 6346 | ** documentation for additional information about the meaning and use of ** each of these values. */ #define SQLITE_CHECKPOINT_PASSIVE 0 #define SQLITE_CHECKPOINT_FULL 1 #define SQLITE_CHECKPOINT_RESTART 2 | > > > > > > > > | > > > < < < | | | | > > > | 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 | ** documentation for additional information about the meaning and use of ** each of these values. */ #define SQLITE_CHECKPOINT_PASSIVE 0 #define SQLITE_CHECKPOINT_FULL 1 #define SQLITE_CHECKPOINT_RESTART 2 /* ** 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() */ sqlite3 *db, /* Database handle */ int op, /* SQLITE_UPDATE, DELETE or INSERT */ char const *zDb, /* Database name */ char const *zName, /* Table name */ sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ ), 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 *); /* ** CAPI3REF: The transaction hook. */ SQLITE_EXPERIMENTAL void *sqlite3_transaction_hook(sqlite3 *, void(*)(void *, int, int), void *); #define SQLITE_BEGIN 1 #define SQLITE_COMMIT 2 #define SQLITE_ROLLBACK 3 /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
829 830 831 832 833 834 835 836 837 838 839 840 841 842 | void *pUpdateArg; void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); void *pPreUpdateArg; /* First argument to xPreUpdateCallback */ void (*xPreUpdateCallback)( /* Registered using sqlite3_preupdate_hook() */ void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64 ); PreUpdate *pPreUpdate; /* Context for active pre-update callback */ #ifndef SQLITE_OMIT_WAL int (*xWalCallback)(void *, sqlite3 *, const char *, int); void *pWalArg; #endif void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*); void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*); void *pCollNeededArg; | > > > | 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 | void *pUpdateArg; void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); void *pPreUpdateArg; /* First argument to xPreUpdateCallback */ void (*xPreUpdateCallback)( /* Registered using sqlite3_preupdate_hook() */ 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; #endif void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*); void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*); void *pCollNeededArg; |
︙ | ︙ | |||
2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 | void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); Vdbe *sqlite3GetVdbe(Parse*); void sqlite3PrngSaveState(void); void sqlite3PrngRestoreState(void); void sqlite3PrngResetState(void); void sqlite3RollbackAll(sqlite3*); void sqlite3CodeVerifySchema(Parse*, int); void sqlite3BeginTransaction(Parse*, int); void sqlite3CommitTransaction(Parse*); void sqlite3RollbackTransaction(Parse*); void sqlite3Savepoint(Parse*, int, Token*); void sqlite3CloseSavepoints(sqlite3 *); int sqlite3ExprIsConstant(Expr*); | > | 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 | void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); Vdbe *sqlite3GetVdbe(Parse*); 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*); void sqlite3RollbackTransaction(Parse*); void sqlite3Savepoint(Parse*, int, Token*); void sqlite3CloseSavepoints(sqlite3 *); int sqlite3ExprIsConstant(Expr*); |
︙ | ︙ |
Changes to src/tclsqlite.c.
︙ | ︙ | |||
120 121 122 123 124 125 126 127 128 129 130 131 132 133 | char *zAuth; /* The authorization callback routine */ int disableAuth; /* Disable the authorizer if it exists */ 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 *pPreUpdateHook; /* Pre-update hook script (if any) */ Tcl_Obj *pRollbackHook; /* Rollback 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 */ 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 */ | > | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | char *zAuth; /* The authorization callback routine */ int disableAuth; /* Disable the authorizer if it exists */ 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 *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 */ 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 */ |
︙ | ︙ | |||
592 593 594 595 596 597 598 599 600 601 602 603 604 605 | 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); } } /* ** This procedure handles wal_hook callbacks. */ static int DbWalHandler( void *clientData, sqlite3 *db, | > > > > > > > > > > > > > > > > > > > > > > > > | 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 | 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); } } /* ** 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. */ static int DbWalHandler( void *clientData, sqlite3 *db, |
︙ | ︙ | |||
1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 | } } sqlite3_preupdate_hook(db, (pDb->pPreUpdateHook?DbPreUpdateHandler:0), pDb); 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); } /* ** The "sqlite" command below creates a new Tcl command for each ** connection it opens to an SQLite database. This routine is invoked ** whenever one of those connection-specific commands is executed ** in Tcl. For example, if you run Tcl code like this: | > | 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 | } } sqlite3_preupdate_hook(db, (pDb->pPreUpdateHook?DbPreUpdateHandler:0), pDb); 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); } /* ** The "sqlite" command below creates a new Tcl command for each ** connection it opens to an SQLite database. This routine is invoked ** whenever one of those connection-specific commands is executed ** in Tcl. For example, if you run Tcl code like this: |
︙ | ︙ | |||
1655 1656 1657 1658 1659 1660 1661 | "errorcode", "eval", "exists", "function", "incrblob", "interrupt", "last_insert_rowid", "nullvalue", "onecolumn", "preupdate", "profile", "progress", "rekey", "restore", "rollback_hook", "status", "timeout", "total_changes", "trace", | > | | > | 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 | "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", "wal_hook", 0 }; enum DB_enum { 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_PREUPDATE, DB_PROFILE, DB_PROGRESS, DB_REKEY, DB_RESTORE, DB_ROLLBACK_HOOK, DB_STATUS, DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE, 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 */ if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); return TCL_ERROR; |
︙ | ︙ | |||
2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 | break; } /* ** $db wal_hook ?script? ** $db update_hook ?script? ** $db rollback_hook ?script? */ case DB_WAL_HOOK: case DB_UPDATE_HOOK: | > | > > | 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 | break; } /* ** $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_TRANSACTION_HOOK: { sqlite3 *db = pDb->db; /* 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_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; } DbHookCmd(interp, pDb, (objc==3 ? objv[2] : 0), ppHook); break; |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 | ** "transaction savepoint". */ if( db->autoCommit ){ db->autoCommit = 0; db->isTransactionSavepoint = 1; }else{ db->nSavepoint++; } /* Link the new savepoint into the database handle's list. */ pNew->pNext = db->pSavepoint; db->pSavepoint = pNew; pNew->nDeferredCons = db->nDeferredCons; } } | > > | 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 | ** "transaction savepoint". */ if( db->autoCommit ){ db->autoCommit = 0; db->isTransactionSavepoint = 1; }else{ db->nSavepoint++; } sqlite3TransactionHook(db, SQLITE_BEGIN, db->nSavepoint); /* Link the new savepoint into the database handle's list. */ pNew->pNext = db->pSavepoint; db->pSavepoint = pNew; pNew->nDeferredCons = db->nDeferredCons; } } |
︙ | ︙ | |||
2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 | } } if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){ sqlite3ExpirePreparedStatements(db); sqlite3ResetInternalSchema(db, 0); db->flags = (db->flags | SQLITE_InternChanges); } } /* Regardless of whether this is a RELEASE or ROLLBACK, destroy all ** savepoints nested inside of the savepoint being operated on. */ while( db->pSavepoint!=pSavepoint ){ pTmp = db->pSavepoint; db->pSavepoint = pTmp->pNext; | > > > > > > > | 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 | } } if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){ sqlite3ExpirePreparedStatements(db); 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 ** savepoints nested inside of the savepoint being operated on. */ while( db->pSavepoint!=pSavepoint ){ pTmp = db->pSavepoint; db->pSavepoint = pTmp->pNext; |
︙ | ︙ | |||
2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 | if( iRollback ){ assert( desiredAutoCommit==1 ); sqlite3RollbackAll(db); db->autoCommit = 1; }else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){ goto vdbe_return; }else{ db->autoCommit = (u8)desiredAutoCommit; if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ p->pc = pc; db->autoCommit = (u8)(1-desiredAutoCommit); p->rc = rc = SQLITE_BUSY; goto vdbe_return; } | > > > | 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 | if( iRollback ){ assert( desiredAutoCommit==1 ); sqlite3RollbackAll(db); db->autoCommit = 1; }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; db->autoCommit = (u8)(1-desiredAutoCommit); p->rc = rc = SQLITE_BUSY; goto vdbe_return; } |
︙ | ︙ | |||
2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 | assert( sqlite3BtreeIsInTrans(pBt) ); if( p->iStatement==0 ){ assert( db->nStatement>=0 && db->nSavepoint>=0 ); db->nStatement++; p->iStatement = db->nSavepoint + db->nStatement; } rc = sqlite3BtreeBeginStmt(pBt, p->iStatement); /* Store the current value of the database handles deferred constraint ** counter. If the statement transaction needs to be rolled back, ** the value of this counter needs to be restored too. */ p->nStmtDefCons = db->nDeferredCons; } } | > | 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 | assert( sqlite3BtreeIsInTrans(pBt) ); if( p->iStatement==0 ){ assert( db->nStatement>=0 && db->nSavepoint>=0 ); db->nStatement++; 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, ** the value of this counter needs to be restored too. */ p->nStmtDefCons = db->nDeferredCons; } } |
︙ | ︙ |
Changes to src/vdbeapi.c.
︙ | ︙ | |||
397 398 399 400 401 402 403 | #ifndef SQLITE_OMIT_TRACE if( db->xProfile && !db->init.busy ){ sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime); } #endif db->activeVdbeCnt++; | | > > > > > > > > | 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 | #ifndef SQLITE_OMIT_TRACE if( db->xProfile && !db->init.busy ){ sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime); } #endif db->activeVdbeCnt++; 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 if( p->explain ){ rc = sqlite3VdbeList(p); }else #endif /* SQLITE_OMIT_EXPLAIN */ |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 | } sqlite3EndBenignMalloc(); enable_simulated_io_errors(); sqlite3VtabCommit(db); } #endif return rc; } /* ** This routine checks that the sqlite3.activeVdbeCnt count variable ** matches the number of vdbe's in the list sqlite3.pVdbe that are | > > > > > > | 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 | } sqlite3EndBenignMalloc(); enable_simulated_io_errors(); sqlite3VtabCommit(db); } #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; } /* ** This routine checks that the sqlite3.activeVdbeCnt count variable ** matches the number of vdbe's in the list sqlite3.pVdbe that are |
︙ | ︙ | |||
1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 | } if( rc==SQLITE_OK ){ rc = rc2; } } } db->nStatement--; p->iStatement = 0; /* If the statement transaction is being rolled back, also restore the ** database handles deferred constraint counter to the value it had when ** the statement transaction was opened. */ if( eOp==SAVEPOINT_ROLLBACK ){ db->nDeferredCons = p->nStmtDefCons; | > > > | 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 | } if( rc==SQLITE_OK ){ rc = rc2; } } } 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 ** database handles deferred constraint counter to the value it had when ** the statement transaction was opened. */ if( eOp==SAVEPOINT_ROLLBACK ){ db->nDeferredCons = p->nStmtDefCons; |
︙ | ︙ |
Changes to test/hook.test.
︙ | ︙ | |||
612 613 614 615 616 617 618 619 620 621 622 623 | do_execsql_test 7.5.2.0 { CREATE TABLE t8(a, b); INSERT INTO t8 VALUES('one', 'two'); INSERT INTO t8 VALUES('three', 'four'); ALTER TABLE t8 ADD COLUMN c DEFAULT 'xxx'; } do_preupdate_test 7.5.2.1 { DELETE FROM t8 WHERE a = 'one' } { DELETE main t8 1 1 one two xxx } | > > > > < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 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 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 | do_execsql_test 7.5.2.0 { CREATE TABLE t8(a, b); INSERT INTO t8 VALUES('one', 'two'); INSERT INTO t8 VALUES('three', 'four'); 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 |
Changes to test/tclsqlite.test.
︙ | ︙ | |||
31 32 33 34 35 36 37 | set v [catch {sqlite3 bogus} msg] regsub {really_sqlite3} $msg {sqlite3} msg lappend v $msg } [list 1 "wrong # args: should be \"$r\""] do_test tcl-1.2 { set v [catch {db bogus} msg] lappend v $msg | | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | set v [catch {sqlite3 bogus} msg] regsub {really_sqlite3} $msg {sqlite3} msg lappend v $msg } [list 1 "wrong # args: should be \"$r\""] 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, 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 } {1 {bad option "bogus": must be flush or size}} do_test tcl-1.2.2 { set v [catch {db cache} msg] lappend v $msg |
︙ | ︙ |