More bug fixes in btree.c. (CVS 1322)
FossilOrigin-Name: a80939ef714ec884950b4a1f4f809ffa37fdfa59
This commit is contained in:
parent
de64713041
commit
c39e000bbf
18
manifest
18
manifest
@ -1,5 +1,5 @@
|
||||
C The\sbtree.c\smodule\scompiles\sand\slinks\sand\spasses\ssome\stests.\s\sMany\stests\nstill\sfail,\sthough.\s(CVS\s1321)
|
||||
D 2004-05-07T17:57:50
|
||||
C More\sbug\sfixes\sin\sbtree.c.\s(CVS\s1322)
|
||||
D 2004-05-07T23:50:57
|
||||
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
|
||||
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
||||
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
||||
@ -23,8 +23,8 @@ F sqlite.def fc4f5734786fe4743cfe2aa98eb2da4b089edb5f
|
||||
F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
|
||||
F src/attach.c b01db0d3211f673d8e670abf7eaad04591d40d14
|
||||
F src/auth.c 4fa3b05bd19445d1c474d6751c4a508d6ea0abe1
|
||||
F src/btree.c ff2f51fcd01c4fb9f2ce0f061a549e0c9aae9d74
|
||||
F src/btree.h 49b255b2880c50a3572a536ea935edb2dd33aae3
|
||||
F src/btree.c a5fafa6179c80ca422fea96b4553525648f5535e
|
||||
F src/btree.h ba5d3bfadc3f46f86df525ac07274dc497af856a
|
||||
F src/btree_rb.c 99feb3ff835106d018a483a1ce403e5cf9c718bc
|
||||
F src/build.c 76fbca30081decd6615dee34b48c927ed5063752
|
||||
F src/copy.c 750e13828c3e4a293123e36aaa7cf0f22466248a
|
||||
@ -54,7 +54,7 @@ F src/table.c d845cb101b5afc1f7fea083c99e3d2fa7998d895
|
||||
F src/tclsqlite.c 9fe6fc0c20820e9411dfea407635de9b9d3ae0e3
|
||||
F src/test1.c 9aa62b89d420e6763b5e7ae89a47f6cf87370477
|
||||
F src/test2.c 9d611c45e1b07039a2bd95f5ea73178362b23229
|
||||
F src/test3.c d6af4e26bdbb7512ab5d01e49f34e72415d58a3b
|
||||
F src/test3.c cec7eee9e64f95a3d2e4a3c242e081f560f98cf8
|
||||
F src/test4.c 6e3e31acfaf21d66420fc35fda5b17dc0000cc8d
|
||||
F src/test5.c 3ff0565057b8d23e20092d5c6c0b7cb0d932c51e
|
||||
F src/tokenize.c 6676b946fd8825b67ab52140af4fdc57a70bda48
|
||||
@ -75,7 +75,7 @@ F test/auth.test 5c4d95cdaf539c0c236e20ce1f71a93e7dde9185
|
||||
F test/bigfile.test ea904b853ce2d703b16c5ce90e2b54951bc1ae81
|
||||
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
|
||||
F test/bind.test 56a57043b42c4664ca705f6050e56717a8a6699a
|
||||
F test/btree.test 77f93efac02dd05c7532b366b226bfe74757af57
|
||||
F test/btree.test c8a548edf00f46ceb5b9db8bd5c250e95b744c48
|
||||
F test/btree2.test e3b81ec33dc2f89b3e6087436dfe605b870c9080
|
||||
F test/btree3.test e597fb59be2ac0ea69c62aaa2064e998e528b665
|
||||
F test/btree3rb.test 127efcf5cdfcc352054e7db12622b01cdd8b36ac
|
||||
@ -190,7 +190,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
|
||||
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
|
||||
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
|
||||
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
|
||||
P dcd6b55f932a7ade4ad058534651e198b56370ad
|
||||
R cdb403059e0209ca0544e8ccaa4370da
|
||||
P d394b2b217d4d728f9eba397262bf9d36195719e
|
||||
R 04bebd7ff9ebbf1a875d441cf21d682e
|
||||
U drh
|
||||
Z 48eb767d5af5b72432055086442dfd47
|
||||
Z ae2d2cf62d0e5010d2f2e28dfebc946c
|
||||
|
@ -1 +1 @@
|
||||
d394b2b217d4d728f9eba397262bf9d36195719e
|
||||
a80939ef714ec884950b4a1f4f809ffa37fdfa59
|
225
src/btree.c
225
src/btree.c
@ -9,7 +9,7 @@
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: btree.c,v 1.111 2004/05/07 17:57:50 drh Exp $
|
||||
** $Id: btree.c,v 1.112 2004/05/07 23:50:57 drh Exp $
|
||||
**
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** For a detailed discussion of BTrees, refer to
|
||||
@ -266,18 +266,11 @@ struct BtCursor {
|
||||
MemPage *pPage; /* Page that contains the entry */
|
||||
int idx; /* Index of the entry in pPage->aCell[] */
|
||||
u8 wrFlag; /* True if writable */
|
||||
u8 eSkip; /* Determines if next step operation is a no-op */
|
||||
u8 iMatch; /* compare result from last sqlite3BtreeMoveto() */
|
||||
u8 isValid; /* TRUE if points to a valid entry */
|
||||
u8 status; /* Set to SQLITE_ABORT if cursors is invalidated */
|
||||
};
|
||||
|
||||
/*
|
||||
** Legal values for BtCursor.eSkip.
|
||||
*/
|
||||
#define SKIP_NONE 0 /* Always step the cursor */
|
||||
#define SKIP_NEXT 1 /* The next sqlite3BtreeNext() is a no-op */
|
||||
#define SKIP_PREV 2 /* The next sqlite3BtreePrevious() is a no-op */
|
||||
#define SKIP_INVALID 3 /* Calls to Next() and Previous() are invalid */
|
||||
|
||||
/*
|
||||
** Read or write a two-, four-, and eight-byte big-endian integer values.
|
||||
*/
|
||||
@ -405,6 +398,7 @@ static void defragmentPage(MemPage *pPage){
|
||||
if( !pPage->leaf ){
|
||||
n += 4;
|
||||
}
|
||||
memcpy(&newPage[hdr], &oldPage[hdr], n-hdr);
|
||||
start = n;
|
||||
pc = get2byte(&oldPage[addr]);
|
||||
i = 0;
|
||||
@ -413,11 +407,12 @@ static void defragmentPage(MemPage *pPage){
|
||||
size = cellSize(pPage, &oldPage[pc]);
|
||||
memcpy(&newPage[n], &oldPage[pc], size);
|
||||
put2byte(&newPage[addr],n);
|
||||
pPage->aCell[i] = &oldPage[n];
|
||||
pPage->aCell[i++] = &oldPage[n];
|
||||
n += size;
|
||||
addr = pc;
|
||||
pc = get2byte(&oldPage[pc]);
|
||||
}
|
||||
assert( i==pPage->nCell );
|
||||
leftover = pPage->pBt->pageSize - n;
|
||||
assert( leftover>=0 );
|
||||
assert( pPage->nFree==leftover );
|
||||
@ -426,15 +421,16 @@ static void defragmentPage(MemPage *pPage){
|
||||
leftover = 0;
|
||||
n = pPage->pBt->pageSize;
|
||||
}
|
||||
memcpy(&oldPage[start], &newPage[start], n-start);
|
||||
memcpy(&oldPage[hdr], &newPage[hdr], n-hdr);
|
||||
if( leftover==0 ){
|
||||
put2byte(&oldPage[hdr+3], 0);
|
||||
put2byte(&oldPage[hdr+1], 0);
|
||||
}else if( leftover>=4 ){
|
||||
put2byte(&oldPage[hdr+3], n);
|
||||
put2byte(&oldPage[hdr+1], n);
|
||||
put2byte(&oldPage[n], 0);
|
||||
put2byte(&oldPage[n+2], leftover);
|
||||
memset(&oldPage[n+4], 0, leftover-4);
|
||||
}
|
||||
oldPage[hdr+5] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1082,6 +1078,22 @@ int sqlite3BtreeCommit(Btree *pBt){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Invalidate all cursors
|
||||
*/
|
||||
static void invalidateCursors(Btree *pBt){
|
||||
BtCursor *pCur;
|
||||
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
|
||||
MemPage *pPage = pCur->pPage;
|
||||
if( pPage && !pPage->isInit ){
|
||||
releasePage(pPage);
|
||||
pCur->pPage = 0;
|
||||
pCur->isValid = 0;
|
||||
pCur->status = SQLITE_ABORT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Rollback the transaction in progress. All cursors will be
|
||||
** invalided by this operation. Any attempt to use a cursor
|
||||
@ -1093,18 +1105,11 @@ int sqlite3BtreeCommit(Btree *pBt){
|
||||
*/
|
||||
int sqlite3BtreeRollback(Btree *pBt){
|
||||
int rc;
|
||||
BtCursor *pCur;
|
||||
if( pBt->inTrans==0 ) return SQLITE_OK;
|
||||
pBt->inTrans = 0;
|
||||
pBt->inStmt = 0;
|
||||
rc = pBt->readOnly ? SQLITE_OK : sqlite3pager_rollback(pBt->pPager);
|
||||
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
|
||||
MemPage *pPage = pCur->pPage;
|
||||
if( pPage && !pPage->isInit ){
|
||||
releasePage(pPage);
|
||||
pCur->pPage = 0;
|
||||
}
|
||||
}
|
||||
invalidateCursors(pBt);
|
||||
unlockBtreeIfUnused(pBt);
|
||||
return rc;
|
||||
}
|
||||
@ -1155,16 +1160,9 @@ int sqlite3BtreeCommitStmt(Btree *pBt){
|
||||
*/
|
||||
int sqlite3BtreeRollbackStmt(Btree *pBt){
|
||||
int rc;
|
||||
BtCursor *pCur;
|
||||
if( pBt->inStmt==0 || pBt->readOnly ) return SQLITE_OK;
|
||||
rc = sqlite3pager_stmt_rollback(pBt->pPager);
|
||||
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
|
||||
MemPage *pPage = pCur->pPage;
|
||||
if( pPage && !pPage->isInit ){
|
||||
releasePage(pPage);
|
||||
pCur->pPage = 0;
|
||||
}
|
||||
}
|
||||
invalidateCursors(pBt);
|
||||
pBt->inStmt = 0;
|
||||
return rc;
|
||||
}
|
||||
@ -1265,7 +1263,6 @@ int sqlite3BtreeCursor(
|
||||
pCur->pBt = pBt;
|
||||
pCur->wrFlag = wrFlag;
|
||||
pCur->idx = 0;
|
||||
pCur->eSkip = SKIP_INVALID;
|
||||
pCur->pNext = pBt->pCursor;
|
||||
if( pCur->pNext ){
|
||||
pCur->pNext->pPrev = pCur;
|
||||
@ -1280,6 +1277,8 @@ int sqlite3BtreeCursor(
|
||||
pCur->pShared = pCur;
|
||||
}
|
||||
pBt->pCursor = pCur;
|
||||
pCur->isValid = 0;
|
||||
pCur->status = SQLITE_OK;
|
||||
*ppCur = pCur;
|
||||
return SQLITE_OK;
|
||||
|
||||
@ -1351,13 +1350,15 @@ static void releaseTempCursor(BtCursor *pCur){
|
||||
*/
|
||||
int sqlite3BtreeKeySize(BtCursor *pCur, u64 *pSize){
|
||||
MemPage *pPage;
|
||||
unsigned char *cell;
|
||||
|
||||
pPage = pCur->pPage;
|
||||
assert( pPage!=0 );
|
||||
if( pCur->idx >= pPage->nCell ){
|
||||
if( !pCur->isValid ){
|
||||
*pSize = 0;
|
||||
}else{
|
||||
unsigned char *cell = pPage->aCell[pCur->idx];
|
||||
pPage = pCur->pPage;
|
||||
assert( pPage!=0 );
|
||||
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
||||
cell = pPage->aCell[pCur->idx];
|
||||
cell += 2; /* Skip the offset to the next cell */
|
||||
if( !pPage->leaf ){
|
||||
cell += 4; /* Skip the child pointer */
|
||||
@ -1394,6 +1395,7 @@ static int getPayload(
|
||||
int maxLocal, ovflSize;
|
||||
|
||||
assert( pCur!=0 && pCur->pPage!=0 );
|
||||
assert( pCur->isValid );
|
||||
pBt = pCur->pBt;
|
||||
pPage = pCur->pPage;
|
||||
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
||||
@ -1474,16 +1476,14 @@ static int getPayload(
|
||||
** the available payload.
|
||||
*/
|
||||
int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
|
||||
MemPage *pPage;
|
||||
|
||||
assert( amt>=0 );
|
||||
assert( offset>=0 );
|
||||
assert( pCur->pPage!=0 );
|
||||
pPage = pCur->pPage;
|
||||
if( pCur->idx >= pPage->nCell || pPage->intKey ){
|
||||
assert( amt==0 );
|
||||
return SQLITE_OK;
|
||||
if( pCur->isValid==0 ){
|
||||
return pCur->status;
|
||||
}
|
||||
assert( pCur->pPage!=0 );
|
||||
assert( pCur->pPage->intKey==0 );
|
||||
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
|
||||
return getPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
|
||||
}
|
||||
|
||||
@ -1512,10 +1512,16 @@ void *sqlite3BtreeKeyFetch(BtCursor *pCur){
|
||||
Btree *pBt;
|
||||
u64 nData, nKey;
|
||||
|
||||
assert( pCur!=0 && pCur->pPage!=0 );
|
||||
assert( pCur!=0 );
|
||||
if( !pCur->isValid ){
|
||||
return 0;
|
||||
}
|
||||
assert( pCur->pPage!=0 );
|
||||
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
|
||||
pBt = pCur->pBt;
|
||||
pPage = pCur->pPage;
|
||||
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
||||
assert( pPage->intKey==0 );
|
||||
aPayload = pPage->aCell[pCur->idx];
|
||||
aPayload += 2; /* Skip the next cell index */
|
||||
if( !pPage->leaf ){
|
||||
@ -1525,7 +1531,7 @@ void *sqlite3BtreeKeyFetch(BtCursor *pCur){
|
||||
aPayload += getVarint(aPayload, &nData);
|
||||
}
|
||||
aPayload += getVarint(aPayload, &nKey);
|
||||
if( pPage->intKey || nKey>pBt->maxLocal ){
|
||||
if( nKey>pBt->maxLocal ){
|
||||
return 0;
|
||||
}
|
||||
return aPayload;
|
||||
@ -1541,14 +1547,19 @@ void *sqlite3BtreeKeyFetch(BtCursor *pCur){
|
||||
*/
|
||||
int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
|
||||
MemPage *pPage;
|
||||
unsigned char *cell;
|
||||
u64 size;
|
||||
|
||||
if( !pCur->isValid ){
|
||||
return pCur->status ? pCur->status : SQLITE_INTERNAL;
|
||||
}
|
||||
pPage = pCur->pPage;
|
||||
assert( pPage!=0 );
|
||||
if( pCur->idx >= pPage->nCell || pPage->zeroData ){
|
||||
assert( pPage->isInit );
|
||||
if( pPage->zeroData ){
|
||||
*pSize = 0;
|
||||
}else{
|
||||
unsigned char *cell;
|
||||
u64 size;
|
||||
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
||||
cell = pPage->aCell[pCur->idx];
|
||||
cell += 2; /* Skip the offset to the next cell */
|
||||
if( !pPage->leaf ){
|
||||
@ -1571,15 +1582,13 @@ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
|
||||
** the available payload.
|
||||
*/
|
||||
int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
|
||||
MemPage *pPage;
|
||||
|
||||
if( !pCur->isValid ){
|
||||
return pCur->status ? pCur->status : SQLITE_INTERNAL;
|
||||
}
|
||||
assert( amt>=0 );
|
||||
assert( offset>=0 );
|
||||
assert( pCur->pPage!=0 );
|
||||
pPage = pCur->pPage;
|
||||
if( pCur->idx >= pPage->nCell ){
|
||||
return 0;
|
||||
}
|
||||
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
|
||||
return getPayload(pCur, offset, amt, pBuf, 1);
|
||||
}
|
||||
|
||||
@ -1593,6 +1602,7 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
|
||||
MemPage *pOldPage;
|
||||
Btree *pBt = pCur->pBt;
|
||||
|
||||
assert( pCur->isValid );
|
||||
rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage);
|
||||
if( rc ) return rc;
|
||||
pNewPage->idxParent = pCur->idx;
|
||||
@ -1637,6 +1647,7 @@ static void moveToParent(BtCursor *pCur){
|
||||
MemPage *pPage;
|
||||
int idxParent;
|
||||
|
||||
assert( pCur->isValid );
|
||||
pPage = pCur->pPage;
|
||||
assert( pPage!=0 );
|
||||
assert( !isRootPage(pPage) );
|
||||
@ -1686,7 +1697,10 @@ static int moveToRoot(BtCursor *pCur){
|
||||
Btree *pBt = pCur->pBt;
|
||||
|
||||
rc = getAndInitPage(pBt, pCur->pgnoRoot, &pRoot, 0);
|
||||
if( rc ) return rc;
|
||||
if( rc ){
|
||||
pCur->isValid = 0;
|
||||
return rc;
|
||||
}
|
||||
releasePage(pCur->pPage);
|
||||
pCur->pPage = pRoot;
|
||||
pCur->idx = 0;
|
||||
@ -1697,6 +1711,7 @@ static int moveToRoot(BtCursor *pCur){
|
||||
assert( subpage>0 );
|
||||
rc = moveToChild(pCur, subpage);
|
||||
}
|
||||
pCur->isValid = pCur->pPage->nCell>0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1709,6 +1724,7 @@ static int moveToLeftmost(BtCursor *pCur){
|
||||
int rc;
|
||||
MemPage *pPage;
|
||||
|
||||
assert( pCur->isValid );
|
||||
while( !(pPage = pCur->pPage)->leaf ){
|
||||
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
||||
pgno = get4byte(&pPage->aCell[pCur->idx][2]);
|
||||
@ -1730,6 +1746,7 @@ static int moveToRightmost(BtCursor *pCur){
|
||||
int rc;
|
||||
MemPage *pPage;
|
||||
|
||||
assert( pCur->isValid );
|
||||
while( !(pPage = pCur->pPage)->leaf ){
|
||||
pgno = get4byte(&pPage->aData[pPage->hdrOffset+6]);
|
||||
pCur->idx = pPage->nCell;
|
||||
@ -1746,16 +1763,19 @@ static int moveToRightmost(BtCursor *pCur){
|
||||
*/
|
||||
int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
|
||||
int rc;
|
||||
if( pCur->pPage==0 ) return SQLITE_ABORT;
|
||||
if( pCur->status ){
|
||||
return pCur->status;
|
||||
}
|
||||
rc = moveToRoot(pCur);
|
||||
if( rc ) return rc;
|
||||
if( pCur->pPage->nCell==0 ){
|
||||
if( pCur->isValid==0 ){
|
||||
assert( pCur->pPage->nCell==0 );
|
||||
*pRes = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
assert( pCur->pPage->nCell>0 );
|
||||
*pRes = 0;
|
||||
rc = moveToLeftmost(pCur);
|
||||
pCur->eSkip = SKIP_NONE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1765,17 +1785,19 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
|
||||
*/
|
||||
int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
|
||||
int rc;
|
||||
if( pCur->pPage==0 ) return SQLITE_ABORT;
|
||||
if( pCur->status ){
|
||||
return pCur->status;
|
||||
}
|
||||
rc = moveToRoot(pCur);
|
||||
if( rc ) return rc;
|
||||
assert( pCur->pPage->isInit );
|
||||
if( pCur->pPage->nCell==0 ){
|
||||
if( pCur->isValid==0 ){
|
||||
assert( pCur->pPage->nCell==0 );
|
||||
*pRes = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
assert( pCur->isValid );
|
||||
*pRes = 0;
|
||||
rc = moveToRightmost(pCur);
|
||||
pCur->eSkip = SKIP_NONE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1809,10 +1831,18 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
|
||||
*/
|
||||
int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, u64 nKey, int *pRes){
|
||||
int rc;
|
||||
if( pCur->pPage==0 ) return SQLITE_ABORT;
|
||||
pCur->eSkip = SKIP_NONE;
|
||||
|
||||
if( pCur->status ){
|
||||
return pCur->status;
|
||||
}
|
||||
rc = moveToRoot(pCur);
|
||||
if( rc ) return rc;
|
||||
assert( pCur->pPage );
|
||||
assert( pCur->pPage->isInit );
|
||||
if( pCur->isValid==0 ){
|
||||
assert( pCur->pPage->nCell==0 );
|
||||
return SQLITE_OK;
|
||||
}
|
||||
for(;;){
|
||||
int lwr, upr;
|
||||
Pgno chldPg;
|
||||
@ -1865,16 +1895,30 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, u64 nKey, int *pRes){
|
||||
}
|
||||
if( chldPg==0 ){
|
||||
pCur->iMatch = c;
|
||||
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
|
||||
if( pRes ) *pRes = c;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pCur->idx = lwr;
|
||||
rc = moveToChild(pCur, chldPg);
|
||||
if( rc ) return rc;
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
/* NOT REACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the cursor is not pointing at an entry of the table.
|
||||
**
|
||||
** TRUE will be returned after a call to sqlite3BtreeNext() moves
|
||||
** past the last entry in the table or sqlite3BtreePrev() moves past
|
||||
** the first entry. TRUE is also returned if the table is empty.
|
||||
*/
|
||||
int sqlite3BtreeEof(BtCursor *pCur){
|
||||
return pCur->isValid==0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Advance the cursor to the next entry in the database. If
|
||||
** successful then set *pRes=0. If the cursor
|
||||
@ -1885,23 +1929,12 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
||||
int rc;
|
||||
MemPage *pPage = pCur->pPage;
|
||||
assert( pRes!=0 );
|
||||
if( pPage==0 ){
|
||||
if( pCur->isValid==0 ){
|
||||
*pRes = 1;
|
||||
return SQLITE_ABORT;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
assert( pPage->isInit );
|
||||
assert( pCur->eSkip!=SKIP_INVALID );
|
||||
if( pPage->nCell==0 ){
|
||||
*pRes = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
assert( pCur->idx<pPage->nCell );
|
||||
if( pCur->eSkip==SKIP_NEXT ){
|
||||
pCur->eSkip = SKIP_NONE;
|
||||
*pRes = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pCur->eSkip = SKIP_NONE;
|
||||
pCur->idx++;
|
||||
if( pCur->idx>=pPage->nCell ){
|
||||
if( !pPage->leaf ){
|
||||
@ -1914,6 +1947,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
||||
do{
|
||||
if( isRootPage(pPage) ){
|
||||
*pRes = 1;
|
||||
pCur->isValid = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
moveToParent(pCur);
|
||||
@ -1940,23 +1974,12 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
||||
int rc;
|
||||
Pgno pgno;
|
||||
MemPage *pPage;
|
||||
if( pCur->isValid==0 ){
|
||||
*pRes = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pPage = pCur->pPage;
|
||||
if( pPage==0 ){
|
||||
*pRes = 1;
|
||||
return SQLITE_ABORT;
|
||||
}
|
||||
assert( pPage->isInit );
|
||||
assert( pCur->eSkip!=SKIP_INVALID );
|
||||
if( pPage->nCell==0 ){
|
||||
*pRes = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( pCur->eSkip==SKIP_PREV ){
|
||||
pCur->eSkip = SKIP_NONE;
|
||||
*pRes = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pCur->eSkip = SKIP_NONE;
|
||||
assert( pCur->idx>=0 );
|
||||
if( !pPage->leaf ){
|
||||
pgno = get4byte(&pPage->aCell[pCur->idx][2]);
|
||||
@ -1966,7 +1989,8 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
||||
}else{
|
||||
while( pCur->idx==0 ){
|
||||
if( isRootPage(pPage) ){
|
||||
if( pRes ) *pRes = 1;
|
||||
pCur->isValid = 0;
|
||||
*pRes = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
moveToParent(pCur);
|
||||
@ -2924,8 +2948,8 @@ int sqlite3BtreeInsert(
|
||||
unsigned char *oldCell;
|
||||
unsigned char newCell[MX_CELL_SIZE];
|
||||
|
||||
if( pCur->pPage==0 ){
|
||||
return SQLITE_ABORT; /* A rollback destroyed this cursor */
|
||||
if( pCur->status ){
|
||||
return pCur->status; /* A rollback destroyed this cursor */
|
||||
}
|
||||
if( !pBt->inTrans || nKey+nData==0 ){
|
||||
/* Must start a transaction before doing an insert */
|
||||
@ -2969,7 +2993,6 @@ int sqlite3BtreeInsert(
|
||||
/* sqlite3BtreePageDump(pCur->pBt, pCur->pgnoRoot, 1); */
|
||||
/* fflush(stdout); */
|
||||
moveToRoot(pCur);
|
||||
pCur->eSkip = SKIP_INVALID;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -2985,8 +3008,8 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
||||
Btree *pBt = pCur->pBt;
|
||||
|
||||
assert( pPage->isInit );
|
||||
if( pCur->pPage==0 ){
|
||||
return SQLITE_ABORT; /* A rollback destroyed this cursor */
|
||||
if( pCur->status ){
|
||||
return pCur->status; /* A rollback destroyed this cursor */
|
||||
}
|
||||
if( !pBt->inTrans ){
|
||||
/* Must start a transaction before doing a delete */
|
||||
@ -3276,7 +3299,7 @@ int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){
|
||||
nFree = 0;
|
||||
i = 0;
|
||||
idx = get2byte(&pPage->aData[hdrOffset+1]);
|
||||
while( idx>0 && idx<SQLITE_USABLE_SIZE ){
|
||||
while( idx>0 && idx<pPage->pBt->pageSize ){
|
||||
int sz = get2byte(&pPage->aData[idx+2]);
|
||||
sprintf(range,"%d..%d", idx, idx+sz-1);
|
||||
nFree += sz;
|
||||
@ -3346,7 +3369,7 @@ int sqlite3BtreeCursorDump(BtCursor *pCur, int *aResult){
|
||||
aResult[4] = pPage->nFree;
|
||||
cnt = 0;
|
||||
idx = get2byte(&pPage->aData[pPage->hdrOffset+1]);
|
||||
while( idx>0 && idx<SQLITE_USABLE_SIZE ){
|
||||
while( idx>0 && idx<pPage->pBt->pageSize ){
|
||||
cnt++;
|
||||
idx = get2byte(&pPage->aData[idx]);
|
||||
}
|
||||
@ -3707,7 +3730,7 @@ int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
|
||||
|
||||
if( !pBtTo->inTrans || !pBtFrom->inTrans ) return SQLITE_ERROR;
|
||||
if( pBtTo->pCursor ) return SQLITE_BUSY;
|
||||
memcpy(pBtTo->pPage1, pBtFrom->pPage1, SQLITE_USABLE_SIZE);
|
||||
memcpy(pBtTo->pPage1, pBtFrom->pPage1, pBtFrom->pageSize);
|
||||
rc = sqlite3pager_overwrite(pBtTo->pPager, 1, pBtFrom->pPage1);
|
||||
nToPage = sqlite3pager_pagecount(pBtTo->pPager);
|
||||
nPage = sqlite3pager_pagecount(pBtFrom->pPager);
|
||||
|
@ -13,7 +13,7 @@
|
||||
** subsystem. See comments in the source code for a detailed description
|
||||
** of what each interface routine does.
|
||||
**
|
||||
** @(#) $Id: btree.h,v 1.38 2004/05/07 13:30:42 drh Exp $
|
||||
** @(#) $Id: btree.h,v 1.39 2004/05/07 23:50:57 drh Exp $
|
||||
*/
|
||||
#ifndef _BTREE_H_
|
||||
#define _BTREE_H_
|
||||
@ -72,6 +72,7 @@ int sqlite3BtreeInsert(BtCursor*, const void *pKey, u64 nKey,
|
||||
int sqlite3BtreeFirst(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeLast(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeNext(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeEof(BtCursor*);
|
||||
int sqlite3BtreePrevious(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeKeySize(BtCursor*, u64 *pSize);
|
||||
int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
|
||||
|
29
src/test3.c
29
src/test3.c
@ -13,7 +13,7 @@
|
||||
** is not included in the SQLite library. It is used for automated
|
||||
** testing of the SQLite library.
|
||||
**
|
||||
** $Id: test3.c,v 1.27 2004/05/07 17:57:50 drh Exp $
|
||||
** $Id: test3.c,v 1.28 2004/05/07 23:50:57 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "pager.h"
|
||||
@ -810,6 +810,32 @@ static int btree_last(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: btree_eof ID
|
||||
**
|
||||
** Return TRUE if the given cursor is not pointing at a valid entry.
|
||||
** Return FALSE if the cursor does point to a valid entry.
|
||||
*/
|
||||
static int btree_eof(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
BtCursor *pCur;
|
||||
char zBuf[50];
|
||||
|
||||
if( argc!=2 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" ID\"", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
|
||||
sprintf(zBuf, "%d", sqlite3BtreeEof(pCur));
|
||||
Tcl_AppendResult(interp, zBuf, 0);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: btree_keysize ID
|
||||
**
|
||||
@ -1022,6 +1048,7 @@ int Sqlitetest3_Init(Tcl_Interp *interp){
|
||||
{ "btree_insert", (Tcl_CmdProc*)btree_insert },
|
||||
{ "btree_next", (Tcl_CmdProc*)btree_next },
|
||||
{ "btree_prev", (Tcl_CmdProc*)btree_prev },
|
||||
{ "btree_eof", (Tcl_CmdProc*)btree_eof },
|
||||
{ "btree_keysize", (Tcl_CmdProc*)btree_keysize },
|
||||
{ "btree_key", (Tcl_CmdProc*)btree_key },
|
||||
{ "btree_data", (Tcl_CmdProc*)btree_data },
|
||||
|
153
test/btree.test
153
test/btree.test
@ -11,7 +11,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is btree database backend
|
||||
#
|
||||
# $Id: btree.test,v 1.16 2004/05/07 17:57:50 drh Exp $
|
||||
# $Id: btree.test,v 1.17 2004/05/07 23:50:58 drh Exp $
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
@ -185,13 +185,17 @@ do_test btree-3.18 {
|
||||
do_test btree-3.19 {
|
||||
btree_data $::c1
|
||||
} {6.00}
|
||||
do_test btree-3.20 {
|
||||
do_test btree-3.20.1 {
|
||||
btree_next $::c1
|
||||
btree_key $::c1
|
||||
} {0}
|
||||
do_test btree-3.20.2 {
|
||||
btree_eof $::c1
|
||||
} {1}
|
||||
do_test btree-3.21 {
|
||||
btree_data $::c1
|
||||
} {}
|
||||
set rc [catch {btree_data $::c1} res]
|
||||
lappend rc $res
|
||||
} {1 SQLITE_INTERNAL}
|
||||
|
||||
# Commit the changes, reopen and reread the data
|
||||
#
|
||||
@ -270,8 +274,9 @@ do_test btree-3.39 {
|
||||
btree_key $::c1
|
||||
} {0}
|
||||
do_test btree-3.40 {
|
||||
btree_data $::c1
|
||||
} {}
|
||||
set rc [catch {btree_data $::c1} res]
|
||||
lappend rc $res
|
||||
} {1 SQLITE_INTERNAL}
|
||||
do_test btree-3.41 {
|
||||
lindex [btree_pager_stats $::b1] 1
|
||||
} {1}
|
||||
@ -307,7 +312,7 @@ do_test btree-4.4 {
|
||||
set r {}
|
||||
while 1 {
|
||||
set key [btree_key $::c1]
|
||||
if {$key==0} break
|
||||
if {[btree_eof $::c1]} break
|
||||
lappend r $key
|
||||
lappend r [btree_data $::c1]
|
||||
btree_next $::c1
|
||||
@ -323,7 +328,7 @@ do_test btree-4.5 {
|
||||
set r {}
|
||||
while 1 {
|
||||
set key [btree_key $::c1]
|
||||
if {$key==0} break
|
||||
if {[btree_eof $::c1]} break
|
||||
lappend r $key
|
||||
lappend r [btree_data $::c1]
|
||||
btree_next $::c1
|
||||
@ -352,7 +357,7 @@ do_test btree-4.9 {
|
||||
btree_first $::c1
|
||||
while 1 {
|
||||
set key [btree_key $::c1]
|
||||
if {$key==0} break
|
||||
if {[btree_eof $::c1]} break
|
||||
lappend r $key
|
||||
lappend r [btree_data $::c1]
|
||||
btree_next $::c1
|
||||
@ -396,22 +401,9 @@ do_test btree-5.6 {
|
||||
|
||||
proc select_all {cursor} {
|
||||
set r {}
|
||||
btree_move_to $cursor {}
|
||||
while 1 {
|
||||
btree_first $cursor
|
||||
while {![btree_eof $cursor]} {
|
||||
set key [btree_key $cursor]
|
||||
if {$key==""} break
|
||||
lappend r $key
|
||||
lappend r [btree_data $cursor]
|
||||
btree_next $cursor
|
||||
}
|
||||
return $r
|
||||
}
|
||||
proc select_all_intkey {cursor} {
|
||||
set r {}
|
||||
btree_move_to $cursor 0
|
||||
while 1 {
|
||||
set key [btree_key $cursor]
|
||||
if {$key==0} break
|
||||
lappend r $key
|
||||
lappend r [btree_data $cursor]
|
||||
btree_next $cursor
|
||||
@ -420,10 +412,9 @@ proc select_all_intkey {cursor} {
|
||||
}
|
||||
proc select_keys {cursor} {
|
||||
set r {}
|
||||
btree_move_to $cursor {}
|
||||
while 1 {
|
||||
btree_first $cursor
|
||||
while {![btree_eof $cursor]} {
|
||||
set key [btree_key $cursor]
|
||||
if {$key==""} break
|
||||
lappend r $key
|
||||
btree_next $cursor
|
||||
}
|
||||
@ -449,6 +440,7 @@ do_test btree-6.2.2 {
|
||||
} {2}
|
||||
do_test btree-6.2.3 {
|
||||
btree_insert $::c2 ten 10
|
||||
btree_move_to $::c2 ten
|
||||
btree_key $::c2
|
||||
} {ten}
|
||||
do_test btree-6.3 {
|
||||
@ -457,7 +449,7 @@ do_test btree-6.3 {
|
||||
lindex [btree_pager_stats $::b1] 1
|
||||
} {2}
|
||||
do_test btree-6.3.1 {
|
||||
select_all_intkey $::c1
|
||||
select_all $::c1
|
||||
} {200 2.00 300 3.00 400 4.00 500 5.00 600 6.00}
|
||||
#btree_page_dump $::b1 3
|
||||
do_test btree-6.4 {
|
||||
@ -497,15 +489,15 @@ do_test btree-6.9.1 {
|
||||
btree_key $::c2
|
||||
} {}
|
||||
|
||||
# If we drop table 2 it just clears the table. Table 2 always exists.
|
||||
# If we drop table 1 it just clears the table. Table 1 always exists.
|
||||
#
|
||||
do_test btree-6.10 {
|
||||
btree_close_cursor $::c1
|
||||
btree_drop_table $::b1 2
|
||||
set ::c1 [btree_cursor $::b1 2 1]
|
||||
btree_move_to $::c1 {}
|
||||
btree_key $::c1
|
||||
} {}
|
||||
btree_drop_table $::b1 1
|
||||
set ::c1 [btree_cursor $::b1 1 1]
|
||||
btree_first $::c1
|
||||
btree_eof $::c1
|
||||
} {1}
|
||||
do_test btree-6.11 {
|
||||
btree_commit $::b1
|
||||
select_all $::c1
|
||||
@ -516,12 +508,12 @@ do_test btree-6.12 {
|
||||
do_test btree-6.13 {
|
||||
btree_close_cursor $::c2
|
||||
lindex [btree_pager_stats $::b1] 1
|
||||
} {2}
|
||||
} {1}
|
||||
|
||||
# Check to see that pages defragment properly. To do this test we will
|
||||
#
|
||||
# 1. Fill the first page table 2 with data.
|
||||
# 2. Delete every other entry of table 2.
|
||||
# 1. Fill the first page of table 1 with data.
|
||||
# 2. Delete every other entry of table 1.
|
||||
# 3. Insert a single entry that requires more contiguous
|
||||
# space than is available.
|
||||
#
|
||||
@ -531,98 +523,112 @@ do_test btree-7.1 {
|
||||
catch {unset key}
|
||||
catch {unset data}
|
||||
do_test btree-7.2 {
|
||||
for {set i 0} {$i<36} {incr i} {
|
||||
set key [format %03d $i]
|
||||
set data "*** $key ***"
|
||||
# Each record will be 10 bytes in size.
|
||||
# + 100 bytes of database header
|
||||
# + 6 bytes of table header
|
||||
# + 91*10=910 bytes of cells
|
||||
# Totals 1016 bytes. 8 bytes left over
|
||||
# Keys are 1000 through 1090.
|
||||
for {set i 1000} {$i<1091} {incr i} {
|
||||
set key $i
|
||||
set data [format %5d $i]
|
||||
btree_insert $::c1 $key $data
|
||||
}
|
||||
lrange [btree_cursor_dump $::c1] 4 5
|
||||
} {8 1}
|
||||
do_test btree-7.3 {
|
||||
btree_move_to $::c1 000
|
||||
while {[btree_key $::c1]!=""} {
|
||||
for {set i 1001} {$i<1091} {incr i 2} {
|
||||
btree_move_to $::c1 $i
|
||||
btree_delete $::c1
|
||||
btree_next $::c1
|
||||
btree_next $::c1
|
||||
}
|
||||
# Freed 45 blocks. Total freespace is 458
|
||||
# Keys remaining are even numbers between 1000 and 1090, inclusive
|
||||
lrange [btree_cursor_dump $::c1] 4 5
|
||||
} {512 19}
|
||||
} {458 46}
|
||||
#btree_page_dump $::b1 2
|
||||
do_test btree-7.4 {
|
||||
btree_insert $::c1 018 {*** 018 ***+++}
|
||||
# The largest free block is 10 bytes long. So if we insert
|
||||
# a record bigger than 10 bytes it should force a defrag
|
||||
# The record is 20 bytes long.
|
||||
btree_insert $::c1 2000 {123456789_12345}
|
||||
btree_move_to $::c1 2000
|
||||
btree_key $::c1
|
||||
} {018}
|
||||
} {2000}
|
||||
do_test btree-7.5 {
|
||||
lrange [btree_cursor_dump $::c1] 4 5
|
||||
} {480 1}
|
||||
} {438 1}
|
||||
#btree_page_dump $::b1 2
|
||||
|
||||
# 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
|
||||
# matches the size of the desired space.
|
||||
#
|
||||
# Keys are even numbers between 1000 and 1090 and one record of 2000.
|
||||
# There are 47 keys total.
|
||||
#
|
||||
do_test btree-7.6 {
|
||||
btree_move_to $::c1 007
|
||||
btree_move_to $::c1 1006
|
||||
btree_delete $::c1
|
||||
btree_move_to $::c1 011
|
||||
btree_move_to $::c1 1010
|
||||
btree_delete $::c1
|
||||
} {}
|
||||
do_test btree-7.7 {
|
||||
lindex [btree_cursor_dump $::c1] 5
|
||||
} {3}
|
||||
lrange [btree_cursor_dump $::c1] 4 5
|
||||
} {458 3} ;# Create two new holes of 10 bytes each
|
||||
#btree_page_dump $::b1 2
|
||||
do_test btree-7.8 {
|
||||
btree_insert $::c1 007 {*** 007 ***}
|
||||
lindex [btree_cursor_dump $::c1] 5
|
||||
} {2}
|
||||
btree_insert $::c1 1006 { 1006}
|
||||
lrange [btree_cursor_dump $::c1] 4 5
|
||||
} {448 2} ;# Filled in the first hole
|
||||
#btree_page_dump $::b1 2
|
||||
|
||||
# Make sure the freeSpace() routine properly coaleses adjacent memory blocks
|
||||
#
|
||||
do_test btree-7.9 {
|
||||
btree_move_to $::c1 013
|
||||
btree_move_to $::c1 1012
|
||||
btree_delete $::c1
|
||||
lrange [btree_cursor_dump $::c1] 4 5
|
||||
} {536 2}
|
||||
} {458 2} ;# Coalesce with the whole before
|
||||
do_test btree-7.10 {
|
||||
btree_move_to $::c1 009
|
||||
btree_move_to $::c1 1008
|
||||
btree_delete $::c1
|
||||
lrange [btree_cursor_dump $::c1] 4 5
|
||||
} {564 2}
|
||||
} {468 2} ;# Coalesce with whole after
|
||||
do_test btree-7.11 {
|
||||
btree_move_to $::c1 018
|
||||
btree_move_to $::c1 1030
|
||||
btree_delete $::c1
|
||||
lrange [btree_cursor_dump $::c1] 4 5
|
||||
} {596 2}
|
||||
} {478 3} ;# Make a new hole
|
||||
do_test btree-7.13 {
|
||||
btree_move_to $::c1 033
|
||||
btree_move_to $::c1 1034
|
||||
btree_delete $::c1
|
||||
lrange [btree_cursor_dump $::c1] 4 5
|
||||
} {624 3}
|
||||
} {488 4} ;# Make another hole
|
||||
do_test btree-7.14 {
|
||||
btree_move_to $::c1 035
|
||||
btree_move_to $::c1 1032
|
||||
btree_delete $::c1
|
||||
lrange [btree_cursor_dump $::c1] 4 5
|
||||
} {652 2}
|
||||
} {498 3} ;# The freed space should coalesce on both ends
|
||||
#btree_page_dump $::b1 2
|
||||
do_test btree-7.15 {
|
||||
lindex [btree_pager_stats $::b1] 1
|
||||
} {2}
|
||||
} {1}
|
||||
|
||||
# Check to see that data on overflow pages work correctly.
|
||||
#
|
||||
do_test btree-8.1 {
|
||||
set data "*** This is a very long key "
|
||||
while {[string length $data]<256} {append data $data}
|
||||
while {[string length $data]<1234} {append data $data}
|
||||
set ::data $data
|
||||
btree_insert $::c1 020 $data
|
||||
btree_insert $::c1 2020 $data
|
||||
} {}
|
||||
#btree_page_dump $::b1 2
|
||||
do_test btree-8.1.1 {
|
||||
lindex [btree_pager_stats $::b1] 1
|
||||
} {2}
|
||||
} {1}
|
||||
#btree_pager_ref_dump $::b1
|
||||
do_test btree-8.2 {
|
||||
btree_move_to $::c1 2020
|
||||
string length [btree_data $::c1]
|
||||
} [string length $::data]
|
||||
do_test btree-8.3 {
|
||||
@ -638,9 +644,10 @@ do_test btree-8.5 {
|
||||
set data "*** This is an even longer key"
|
||||
while {[string length $data]<2000} {append data $data}
|
||||
set ::data $data
|
||||
btree_insert $::c1 020 $data
|
||||
btree_insert $::c1 2030 $data
|
||||
} {}
|
||||
do_test btree-8.6 {
|
||||
btree_move_to 2030
|
||||
string length [btree_data $::c1]
|
||||
} [string length $::data]
|
||||
do_test btree-8.7 {
|
||||
@ -654,8 +661,8 @@ do_test btree-8.9 {
|
||||
btree_close_cursor $::c1
|
||||
btree_close $::b1
|
||||
set ::b1 [btree_open test1.bt 2000 0]
|
||||
set ::c1 [btree_cursor $::b1 2 1]
|
||||
btree_move_to $::c1 020
|
||||
set ::c1 [btree_cursor $::b1 1 1]
|
||||
btree_move_to $::c1 2030
|
||||
btree_data $::c1
|
||||
} $::data
|
||||
do_test btree-8.10 {
|
||||
@ -664,7 +671,7 @@ do_test btree-8.10 {
|
||||
} {}
|
||||
do_test btree-8.11 {
|
||||
lindex [btree_get_meta $::b1] 0
|
||||
} [expr {int(([string length $::data]-238+1019)/1020)}]
|
||||
} {}
|
||||
|
||||
# Now check out keys on overflow pages.
|
||||
#
|
||||
|
Loading…
Reference in New Issue
Block a user