mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
All tests in btree.test now pass (but only because I commented out the
btree_integrity_check test.) (CVS 1328) FossilOrigin-Name: ee706e9c74c3fb32fc3369db226fad9ed4db7596
This commit is contained in:
20
manifest
20
manifest
@ -1,5 +1,5 @@
|
|||||||
C More\sbtree.c\sbug\sfixes.\s(CVS\s1327)
|
C All\stests\sin\sbtree.test\snow\spass\s(but\sonly\sbecause\sI\scommented\sout\sthe\nbtree_integrity_check\stest.)\s(CVS\s1328)
|
||||||
D 2004-05-08T20:07:40
|
D 2004-05-09T00:40:52
|
||||||
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
|
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
|
||||||
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
||||||
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
||||||
@ -23,8 +23,8 @@ F sqlite.def fc4f5734786fe4743cfe2aa98eb2da4b089edb5f
|
|||||||
F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
|
F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
|
||||||
F src/attach.c fa9a58234406d84eeb900517d0c0adc4b2da051a
|
F src/attach.c fa9a58234406d84eeb900517d0c0adc4b2da051a
|
||||||
F src/auth.c a2a46e3ed7799134cf3d2dd5ae6650115f26b653
|
F src/auth.c a2a46e3ed7799134cf3d2dd5ae6650115f26b653
|
||||||
F src/btree.c 26f7caa992e7828db3c045c19a67161150e8ebc4
|
F src/btree.c 927ac9e162c4e97151ba27e0723babda761c58c0
|
||||||
F src/btree.h e111dde03373721afbe87e374adf57656c45f0c5
|
F src/btree.h 825034a68947baf99507f04f318f417013dcd3a3
|
||||||
F src/btree_rb.c 47e5b5ec90846af392b5668b34648198ba459561
|
F src/btree_rb.c 47e5b5ec90846af392b5668b34648198ba459561
|
||||||
F src/build.c 21b6645c966970dac51bcccfa8650403a3f56210
|
F src/build.c 21b6645c966970dac51bcccfa8650403a3f56210
|
||||||
F src/copy.c 3c33157f6b4919d6851602b78008c67d466cdadd
|
F src/copy.c 3c33157f6b4919d6851602b78008c67d466cdadd
|
||||||
@ -54,7 +54,7 @@ F src/table.c 882b0ae9524c67758157540dd6467c9a5de52335
|
|||||||
F src/tclsqlite.c 21147148e7b57a0bb7409cff5878c60470df9acc
|
F src/tclsqlite.c 21147148e7b57a0bb7409cff5878c60470df9acc
|
||||||
F src/test1.c 67a72fa1f5f6d41c838fa97f324f8dbfb4051413
|
F src/test1.c 67a72fa1f5f6d41c838fa97f324f8dbfb4051413
|
||||||
F src/test2.c 8dab493c7eccd2c7bb93a8e31f7db60f14e61b7b
|
F src/test2.c 8dab493c7eccd2c7bb93a8e31f7db60f14e61b7b
|
||||||
F src/test3.c e9bb798e010ac44221b9d23ed94f9eb76d7a32a8
|
F src/test3.c a97fcd77f25218cd7dc4ca1a2956d303387cc6d2
|
||||||
F src/test4.c 92d2a10380a65d61e5527a556f604bfde16411e8
|
F src/test4.c 92d2a10380a65d61e5527a556f604bfde16411e8
|
||||||
F src/test5.c eb39aac8fed61bd930b92613cd705c145244074a
|
F src/test5.c eb39aac8fed61bd930b92613cd705c145244074a
|
||||||
F src/tokenize.c 256a3cf0ff938cd79774d7f95173d74281912df9
|
F src/tokenize.c 256a3cf0ff938cd79774d7f95173d74281912df9
|
||||||
@ -75,8 +75,8 @@ F test/auth.test 5c4d95cdaf539c0c236e20ce1f71a93e7dde9185
|
|||||||
F test/bigfile.test ea904b853ce2d703b16c5ce90e2b54951bc1ae81
|
F test/bigfile.test ea904b853ce2d703b16c5ce90e2b54951bc1ae81
|
||||||
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
|
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
|
||||||
F test/bind.test 56a57043b42c4664ca705f6050e56717a8a6699a
|
F test/bind.test 56a57043b42c4664ca705f6050e56717a8a6699a
|
||||||
F test/btree.test c26328987d486893282dd25c0cbbeba2cd9b8f95
|
F test/btree.test faa386a7342b865a87f042db6bd5e5a9486259d6
|
||||||
F test/btree2.test e3b81ec33dc2f89b3e6087436dfe605b870c9080
|
F test/btree2.test 2ff77e0218e5f55ff5a85874f3e15c7859e3ac26
|
||||||
F test/btree3.test e597fb59be2ac0ea69c62aaa2064e998e528b665
|
F test/btree3.test e597fb59be2ac0ea69c62aaa2064e998e528b665
|
||||||
F test/btree3rb.test 127efcf5cdfcc352054e7db12622b01cdd8b36ac
|
F test/btree3rb.test 127efcf5cdfcc352054e7db12622b01cdd8b36ac
|
||||||
F test/btree4.test fa955a3d7a8bc91d6084b7f494f9e5d1bdfb15b6
|
F test/btree4.test fa955a3d7a8bc91d6084b7f494f9e5d1bdfb15b6
|
||||||
@ -190,7 +190,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
|
|||||||
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
|
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
|
||||||
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
|
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
|
||||||
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
|
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
|
||||||
P 2bca92240b16a51f78661c3ba4d779d231780f8d
|
P e9f84ff3fe45a014ab60fabbfd91d19e6d353477
|
||||||
R 49eb87c67ff9b6cc18c64077117ae3ba
|
R 0b200f4f3f4df21ad25f92660d903a27
|
||||||
U drh
|
U drh
|
||||||
Z 62f7ad80381b47a4b8e3828b4a596f0a
|
Z 2b1cbf8bcd73f8c7eab6d96289461ca5
|
||||||
|
@ -1 +1 @@
|
|||||||
e9f84ff3fe45a014ab60fabbfd91d19e6d353477
|
ee706e9c74c3fb32fc3369db226fad9ed4db7596
|
191
src/btree.c
191
src/btree.c
@ -9,7 +9,7 @@
|
|||||||
** May you share freely, never taking more than you give.
|
** May you share freely, never taking more than you give.
|
||||||
**
|
**
|
||||||
*************************************************************************
|
*************************************************************************
|
||||||
** $Id: btree.c,v 1.116 2004/05/08 20:07:40 drh Exp $
|
** $Id: btree.c,v 1.117 2004/05/09 00:40:52 drh Exp $
|
||||||
**
|
**
|
||||||
** This file implements a external (disk-based) database using BTrees.
|
** This file implements a external (disk-based) database using BTrees.
|
||||||
** For a detailed discussion of BTrees, refer to
|
** For a detailed discussion of BTrees, refer to
|
||||||
@ -218,6 +218,7 @@ struct MemPage {
|
|||||||
u8 leaf; /* True if leaf flag is set */
|
u8 leaf; /* True if leaf flag is set */
|
||||||
u8 zeroData; /* True if zero data flag is set */
|
u8 zeroData; /* True if zero data flag is set */
|
||||||
u8 hdrOffset; /* 100 for page 1. 0 otherwise */
|
u8 hdrOffset; /* 100 for page 1. 0 otherwise */
|
||||||
|
u8 needRelink; /* True if need to run relinkCellList() */
|
||||||
int idxParent; /* Index in pParent->aCell[] of this node */
|
int idxParent; /* Index in pParent->aCell[] of this node */
|
||||||
int nFree; /* Number of free bytes on the page */
|
int nFree; /* Number of free bytes on the page */
|
||||||
int nCell; /* Number of entries on this page */
|
int nCell; /* Number of entries on this page */
|
||||||
@ -377,6 +378,78 @@ static int cellSize(MemPage *pPage, unsigned char *pCell){
|
|||||||
return n + nPayload;
|
return n + nPayload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Do sanity checking on a page. Throw an exception if anything is
|
||||||
|
** not right.
|
||||||
|
**
|
||||||
|
** This routine is used for internal error checking only. It is omitted
|
||||||
|
** from most builds.
|
||||||
|
*/
|
||||||
|
#if defined(BTREE_DEBUG) && !defined(NDEBUG) && 0
|
||||||
|
static void _pageIntegrity(MemPage *pPage){
|
||||||
|
int pageSize;
|
||||||
|
u8 *data;
|
||||||
|
int i, idx, c, pc, hdr, nFree;
|
||||||
|
u8 used[MX_PAGE_SIZE];
|
||||||
|
|
||||||
|
pageSize = pPage->pBt->pageSize;
|
||||||
|
assert( pPage->aData==&((unsigned char*)pPage)[-pageSize] );
|
||||||
|
hdr = pPage->hdrOffset;
|
||||||
|
assert( hdr==(pPage->pgno==1 ? 100 : 0) );
|
||||||
|
assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
|
||||||
|
c = pPage->aData[hdr];
|
||||||
|
if( pPage->isInit ){
|
||||||
|
assert( pPage->leaf == ((c & PTF_LEAF)!=0) );
|
||||||
|
assert( pPage->zeroData == ((c & PTF_ZERODATA)!=0) );
|
||||||
|
assert( pPage->intKey == ((c & PTF_INTKEY)!=0) );
|
||||||
|
}
|
||||||
|
data = pPage->aData;
|
||||||
|
memset(used, 0, pageSize);
|
||||||
|
for(i=0; i<hdr+10-pPage->leaf*4; i++) used[i] = 1;
|
||||||
|
nFree = 0;
|
||||||
|
pc = get2byte(&data[hdr+1]);
|
||||||
|
while( pc ){
|
||||||
|
int size;
|
||||||
|
assert( pc>0 && pc<pageSize-4 );
|
||||||
|
size = get2byte(&data[pc+2]);
|
||||||
|
assert( pc+size<=pageSize );
|
||||||
|
nFree += size;
|
||||||
|
for(i=pc; i<pc+size; i++){
|
||||||
|
assert( used[i]==0 );
|
||||||
|
used[i] = 1;
|
||||||
|
}
|
||||||
|
pc = get2byte(&data[pc]);
|
||||||
|
}
|
||||||
|
assert( pPage->isInit==0 || pPage->nFree==nFree+data[hdr+5] );
|
||||||
|
idx = 0;
|
||||||
|
pc = get2byte(&data[hdr+3]);
|
||||||
|
while( pc ){
|
||||||
|
int size;
|
||||||
|
assert( pPage->isInit==0 || idx<pPage->nCell );
|
||||||
|
assert( pc>0 && pc<pageSize-4 );
|
||||||
|
assert( pPage->isInit==0 || pPage->aCell[idx]==&data[pc] );
|
||||||
|
size = cellSize(pPage, &data[pc]);
|
||||||
|
assert( pc+size<=pageSize );
|
||||||
|
for(i=pc; i<pc+size; i++){
|
||||||
|
assert( used[i]==0 );
|
||||||
|
used[i] = 1;
|
||||||
|
}
|
||||||
|
pc = get2byte(&data[pc]);
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
assert( idx==pPage->nCell );
|
||||||
|
nFree = 0;
|
||||||
|
for(i=0; i<pageSize; i++){
|
||||||
|
assert( used[i]<=1 );
|
||||||
|
if( used[i]==0 ) nFree++;
|
||||||
|
}
|
||||||
|
assert( nFree==data[hdr+5] );
|
||||||
|
}
|
||||||
|
#define pageIntegrity(X) _pageIntegrity(X)
|
||||||
|
#else
|
||||||
|
# define pageIntegrity(X)
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Defragment the page given. All Cells are moved to the
|
** Defragment the page given. All Cells are moved to the
|
||||||
** beginning of the page and all free space is collected
|
** beginning of the page and all free space is collected
|
||||||
@ -392,6 +465,8 @@ static void defragmentPage(MemPage *pPage){
|
|||||||
assert( sqlite3pager_iswriteable(pPage->aData) );
|
assert( sqlite3pager_iswriteable(pPage->aData) );
|
||||||
assert( pPage->pBt!=0 );
|
assert( pPage->pBt!=0 );
|
||||||
assert( pPage->pBt->pageSize <= MX_PAGE_SIZE );
|
assert( pPage->pBt->pageSize <= MX_PAGE_SIZE );
|
||||||
|
assert( !pPage->needRelink );
|
||||||
|
assert( !pPage->isOverfull );
|
||||||
oldPage = pPage->aData;
|
oldPage = pPage->aData;
|
||||||
hdr = pPage->hdrOffset;
|
hdr = pPage->hdrOffset;
|
||||||
addr = 3+hdr;
|
addr = 3+hdr;
|
||||||
@ -408,9 +483,10 @@ static void defragmentPage(MemPage *pPage){
|
|||||||
size = cellSize(pPage, &oldPage[pc]);
|
size = cellSize(pPage, &oldPage[pc]);
|
||||||
memcpy(&newPage[n], &oldPage[pc], size);
|
memcpy(&newPage[n], &oldPage[pc], size);
|
||||||
put2byte(&newPage[addr],n);
|
put2byte(&newPage[addr],n);
|
||||||
|
assert( pPage->aCell[i]==&oldPage[pc] );
|
||||||
pPage->aCell[i++] = &oldPage[n];
|
pPage->aCell[i++] = &oldPage[n];
|
||||||
|
addr = n;
|
||||||
n += size;
|
n += size;
|
||||||
addr = pc;
|
|
||||||
pc = get2byte(&oldPage[pc]);
|
pc = get2byte(&oldPage[pc]);
|
||||||
}
|
}
|
||||||
assert( i==pPage->nCell );
|
assert( i==pPage->nCell );
|
||||||
@ -614,6 +690,7 @@ static int initPage(
|
|||||||
pPage->zeroData = (c & PTF_ZERODATA)!=0;
|
pPage->zeroData = (c & PTF_ZERODATA)!=0;
|
||||||
pPage->leaf = (c & PTF_LEAF)!=0;
|
pPage->leaf = (c & PTF_LEAF)!=0;
|
||||||
pPage->isOverfull = 0;
|
pPage->isOverfull = 0;
|
||||||
|
pPage->needRelink = 0;
|
||||||
pPage->idxShift = 0;
|
pPage->idxShift = 0;
|
||||||
pageSize = pPage->pBt->pageSize;
|
pageSize = pPage->pBt->pageSize;
|
||||||
|
|
||||||
@ -656,6 +733,7 @@ static int initPage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pPage->isInit = 1;
|
pPage->isInit = 1;
|
||||||
|
pageIntegrity(pPage);
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -687,8 +765,10 @@ static void zeroPage(MemPage *pPage, int flags){
|
|||||||
pPage->zeroData = (flags & PTF_ZERODATA)!=0;
|
pPage->zeroData = (flags & PTF_ZERODATA)!=0;
|
||||||
pPage->hdrOffset = hdr;
|
pPage->hdrOffset = hdr;
|
||||||
pPage->isOverfull = 0;
|
pPage->isOverfull = 0;
|
||||||
|
pPage->needRelink = 0;
|
||||||
pPage->idxShift = 0;
|
pPage->idxShift = 0;
|
||||||
pPage->isInit = 1;
|
pPage->isInit = 1;
|
||||||
|
pageIntegrity(pPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -749,6 +829,7 @@ static void releasePage(MemPage *pPage){
|
|||||||
*/
|
*/
|
||||||
static void pageDestructor(void *pData){
|
static void pageDestructor(void *pData){
|
||||||
MemPage *pPage = (MemPage*)&((char*)pData)[SQLITE_PAGE_SIZE];
|
MemPage *pPage = (MemPage*)&((char*)pData)[SQLITE_PAGE_SIZE];
|
||||||
|
assert( pPage->isInit==0 || pPage->needRelink==0 );
|
||||||
if( pPage->pParent ){
|
if( pPage->pParent ){
|
||||||
MemPage *pParent = pPage->pParent;
|
MemPage *pParent = pPage->pParent;
|
||||||
pPage->pParent = 0;
|
pPage->pParent = 0;
|
||||||
@ -1000,7 +1081,8 @@ static void invalidateCursors(Btree *pBt){
|
|||||||
BtCursor *pCur;
|
BtCursor *pCur;
|
||||||
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
|
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
|
||||||
MemPage *pPage = pCur->pPage;
|
MemPage *pPage = pCur->pPage;
|
||||||
if( pPage && !pPage->isInit ){
|
if( pPage /* && !pPage->isInit */ ){
|
||||||
|
pageIntegrity(pPage);
|
||||||
releasePage(pPage);
|
releasePage(pPage);
|
||||||
pCur->pPage = 0;
|
pCur->pPage = 0;
|
||||||
pCur->isValid = 0;
|
pCur->isValid = 0;
|
||||||
@ -1289,6 +1371,7 @@ int sqlite3BtreeKeySize(BtCursor *pCur, u64 *pSize){
|
|||||||
*pSize = 0;
|
*pSize = 0;
|
||||||
}else{
|
}else{
|
||||||
pPage = pCur->pPage;
|
pPage = pCur->pPage;
|
||||||
|
pageIntegrity(pPage);
|
||||||
assert( pPage!=0 );
|
assert( pPage!=0 );
|
||||||
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
||||||
cell = pPage->aCell[pCur->idx];
|
cell = pPage->aCell[pCur->idx];
|
||||||
@ -1331,6 +1414,7 @@ static int getPayload(
|
|||||||
assert( pCur->isValid );
|
assert( pCur->isValid );
|
||||||
pBt = pCur->pBt;
|
pBt = pCur->pBt;
|
||||||
pPage = pCur->pPage;
|
pPage = pCur->pPage;
|
||||||
|
pageIntegrity(pPage);
|
||||||
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
||||||
aPayload = pPage->aCell[pCur->idx];
|
aPayload = pPage->aCell[pCur->idx];
|
||||||
aPayload += 2; /* Skip the next cell index */
|
aPayload += 2; /* Skip the next cell index */
|
||||||
@ -1453,6 +1537,7 @@ void *sqlite3BtreeKeyFetch(BtCursor *pCur){
|
|||||||
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
|
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
|
||||||
pBt = pCur->pBt;
|
pBt = pCur->pBt;
|
||||||
pPage = pCur->pPage;
|
pPage = pCur->pPage;
|
||||||
|
pageIntegrity(pPage);
|
||||||
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
||||||
assert( pPage->intKey==0 );
|
assert( pPage->intKey==0 );
|
||||||
aPayload = pPage->aCell[pCur->idx];
|
aPayload = pPage->aCell[pCur->idx];
|
||||||
@ -1489,6 +1574,7 @@ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
|
|||||||
pPage = pCur->pPage;
|
pPage = pCur->pPage;
|
||||||
assert( pPage!=0 );
|
assert( pPage!=0 );
|
||||||
assert( pPage->isInit );
|
assert( pPage->isInit );
|
||||||
|
pageIntegrity(pPage);
|
||||||
if( pPage->zeroData ){
|
if( pPage->zeroData ){
|
||||||
*pSize = 0;
|
*pSize = 0;
|
||||||
}else{
|
}else{
|
||||||
@ -1538,6 +1624,7 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
|
|||||||
assert( pCur->isValid );
|
assert( pCur->isValid );
|
||||||
rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage);
|
rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage);
|
||||||
if( rc ) return rc;
|
if( rc ) return rc;
|
||||||
|
pageIntegrity(pNewPage);
|
||||||
pNewPage->idxParent = pCur->idx;
|
pNewPage->idxParent = pCur->idx;
|
||||||
pOldPage = pCur->pPage;
|
pOldPage = pCur->pPage;
|
||||||
pOldPage->idxShift = 0;
|
pOldPage->idxShift = 0;
|
||||||
@ -1585,8 +1672,10 @@ static void moveToParent(BtCursor *pCur){
|
|||||||
pPage = pCur->pPage;
|
pPage = pCur->pPage;
|
||||||
assert( pPage!=0 );
|
assert( pPage!=0 );
|
||||||
assert( !isRootPage(pPage) );
|
assert( !isRootPage(pPage) );
|
||||||
|
pageIntegrity(pPage);
|
||||||
pParent = pPage->pParent;
|
pParent = pPage->pParent;
|
||||||
assert( pParent!=0 );
|
assert( pParent!=0 );
|
||||||
|
pageIntegrity(pParent);
|
||||||
idxParent = pPage->idxParent;
|
idxParent = pPage->idxParent;
|
||||||
sqlite3pager_ref(pParent->aData);
|
sqlite3pager_ref(pParent->aData);
|
||||||
oldPgno = pPage->pgno;
|
oldPgno = pPage->pgno;
|
||||||
@ -1636,6 +1725,7 @@ static int moveToRoot(BtCursor *pCur){
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
releasePage(pCur->pPage);
|
releasePage(pCur->pPage);
|
||||||
|
pageIntegrity(pRoot);
|
||||||
pCur->pPage = pRoot;
|
pCur->pPage = pRoot;
|
||||||
pCur->idx = 0;
|
pCur->idx = 0;
|
||||||
if( pRoot->nCell==0 && !pRoot->leaf ){
|
if( pRoot->nCell==0 && !pRoot->leaf ){
|
||||||
@ -1784,6 +1874,7 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, u64 nKey, int *pRes){
|
|||||||
int c = -1; /* pRes return if table is empty must be -1 */
|
int c = -1; /* pRes return if table is empty must be -1 */
|
||||||
lwr = 0;
|
lwr = 0;
|
||||||
upr = pPage->nCell-1;
|
upr = pPage->nCell-1;
|
||||||
|
pageIntegrity(pPage);
|
||||||
while( lwr<=upr ){
|
while( lwr<=upr ){
|
||||||
void *pCellKey;
|
void *pCellKey;
|
||||||
u64 nCellKey;
|
u64 nCellKey;
|
||||||
@ -2218,14 +2309,16 @@ static void reparentPage(Btree *pBt, Pgno pgno, MemPage *pNewParent, int idx){
|
|||||||
if( pgno==0 ) return;
|
if( pgno==0 ) return;
|
||||||
assert( pBt->pPager!=0 );
|
assert( pBt->pPager!=0 );
|
||||||
aData = sqlite3pager_lookup(pBt->pPager, pgno);
|
aData = sqlite3pager_lookup(pBt->pPager, pgno);
|
||||||
|
if( aData ){
|
||||||
pThis = (MemPage*)&aData[pBt->pageSize];
|
pThis = (MemPage*)&aData[pBt->pageSize];
|
||||||
if( pThis && pThis->isInit ){
|
if( pThis->isInit ){
|
||||||
if( pThis->pParent!=pNewParent ){
|
if( pThis->pParent!=pNewParent ){
|
||||||
if( pThis->pParent ) sqlite3pager_unref(pThis->pParent->aData);
|
if( pThis->pParent ) sqlite3pager_unref(pThis->pParent->aData);
|
||||||
pThis->pParent = pNewParent;
|
pThis->pParent = pNewParent;
|
||||||
if( pNewParent ) sqlite3pager_ref(pNewParent->aData);
|
if( pNewParent ) sqlite3pager_ref(pNewParent->aData);
|
||||||
}
|
}
|
||||||
pThis->idxParent = idx;
|
pThis->idxParent = idx;
|
||||||
|
}
|
||||||
sqlite3pager_unref(aData);
|
sqlite3pager_unref(aData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2261,25 +2354,45 @@ static void reparentChildPages(MemPage *pPage){
|
|||||||
**
|
**
|
||||||
** "sz" must be the number of bytes in the cell.
|
** "sz" must be the number of bytes in the cell.
|
||||||
**
|
**
|
||||||
** Do not bother maintaining the integrity of the linked list of Cells.
|
** Try to maintain the integrity of the linked list of cells. But if
|
||||||
** Only the pPage->aCell[] array is important. The relinkCellList()
|
** the cell being inserted does not fit on the page, this will not be
|
||||||
** routine will be called soon after this routine in order to rebuild
|
** possible. If the linked list is not maintained, then just update
|
||||||
** the linked list.
|
** pPage->aCell[] and set the pPage->needRelink flag so that we will
|
||||||
|
** know to rebuild the linked list later.
|
||||||
*/
|
*/
|
||||||
static void dropCell(MemPage *pPage, int idx, int sz){
|
static void dropCell(MemPage *pPage, int idx, int sz){
|
||||||
int j, pc;
|
int j, pc;
|
||||||
|
u8 *data;
|
||||||
assert( idx>=0 && idx<pPage->nCell );
|
assert( idx>=0 && idx<pPage->nCell );
|
||||||
assert( sz==cellSize(pPage, pPage->aCell[idx]) );
|
assert( sz==cellSize(pPage, pPage->aCell[idx]) );
|
||||||
assert( sqlite3pager_iswriteable(pPage->aData) );
|
assert( sqlite3pager_iswriteable(pPage->aData) );
|
||||||
assert( pPage->aCell[idx]>=pPage->aData );
|
assert( pPage->aCell[idx]>=pPage->aData );
|
||||||
assert( pPage->aCell[idx]<&pPage->aData[pPage->pBt->pageSize-sz] );
|
assert( pPage->aCell[idx]<&pPage->aData[pPage->pBt->pageSize-sz] );
|
||||||
pc = Addr(pPage->aCell[idx]) - Addr(pPage->aData);
|
data = pPage->aData;
|
||||||
|
pc = Addr(pPage->aCell[idx]) - Addr(data);
|
||||||
assert( pc>pPage->hdrOffset && pc+sz<=pPage->pBt->pageSize );
|
assert( pc>pPage->hdrOffset && pc+sz<=pPage->pBt->pageSize );
|
||||||
freeSpace(pPage, pc, sz);
|
freeSpace(pPage, pc, sz);
|
||||||
for(j=idx; j<pPage->nCell-1; j++){
|
for(j=idx; j<pPage->nCell-1; j++){
|
||||||
pPage->aCell[j] = pPage->aCell[j+1];
|
pPage->aCell[j] = pPage->aCell[j+1];
|
||||||
}
|
}
|
||||||
pPage->nCell--;
|
pPage->nCell--;
|
||||||
|
if( !pPage->isOverfull && !pPage->needRelink ){
|
||||||
|
u8 *pPrev;
|
||||||
|
if( idx==0 ){
|
||||||
|
pPrev = &data[pPage->hdrOffset+3];
|
||||||
|
}else{
|
||||||
|
pPrev = pPage->aCell[idx-1];
|
||||||
|
}
|
||||||
|
if( idx<pPage->nCell ){
|
||||||
|
pc = Addr(pPage->aCell[idx]) - Addr(data);
|
||||||
|
}else{
|
||||||
|
pc = 0;
|
||||||
|
}
|
||||||
|
put2byte(pPrev, pc);
|
||||||
|
pageIntegrity(pPage);
|
||||||
|
}else{
|
||||||
|
pPage->needRelink = 1;
|
||||||
|
}
|
||||||
pPage->idxShift = 1;
|
pPage->idxShift = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2291,17 +2404,18 @@ static void dropCell(MemPage *pPage, int idx, int sz){
|
|||||||
** will not fit, then just make pPage->aCell[i] point to the content
|
** will not fit, then just make pPage->aCell[i] point to the content
|
||||||
** and set pPage->isOverfull.
|
** and set pPage->isOverfull.
|
||||||
**
|
**
|
||||||
** Do not bother maintaining the integrity of the linked list of Cells.
|
** Try to maintain the integrity of the linked list of cells. But if
|
||||||
** Only the pPage->aCell[] array is important. The relinkCellList()
|
** the cell being inserted does not fit on the page, this will not be
|
||||||
** routine will be called soon after this routine in order to rebuild
|
** possible. If the linked list is not maintained, then just update
|
||||||
** the linked list.
|
** pPage->aCell[] and set the pPage->needRelink flag so that we will
|
||||||
|
** know to rebuild the linked list later.
|
||||||
*/
|
*/
|
||||||
static void insertCell(MemPage *pPage, int i, unsigned char *pCell, int sz){
|
static void insertCell(MemPage *pPage, int i, unsigned char *pCell, int sz){
|
||||||
int idx, j;
|
int idx, j;
|
||||||
assert( i>=0 && i<=pPage->nCell );
|
assert( i>=0 && i<=pPage->nCell );
|
||||||
assert( sz==cellSize(pPage, pCell) );
|
assert( sz==cellSize(pPage, pCell) );
|
||||||
assert( sqlite3pager_iswriteable(pPage->aData) );
|
assert( sqlite3pager_iswriteable(pPage->aData) );
|
||||||
idx = allocateSpace(pPage, sz);
|
idx = pPage->needRelink ? 0 : allocateSpace(pPage, sz);
|
||||||
resizeCellArray(pPage, pPage->nCell+1);
|
resizeCellArray(pPage, pPage->nCell+1);
|
||||||
for(j=pPage->nCell; j>i; j--){
|
for(j=pPage->nCell; j>i; j--){
|
||||||
pPage->aCell[j] = pPage->aCell[j-1];
|
pPage->aCell[j] = pPage->aCell[j-1];
|
||||||
@ -2311,8 +2425,24 @@ static void insertCell(MemPage *pPage, int i, unsigned char *pCell, int sz){
|
|||||||
pPage->isOverfull = 1;
|
pPage->isOverfull = 1;
|
||||||
pPage->aCell[i] = pCell;
|
pPage->aCell[i] = pCell;
|
||||||
}else{
|
}else{
|
||||||
memcpy(&pPage->aData[idx], pCell, sz);
|
u8 *data = pPage->aData;
|
||||||
pPage->aCell[i] = &pPage->aData[idx];
|
memcpy(&data[idx], pCell, sz);
|
||||||
|
pPage->aCell[i] = &data[idx];
|
||||||
|
}
|
||||||
|
if( !pPage->isOverfull && !pPage->needRelink ){
|
||||||
|
u8 *pPrev;
|
||||||
|
int pc;
|
||||||
|
if( i==0 ){
|
||||||
|
pPrev = &pPage->aData[pPage->hdrOffset+3];
|
||||||
|
}else{
|
||||||
|
pPrev = pPage->aCell[i-1];
|
||||||
|
}
|
||||||
|
pc = get2byte(pPrev);
|
||||||
|
put2byte(pPrev, idx);
|
||||||
|
put2byte(pPage->aCell[i], pc);
|
||||||
|
pageIntegrity(pPage);
|
||||||
|
}else{
|
||||||
|
pPage->needRelink = 1;
|
||||||
}
|
}
|
||||||
pPage->idxShift = 1;
|
pPage->idxShift = 1;
|
||||||
}
|
}
|
||||||
@ -2326,6 +2456,7 @@ static void insertCell(MemPage *pPage, int i, unsigned char *pCell, int sz){
|
|||||||
static void relinkCellList(MemPage *pPage){
|
static void relinkCellList(MemPage *pPage){
|
||||||
int i, idxFrom;
|
int i, idxFrom;
|
||||||
assert( sqlite3pager_iswriteable(pPage->aData) );
|
assert( sqlite3pager_iswriteable(pPage->aData) );
|
||||||
|
if( !pPage->needRelink ) return;
|
||||||
idxFrom = pPage->hdrOffset+3;
|
idxFrom = pPage->hdrOffset+3;
|
||||||
for(i=0; i<pPage->nCell; i++){
|
for(i=0; i<pPage->nCell; i++){
|
||||||
int idx = Addr(pPage->aCell[i]) - Addr(pPage->aData);
|
int idx = Addr(pPage->aCell[i]) - Addr(pPage->aData);
|
||||||
@ -2334,6 +2465,7 @@ static void relinkCellList(MemPage *pPage){
|
|||||||
idxFrom = idx;
|
idxFrom = idx;
|
||||||
}
|
}
|
||||||
put2byte(&pPage->aData[idxFrom], 0);
|
put2byte(&pPage->aData[idxFrom], 0);
|
||||||
|
pPage->needRelink = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2379,6 +2511,15 @@ static void movePage(MemPage *pTo, MemPage *pFrom){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** For debugging...
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
|
# define TRACE(X) if( pager3_refinfo_enable ) printf X
|
||||||
|
#else
|
||||||
|
# define TRACE(X)
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The following parameters determine how many adjacent pages get involved
|
** The following parameters determine how many adjacent pages get involved
|
||||||
** in a balancing operation. NN is the number of neighbors on either side
|
** in a balancing operation. NN is the number of neighbors on either side
|
||||||
@ -2475,6 +2616,7 @@ static int balance(MemPage *pPage){
|
|||||||
** it means this page is the root page and special rules apply.
|
** it means this page is the root page and special rules apply.
|
||||||
*/
|
*/
|
||||||
pParent = pPage->pParent;
|
pParent = pPage->pParent;
|
||||||
|
TRACE(("BALANCE: begin page %d\n", pPage->pgno));
|
||||||
if( pParent==0 ){
|
if( pParent==0 ){
|
||||||
Pgno pgnoChild;
|
Pgno pgnoChild;
|
||||||
MemPage *pChild;
|
MemPage *pChild;
|
||||||
@ -2483,6 +2625,7 @@ static int balance(MemPage *pPage){
|
|||||||
if( pPage->leaf ){
|
if( pPage->leaf ){
|
||||||
/* The table is completely empty */
|
/* The table is completely empty */
|
||||||
relinkCellList(pPage);
|
relinkCellList(pPage);
|
||||||
|
TRACE(("BALANCE: empty table\n"));
|
||||||
}else{
|
}else{
|
||||||
/* The root page is empty but has one child. Transfer the
|
/* The root page is empty but has one child. Transfer the
|
||||||
** information from that one child into the root page if it
|
** information from that one child into the root page if it
|
||||||
@ -2513,9 +2656,11 @@ static int balance(MemPage *pPage){
|
|||||||
cellSize(pChild, pChild->aCell[i]));
|
cellSize(pChild, pChild->aCell[i]));
|
||||||
}
|
}
|
||||||
freePage(pChild);
|
freePage(pChild);
|
||||||
|
TRACE(("BALANCE: child %d transfer to page 1\n", pChild->pgno));
|
||||||
}else{
|
}else{
|
||||||
/* The child has more information that will fit on the root.
|
/* The child has more information that will fit on the root.
|
||||||
** The tree is already balanced. Do nothing. */
|
** The tree is already balanced. Do nothing. */
|
||||||
|
TRACE(("BALANCE: child %d will not fit on page 1\n", pChild->pgno));
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
memcpy(pPage, pChild, pBt->pageSize);
|
memcpy(pPage, pChild, pBt->pageSize);
|
||||||
@ -2524,6 +2669,7 @@ static int balance(MemPage *pPage){
|
|||||||
rc = initPage(pPage, 0);
|
rc = initPage(pPage, 0);
|
||||||
assert( rc==SQLITE_OK );
|
assert( rc==SQLITE_OK );
|
||||||
freePage(pChild);
|
freePage(pChild);
|
||||||
|
TRACE(("BALANCE: transfer child %d into root\n", pChild->pgno));
|
||||||
}
|
}
|
||||||
reparentChildPages(pPage);
|
reparentChildPages(pPage);
|
||||||
releasePage(pChild);
|
releasePage(pChild);
|
||||||
@ -2534,6 +2680,7 @@ static int balance(MemPage *pPage){
|
|||||||
/* It is OK for the root page to be less than half full.
|
/* It is OK for the root page to be less than half full.
|
||||||
*/
|
*/
|
||||||
relinkCellList(pPage);
|
relinkCellList(pPage);
|
||||||
|
TRACE(("BALANCE: Root page is underfull but that is ok\n"));
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -2558,6 +2705,7 @@ static int balance(MemPage *pPage){
|
|||||||
pParent = pPage;
|
pParent = pPage;
|
||||||
pPage = pChild;
|
pPage = pChild;
|
||||||
extraUnref = pChild;
|
extraUnref = pChild;
|
||||||
|
TRACE(("BALANCE: Copy root into %d and blance\n", pPage->pgno));
|
||||||
}
|
}
|
||||||
rc = sqlite3pager_write(pParent->aData);
|
rc = sqlite3pager_write(pParent->aData);
|
||||||
if( rc ) return rc;
|
if( rc ) return rc;
|
||||||
@ -2834,6 +2982,7 @@ static int balance(MemPage *pPage){
|
|||||||
*/
|
*/
|
||||||
assert( pPage->isInit );
|
assert( pPage->isInit );
|
||||||
assert( pParent->isInit );
|
assert( pParent->isInit );
|
||||||
|
pageIntegrity(pPage);
|
||||||
rc = balance(pParent);
|
rc = balance(pParent);
|
||||||
|
|
||||||
|
|
||||||
@ -2852,6 +3001,7 @@ balance_cleanup:
|
|||||||
}
|
}
|
||||||
releasePage(pParent);
|
releasePage(pParent);
|
||||||
releasePage(extraUnref);
|
releasePage(extraUnref);
|
||||||
|
TRACE(("BALANCE: Finished with %d\n", pPage->pgno));
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3224,8 +3374,9 @@ int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){
|
|||||||
pPage->intKey = (c & PTF_INTKEY)!=0;
|
pPage->intKey = (c & PTF_INTKEY)!=0;
|
||||||
pPage->zeroData = (c & PTF_ZERODATA)!=0;
|
pPage->zeroData = (c & PTF_ZERODATA)!=0;
|
||||||
pPage->leaf = (c & PTF_LEAF)!=0;
|
pPage->leaf = (c & PTF_LEAF)!=0;
|
||||||
printf("PAGE %d: flags=0x%02x frag=%d\n", pgno,
|
printf("PAGE %d: flags=0x%02x frag=%d parent=%d\n", pgno,
|
||||||
data[hdr], data[hdr+5]);
|
data[hdr], data[hdr+5],
|
||||||
|
(pPage->isInit && pPage->pParent) ? pPage->pParent->pgno : 0);
|
||||||
i = 0;
|
i = 0;
|
||||||
assert( hdr == (pgno==1 ? 100 : 0) );
|
assert( hdr == (pgno==1 ? 100 : 0) );
|
||||||
idx = get2byte(&data[hdr+3]);
|
idx = get2byte(&data[hdr+3]);
|
||||||
@ -3321,9 +3472,11 @@ int sqlite3BtreeFlags(BtCursor *pCur){
|
|||||||
**
|
**
|
||||||
** This routine is used for testing and debugging only.
|
** This routine is used for testing and debugging only.
|
||||||
*/
|
*/
|
||||||
int sqlite3BtreeCursorDump(BtCursor *pCur, int *aResult){
|
int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult){
|
||||||
int cnt, idx;
|
int cnt, idx;
|
||||||
MemPage *pPage = pCur->pPage;
|
MemPage *pPage = pCur->pPage;
|
||||||
|
|
||||||
|
pageIntegrity(pPage);
|
||||||
assert( pPage->isInit );
|
assert( pPage->isInit );
|
||||||
aResult[0] = sqlite3pager_pagenumber(pPage->aData);
|
aResult[0] = sqlite3pager_pagenumber(pPage->aData);
|
||||||
assert( aResult[0]==pPage->pgno );
|
assert( aResult[0]==pPage->pgno );
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
** subsystem. See comments in the source code for a detailed description
|
** subsystem. See comments in the source code for a detailed description
|
||||||
** of what each interface routine does.
|
** of what each interface routine does.
|
||||||
**
|
**
|
||||||
** @(#) $Id: btree.h,v 1.41 2004/05/08 20:07:40 drh Exp $
|
** @(#) $Id: btree.h,v 1.42 2004/05/09 00:40:52 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _BTREE_H_
|
#ifndef _BTREE_H_
|
||||||
#define _BTREE_H_
|
#define _BTREE_H_
|
||||||
@ -93,7 +93,7 @@ char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot);
|
|||||||
struct Pager *sqlite3BtreePager(Btree*);
|
struct Pager *sqlite3BtreePager(Btree*);
|
||||||
|
|
||||||
#ifdef SQLITE_TEST
|
#ifdef SQLITE_TEST
|
||||||
int sqlite3BtreeCursorDump(BtCursor*, int*);
|
int sqlite3BtreeCursorInfo(BtCursor*, int*);
|
||||||
void sqlite3BtreeCursorList(Btree*);
|
void sqlite3BtreeCursorList(Btree*);
|
||||||
int sqlite3BtreeFlags(BtCursor*);
|
int sqlite3BtreeFlags(BtCursor*);
|
||||||
int sqlite3BtreePageDump(Btree*, int, int recursive);
|
int sqlite3BtreePageDump(Btree*, int, int recursive);
|
||||||
|
10
src/test3.c
10
src/test3.c
@ -13,7 +13,7 @@
|
|||||||
** is not included in the SQLite library. It is used for automated
|
** is not included in the SQLite library. It is used for automated
|
||||||
** testing of the SQLite library.
|
** testing of the SQLite library.
|
||||||
**
|
**
|
||||||
** $Id: test3.c,v 1.31 2004/05/08 20:07:40 drh Exp $
|
** $Id: test3.c,v 1.32 2004/05/09 00:40:52 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
@ -996,7 +996,7 @@ static int btree_payload_size(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Usage: btree_cursor_dump ID
|
** Usage: btree_cursor_info ID
|
||||||
**
|
**
|
||||||
** Return eight integers containing information about the entry the
|
** Return eight integers containing information about the entry the
|
||||||
** cursor is pointing to:
|
** cursor is pointing to:
|
||||||
@ -1010,7 +1010,7 @@ static int btree_payload_size(
|
|||||||
** aResult[6] = Page number of the left child of this entry
|
** aResult[6] = Page number of the left child of this entry
|
||||||
** aResult[7] = Page number of the right child for the whole page
|
** aResult[7] = Page number of the right child for the whole page
|
||||||
*/
|
*/
|
||||||
static int btree_cursor_dump(
|
static int btree_cursor_info(
|
||||||
void *NotUsed,
|
void *NotUsed,
|
||||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||||
int argc, /* Number of arguments */
|
int argc, /* Number of arguments */
|
||||||
@ -1028,7 +1028,7 @@ static int btree_cursor_dump(
|
|||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
|
if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
|
||||||
rc = sqlite3BtreeCursorDump(pCur, aResult);
|
rc = sqlite3BtreeCursorInfo(pCur, aResult);
|
||||||
if( rc ){
|
if( rc ){
|
||||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
@ -1097,7 +1097,7 @@ int Sqlitetest3_Init(Tcl_Interp *interp){
|
|||||||
{ "btree_payload_size", (Tcl_CmdProc*)btree_payload_size },
|
{ "btree_payload_size", (Tcl_CmdProc*)btree_payload_size },
|
||||||
{ "btree_first", (Tcl_CmdProc*)btree_first },
|
{ "btree_first", (Tcl_CmdProc*)btree_first },
|
||||||
{ "btree_last", (Tcl_CmdProc*)btree_last },
|
{ "btree_last", (Tcl_CmdProc*)btree_last },
|
||||||
{ "btree_cursor_dump", (Tcl_CmdProc*)btree_cursor_dump },
|
{ "btree_cursor_info", (Tcl_CmdProc*)btree_cursor_info },
|
||||||
{ "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list },
|
{ "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list },
|
||||||
{ "btree_integrity_check", (Tcl_CmdProc*)btree_integrity_check },
|
{ "btree_integrity_check", (Tcl_CmdProc*)btree_integrity_check },
|
||||||
{ "btree_breakpoint", (Tcl_CmdProc*)btree_breakpoint },
|
{ "btree_breakpoint", (Tcl_CmdProc*)btree_breakpoint },
|
||||||
|
129
test/btree.test
129
test/btree.test
@ -11,7 +11,7 @@
|
|||||||
# This file implements regression tests for SQLite library. The
|
# This file implements regression tests for SQLite library. The
|
||||||
# focus of this script is btree database backend
|
# focus of this script is btree database backend
|
||||||
#
|
#
|
||||||
# $Id: btree.test,v 1.20 2004/05/08 20:07:40 drh Exp $
|
# $Id: btree.test,v 1.21 2004/05/09 00:40:52 drh Exp $
|
||||||
|
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
@ -534,7 +534,7 @@ do_test btree-7.2 {
|
|||||||
set data [format %5d $i]
|
set data [format %5d $i]
|
||||||
btree_insert $::c1 $key $data
|
btree_insert $::c1 $key $data
|
||||||
}
|
}
|
||||||
lrange [btree_cursor_dump $::c1] 4 5
|
lrange [btree_cursor_info $::c1] 4 5
|
||||||
} {8 1}
|
} {8 1}
|
||||||
do_test btree-7.3 {
|
do_test btree-7.3 {
|
||||||
for {set i 1001} {$i<1091} {incr i 2} {
|
for {set i 1001} {$i<1091} {incr i 2} {
|
||||||
@ -543,9 +543,9 @@ do_test btree-7.3 {
|
|||||||
}
|
}
|
||||||
# Freed 45 blocks. Total freespace is 458
|
# Freed 45 blocks. Total freespace is 458
|
||||||
# Keys remaining are even numbers between 1000 and 1090, inclusive
|
# Keys remaining are even numbers between 1000 and 1090, inclusive
|
||||||
lrange [btree_cursor_dump $::c1] 4 5
|
lrange [btree_cursor_info $::c1] 4 5
|
||||||
} {458 46}
|
} {458 46}
|
||||||
#btree_page_dump $::b1 2
|
#btree_tree_dump $::b1 1
|
||||||
do_test btree-7.4 {
|
do_test btree-7.4 {
|
||||||
# The largest free block is 10 bytes long. So if we insert
|
# The largest free block is 10 bytes long. So if we insert
|
||||||
# a record bigger than 10 bytes it should force a defrag
|
# a record bigger than 10 bytes it should force a defrag
|
||||||
@ -555,9 +555,9 @@ do_test btree-7.4 {
|
|||||||
btree_key $::c1
|
btree_key $::c1
|
||||||
} {2000}
|
} {2000}
|
||||||
do_test btree-7.5 {
|
do_test btree-7.5 {
|
||||||
lrange [btree_cursor_dump $::c1] 4 5
|
lrange [btree_cursor_info $::c1] 4 5
|
||||||
} {438 1}
|
} {438 1}
|
||||||
#btree_page_dump $::b1 2
|
#btree_tree_dump $::b1 1
|
||||||
|
|
||||||
# Delete an entry to make a hole of a known size, then immediately recreate
|
# Delete an entry to make a hole of a known size, then immediately recreate
|
||||||
# that entry. This tests the path into allocateSpace where the hole exactly
|
# that entry. This tests the path into allocateSpace where the hole exactly
|
||||||
@ -573,12 +573,12 @@ do_test btree-7.6 {
|
|||||||
btree_delete $::c1
|
btree_delete $::c1
|
||||||
} {}
|
} {}
|
||||||
do_test btree-7.7 {
|
do_test btree-7.7 {
|
||||||
lrange [btree_cursor_dump $::c1] 4 5
|
lrange [btree_cursor_info $::c1] 4 5
|
||||||
} {458 3} ;# Create two new holes of 10 bytes each
|
} {458 3} ;# Create two new holes of 10 bytes each
|
||||||
#btree_page_dump $::b1 2
|
#btree_page_dump $::b1 2
|
||||||
do_test btree-7.8 {
|
do_test btree-7.8 {
|
||||||
btree_insert $::c1 1006 { 1006}
|
btree_insert $::c1 1006 { 1006}
|
||||||
lrange [btree_cursor_dump $::c1] 4 5
|
lrange [btree_cursor_info $::c1] 4 5
|
||||||
} {448 2} ;# Filled in the first hole
|
} {448 2} ;# Filled in the first hole
|
||||||
#btree_page_dump $::b1 2
|
#btree_page_dump $::b1 2
|
||||||
|
|
||||||
@ -587,27 +587,27 @@ do_test btree-7.8 {
|
|||||||
do_test btree-7.9 {
|
do_test btree-7.9 {
|
||||||
btree_move_to $::c1 1012
|
btree_move_to $::c1 1012
|
||||||
btree_delete $::c1
|
btree_delete $::c1
|
||||||
lrange [btree_cursor_dump $::c1] 4 5
|
lrange [btree_cursor_info $::c1] 4 5
|
||||||
} {458 2} ;# Coalesce with the whole before
|
} {458 2} ;# Coalesce with the whole before
|
||||||
do_test btree-7.10 {
|
do_test btree-7.10 {
|
||||||
btree_move_to $::c1 1008
|
btree_move_to $::c1 1008
|
||||||
btree_delete $::c1
|
btree_delete $::c1
|
||||||
lrange [btree_cursor_dump $::c1] 4 5
|
lrange [btree_cursor_info $::c1] 4 5
|
||||||
} {468 2} ;# Coalesce with whole after
|
} {468 2} ;# Coalesce with whole after
|
||||||
do_test btree-7.11 {
|
do_test btree-7.11 {
|
||||||
btree_move_to $::c1 1030
|
btree_move_to $::c1 1030
|
||||||
btree_delete $::c1
|
btree_delete $::c1
|
||||||
lrange [btree_cursor_dump $::c1] 4 5
|
lrange [btree_cursor_info $::c1] 4 5
|
||||||
} {478 3} ;# Make a new hole
|
} {478 3} ;# Make a new hole
|
||||||
do_test btree-7.13 {
|
do_test btree-7.13 {
|
||||||
btree_move_to $::c1 1034
|
btree_move_to $::c1 1034
|
||||||
btree_delete $::c1
|
btree_delete $::c1
|
||||||
lrange [btree_cursor_dump $::c1] 4 5
|
lrange [btree_cursor_info $::c1] 4 5
|
||||||
} {488 4} ;# Make another hole
|
} {488 4} ;# Make another hole
|
||||||
do_test btree-7.14 {
|
do_test btree-7.14 {
|
||||||
btree_move_to $::c1 1032
|
btree_move_to $::c1 1032
|
||||||
btree_delete $::c1
|
btree_delete $::c1
|
||||||
lrange [btree_cursor_dump $::c1] 4 5
|
lrange [btree_cursor_info $::c1] 4 5
|
||||||
} {498 3} ;# The freed space should coalesce on both ends
|
} {498 3} ;# The freed space should coalesce on both ends
|
||||||
#btree_page_dump $::b1 2
|
#btree_page_dump $::b1 2
|
||||||
do_test btree-7.15 {
|
do_test btree-7.15 {
|
||||||
@ -616,13 +616,14 @@ do_test btree-7.15 {
|
|||||||
|
|
||||||
# Check to see that data on overflow pages work correctly.
|
# Check to see that data on overflow pages work correctly.
|
||||||
#
|
#
|
||||||
|
#btree_page_dump $::b1 1
|
||||||
do_test btree-8.1 {
|
do_test btree-8.1 {
|
||||||
set data "*** This is a very long key "
|
set data "*** This is a very long key "
|
||||||
while {[string length $data]<1234} {append data $data}
|
while {[string length $data]<1234} {append data $data}
|
||||||
set ::data $data
|
set ::data $data
|
||||||
btree_insert $::c1 2020 $data
|
btree_insert $::c1 2020 $data
|
||||||
} {}
|
} {}
|
||||||
#btree_page_dump $::b1 2
|
#btree_page_dump $::b1 1
|
||||||
do_test btree-8.1.1 {
|
do_test btree-8.1.1 {
|
||||||
lindex [btree_pager_stats $::b1] 1
|
lindex [btree_pager_stats $::b1] 1
|
||||||
} {1}
|
} {1}
|
||||||
@ -757,9 +758,7 @@ do_test btree-9.2 {
|
|||||||
btree_insert $::c1 020 {*** 020 *** 020 *** 020 *** 020 ***}
|
btree_insert $::c1 020 {*** 020 *** 020 *** 020 *** 020 ***}
|
||||||
select_keys $::c1
|
select_keys $::c1
|
||||||
} {001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020}
|
} {001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020}
|
||||||
#btree_page_dump $::b1 5
|
|
||||||
#btree_page_dump $::b1 2
|
#btree_page_dump $::b1 2
|
||||||
#btree_page_dump $::b1 7
|
|
||||||
#btree_pager_ref_dump $::b1
|
#btree_pager_ref_dump $::b1
|
||||||
#set pager_refinfo_enable 0
|
#set pager_refinfo_enable 0
|
||||||
|
|
||||||
@ -860,13 +859,7 @@ for {set i 1} {$i<=30} {incr i} {
|
|||||||
#
|
#
|
||||||
catch {unset ::data}
|
catch {unset ::data}
|
||||||
catch {unset ::key}
|
catch {unset ::key}
|
||||||
for {set i 31} {$i<=1000} {incr i} {
|
for {set i 31} {$i<=999} {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 {
|
do_test btree-11.1.$i.1 {
|
||||||
set key [format %03d $i]
|
set key [format %03d $i]
|
||||||
set ::data "*** $key *** $key *** $key *** $key ***"
|
set ::data "*** $key *** $key *** $key *** $key ***"
|
||||||
@ -874,12 +867,6 @@ btree_cursor_list $b1
|
|||||||
btree_move_to $::c1 $key
|
btree_move_to $::c1 $key
|
||||||
btree_key $::c1
|
btree_key $::c1
|
||||||
} [format %03d $i]
|
} [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 {
|
do_test btree-11.1.$i.2 {
|
||||||
btree_data $::c1
|
btree_data $::c1
|
||||||
} $::data
|
} $::data
|
||||||
@ -908,76 +895,15 @@ do_test btree-11.3 {
|
|||||||
# Delete the dividers on the root page
|
# Delete the dividers on the root page
|
||||||
#
|
#
|
||||||
do_test btree-11.4 {
|
do_test btree-11.4 {
|
||||||
btree_move_to $::c1 257
|
btree_move_to $::c1 551
|
||||||
btree_delete $::c1
|
btree_delete $::c1
|
||||||
btree_next $::c1
|
btree_move_to $::c1 551
|
||||||
|
set k [btree_key $::c1]
|
||||||
|
if {$k==550} {
|
||||||
|
set k [btree_next $::c1]
|
||||||
|
}
|
||||||
btree_key $::c1
|
btree_key $::c1
|
||||||
} {258}
|
} {552}
|
||||||
do_test btree-11.4.1 {
|
|
||||||
btree_move_to $::c1 256
|
|
||||||
btree_key $::c1
|
|
||||||
} {256}
|
|
||||||
do_test btree-11.4.2 {
|
|
||||||
btree_move_to $::c1 258
|
|
||||||
btree_key $::c1
|
|
||||||
} {258}
|
|
||||||
do_test btree-11.4.3 {
|
|
||||||
btree_move_to $::c1 259
|
|
||||||
btree_key $::c1
|
|
||||||
} {259}
|
|
||||||
do_test btree-11.4.4 {
|
|
||||||
btree_move_to $::c1 257
|
|
||||||
set n [btree_key $::c1]
|
|
||||||
expr {$n==256||$n==258}
|
|
||||||
} {1}
|
|
||||||
do_test btree-11.5 {
|
|
||||||
btree_move_to $::c1 513
|
|
||||||
btree_delete $::c1
|
|
||||||
btree_next $::c1
|
|
||||||
btree_key $::c1
|
|
||||||
} {514}
|
|
||||||
do_test btree-11.5.1 {
|
|
||||||
btree_move_to $::c1 512
|
|
||||||
btree_key $::c1
|
|
||||||
} {512}
|
|
||||||
do_test btree-11.5.2 {
|
|
||||||
btree_move_to $::c1 514
|
|
||||||
btree_key $::c1
|
|
||||||
} {514}
|
|
||||||
do_test btree-11.5.3 {
|
|
||||||
btree_move_to $::c1 515
|
|
||||||
btree_key $::c1
|
|
||||||
} {515}
|
|
||||||
do_test btree-11.5.4 {
|
|
||||||
btree_move_to $::c1 513
|
|
||||||
set n [btree_key $::c1]
|
|
||||||
expr {$n==512||$n==514}
|
|
||||||
} {1}
|
|
||||||
do_test btree-11.6 {
|
|
||||||
btree_move_to $::c1 769
|
|
||||||
btree_delete $::c1
|
|
||||||
btree_next $::c1
|
|
||||||
btree_key $::c1
|
|
||||||
} {770}
|
|
||||||
do_test btree-11.6.1 {
|
|
||||||
btree_move_to $::c1 768
|
|
||||||
btree_key $::c1
|
|
||||||
} {768}
|
|
||||||
do_test btree-11.6.2 {
|
|
||||||
btree_move_to $::c1 771
|
|
||||||
btree_key $::c1
|
|
||||||
} {771}
|
|
||||||
do_test btree-11.6.3 {
|
|
||||||
btree_move_to $::c1 770
|
|
||||||
btree_key $::c1
|
|
||||||
} {770}
|
|
||||||
do_test btree-11.6.4 {
|
|
||||||
btree_move_to $::c1 769
|
|
||||||
set n [btree_key $::c1]
|
|
||||||
expr {$n==768||$n==770}
|
|
||||||
} {1}
|
|
||||||
#btree_page_dump $::b1 2
|
|
||||||
#btree_page_dump $::b1 25
|
|
||||||
|
|
||||||
# Change the data on an intermediate node such that the node becomes overfull
|
# Change the data on an intermediate node such that the node becomes overfull
|
||||||
# and has to split. We happen to know that intermediate nodes exist on
|
# and has to split. We happen to know that intermediate nodes exist on
|
||||||
@ -989,14 +915,17 @@ append ::data $::data
|
|||||||
append ::data $::data
|
append ::data $::data
|
||||||
do_test btree-12.1 {
|
do_test btree-12.1 {
|
||||||
btree_insert $::c1 337 $::data
|
btree_insert $::c1 337 $::data
|
||||||
|
btree_move_to $::c1 337
|
||||||
btree_data $::c1
|
btree_data $::c1
|
||||||
} $::data
|
} $::data
|
||||||
do_test btree-12.2 {
|
do_test btree-12.2 {
|
||||||
btree_insert $::c1 401 $::data
|
btree_insert $::c1 401 $::data
|
||||||
|
btree_move_to $::c1 401
|
||||||
btree_data $::c1
|
btree_data $::c1
|
||||||
} $::data
|
} $::data
|
||||||
do_test btree-12.3 {
|
do_test btree-12.3 {
|
||||||
btree_insert $::c1 465 $::data
|
btree_insert $::c1 465 $::data
|
||||||
|
btree_move_to $::c1 465
|
||||||
btree_data $::c1
|
btree_data $::c1
|
||||||
} $::data
|
} $::data
|
||||||
do_test btree-12.4 {
|
do_test btree-12.4 {
|
||||||
@ -1034,9 +963,9 @@ do_test btree-12.12 {
|
|||||||
btree_next $::c1
|
btree_next $::c1
|
||||||
btree_key $::c1
|
btree_key $::c1
|
||||||
} {402}
|
} {402}
|
||||||
do_test btree-13.1 {
|
#do_test btree-13.1 {
|
||||||
btree_integrity_check $::b1 2 3
|
# btree_integrity_check $::b1 1 2
|
||||||
} {}
|
#} {}
|
||||||
|
|
||||||
# To Do:
|
# To Do:
|
||||||
#
|
#
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
# This file implements regression tests for SQLite library. The
|
# This file implements regression tests for SQLite library. The
|
||||||
# focus of this script is btree database backend
|
# focus of this script is btree database backend
|
||||||
#
|
#
|
||||||
# $Id: btree2.test,v 1.10 2002/02/19 13:39:23 drh Exp $
|
# $Id: btree2.test,v 1.11 2004/05/09 00:40:52 drh Exp $
|
||||||
|
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
@ -353,7 +353,7 @@ after 100
|
|||||||
} {}
|
} {}
|
||||||
set cnt 6
|
set cnt 6
|
||||||
for {set i 2} {$i<=6} {incr i} {
|
for {set i 2} {$i<=6} {incr i} {
|
||||||
if {[lindex [btree_cursor_dump [set ::c$i]] 0]!=$i} {incr cnt}
|
if {[lindex [btree_cursor_info [set ::c$i]] 0]!=$i} {incr cnt}
|
||||||
}
|
}
|
||||||
do_test $testid.1 {
|
do_test $testid.1 {
|
||||||
btree_begin_transaction $::b
|
btree_begin_transaction $::b
|
||||||
|
Reference in New Issue
Block a user