-C Remove\ssome\scalls\sto\sthe\s'breakpoint'\stest\scommand.
-D 2014-11-11T19:07:56.372
+C When\sa\stransaction\sor\ssavepoint\srollback\soccurs,\ssave\sthe\spositions\sof\sall\sopen\sread-cursors\sso\sthat\sthey\scan\sbe\srestored\sfollowing\sthe\srollback\soperation.
+D 2014-11-12T14:56:02.923
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F src/backup.c 86b311af1ad35decd1f2f0cee457d344acb83c3b
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5
-F src/btree.c eaef0003bbfe740c62189355dabc818fc3a98999
-F src/btree.h d24fc2f3bc53be220b79b95800bdb2ee207b1089
+F src/btree.c d5d991b518fa5bebc64037dfeb98a48051d864d7
+F src/btree.h e31a3a3ebdedb1caf9bda3ad5dbab3db9b780f6e
F src/btreeInt.h 026d0129724e8f265fdc60d44ec240cf5a4e6179
F src/build.c 67bb05b1077e0cdaccb2e36bfcbe7a5df9ed31e8
F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73
F src/vacuum.c 9b30ec729337dd012ed88d4c292922c8ef9cf00c
-F src/vdbe.c c71d819bb34269c3dbccd92e6bb308f0ec025b5d
+F src/vdbe.c 5e47308836e9bb5fdb4835fdf88eeab071848d3f
F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3
F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78
F src/vdbeapi.c 07acb615d1e4170e71fc1b0d087f3c53a1ad8e83
F test/releasetest.tcl a4279c890698584feb2ffc86735857a4e4474180
F test/resolver01.test 33abf37ff8335e6bf98f2b45a0af3e06996ccd9a
F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea
+F test/rollback2.test 552abaab8e721b6060a727d639896427059e51ec
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
F test/rowid.test 742b5741584a8a44fd83e856cc2896688401d645
F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P a066a3832a7c6de65c3016e77e49ac00e09db749
-R e8fc41a7f82a02ab8618a341f7ef7735
-U mistachkin
-Z 90417f4c358533080e79b8017b4e7453
+P 1412fcc480799ecbd68d44dd18d5bad40e20ccf1
+R 668a86f911283b47b6c156fecf772681
+U dan
+Z cf8e25329461439611751d7913ef3ef9
-1412fcc480799ecbd68d44dd18d5bad40e20ccf1
\ No newline at end of file
+dd03a2802f3f276525f3cef9a93f825dd8606626
\ No newline at end of file
** 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){
+** 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==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;
+ 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);
}
- sqlite3BtreeLeave(pBtree);
+ return rc;
}
/*
rc = SQLITE_OK;
}
if( tripCode ){
- sqlite3BtreeTripAllCursors(p, tripCode, writeOnly);
+ int rc2 = sqlite3BtreeTripAllCursors(p, tripCode, writeOnly);
+ assert( rc==SQLITE_OK || (writeOnly==0 && rc2==SQLITE_OK) );
+ if( rc2!=SQLITE_OK ) rc = rc2;
}
btreeIntegrity(p);
int sqlite3BtreeDropTable(Btree*, int, int*);
int sqlite3BtreeClearTable(Btree*, int, int*);
int sqlite3BtreeClearTableOfCursor(BtCursor*);
-void sqlite3BtreeTripAllCursors(Btree*, int, int);
+int sqlite3BtreeTripAllCursors(Btree*, int, int);
void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
if( p1==SAVEPOINT_ROLLBACK ){
isSchemaChange = (db->flags & SQLITE_InternChanges)!=0;
for(ii=0; ii<db->nDb; ii++){
- sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT,
+ rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT,
isSchemaChange==0);
+ if( rc!=SQLITE_OK ) goto abort_due_to_error;
}
}else{
isSchemaChange = 0;
--- /dev/null
+# 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
+