-C Get\sthe\scode\sback\sto\sthe\spoint\swhere\sit\swill\scompile\sthe\sbtree.c\stests.\nMove\sthe\sdefault\skey\scomparison\sroutine\sfrom\sbtree.c\sinto\svdbeaux.c.\nCommented\sout\scode\sin\svdbe.c\sthat\swill\sneed\sto\sbe\sfixed.\s(CVS\s1326)
-D 2004-05-08T10:56:11
+C More\sbtree.c\sbug\sfixes.\s(CVS\s1327)
+D 2004-05-08T20:07:40
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
F src/attach.c fa9a58234406d84eeb900517d0c0adc4b2da051a
F src/auth.c a2a46e3ed7799134cf3d2dd5ae6650115f26b653
-F src/btree.c 27600f910e247c905389ecf3f246f27e9649cbea
-F src/btree.h 07a16dbb8c29291d0768b956649350d8f8c3dac3
+F src/btree.c 26f7caa992e7828db3c045c19a67161150e8ebc4
+F src/btree.h e111dde03373721afbe87e374adf57656c45f0c5
F src/btree_rb.c 47e5b5ec90846af392b5668b34648198ba459561
F src/build.c 21b6645c966970dac51bcccfa8650403a3f56210
F src/copy.c 3c33157f6b4919d6851602b78008c67d466cdadd
F src/md5.c 01d2f55b06316d242749759b6a37186439ef7fe3
F src/os.c 4092dcc87e66f49ed660fae1519569a0cee34da0
F src/os.h fbb2f6595fc34fa351830d88fe1c6b85118f0383
-F src/pager.c 97a675f1653ec2dc2907ebc247b1bae5a4d6ed9a
+F src/pager.c 350f5cd153b248c67058cafc75c3f1b7d28c2b0b
F src/pager.h 0c95b18f2785b58bfbb2b6f6a221f23caf378687
F src/parse.y d0258aa3cc8b0c5742b07b699d10fa98f3caea7d
F src/pragma.c d9f8332a1a87bc4058113ee9686e0c14286d69fd
F src/tclsqlite.c 21147148e7b57a0bb7409cff5878c60470df9acc
F src/test1.c 67a72fa1f5f6d41c838fa97f324f8dbfb4051413
F src/test2.c 8dab493c7eccd2c7bb93a8e31f7db60f14e61b7b
-F src/test3.c c5a25235b6b2ada516550eb17b57f8dd002f6b41
+F src/test3.c e9bb798e010ac44221b9d23ed94f9eb76d7a32a8
F src/test4.c 92d2a10380a65d61e5527a556f604bfde16411e8
F src/test5.c eb39aac8fed61bd930b92613cd705c145244074a
F src/tokenize.c 256a3cf0ff938cd79774d7f95173d74281912df9
F test/bigfile.test ea904b853ce2d703b16c5ce90e2b54951bc1ae81
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
F test/bind.test 56a57043b42c4664ca705f6050e56717a8a6699a
-F test/btree.test d9d00f8ac8bfa4945861f92c5b14fbe884d874c4
+F test/btree.test c26328987d486893282dd25c0cbbeba2cd9b8f95
F test/btree2.test e3b81ec33dc2f89b3e6087436dfe605b870c9080
F test/btree3.test e597fb59be2ac0ea69c62aaa2064e998e528b665
F test/btree3rb.test 127efcf5cdfcc352054e7db12622b01cdd8b36ac
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P 1a09a1ada199b76926c64bd79ad39d6d50a75011
-R 020d676c42c3c99a03395fc2bd1d45bd
+P 2bca92240b16a51f78661c3ba4d779d231780f8d
+R 49eb87c67ff9b6cc18c64077117ae3ba
U drh
-Z e3b04ec339a83a6885a62a5e117d1378
+Z 62f7ad80381b47a4b8e3828b4a596f0a
** May you share freely, never taking more than you give.
**
*************************************************************************
-** $Id: btree.c,v 1.115 2004/05/08 10:56:11 drh Exp $
+** $Id: btree.c,v 1.116 2004/05/08 20:07:40 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
*/
struct MemPage {
u32 notUsed;
- struct Btree *pBt; /* Pointer back to BTree structure */
- unsigned char *aData; /* Pointer back to the start of the page */
u8 isInit; /* True if previously initialized */
u8 idxShift; /* True if Cell indices have changed */
u8 isOverfull; /* Some aCell[] do not fit on page */
u8 leaf; /* True if leaf flag is set */
u8 zeroData; /* True if zero data flag is set */
u8 hdrOffset; /* 100 for page 1. 0 otherwise */
- Pgno pgno; /* Page number for this page */
- MemPage *pParent; /* The parent of this page. NULL for root */
int idxParent; /* Index in pParent->aCell[] of this node */
int nFree; /* Number of free bytes on the page */
int nCell; /* Number of entries on this page */
int nCellAlloc; /* Number of slots allocated in aCell[] */
unsigned char **aCell; /* Pointer to start of each cell */
+ struct Btree *pBt; /* Pointer back to BTree structure */
+
+ unsigned char *aData; /* Pointer back to the start of the page */
+ Pgno pgno; /* Page number for this page */
+ MemPage *pParent; /* The parent of this page. NULL for root */
};
/*
assert( pParent==0 || pParent->pBt==pPage->pBt );
assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
assert( pPage->aData == &((unsigned char*)pPage)[-pPage->pBt->pageSize] );
- assert( pPage->isInit==0 || pPage->pParent==pParent );
- if( pPage->isInit ) return SQLITE_OK;
- assert( pPage->pParent==0 );
- pPage->pParent = pParent;
- if( pParent ){
+ assert( pPage->pParent==0 || pPage->pParent==pParent );
+ if( pPage->pParent==0 && pParent!=0 ){
+ pPage->pParent = pParent;
sqlite3pager_ref(pParent->aData);
}
+ if( pPage->isInit ) return SQLITE_OK;
pPage->nCell = pPage->nCellAlloc = 0;
assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) );
hdr = pPage->hdrOffset;
pPage->intKey = (c & PTF_INTKEY)!=0;
pPage->zeroData = (c & PTF_ZERODATA)!=0;
pPage->leaf = (c & PTF_LEAF)!=0;
+ pPage->isOverfull = 0;
+ pPage->idxShift = 0;
pageSize = pPage->pBt->pageSize;
/* Initialize the cell count and cell pointers */
int hdr = pPage->hdrOffset;
int first;
+ assert( sqlite3pager_pagenumber(data)==pPage->pgno );
+ assert( &data[pBt->pageSize] == (unsigned char*)pPage );
assert( sqlite3pager_iswriteable(data) );
memset(&data[hdr], 0, pBt->pageSize - hdr);
data[hdr] = flags;
pPage->leaf = (flags & PTF_LEAF)!=0;
pPage->zeroData = (flags & PTF_ZERODATA)!=0;
pPage->hdrOffset = hdr;
+ pPage->isOverfull = 0;
+ pPage->idxShift = 0;
+ pPage->isInit = 1;
}
/*
}
}
+#ifdef SQLITE_TEST
+/*
+** Print debugging information about all cursors to standard output.
+*/
+void sqlite3BtreeCursorList(Btree *pBt){
+ BtCursor *pCur;
+ for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
+ MemPage *pPage = pCur->pPage;
+ char *zMode = pCur->wrFlag ? "rw" : "ro";
+ printf("CURSOR %08x rooted at %4d(%s) currently at %d.%d%s\n",
+ (int)pCur, pCur->pgnoRoot, zMode,
+ pPage ? pPage->pgno : 0, pCur->idx,
+ pCur->isValid ? "" : " eof"
+ );
+ }
+}
+#endif
+
/*
** Rollback the transaction in progress. All cursors will be
** invalided by this operation. Any attempt to use a cursor
*/
static int isRootPage(MemPage *pPage){
MemPage *pParent = pPage->pParent;
- assert( pParent==0 || pParent->isInit );
- if( pParent==0 || (pParent->pgno==1 && pParent->nCell==0) ) return 1;
+ if( pParent==0 ) return 1;
+ if( pParent->pgno>1 ) return 0;
+ if( get2byte(&pParent->aData[pParent->hdrOffset+3])==0 ) return 1;
return 0;
}
put2byte(&pPage->aData[idxFrom], 0);
}
+/*
+** GCC does not define the offsetof() macro so we'll have to do it
+** ourselves.
+*/
+#ifndef offsetof
+#define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD))
+#endif
+
/*
** Move the content of the page at pFrom over to pTo. The pFrom->aCell[]
** pointers that point into pFrom->aData[] must be adjusted to point
**
** Over this operation completes, the meta data for pFrom is zeroed.
*/
-static void copyPage(MemPage *pTo, MemPage *pFrom){
+static void movePage(MemPage *pTo, MemPage *pFrom){
uptr from, to;
int i;
int pageSize;
assert( pTo->hdrOffset==0 );
ofst = pFrom->hdrOffset;
- pageSize = pTo->pBt->pageSize;
+ pageSize = pFrom->pBt->pageSize;
sqliteFree(pTo->aCell);
- memcpy(pTo->aData, &pFrom->aData[ofst], pageSize - ofst + sizeof(MemPage));
- memset(pFrom, 0, sizeof(MemPage));
+ memcpy(pTo->aData, &pFrom->aData[ofst], pageSize - ofst);
+ memcpy(pTo, pFrom, offsetof(MemPage, aData));
+ pFrom->isInit = 0;
+ pFrom->aCell = 0;
assert( pTo->aData[5]<155 );
pTo->aData[5] += ofst;
pTo->isOverfull = pFrom->isOverfull;
int usableSpace; /* Bytes in pPage beyond the header */
int pageFlags; /* Value of pPage->aData[0] */
int subtotal; /* Subtotal of bytes in cells on one page */
+ MemPage *extraUnref = 0; /* Unref this page if not zero */
MemPage *apOld[NB]; /* pPage and up to two siblings */
Pgno pgnoOld[NB]; /* Page numbers for each page in apOld[] */
MemPage *apCopy[NB]; /* Private copies of apOld[] pages */
rc = allocatePage(pBt, &pChild, &pgnoChild, pPage->pgno);
if( rc ) return rc;
assert( sqlite3pager_iswriteable(pChild->aData) );
- copyPage(pChild, pPage);
+ movePage(pChild, pPage);
+ assert( pChild->aData[0]==pPage->aData[pPage->hdrOffset] );
pChild->pParent = pPage;
- pChild->idxParent = 0;
sqlite3pager_ref(pPage->aData);
+ pChild->idxParent = 0;
pChild->isOverfull = 1;
- zeroPage(pPage, pPage->aData[pPage->hdrOffset] & ~PTF_LEAF);
+ zeroPage(pPage, pChild->aData[0] & ~PTF_LEAF);
put4byte(&pPage->aData[pPage->hdrOffset+6], pChild->pgno);
pParent = pPage;
pPage = pChild;
+ extraUnref = pChild;
}
rc = sqlite3pager_write(pParent->aData);
if( rc ) return rc;
** process of being overwritten.
*/
for(i=0; i<nOld; i++){
- apCopy[i] = (MemPage*)&aCopy[i+1][-sizeof(MemPage)];
- memset(apCopy[i], 0, sizeof(MemPage));
- apCopy[i]->aData = &((u8*)apCopy)[-pBt->pageSize];
- copyPage(apCopy[i], apOld[i]);
+ MemPage *p = apCopy[i] = (MemPage*)&aCopy[i+1][-sizeof(MemPage)];
+ p->aData = &((u8*)p)[-pBt->pageSize];
+ p->aCell = 0;
+ p->hdrOffset = 0;
+ movePage(p, apOld[i]);
}
/*
nCell++;
}
if( i<nOld-1 ){
- szCell[nCell] = cellSize(pParent, apDiv[i]) - leafCorrection;
- memcpy(aTemp[i], apDiv[i], szCell[nCell] + leafCorrection);
+ szCell[nCell] = cellSize(pParent, apDiv[i]);
+ memcpy(aTemp[i], apDiv[i], szCell[nCell]);
apCell[nCell] = &aTemp[i][leafCorrection];
dropCell(pParent, nxDiv, szCell[nCell]);
- assert( get4byte(&apCell[nCell][2])==pgnoOld[i] );
+ szCell[nCell] -= leafCorrection;
+ assert( get4byte(&aTemp[i][2])==pgnoOld[i] );
if( !pOld->leaf ){
assert( leafCorrection==0 );
/* The right pointer of the child page pOld becomes the left
assert( pPage->pgno>1 );
pageFlags = pPage->aData[0];
for(i=0; i<k; i++){
+ MemPage *pNew;
if( i<nOld ){
- apNew[i] = apOld[i];
+ pNew = apNew[i] = apOld[i];
pgnoNew[i] = pgnoOld[i];
apOld[i] = 0;
- sqlite3pager_write(apNew[i]);
+ sqlite3pager_write(pNew->aData);
}else{
- rc = allocatePage(pBt, &apNew[i], &pgnoNew[i], pgnoNew[i-1]);
+ rc = allocatePage(pBt, &pNew, &pgnoNew[i], pgnoNew[i-1]);
if( rc ) goto balance_cleanup;
+ apNew[i] = pNew;
}
nNew++;
- zeroPage(apNew[i], pageFlags);
- apNew[i]->isInit = 1;
+ zeroPage(pNew, pageFlags);
}
/* Free any old pages that were not reused as new pages.
while( i<nOld ){
rc = freePage(apOld[i]);
if( rc ) goto balance_cleanup;
- sqlite3pager_unref(apOld[i]->aData);
+ releasePage(apOld[i]);
apOld[i] = 0;
i++;
}
/*
** balance the parent page.
*/
+ assert( pPage->isInit );
+ assert( pParent->isInit );
rc = balance(pParent);
+
/*
** Cleanup before returning.
for(i=0; i<nOld; i++){
releasePage(apOld[i]);
if( apCopy[i] ){
- releasePage(apCopy[i]->pParent);
sqliteFree(apCopy[i]->aCell);
}
}
releasePage(apNew[i]);
}
releasePage(pParent);
+ releasePage(extraUnref);
return rc;
}
unsigned char *pNext;
int szNext;
int notUsed;
+ unsigned char tempbuf[4];
getTempCursor(pCur, &leafCur);
rc = sqlite3BtreeNext(&leafCur, ¬Used);
if( rc!=SQLITE_OK ){
dropCell(pPage, pCur->idx, cellSize(pPage, pCell));
pNext = leafCur.pPage->aCell[leafCur.idx];
szNext = cellSize(leafCur.pPage, pNext);
- insertCell(pPage, pCur->idx, &pNext[-4], szNext+4);
+ memcpy(tempbuf, &pNext[-2], 4);
put4byte(&pNext[-2], pgnoChild);
+ insertCell(pPage, pCur->idx, &pNext[-4], szNext+4);
rc = balance(pPage);
if( rc ) return rc;
+ memcpy(&pNext[-2], tempbuf, 4);
dropCell(leafCur.pPage, leafCur.idx, szNext);
rc = balance(leafCur.pPage);
releaseTempCursor(&leafCur);
int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){
int rc;
MemPage *pPage;
- int i, j;
+ int i, j, c;
int nFree;
u16 idx;
int hdr;
}
hdr = pPage->hdrOffset;
data = pPage->aData;
+ c = data[hdr];
+ pPage->intKey = (c & PTF_INTKEY)!=0;
+ pPage->zeroData = (c & PTF_ZERODATA)!=0;
+ pPage->leaf = (c & PTF_LEAF)!=0;
printf("PAGE %d: flags=0x%02x frag=%d\n", pgno,
data[hdr], data[hdr+5]);
i = 0;
# This file implements regression tests for SQLite library. The
# focus of this script is btree database backend
#
-# $Id: btree.test,v 1.19 2004/05/08 10:56:20 drh Exp $
+# $Id: btree.test,v 1.20 2004/05/08 20:07:40 drh Exp $
set testdir [file dirname $argv0]
lindex [btree_pager_stats $::b1] 1
} {2}
do_test btree-10.3 {
- for {set i 1} {$i<=20} {incr i} {
+ for {set i 1} {$i<=30} {incr i} {
set key [format %03d $i]
set data "*** $key *** $key *** $key *** $key ***"
btree_insert $::c1 $key $data
}
select_keys $::c1
-} {001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020}
-#btree_page_dump $::b1 7
-btree_page_dump $::b1 1
-#btree_page_dump $::b1 6
+} {001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030}
+#btree_tree_dump $::b1 2
do_test btree-10.4 {
- btree_move_to $::c1 011
+ # The divider entry is 012. This is found by uncommenting the
+ # btree_tree_dump call above and looking at the tree. If the page size
+ # changes, this test will no longer work.
+ btree_move_to $::c1 012
btree_delete $::c1
select_keys $::c1
-} {001 002 003 004 005 006 007 008 009 010 012 013 014 015 016 017 018 019 020}
-#btree_tree_dump $::b1 2
+} {001 002 003 004 005 006 007 008 009 010 011 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030}
#btree_pager_ref_dump $::b1
-for {set i 1} {$i<=20} {incr i} {
+#btree_tree_dump $::b1 2
+for {set i 1} {$i<=30} {incr i} {
+ # Check the number of unreference pages. This should be 3 in most cases,
+ # but 2 when the cursor is pointing to the divider entry which is now 013.
do_test btree-10.5.$i {
btree_move_to $::c1 [format %03d $i]
lindex [btree_pager_stats $::b1] 1
- } {2}
+ } [expr {$i==13?2:3}]
#btree_pager_ref_dump $::b1
#btree_tree_dump $::b1 2
}
#
catch {unset ::data}
catch {unset ::key}
-for {set i 21} {$i<=1000} {incr i} {
+for {set i 31} {$i<=1000} {incr i} {
+if {$i==88} {
+set pager_refinfo_enable 1
+btree_tree_dump $b1 2
+btree_pager_ref_dump $b1
+btree_cursor_list $b1
+}
do_test btree-11.1.$i.1 {
set key [format %03d $i]
set ::data "*** $key *** $key *** $key *** $key ***"
btree_insert $::c1 $key $data
+ btree_move_to $::c1 $key
btree_key $::c1
} [format %03d $i]
+if {$i==88} {
+btree_pager_ref_dump $b1
+btree_cursor_list $b1
+btree_tree_dump $b1 2
+exit
+}
do_test btree-11.1.$i.2 {
btree_data $::c1
} $::data
set ::key [format %03d [expr {$i/2}]]
- if {$::key=="011"} {set ::key 010}
+ if {$::key=="012"} {set ::key 013}
do_test btree-11.1.$i.3 {
btree_move_to $::c1 $::key
btree_key $::c1