Extra tests and resulting bugfixes for btree cursors. (CVS 2106)
FossilOrigin-Name: e1530854c9004c25f5ffa21f9cfb9c44c83cc7f0
This commit is contained in:
parent
602479eae8
commit
c7dc75334f
16
manifest
16
manifest
@ -1,5 +1,5 @@
|
||||
C Clarify\sthe\sLIMIT\sclause\sin\sthe\sdocumentation.\s\sTicket\s#1002.\s(CVS\s2105)
|
||||
D 2004-11-16T23:21:57
|
||||
C Extra\stests\sand\sresulting\sbugfixes\sfor\sbtree\scursors.\s(CVS\s2106)
|
||||
D 2004-11-17T10:22:03
|
||||
F Makefile.in e747bb5ba34ccbdd81f79dcf1b2b33c02817c21d
|
||||
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
|
||||
F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1
|
||||
@ -29,7 +29,7 @@ F sqlite3.def dbaeb20c153e1d366e8f421b55a573f5dfc00863
|
||||
F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a
|
||||
F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689
|
||||
F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea
|
||||
F src/btree.c c878e87a415a429a335bf26d834a311c5c40f5d1
|
||||
F src/btree.c 49b09718cd988d1c7c981b03e94679bc10b5f711
|
||||
F src/btree.h 861e40b759a195ba63819740e484390012cf81ab
|
||||
F src/build.c a95eb1181247368b0ffe2eed121a43735976a964
|
||||
F src/date.c 65536e7ea04fdde6e0551264fca15966966e171f
|
||||
@ -101,7 +101,7 @@ F test/btree4.test 3797b4305694c7af6828675b0f4b1424b8ca30e4
|
||||
F test/btree5.test 8e5ff32c02e685d36516c6499add9375fe1377f2
|
||||
F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027
|
||||
F test/btree7.test a6d3b842db22af97dd14b989e90a2fd96066b72f
|
||||
F test/btree8.test 12db22f6963d9b33a5aa8e8b766033afc82b22c2
|
||||
F test/btree8.test d4e5932e54ae10f934d92ebaff94b594923d9ebc
|
||||
F test/capi2.test cd5e149564094bda9a587e70ec5949863222cd23
|
||||
F test/capi3.test da88858ea5318c0cbd0990be9d8db0237496a3dc
|
||||
F test/capi3b.test 5b6a66f9f295f79f443b5d3f33187fa5ef6cf336
|
||||
@ -258,7 +258,7 @@ F www/tclsqlite.tcl 560ecd6a916b320e59f2917317398f3d59b7cc25
|
||||
F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618
|
||||
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
|
||||
F www/whentouse.tcl fdacb0ba2d39831e8a6240d05a490026ad4c4e4c
|
||||
P a2e1c35b327e33684ab19e5f65727c42c7b2949c
|
||||
R 6e228a47591f03e112c91e1ff652d971
|
||||
U drh
|
||||
Z 79f791e3dea5459910a0112484707216
|
||||
P e05f52d907e267b4f9ea204427229e7d7ef58641
|
||||
R 41b0c2001282ed7479703649a89b1f7a
|
||||
U danielk1977
|
||||
Z f5df5e3af5cd05954b652b1bc18662f8
|
||||
|
@ -1 +1 @@
|
||||
e05f52d907e267b4f9ea204427229e7d7ef58641
|
||||
e1530854c9004c25f5ffa21f9cfb9c44c83cc7f0
|
49
src/btree.c
49
src/btree.c
@ -9,7 +9,7 @@
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: btree.c,v 1.219 2004/11/16 15:50:20 danielk1977 Exp $
|
||||
** $Id: btree.c,v 1.220 2004/11/17 10:22:03 danielk1977 Exp $
|
||||
**
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** For a detailed discussion of BTrees, refer to
|
||||
@ -3951,6 +3951,18 @@ static int balance_nonroot(MemPage *pPage){
|
||||
/* If the cursor is not valid, do not do anything with it. */
|
||||
if( !pCur->isValid ) continue;
|
||||
|
||||
/* If the cursor pointed to one of the cells moved around during the
|
||||
** balancing, then set variable iCell to the index of the cell in apCell.
|
||||
** This is used by the block below to figure out where the cell was
|
||||
** moved to, and adjust the cursor appropriately.
|
||||
**
|
||||
** If the cursor points to the parent page, but the cell was not involved
|
||||
** in the balance, then declare the cache of the cell-parse invalid, as a
|
||||
** defragmentation may of occured during the balance. Also, if the index
|
||||
** of the cell is greater than that of the divider cells, then it may
|
||||
** need to be adjusted (in case there are now more or less divider cells
|
||||
** than there were before the balancing).
|
||||
*/
|
||||
for(i=0; iCell<0 && i<nOld; i++){
|
||||
if( pgno==apCopy[i]->pgno ){
|
||||
iCell = nCellCnt + pCur->idx;
|
||||
@ -3958,7 +3970,6 @@ static int balance_nonroot(MemPage *pPage){
|
||||
}
|
||||
nCellCnt += (apCopy[i]->nCell + apCopy[i]->nOverflow) + (leafData?0:1);
|
||||
}
|
||||
|
||||
if( pgno==pParent->pgno ){
|
||||
assert( !leafData );
|
||||
assert( iCell==-1 );
|
||||
@ -3971,10 +3982,14 @@ static int balance_nonroot(MemPage *pPage){
|
||||
TRACE(("BALANCE: Cursor %p migrates from %d,%d to %d,%d\n",
|
||||
pCur, pgno, pCur->idx, pgno, pCur->idx+(nNew-nOld)));
|
||||
pCur->idx += (nNew-nOld);
|
||||
pCur->info.nSize = 0;
|
||||
}
|
||||
pCur->info.nSize = 0;
|
||||
}
|
||||
|
||||
/* If iCell is greater than or equal to zero, then pCur points at a
|
||||
** cell that was moved around during the balance. Figure out where
|
||||
** the cell was moved to and adjust pCur to match.
|
||||
*/
|
||||
if( iCell>=0 ){
|
||||
int idxNew;
|
||||
Pgno pgnoNew;
|
||||
@ -4247,6 +4262,7 @@ static int balance_deeper(MemPage *pPage){
|
||||
cdata = pChild->aData;
|
||||
memcpy(cdata, &data[hdr], pPage->cellOffset+2*pPage->nCell-hdr);
|
||||
memcpy(&cdata[brk], &data[brk], usableSize-brk);
|
||||
assert( pChild->isInit==0 );
|
||||
rc = initPage(pChild, pPage);
|
||||
if( rc ) return rc;
|
||||
memcpy(pChild->aOvfl, pPage->aOvfl, pPage->nOverflow*sizeof(pPage->aOvfl[0]));
|
||||
@ -4524,8 +4540,9 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
||||
}
|
||||
rc = sqlite3pager_write(leafCur.pPage->aData);
|
||||
if( rc ) goto delete_out;
|
||||
TRACE(("DELETE: table=%d delete internal from %d replace from leaf %d\n",
|
||||
pCur->pgnoRoot, pPage->pgno, leafCur.pPage->pgno));
|
||||
TRACE(("DELETE: table=%d delete internal from %d,%d replace "
|
||||
"from leaf %d,%d\n", pCur->pgnoRoot, pPage->pgno, idx,
|
||||
leafCur.pPage->pgno, leafCur.idx));
|
||||
|
||||
/* Drop the cell from the internal page. Make a copy of the cell from
|
||||
** the leaf page into memory obtained from malloc(). Insert it into
|
||||
@ -4549,6 +4566,10 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
||||
/* If there are any cursors that point to the leaf-cell, move them
|
||||
** so that they point at internal cell. This is easiest done by
|
||||
** calling BtreePrevious().
|
||||
**
|
||||
** Also, any cursors that point to the internal page have their
|
||||
** cached parses invalidated, as the insertCell() above may have
|
||||
** caused a defragmation.
|
||||
*/
|
||||
for(pCur2=pBt->pCursor; pCur2; pCur2 = pCur2->pNext){
|
||||
if( pCur2->pPage==leafCur.pPage && pCur2->idx==leafCur.idx ){
|
||||
@ -4563,6 +4584,9 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
||||
assert( pCur2->idx==idx );
|
||||
pCur2->delShift = delShiftSave;
|
||||
}
|
||||
if( pCur2->pPage==pPage ){
|
||||
pCur2->info.nSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Balance the internal page. Free the memory allocated for the
|
||||
@ -4575,8 +4599,8 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
||||
|
||||
for(pCur2=pBt->pCursor; pCur2; pCur2 = pCur2->pNext){
|
||||
if( pCur2->pPage==leafCur.pPage && pCur2->idx>leafCur.idx ){
|
||||
TRACE(("DELETE: Cursor %p migrates from %d,%d to %d,%d\n",
|
||||
pCur2, pPage->pgno, pCur2->idx, pPage->pgno, pCur2->idx-1));
|
||||
TRACE(("DELETE: Cursor %p migrates from %d,%d to %d,%d\n", pCur2,
|
||||
leafCur.pPage->pgno,pCur2->idx,leafCur.pPage->pgno, pCur2->idx-1));
|
||||
pCur2->idx--;
|
||||
pCur2->info.nSize = 0;
|
||||
}
|
||||
@ -4988,7 +5012,7 @@ int sqlite3BtreeFlags(BtCursor *pCur){
|
||||
** is used for debugging and testing only.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){
|
||||
static int btreePageDump(Btree *pBt, int pgno, int recursive, MemPage *pParent){
|
||||
int rc;
|
||||
MemPage *pPage;
|
||||
int i, j, c;
|
||||
@ -5004,7 +5028,7 @@ int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){
|
||||
rc = getPage(pBt, (Pgno)pgno, &pPage);
|
||||
isInit = pPage->isInit;
|
||||
if( pPage->isInit==0 ){
|
||||
initPage(pPage, 0);
|
||||
initPage(pPage, pParent);
|
||||
}
|
||||
if( rc ){
|
||||
return rc;
|
||||
@ -5074,16 +5098,19 @@ int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){
|
||||
if( recursive && !pPage->leaf ){
|
||||
for(i=0; i<nCell; i++){
|
||||
unsigned char *pCell = findCell(pPage, i);
|
||||
sqlite3BtreePageDump(pBt, get4byte(pCell), 1);
|
||||
btreePageDump(pBt, get4byte(pCell), 1, pPage);
|
||||
idx = get2byte(pCell);
|
||||
}
|
||||
sqlite3BtreePageDump(pBt, get4byte(&data[hdr+8]), 1);
|
||||
btreePageDump(pBt, get4byte(&data[hdr+8]), 1, pPage);
|
||||
}
|
||||
pPage->isInit = isInit;
|
||||
sqlite3pager_unref(data);
|
||||
fflush(stdout);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){
|
||||
return btreePageDump(pBt, pgno, recursive, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
|
135
test/btree8.test
135
test/btree8.test
@ -13,7 +13,7 @@
|
||||
# this file tests that existing cursors are correctly repositioned
|
||||
# when entries are inserted into or deleted from btrees.
|
||||
#
|
||||
# $Id: btree8.test,v 1.3 2004/11/16 15:50:21 danielk1977 Exp $
|
||||
# $Id: btree8.test,v 1.4 2004/11/17 10:22:04 danielk1977 Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -26,7 +26,6 @@ source $testdir/tester.tcl
|
||||
# btree-8.4.*: Test cursor persistence when deleting records from indices.
|
||||
#
|
||||
|
||||
|
||||
# Transform the number $num into a string of length $len by repeating the
|
||||
# string representation of the number as many times as necessary. Repeats
|
||||
# are seperated by a '.' character. Eg:
|
||||
@ -92,8 +91,12 @@ db close
|
||||
#
|
||||
|
||||
# Open the database at the btree level and begin a transaction
|
||||
do_test btree8-1.1 {
|
||||
do_test btree8-1.0 {
|
||||
set ::bt [btree_open test.db 100 0]
|
||||
expr 0
|
||||
} {0}
|
||||
|
||||
do_test btree8-1.1 {
|
||||
btree_begin_transaction $::bt
|
||||
expr 0
|
||||
} {0}
|
||||
@ -280,5 +283,131 @@ foreach csr $csr_list {
|
||||
}
|
||||
set csr_list [list]
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# Tests btree8.5.* also test the types of trees used for SQL indices.
|
||||
# This time, 300 entries of 150 bytes each are inserted into the btree (this
|
||||
# produces a tree of height 3 - root page is the grandparent of the leaves).
|
||||
# A cursor points at each entry. We check that all cursors retain there
|
||||
# validity when:
|
||||
#
|
||||
# * Each entry is deleted (test cases btree-8.5.1.*)
|
||||
# * An entry is inserted just after/before each existing key (test
|
||||
# cases btree-8.5.2.*).
|
||||
#
|
||||
|
||||
# Open a cursor on each entry in the tree in B-tree $bt, root-page $tnum.
|
||||
# Return a list of the cursors.
|
||||
#
|
||||
proc open_cursors {bt tnum} {
|
||||
set c [btree_cursor $bt $tnum 0]
|
||||
set csr_list [list]
|
||||
for {btree_first $c} {![btree_eof $c]} {btree_next $c} {
|
||||
set c2 [btree_cursor $bt $tnum 0]
|
||||
btree_move_to $c2 [btree_key $c]
|
||||
lappend csr_list $c2
|
||||
}
|
||||
btree_close_cursor $c
|
||||
return $csr_list
|
||||
}
|
||||
|
||||
# Close all cursors in the list $csr_list.
|
||||
#
|
||||
proc close_cursors {csr_list} {
|
||||
foreach c $csr_list {
|
||||
btree_close_cursor $c
|
||||
}
|
||||
}
|
||||
|
||||
# Check that the key for each cursor in csr_list matches the corresponding
|
||||
# entry in key_list. If not, raise an exception.
|
||||
#
|
||||
proc check_cursors {key_list csr_list} {
|
||||
foreach k $key_list c $csr_list {
|
||||
if {[string compare $k [btree_key $c]]} {
|
||||
error "Csr key '[btree_key $c]' - should be '$k'"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Set up the table used for the btree-8.5.* tests
|
||||
do_test btree-8.5.0 {
|
||||
btree_begin_transaction $::bt
|
||||
set c [btree_cursor $::bt $::inum 1]
|
||||
for {set i 2} {$i<=600} {incr i 2} {
|
||||
set key [num_to_string $i 150]
|
||||
lappend key_list $key
|
||||
btree_insert $c $key ""
|
||||
}
|
||||
btree_close_cursor $c
|
||||
btree_commit $::bt
|
||||
} {}
|
||||
|
||||
# Test cases btree-8.5.1.* - Check that cursors survive DELETE operations.
|
||||
set testnum 0
|
||||
foreach key [lrange $::key_list 0 0] {
|
||||
incr testnum
|
||||
|
||||
btree_begin_transaction $::bt
|
||||
|
||||
# Open the 300 cursors.
|
||||
do_test btree-8.5.1.$testnum.1 {
|
||||
set ::csr_list [open_cursors $::bt $::inum]
|
||||
llength $::csr_list
|
||||
} {300}
|
||||
|
||||
# Delete an entry.
|
||||
do_test btree-8.5.1.$testnum.2 {
|
||||
set c [btree_cursor $::bt $::inum 1]
|
||||
btree_move_to $c $::key
|
||||
btree_delete $c
|
||||
btree_close_cursor $c
|
||||
} {}
|
||||
|
||||
# Check that all 300 cursors are Ok.
|
||||
do_test btree-8.5.1.$testnum.3 {
|
||||
catch {
|
||||
set e [lsearch $::key_list $::key]
|
||||
check_cursors [lreplace $::key_list $e $e ""] $::csr_list
|
||||
} msg
|
||||
set msg
|
||||
} {}
|
||||
|
||||
close_cursors $::csr_list
|
||||
btree_rollback $::bt
|
||||
}
|
||||
|
||||
# Test cases btree-8.5.2.* - Check that cursors survive INSERT operations.
|
||||
set testnum 0
|
||||
foreach key $::key_list {
|
||||
incr testnum
|
||||
|
||||
btree_begin_transaction $::bt
|
||||
|
||||
# Open the 300 cursors.
|
||||
do_test btree-8.5.2.$testnum.1 {
|
||||
set ::csr_list [open_cursors $::bt $::inum]
|
||||
llength $::csr_list
|
||||
} {300}
|
||||
|
||||
# Insert new entries, one before the key, and one after.
|
||||
do_test btree-8.5.2.$testnum.2 {
|
||||
set c [btree_cursor $::bt $::inum 1]
|
||||
btree_insert $c "$::key$::key" ""
|
||||
btree_insert $c [string range $::key 0 end-1] ""
|
||||
btree_close_cursor $c
|
||||
} {}
|
||||
|
||||
# Check that all 300 cursors are Ok.
|
||||
do_test btree-8.5.2.$testnum.3 {
|
||||
catch {
|
||||
check_cursors $::key_list $::csr_list
|
||||
} msg
|
||||
set msg
|
||||
} {}
|
||||
|
||||
close_cursors $::csr_list
|
||||
btree_rollback $::bt
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user