Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch read-after-rollback Excluding Merge-Ins
This is equivalent to a diff from 8289c3e9 to fa6e6a9a
2014-11-11
| ||
14:59 | Permit read operations to continue after a ROLLBACK as long as the schema does not change. (check-in: b5df5ac0 user: drh tags: trunk) | |
12:20 | Add new test file e_blobclose.test, containing tests for sqlite3_blob_close(). (check-in: 5a1eac24 user: dan tags: trunk) | |
01:33 | Experimental changes that permit read operations to continue after a ROLLBACK, as long as the schema is unchanged. (Closed-Leaf check-in: fa6e6a9a user: drh tags: read-after-rollback) | |
2014-11-10
| ||
19:16 | New test cases for deleting content out from under a SELECT statement. (check-in: 8289c3e9 user: drh tags: trunk) | |
17:53 | Add test file e_blobwrite.test, containing tests for the sqlite3_blob_write() interface. (check-in: 1df77e5f user: dan tags: trunk) | |
Changes to src/backup.c.
︙ | ︙ | |||
603 604 605 606 607 608 609 | while( *pp!=p ){ pp = &(*pp)->pNext; } *pp = p->pNext; } /* If a transaction is still open on the Btree, roll it back. */ | | | 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 | while( *pp!=p ){ pp = &(*pp)->pNext; } *pp = p->pNext; } /* If a transaction is still open on the Btree, roll it back. */ sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0); /* Set the error code of the destination database handle. */ rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc; if( p->pDestDb ){ sqlite3Error(p->pDestDb, rc); /* Exit the mutexes and free the backup context structure. */ |
︙ | ︙ |
Changes to src/btree.c.
︙ | ︙ | |||
2209 2210 2211 2212 2213 2214 2215 | } } /* Rollback any active transaction and free the handle structure. ** The call to sqlite3BtreeRollback() drops any table-locks held by ** this handle. */ | | | 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 | } } /* Rollback any active transaction and free the handle structure. ** The call to sqlite3BtreeRollback() drops any table-locks held by ** this handle. */ sqlite3BtreeRollback(p, SQLITE_OK, 0); sqlite3BtreeLeave(p); /* If there are still other outstanding references to the shared-btree ** structure, return now. The remainder of this procedure cleans ** up the shared-btree. */ assert( p->wantToLock==0 && p->locked==0 ); |
︙ | ︙ | |||
3502 3503 3504 3505 3506 3507 3508 | } sqlite3BtreeLeave(p); return rc; } /* ** This routine sets the state to CURSOR_FAULT and the error | | | > | | | | < | | | | < | > > | > > > | < | | > > > | | 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 | } sqlite3BtreeLeave(p); return rc; } /* ** This routine sets the state to CURSOR_FAULT and the error ** code to errCode for every cursor on any BtShared that pBtree ** references. Or if the writeOnly flag is set to 1, then only ** trip write cursors and leave read cursors unchanged. ** ** Every cursor is a candidate to be tripped, including cursors ** that belong to other database connections that happen to be ** sharing the cache with pBtree. ** ** This routine gets called when a rollback occurs. The writeOnly ** flag is set to 1 if the transaction did not make any schema ** changes, in which case the read cursors can continue operating. ** If schema changes did occur in the transaction, then both read ** and write cursors must both be tripped. */ void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){ BtCursor *p; assert( (writeOnly==0 || writeOnly==1) && BTCF_WriteFlag==1 ); if( pBtree==0 ) return; sqlite3BtreeEnter(pBtree); for(p=pBtree->pBt->pCursor; p; p=p->pNext){ int i; if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ) continue; sqlite3BtreeClearCursor(p); p->eState = CURSOR_FAULT; p->skipNext = errCode; for(i=0; i<=p->iPage; i++){ releasePage(p->apPage[i]); p->apPage[i] = 0; } } sqlite3BtreeLeave(pBtree); } /* ** Rollback the transaction in progress. ** ** If tripCode is not SQLITE_OK then cursors will be invalidated (tripped). ** Only write cursors are tripped if writeOnly is true but all cursors are ** tripped if writeOnly is false. Any attempt to use ** a tripped cursor will result in an error. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){ int rc; BtShared *pBt = p->pBt; MemPage *pPage1; assert( writeOnly==1 || writeOnly==0 ); assert( tripCode==SQLITE_ABORT_ROLLBACK || tripCode==SQLITE_OK ); sqlite3BtreeEnter(p); if( tripCode==SQLITE_OK ){ rc = tripCode = saveAllCursors(pBt, 0, 0); if( rc ) writeOnly = 0; }else{ rc = SQLITE_OK; } if( tripCode ){ sqlite3BtreeTripAllCursors(p, tripCode, writeOnly); } btreeIntegrity(p); if( p->inTrans==TRANS_WRITE ){ int rc2; assert( TRANS_WRITE==pBt->inTransaction ); |
︙ | ︙ |
Changes to src/btree.h.
︙ | ︙ | |||
79 80 81 82 83 84 85 | #endif int sqlite3BtreeSetAutoVacuum(Btree *, int); int sqlite3BtreeGetAutoVacuum(Btree *); int sqlite3BtreeBeginTrans(Btree*,int); int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster); int sqlite3BtreeCommitPhaseTwo(Btree*, int); int sqlite3BtreeCommit(Btree*); | | | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | #endif int sqlite3BtreeSetAutoVacuum(Btree *, int); int sqlite3BtreeGetAutoVacuum(Btree *); int sqlite3BtreeBeginTrans(Btree*,int); int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster); int sqlite3BtreeCommitPhaseTwo(Btree*, int); int sqlite3BtreeCommit(Btree*); int sqlite3BtreeRollback(Btree*,int,int); int sqlite3BtreeBeginStmt(Btree*,int); int sqlite3BtreeCreateTable(Btree*, int*, int flags); int sqlite3BtreeIsInTrans(Btree*); int sqlite3BtreeIsInReadTrans(Btree*); int sqlite3BtreeIsInBackup(Btree*); void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); int sqlite3BtreeSchemaLocked(Btree *pBtree); |
︙ | ︙ | |||
112 113 114 115 116 117 118 | */ #define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */ #define BTREE_BLOBKEY 2 /* Table has keys only - no data */ int sqlite3BtreeDropTable(Btree*, int, int*); int sqlite3BtreeClearTable(Btree*, int, int*); int sqlite3BtreeClearTableOfCursor(BtCursor*); | | | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | */ #define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */ #define BTREE_BLOBKEY 2 /* Table has keys only - no data */ int sqlite3BtreeDropTable(Btree*, int, int*); int sqlite3BtreeClearTable(Btree*, int, int*); int sqlite3BtreeClearTableOfCursor(BtCursor*); void sqlite3BtreeTripAllCursors(Btree*, int, int); void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); int sqlite3BtreeNewDb(Btree *p); /* |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
1107 1108 1109 1110 1111 1112 1113 | sqlite3_free(db->lookaside.pStart); } sqlite3_free(db); } /* ** Rollback all database files. If tripCode is not SQLITE_OK, then | | | > > > | | 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 | sqlite3_free(db->lookaside.pStart); } sqlite3_free(db); } /* ** Rollback all database files. If tripCode is not SQLITE_OK, then ** any write cursors are invalidated ("tripped" - as in "tripping a circuit ** breaker") and made to return tripCode if there are any further ** attempts to use that cursor. Read cursors remain open and valid ** but are "saved" in case the table pages are moved around. */ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ int i; int inTrans = 0; int schemaChange; assert( sqlite3_mutex_held(db->mutex) ); sqlite3BeginBenignMalloc(); /* Obtain all b-tree mutexes before making any calls to BtreeRollback(). ** This is important in case the transaction being rolled back has ** modified the database schema. If the b-tree mutexes are not taken ** here, then another shared-cache connection might sneak in between ** the database rollback and schema reset, which can cause false ** corruption reports in some cases. */ sqlite3BtreeEnterAll(db); schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0; for(i=0; i<db->nDb; i++){ Btree *p = db->aDb[i].pBt; if( p ){ if( sqlite3BtreeIsInTrans(p) ){ inTrans = 1; } sqlite3BtreeRollback(p, tripCode, !schemaChange); } } sqlite3VtabRollback(db); sqlite3EndBenignMalloc(); if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){ sqlite3ExpirePreparedStatements(db); |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 | db->autoCommit = 0; p->rc = rc = SQLITE_BUSY; goto vdbe_return; } db->isTransactionSavepoint = 0; rc = p->rc; }else{ iSavepoint = db->nSavepoint - iSavepoint - 1; if( p1==SAVEPOINT_ROLLBACK ){ for(ii=0; ii<db->nDb; ii++){ | > > | > > > | | 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 | db->autoCommit = 0; p->rc = rc = SQLITE_BUSY; goto vdbe_return; } db->isTransactionSavepoint = 0; rc = p->rc; }else{ int isSchemaChange; iSavepoint = db->nSavepoint - iSavepoint - 1; if( p1==SAVEPOINT_ROLLBACK ){ isSchemaChange = (db->flags & SQLITE_InternChanges)!=0; for(ii=0; ii<db->nDb; ii++){ sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT, isSchemaChange==0); } }else{ isSchemaChange = 0; } for(ii=0; ii<db->nDb; ii++){ rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } } if( isSchemaChange ){ sqlite3ExpirePreparedStatements(db); sqlite3ResetAllSchemasOfConnection(db); db->flags = (db->flags | SQLITE_InternChanges); } } /* Regardless of whether this is a RELEASE or ROLLBACK, destroy all |
︙ | ︙ | |||
3230 3231 3232 3233 3234 3235 3236 | assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR))==pOp->p5 ); assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 ); assert( p->bIsReader ); assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx || p->readOnly==0 ); if( p->expired ){ | | | 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 | assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR))==pOp->p5 ); assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 ); assert( p->bIsReader ); assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx || p->readOnly==0 ); if( p->expired ){ rc = SQLITE_ABORT_ROLLBACK; break; } nField = 0; pKeyInfo = 0; p2 = pOp->p2; iDb = pOp->p3; |
︙ | ︙ |
Changes to src/wal.c.
︙ | ︙ | |||
2502 2503 2504 2505 2506 2507 2508 | /* Restore the clients cache of the wal-index header to the state it ** was in before the client began writing to the database. */ memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr)); for(iFrame=pWal->hdr.mxFrame+1; | | < | 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 | /* Restore the clients cache of the wal-index header to the state it ** was in before the client began writing to the database. */ memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr)); for(iFrame=pWal->hdr.mxFrame+1; rc==SQLITE_OK && iFrame<=iMax; iFrame++ ){ /* This call cannot fail. Unless the page for which the page number ** is passed as the second argument is (a) in the cache and ** (b) has an outstanding reference, then xUndo is either a no-op ** (if (a) is false) or simply expels the page from the cache (if (b) ** is false). ** ** If the upper layer is doing a rollback, it is guaranteed that there ** are no outstanding references to any page other than page 1. And ** page 1 is never written to the log until the transaction is ** committed. As a result, the call to xUndo may not fail. */ assert( walFramePgno(pWal, iFrame)!=1 ); rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame)); } if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal); } return rc; } /* ** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32 ** values. This function populates the array with values required to ** "rollback" the write position of the WAL handle back to the current |
︙ | ︙ |
Changes to test/capi3.test.
︙ | ︙ | |||
908 909 910 911 912 913 914 | } } {0 {}} do_test capi3-11.9.3 { sqlite3_get_autocommit $DB } 1 do_test capi3-11.10 { sqlite3_step $STMT | | | | | 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 | } } {0 {}} do_test capi3-11.9.3 { sqlite3_get_autocommit $DB } 1 do_test capi3-11.10 { sqlite3_step $STMT } {SQLITE_ROW} ifcapable !autoreset { # If SQLITE_OMIT_AUTORESET is defined, then the statement must be # reset() before it can be passed to step() again. do_test capi3-11.11a { sqlite3_step $STMT } {SQLITE_MISUSE} do_test capi3-11.11b { sqlite3_reset $STMT } {SQLITE_ABORT} } do_test capi3-11.11 { sqlite3_step $STMT } {SQLITE_DONE} do_test capi3-11.12 { sqlite3_step $STMT sqlite3_step $STMT } {SQLITE_ROW} do_test capi3-11.13 { sqlite3_finalize $STMT } {SQLITE_OK} do_test capi3-11.14 { execsql { SELECT a FROM t2; } |
︙ | ︙ |
Changes to test/capi3c.test.
︙ | ︙ | |||
859 860 861 862 863 864 865 | } } {0 {}} do_test capi3c-11.9.3 { sqlite3_get_autocommit $DB } 1 do_test capi3c-11.10 { sqlite3_step $STMT | | | | | 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 | } } {0 {}} do_test capi3c-11.9.3 { sqlite3_get_autocommit $DB } 1 do_test capi3c-11.10 { sqlite3_step $STMT } {SQLITE_ROW} ifcapable !autoreset { # If SQLITE_OMIT_AUTORESET is defined, then the statement must be # reset() before it can be passed to step() again. do_test capi3-11.11a { sqlite3_step $STMT } {SQLITE_MISUSE} do_test capi3-11.11b { sqlite3_reset $STMT } {SQLITE_ABORT} } do_test capi3c-11.11 { sqlite3_step $STMT } {SQLITE_DONE} do_test capi3c-11.12 { sqlite3_step $STMT sqlite3_step $STMT } {SQLITE_ROW} do_test capi3c-11.13 { sqlite3_finalize $STMT } {SQLITE_OK} do_test capi3c-11.14 { execsql { SELECT a FROM t2; } |
︙ | ︙ |
Changes to test/misc8.test.
︙ | ︙ | |||
30 31 32 33 34 35 36 | do_execsql_test misc8-1.3 { INSERT INTO t1 VALUES(7,null,9); SELECT eval('SELECT * FROM t1 ORDER BY a',','); } {1,2,3,4,5,6,7,,9} do_catchsql_test misc8-1.4 { BEGIN; INSERT INTO t1 VALUES(10,11,12); | > | | > > > > > > > > | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | do_execsql_test misc8-1.3 { INSERT INTO t1 VALUES(7,null,9); SELECT eval('SELECT * FROM t1 ORDER BY a',','); } {1,2,3,4,5,6,7,,9} do_catchsql_test misc8-1.4 { BEGIN; INSERT INTO t1 VALUES(10,11,12); SELECT a, coalesce(b, eval('ROLLBACK; SELECT ''bam'';')), c FROM t1 ORDER BY a; } {0 {1 2 3 4 5 6 7 bam 9}} do_catchsql_test misc8-1.5 { INSERT INTO t1 VALUES(10,11,12); SELECT a, coalesce(b, eval('SELECT ''bam''')), c FROM t1 ORDER BY rowid; } {0 {1 2 3 4 5 6 7 bam 9 10 11 12}} do_catchsql_test misc8-1.6 { SELECT a, coalesce(b, eval('DELETE FROM t1; SELECT ''bam''')), c FROM t1 ORDER BY rowid; } {0 {1 2 3 4 5 6 7 bam {}}} do_catchsql_test misc8-1.7 { INSERT INTO t1 VALUES(1,2,3),(4,5,6),(7,null,9); BEGIN; CREATE TABLE t2(x); SELECT a, coalesce(b, eval('ROLLBACK; SELECT ''bam''')), c FROM t1 ORDER BY rowid; } {1 {abort due to ROLLBACK}} finish_test |
Changes to test/rollback.test.
︙ | ︙ | |||
56 57 58 59 60 61 62 | } } {1 {UNIQUE constraint failed: t3.a}} # Try to continue with the SELECT statement # do_test rollback-1.5 { sqlite3_step $STMT | | | | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | } } {1 {UNIQUE constraint failed: t3.a}} # Try to continue with the SELECT statement # do_test rollback-1.5 { sqlite3_step $STMT } {SQLITE_ROW} # Restart the SELECT statement # do_test rollback-1.6 { sqlite3_reset $STMT } {SQLITE_OK} } else { do_test rollback-1.6 { sqlite3_reset $STMT } {SQLITE_OK} } do_test rollback-1.7 { sqlite3_step $STMT } {SQLITE_ROW} |
︙ | ︙ |
Changes to test/savepoint.test.
︙ | ︙ | |||
311 312 313 314 315 316 317 | } {0 {hellontyeight character blob}} do_test savepoint-5.3.2.2 { catchsql {ROLLBACK TO def} } {0 {}} do_test savepoint-5.3.2.3 { set rc [catch {seek $fd 0; read $fd} res] set rc | | | 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 | } {0 {hellontyeight character blob}} do_test savepoint-5.3.2.2 { catchsql {ROLLBACK TO def} } {0 {}} do_test savepoint-5.3.2.3 { set rc [catch {seek $fd 0; read $fd} res] set rc } {0} do_test savepoint-5.3.3 { catchsql {RELEASE def} } {0 {}} do_test savepoint-5.3.4 { close $fd execsql {savepoint def} set fd [db incrblob blobs x 1] |
︙ | ︙ |
Changes to test/savepoint7.test.
︙ | ︙ | |||
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | INSERT INTO t1 VALUES(4,5,6); INSERT INTO t1 VALUES(7,8,9); SAVEPOINT x1; } db eval {SELECT * FROM t1} { db eval { SAVEPOINT x2; INSERT INTO t2 VALUES($a,$b,$c); RELEASE x2; } } db eval {SELECT * FROM t2; RELEASE x1} } {1 2 3 4 5 6 7 8 9} do_test savepoint7-1.2 { db eval {DELETE FROM t2;} db eval {SELECT * FROM t1} { db eval { SAVEPOINT x2; INSERT INTO t2 VALUES($a,$b,$c); RELEASE x2; } } | > | | > | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | INSERT INTO t1 VALUES(4,5,6); INSERT INTO t1 VALUES(7,8,9); SAVEPOINT x1; } db eval {SELECT * FROM t1} { db eval { SAVEPOINT x2; CREATE TABLE IF NOT EXISTS t3(xyz); INSERT INTO t2 VALUES($a,$b,$c); RELEASE x2; } } db eval {SELECT * FROM t2; RELEASE x1} } {1 2 3 4 5 6 7 8 9} do_test savepoint7-1.2 { db eval {DELETE FROM t2;} db eval {SELECT * FROM t1} { db eval { SAVEPOINT x2; INSERT INTO t2 VALUES($a,$b,$c); RELEASE x2; } } db eval {SELECT * FROM t2;} } {1 2 3 4 5 6 7 8 9} do_test savepoint7-1.3 { db eval {DELETE FROM t2; BEGIN;} db eval {SELECT * FROM t1} { db eval { SAVEPOINT x2; INSERT INTO t2 VALUES($a,$b,$c); RELEASE x2; } } db eval {SELECT * FROM t2; ROLLBACK;} } {1 2 3 4 5 6 7 8 9} # However, a ROLLBACK of an inner savepoint will abort all queries, including # queries in outer contexts. # do_test savepoint7-2.1 { db eval {DELETE FROM t2; SAVEPOINT x1; CREATE TABLE t4(abc);} set rc [catch { db eval {SELECT * FROM t1} { db eval { SAVEPOINT x2; INSERT INTO t2 VALUES($a,$b,$c); ROLLBACK TO x2; } } } msg] db eval {RELEASE x1} list $rc $msg [db eval {SELECT * FROM t2}] } {1 {callback requested query abort} {}} do_test savepoint7-2.2 { db eval {DELETE FROM t2;} set rc [catch { db eval {SELECT * FROM t1} { db eval { SAVEPOINT x2; CREATE TABLE t5(pqr); INSERT INTO t2 VALUES($a,$b,$c); ROLLBACK TO x2; } } } msg] list $rc $msg [db eval {SELECT * FROM t2}] } {1 {callback requested query abort} {}} finish_test |
Changes to test/tkt-f777251dc7a.test.
︙ | ︙ | |||
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | proc force_rollback {} { catch {db eval {INSERT OR ROLLBACK INTO t1 VALUES(1)}} } db function force_rollback force_rollback do_test tkt-f7772-1.2 { catchsql { BEGIN IMMEDIATE; SELECT x, force_rollback(), EXISTS(SELECT 1 FROM t3 WHERE w=x) FROM t2; } } {1 {abort due to ROLLBACK}} do_test tkt-f7772-1.3 { sqlite3_get_autocommit db } {1} | > > | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | proc force_rollback {} { catch {db eval {INSERT OR ROLLBACK INTO t1 VALUES(1)}} } db function force_rollback force_rollback do_test tkt-f7772-1.2 { breakpoint catchsql { BEGIN IMMEDIATE; CREATE TABLE xyzzy(abc); SELECT x, force_rollback(), EXISTS(SELECT 1 FROM t3 WHERE w=x) FROM t2; } } {1 {abort due to ROLLBACK}} do_test tkt-f7772-1.3 { sqlite3_get_autocommit db } {1} |
︙ | ︙ | |||
63 64 65 66 67 68 69 | execsql { BEGIN IMMEDIATE; CREATE TEMP TABLE t3(w, z); } catchsql { SELECT x, force_rollback(), EXISTS(SELECT 1 FROM t3 WHERE w=x) FROM t2 } | | | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | execsql { BEGIN IMMEDIATE; CREATE TEMP TABLE t3(w, z); } catchsql { SELECT x, force_rollback(), EXISTS(SELECT 1 FROM t3 WHERE w=x) FROM t2 } } {1 {abort due to ROLLBACK}} do_test tkt-f7772-2.3 { sqlite3_get_autocommit db } {1} do_test tkt-f7772-3.1 { execsql { DROP TABLE IF EXISTS t1; |
︙ | ︙ |
Changes to test/trans3.test.
︙ | ︙ | |||
48 49 50 51 52 53 54 | do_test trans3-1.3.1 { sqlite3_get_autocommit db } 1 do_test trans3-1.4 { db eval {SELECT * FROM t1} } {1 2 3 4} do_test trans3-1.5 { | | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | do_test trans3-1.3.1 { sqlite3_get_autocommit db } 1 do_test trans3-1.4 { db eval {SELECT * FROM t1} } {1 2 3 4} do_test trans3-1.5 { db eval {BEGIN; CREATE TABLE xyzzy(abc);} db eval {INSERT INTO t1 VALUES(5);} set ::ecode {} set x [catch { db eval {SELECT * FROM t1} { if {[catch {db eval ROLLBACK} errmsg]} { set ::ecode [sqlite3_extended_errcode db] error $errmsg |
︙ | ︙ |