Fix the saveCursorPosition() routine in btree.c so that it works

correctly for a eState=CURSOR_SKIPNEXT cursor.

FossilOrigin-Name: 37866b4d483296ab9b7fcb9f5486695d4c2b8ddd
This commit is contained in:
drh 2015-03-25 17:35:01 +00:00
parent cbd3349ab9
commit d2f83139f3
4 changed files with 72 additions and 12 deletions

View File

@ -1,5 +1,5 @@
C Reactivate\san\solder\sassert()\s(adding\san\s"||\sCORRUPT_DB"\sterm)\sand\sadd\sa\nnew\sassert()\sin\sbtree.c.
D 2015-03-25T13:06:54.837
C Fix\sthe\ssaveCursorPosition()\sroutine\sin\sbtree.c\sso\sthat\sit\sworks\ncorrectly\sfor\sa\seState=CURSOR_SKIPNEXT\scursor.
D 2015-03-25T17:35:01.825
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 88a3e6261286db378fdffa1124cad11b3c05f5bb
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -173,7 +173,7 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
F src/backup.c ff743689c4d6c5cb55ad42ed9d174b2b3e71f1e3
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79
F src/btree.c 3634c2ee748bbbb2488cdca9dc8fc8c7bdc2f66f
F src/btree.c 933ab4ad883546193f5fd55f840299165adb8069
F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1
F src/btreeInt.h 2bfefc01875d8da066504c233ec259fcb3b2ef72
F src/build.c 0419bba592c22f6d00e6d57a2ca7136720d02c1a
@ -384,6 +384,7 @@ F test/boundary3.test 56ef82096b4329aca2be74fa1e2b0f762ea0eb45
F test/boundary4.tcl 0bb4b1a94f4fc5ae59b79b9a2b7a140c405e2983
F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b
F test/btree01.test e08b3613540145b353f20c81cb18ead54ff12e0f
F test/btree02.test fe69453d474d8154d19b904157ff1db4812fed99
F test/btreefault.test c2bcb542685eea44621275cfedbd8a13f65201e3
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de
@ -1246,7 +1247,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 42d1793d6516e285a8925bbfd96b3d3375603d15
R 90535e28cf02760b75aa0324ce2f944c
P 1e96520ac1d12ca83f019a60482efa0a074f2f94
R 0d2b32f8ac05ffe0443a79d106bd4efe
U drh
Z 7ee968129b9c07925188972da6333faa
Z 2f58ba8b67469927a3c7d533210b0ef3

View File

@ -1 +1 @@
1e96520ac1d12ca83f019a60482efa0a074f2f94
37866b4d483296ab9b7fcb9f5486695d4c2b8ddd

View File

@ -600,10 +600,15 @@ static void btreeReleaseAllCursorPages(BtCursor *pCur){
static int saveCursorPosition(BtCursor *pCur){
int rc;
assert( CURSOR_VALID==pCur->eState );
assert( CURSOR_VALID==pCur->eState || CURSOR_SKIPNEXT==pCur->eState );
assert( 0==pCur->pKey );
assert( cursorHoldsMutex(pCur) );
if( pCur->eState==CURSOR_SKIPNEXT ){
pCur->eState = CURSOR_VALID;
}else{
pCur->skipNext = 0;
}
rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
assert( rc==SQLITE_OK ); /* KeySize() cannot fail */
@ -674,7 +679,7 @@ static int SQLITE_NOINLINE saveCursorsOnList(
){
do{
if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ){
if( p->eState==CURSOR_VALID ){
if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){
int rc = saveCursorPosition(p);
if( SQLITE_OK!=rc ){
return rc;
@ -746,17 +751,19 @@ static int btreeMoveto(
*/
static int btreeRestoreCursorPosition(BtCursor *pCur){
int rc;
int skipNext;
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState>=CURSOR_REQUIRESEEK );
if( pCur->eState==CURSOR_FAULT ){
return pCur->skipNext;
}
pCur->eState = CURSOR_INVALID;
rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &pCur->skipNext);
rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext);
if( rc==SQLITE_OK ){
sqlite3_free(pCur->pKey);
pCur->pKey = 0;
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID );
pCur->skipNext |= skipNext;
if( pCur->skipNext && pCur->eState==CURSOR_VALID ){
pCur->eState = CURSOR_SKIPNEXT;
}
@ -808,7 +815,7 @@ int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow){
*pDifferentRow = 1;
return rc;
}
if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){
if( pCur->eState!=CURSOR_VALID || pCur->skipNext!=0 ){
*pDifferentRow = 1;
}else{
*pDifferentRow = 0;
@ -3625,7 +3632,7 @@ int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
int i;
if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){
if( p->eState==CURSOR_VALID ){
if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){
rc = saveCursorPosition(p);
if( rc!=SQLITE_OK ){
(void)sqlite3BtreeTripAllCursors(pBtree, rc, 0);

52
test/btree02.test Normal file
View File

@ -0,0 +1,52 @@
# 2015-03-25
#
# 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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# The focus of this script is making multiple calls to saveCursorPosition()
# and restoreCursorPosition() when cursors have eState==CURSOR_SKIPNEXT
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
load_static_extension db eval
do_execsql_test btree02-100 {
CREATE TABLE t1(a TEXT, ax INTEGER, b INT, PRIMARY KEY(a,ax)) WITHOUT ROWID;
WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<10)
INSERT INTO t1(a,ax,b) SELECT printf('%02x',i), random(), i FROM c;
CREATE INDEX t1a ON t1(a);
CREATE TABLE t2(x,y);
CREATE TABLE t3(cnt);
WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<4)
INSERT INTO t3(cnt) SELECT i FROM c;
SELECT count(*) FROM t1;
} {10}
do_test btree02-110 {
db eval BEGIN
set i 0
db eval {SELECT a, ax, b, cnt FROM t1 CROSS JOIN t3 WHERE b IS NOT NULL} {
db eval {INSERT INTO t2(x,y) VALUES($b,$cnt)}
# puts "a,b,cnt = ($a,$b,$cnt)"
incr i
if {$i%2==1} {
set bx [expr {$b+1000}]
# puts "INSERT ($a),$bx"
db eval {INSERT INTO t1(a,ax,b) VALUES(printf('(%s)',$a),random(),$bx)}
} else {
# puts "DELETE a=$a"
db eval {DELETE FROM t1 WHERE a=$a}
}
db eval {COMMIT; BEGIN}
}
db one {COMMIT; SELECT count(*) FROM t1;}
} {20}
finish_test