Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | When a transaction or savepoint rollback occurs, save the positions of all open read-cursors so that they can be restored following the rollback operation. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
dd03a2802f3f276525f3cef9a93f825d |
User & Date: | dan 2014-11-12 14:56:02.923 |
References
2014-11-13
| ||
13:42 | When a transaction or savepoint rollback occurs, save the positions of all open read-cursors so that they can be restored following the rollback operation. Cherry-pick of check-in [dd03a2802f3f27] (check-in: 402780a9c8 user: drh tags: branch-3.8.7) | |
Context
2014-11-13
| ||
13:42 | When a transaction or savepoint rollback occurs, save the positions of all open read-cursors so that they can be restored following the rollback operation. Cherry-pick of check-in [dd03a2802f3f27] (check-in: 402780a9c8 user: drh tags: branch-3.8.7) | |
2014-11-12
| ||
17:45 | Add further tests for rollback operations in the presence of ongoing selects. (check-in: eaf3aae014 user: dan tags: trunk) | |
14:56 | When a transaction or savepoint rollback occurs, save the positions of all open read-cursors so that they can be restored following the rollback operation. (check-in: dd03a2802f user: dan tags: trunk) | |
2014-11-11
| ||
19:07 | Remove some calls to the 'breakpoint' test command. (check-in: 1412fcc480 user: mistachkin tags: trunk) | |
Changes
Changes to src/btree.c.
︙ | ︙ | |||
3510 3511 3512 3513 3514 3515 3516 | ** 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. ** | | | | > | > > | > > > > > > > | > > | | | | | > > > > > > > > | | | > | | | | | | > > | 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 | ** 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. If the writeOnly ** flag is true, then only write-cursors need be tripped - read-only ** cursors save their current positions so that they may continue ** following the rollback. Or, if writeOnly is false, all cursors are ** tripped. In general, writeOnly is false if the transaction being ** rolled back modified the database schema. In this case b-tree root ** pages may be moved or deleted from the database altogether, making ** it unsafe for read cursors to continue. ** ** If the writeOnly flag is true and an error is encountered while ** saving the current position of a read-only cursor, all cursors, ** including all read-cursors are tripped. ** ** SQLITE_OK is returned if successful, or if an error occurs while ** saving a cursor position, an SQLite error code. */ int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){ BtCursor *p; int rc = SQLITE_OK; assert( (writeOnly==0 || writeOnly==1) && BTCF_WriteFlag==1 ); if( pBtree ){ sqlite3BtreeEnter(pBtree); for(p=pBtree->pBt->pCursor; p; p=p->pNext){ int i; if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){ if( p->eState==CURSOR_VALID ){ int rc = saveCursorPosition(p); if( rc!=SQLITE_OK ){ (void)sqlite3BtreeTripAllCursors(pBtree, rc, 0); break; } } }else{ 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); } return rc; } /* ** 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 |
︙ | ︙ | |||
3561 3562 3563 3564 3565 3566 3567 | if( tripCode==SQLITE_OK ){ rc = tripCode = saveAllCursors(pBt, 0, 0); if( rc ) writeOnly = 0; }else{ rc = SQLITE_OK; } if( tripCode ){ | | > > | 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 | if( tripCode==SQLITE_OK ){ rc = tripCode = saveAllCursors(pBt, 0, 0); if( rc ) writeOnly = 0; }else{ rc = SQLITE_OK; } if( tripCode ){ int rc2 = sqlite3BtreeTripAllCursors(p, tripCode, writeOnly); assert( rc==SQLITE_OK || (writeOnly==0 && rc2==SQLITE_OK) ); if( rc2!=SQLITE_OK ) rc = rc2; } btreeIntegrity(p); if( p->inTrans==TRANS_WRITE ){ int rc2; assert( TRANS_WRITE==pBt->inTransaction ); |
︙ | ︙ |
Changes to src/btree.h.
︙ | ︙ | |||
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*); int 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/vdbe.c.
︙ | ︙ | |||
2826 2827 2828 2829 2830 2831 2832 | 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++){ | | > | 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 | 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++){ rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT, isSchemaChange==0); if( rc!=SQLITE_OK ) goto abort_due_to_error; } }else{ isSchemaChange = 0; } for(ii=0; ii<db->nDb; ii++){ rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint); if( rc!=SQLITE_OK ){ |
︙ | ︙ |
Added test/rollback2.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 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 | # 2014 November 12 # # 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. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix rollback2 proc int2hex {i} { format %.2X $i } db func int2hex int2hex do_execsql_test 1.0 { SELECT int2hex(0), int2hex(100), int2hex(255) } {00 64 FF} do_execsql_test 1.1 { CREATE TABLE t1(i, h); CREATE INDEX i1 ON t1(h); WITH data(a, b) AS ( SELECT 1, int2hex(1) UNION ALL SELECT a+1, int2hex(a+1) FROM data WHERE a<40 ) INSERT INTO t1 SELECT * FROM data; } {} proc do_rollback_test {tn args} { set A(-setup) "" set A(-select) "" set A(-result) "" set A(-rollback) ROLLBACK array set O $args foreach k [array names O] { if {[info exists A($k)]==0} { error "unknown option: $k" } set A($k) $O($k) } for {set iRollback 0} 1 {incr iRollback} { catch { db eval ROLLBACK } set res [list] db eval $A(-setup) set i 0 db eval $A(-select) x { if {$i==$iRollback} { db eval $A(-rollback) } foreach k $x(*) { lappend res $x($k) } incr i } do_test $tn.$iRollback [list set {} $res] [list {*}$A(-result)] if {$i < $iRollback} break } } do_rollback_test 2 -setup { BEGIN; DELETE FROM t1 WHERE (i%2)==1; } -select { SELECT i FROM t1 WHERE (i%2)==0 } -result { 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 } finish_test |