1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Factor out btree test logic into a separate test_btree.c file. (CVS 3928)

FossilOrigin-Name: d51274f1cc3a75f6a03e90259ce829ac1dacf78f
This commit is contained in:
drh
2007-05-05 18:39:25 +00:00
parent 59df4cda00
commit 16a9b8363d
10 changed files with 397 additions and 355 deletions

View File

@@ -224,6 +224,7 @@ TESTSRC = \
$(TOP)/src/test9.c \ $(TOP)/src/test9.c \
$(TOP)/src/test_autoext.c \ $(TOP)/src/test_autoext.c \
$(TOP)/src/test_async.c \ $(TOP)/src/test_async.c \
$(TOP)/src/test_btree.c \
$(TOP)/src/test_hexio.c \ $(TOP)/src/test_hexio.c \
$(TOP)/src/test_md5.c \ $(TOP)/src/test_md5.c \
$(TOP)/src/test_schema.c \ $(TOP)/src/test_schema.c \

View File

@@ -180,6 +180,7 @@ TESTSRC = \
$(TOP)/src/test9.c \ $(TOP)/src/test9.c \
$(TOP)/src/test_autoext.c \ $(TOP)/src/test_autoext.c \
$(TOP)/src/test_async.c \ $(TOP)/src/test_async.c \
$(TOP)/src/test_btree.c \
$(TOP)/src/test_hexio.c \ $(TOP)/src/test_hexio.c \
$(TOP)/src/test_md5.c \ $(TOP)/src/test_md5.c \
$(TOP)/src/test_schema.c \ $(TOP)/src/test_schema.c \

View File

@@ -1,6 +1,6 @@
C Fix\sa\ssprintf()\sproblem\sintroduced\sby\s(3916).\s(CVS\s3927) C Factor\sout\sbtree\stest\slogic\sinto\sa\sseparate\stest_btree.c\sfile.\s(CVS\s3928)
D 2007-05-05T12:06:24 D 2007-05-05T18:39:25
F Makefile.in 80d63bf2c61619ae0e29795948ec19e79f91acc3 F Makefile.in ea8888bdcf53313d26576fcabcb6d0a10ecd35cd
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
F VERSION 6de5e9812c227f00155cb59af3535017aef3e258 F VERSION 6de5e9812c227f00155cb59af3535017aef3e258
@@ -44,7 +44,7 @@ F ext/fts2/fts2_tokenizer1.c 5c979fe8815f95396beb22b627571da895a025af
F ext/fts2/mkfts2amal.tcl 2a9ec76b0760fe7f3669dca5bc0d60728bc1c977 F ext/fts2/mkfts2amal.tcl 2a9ec76b0760fe7f3669dca5bc0d60728bc1c977
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
F ltmain.sh 56abb507100ed2d4261f6dd1653dec3cf4066387 F ltmain.sh 56abb507100ed2d4261f6dd1653dec3cf4066387
F main.mk b9fd506a8ff3abd83b01dff9abdb98948a207f26 F main.mk a7522a769f2fe70c9bebd6bd8a36bed79be0e5cb
F mkdll.sh ed62756baf44babf562a7843588790c02fee2106 F mkdll.sh ed62756baf44babf562a7843588790c02fee2106
F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d
F mkopcodeh.awk cde995d269aa06c94adbf6455bea0acedb913fa5 F mkopcodeh.awk cde995d269aa06c94adbf6455bea0acedb913fa5
@@ -59,9 +59,9 @@ F src/alter.c 2c79ec40f65e33deaf90ca493422c74586e481a3
F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651 F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651
F src/attach.c f088f8155541ff75542239ec40cf05f3d81390ba F src/attach.c f088f8155541ff75542239ec40cf05f3d81390ba
F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f
F src/btree.c 7311696faf137cb37421c8e1d0e22e2d3a15de51 F src/btree.c 6d3db6416c71f678a4dd4719ce6d754ad5927c46
F src/btree.h a9cd72b05a14f6be22e057daf954ae548d2bcbe4 F src/btree.h a9cd72b05a14f6be22e057daf954ae548d2bcbe4
F src/btreeInt.h 2de5f19abb59fcc5e87474fe59ef8110cfa0d343 F src/btreeInt.h cb3c0e9eb842d06079a62cdf3492c90c5db7ba75
F src/build.c 0dd6f0d0a5d304be91374f4c7228a3e9b00ff7f1 F src/build.c 0dd6f0d0a5d304be91374f4c7228a3e9b00ff7f1
F src/callback.c 6414ed32d55859d0f65067aa5b88d2da27b3af9e F src/callback.c 6414ed32d55859d0f65067aa5b88d2da27b3af9e
F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675 F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675
@@ -104,7 +104,7 @@ F src/sqlite3ext.h 7d0d363ea7327e817ef0dfe1b7eee1f171b72890
F src/sqliteInt.h 3ffe2f9c801575e315451e7d2831c4a90a165aa8 F src/sqliteInt.h 3ffe2f9c801575e315451e7d2831c4a90a165aa8
F src/table.c a8de75bcedf84d4060d804264b067ab3b1a3561d F src/table.c a8de75bcedf84d4060d804264b067ab3b1a3561d
F src/tclsqlite.c f3414b2d6bc37e6760b49c9abd3504ff69f4441b F src/tclsqlite.c f3414b2d6bc37e6760b49c9abd3504ff69f4441b
F src/test1.c 9fb5a4300897c01add79ff8691114e54e5a83ff0 F src/test1.c 515a91ed7ee95a6fa5b40873aa4f5aa9c858080e
F src/test2.c 24458b17ab2f3c90cbc1c8446bd7ffe69be62f88 F src/test2.c 24458b17ab2f3c90cbc1c8446bd7ffe69be62f88
F src/test3.c 946ea9d1a8c928656e3c70f0a2fcb8e733a15e86 F src/test3.c 946ea9d1a8c928656e3c70f0a2fcb8e733a15e86
F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25 F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25
@@ -115,6 +115,7 @@ F src/test8.c c3c4aeea4e3d70966306d6eca1b77ce7eee2f059
F src/test9.c c0f38f7795cc51d37db6c63874d90f40f10d0f0e F src/test9.c c0f38f7795cc51d37db6c63874d90f40f10d0f0e
F src/test_async.c 9d326ceda4306bcab252b8f7e8e480ed45d7ccb6 F src/test_async.c 9d326ceda4306bcab252b8f7e8e480ed45d7ccb6
F src/test_autoext.c 855157d97aa28cf84233847548bfacda21807436 F src/test_autoext.c 855157d97aa28cf84233847548bfacda21807436
F src/test_btree.c 893030a3c49ea36e9b15b01f1609727dfb11c81e
F src/test_hexio.c 32204b5ce281ebc85f789c69c4ec725129e7e7f5 F src/test_hexio.c 32204b5ce281ebc85f789c69c4ec725129e7e7f5
F src/test_loadext.c 22065d601a18878e5542191001f0eaa5d77c0ed8 F src/test_loadext.c 22065d601a18878e5542191001f0eaa5d77c0ed8
F src/test_md5.c 6c42bc0a3c0b54be34623ff77a0eec32b2fa96e3 F src/test_md5.c 6c42bc0a3c0b54be34623ff77a0eec32b2fa96e3
@@ -132,7 +133,7 @@ F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691
F src/vdbeInt.h cb02cbbceddf3b40d49012e9f41576f17bcbec97 F src/vdbeInt.h cb02cbbceddf3b40d49012e9f41576f17bcbec97
F src/vdbeapi.c 37d793559390bec8a00c556f651f21b5f9e589af F src/vdbeapi.c 37d793559390bec8a00c556f651f21b5f9e589af
F src/vdbeaux.c c432e17fef6efaf102d507e979cee4e47f6ceac4 F src/vdbeaux.c c432e17fef6efaf102d507e979cee4e47f6ceac4
F src/vdbeblob.c 6a25e9bbb874a7dcee4cf8f37d8dd635c129002e F src/vdbeblob.c 57127dc9fd01f3fded2eab30b5842f5f96b1c42b
F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f
F src/vdbemem.c ba98f8572ec4609846b368fa7580db178022f1bb F src/vdbemem.c ba98f8572ec4609846b368fa7580db178022f1bb
F src/vtab.c c5ebebf615b2f29499fbe97a584c4bb342632aa0 F src/vtab.c c5ebebf615b2f29499fbe97a584c4bb342632aa0
@@ -326,7 +327,7 @@ F test/select5.test 0b47058d3e916c1fc9fe81f44b438e02bade21ce
F test/select6.test 399f14b9ba37b768afe5d2cd8c12e4f340a69db8 F test/select6.test 399f14b9ba37b768afe5d2cd8c12e4f340a69db8
F test/select7.test 95697d8e8355ef7538e2fe768da16838bbd0fcde F test/select7.test 95697d8e8355ef7538e2fe768da16838bbd0fcde
F test/server1.test e328b8e641ba8fe9273132cfef497383185dc1f5 F test/server1.test e328b8e641ba8fe9273132cfef497383185dc1f5
F test/shared.test 315934fecff5ecb884449eaa5bae9876961f2f22 F test/shared.test 5c39f216ce85d723eda5875804bbf5ef8a03fcfc
F test/shared2.test 8b48f8d33494413ef4cf250110d89403e2bf6b23 F test/shared2.test 8b48f8d33494413ef4cf250110d89403e2bf6b23
F test/shared3.test 01e3e124dbb3859788aabc7cfb82f7ea04421749 F test/shared3.test 01e3e124dbb3859788aabc7cfb82f7ea04421749
F test/shared_err.test cc528f6e78665787e93d9ce3a782a2ce5179d821 F test/shared_err.test cc528f6e78665787e93d9ce3a782a2ce5179d821
@@ -477,7 +478,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
P ad549a40ed3500fb3d552ed19ff791d1280e0b62 P 54a1d275aa0154a88d433a3c4df538d52c2c3ecb
R 8e70c7a5e1bfad9e41e67f958c0c12ec R b1bb50d4a308744ac562ad6378a81905
U drh U drh
Z 58284854439e023cfa44a554bd182ac1 Z 79b62501eb7362c290096e8263df6144

View File

@@ -1 +1 @@
54a1d275aa0154a88d433a3c4df538d52c2c3ecb d51274f1cc3a75f6a03e90259ce829ac1dacf78f

View File

@@ -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.376 2007/05/05 11:48:54 drh Exp $ ** $Id: btree.c,v 1.377 2007/05/05 18:39:25 drh Exp $
** **
** This file implements a external (disk-based) database using BTrees. ** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information. ** See the header comment on "btreeInt.h" for additional information.
@@ -298,7 +298,7 @@ static void clearCursorPosition(BtCursor *pCur){
** returning the cursor to it's saved position, any saved position is deleted ** returning the cursor to it's saved position, any saved position is deleted
** and the cursor state set to CURSOR_INVALID. ** and the cursor state set to CURSOR_INVALID.
*/ */
static int restoreOrClearCursorPositionX(BtCursor *pCur){ int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur){
int rc; int rc;
assert( pCur->eState==CURSOR_REQUIRESEEK ); assert( pCur->eState==CURSOR_REQUIRESEEK );
#ifndef SQLITE_OMIT_INCRBLOB #ifndef SQLITE_OMIT_INCRBLOB
@@ -317,7 +317,9 @@ static int restoreOrClearCursorPositionX(BtCursor *pCur){
} }
#define restoreOrClearCursorPosition(p) \ #define restoreOrClearCursorPosition(p) \
(p->eState==CURSOR_REQUIRESEEK?restoreOrClearCursorPositionX(p):SQLITE_OK) (p->eState==CURSOR_REQUIRESEEK ? \
sqlite3BtreeRestoreOrClearCursorPosition(p) : \
SQLITE_OK)
#ifndef SQLITE_OMIT_AUTOVACUUM #ifndef SQLITE_OMIT_AUTOVACUUM
/* /*
@@ -417,7 +419,7 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
** **
** This routine works only for pages that do not contain overflow cells. ** This routine works only for pages that do not contain overflow cells.
*/ */
static u8 *findCell(MemPage *pPage, int iCell){ u8 *sqlite3BtreeFindCell(MemPage *pPage, int iCell){
u8 *data = pPage->aData; u8 *data = pPage->aData;
assert( iCell>=0 ); assert( iCell>=0 );
assert( iCell<get2byte(&data[pPage->hdrOffset+3]) ); assert( iCell<get2byte(&data[pPage->hdrOffset+3]) );
@@ -425,7 +427,7 @@ static u8 *findCell(MemPage *pPage, int iCell){
} }
/* /*
** This a more complex version of findCell() that works for ** This a more complex version of sqlite3BtreeFindCell() that works for
** pages that do contain overflow cells. See insert ** pages that do contain overflow cells. See insert
*/ */
static u8 *findOverflowCell(MemPage *pPage, int iCell){ static u8 *findOverflowCell(MemPage *pPage, int iCell){
@@ -442,16 +444,16 @@ static u8 *findOverflowCell(MemPage *pPage, int iCell){
iCell--; iCell--;
} }
} }
return findCell(pPage, iCell); return sqlite3BtreeFindCell(pPage, iCell);
} }
/* /*
** Parse a cell content block and fill in the CellInfo structure. There ** Parse a cell content block and fill in the CellInfo structure. There
** are two versions of this function. parseCell() takes a cell index ** are two versions of this function. sqlite3BtreeParseCell() takes a
** as the second argument and parseCellPtr() takes a pointer to the ** cell index as the second argument and sqlite3BtreeParseCellPtr()
** body of the cell as its second argument. ** takes a pointer to the body of the cell as its second argument.
*/ */
static void parseCellPtr( void sqlite3BtreeParseCellPtr(
MemPage *pPage, /* Page containing the cell */ MemPage *pPage, /* Page containing the cell */
u8 *pCell, /* Pointer to the cell text. */ u8 *pCell, /* Pointer to the cell text. */
CellInfo *pInfo /* Fill in this structure */ CellInfo *pInfo /* Fill in this structure */
@@ -517,12 +519,12 @@ static void parseCellPtr(
pInfo->nSize = pInfo->iOverflow + 4; pInfo->nSize = pInfo->iOverflow + 4;
} }
} }
static void parseCell( void sqlite3BtreeParseCell(
MemPage *pPage, /* Page containing the cell */ MemPage *pPage, /* Page containing the cell */
int iCell, /* The cell index. First cell is 0 */ int iCell, /* The cell index. First cell is 0 */
CellInfo *pInfo /* Fill in this structure */ CellInfo *pInfo /* Fill in this structure */
){ ){
parseCellPtr(pPage, findCell(pPage, iCell), pInfo); sqlite3BtreeParseCellPtr(pPage, sqlite3BtreeFindCell(pPage, iCell), pInfo);
} }
/* /*
@@ -534,13 +536,13 @@ static void parseCell(
#ifndef NDEBUG #ifndef NDEBUG
static int cellSize(MemPage *pPage, int iCell){ static int cellSize(MemPage *pPage, int iCell){
CellInfo info; CellInfo info;
parseCell(pPage, iCell, &info); sqlite3BtreeParseCell(pPage, iCell, &info);
return info.nSize; return info.nSize;
} }
#endif #endif
static int cellSizePtr(MemPage *pPage, u8 *pCell){ static int cellSizePtr(MemPage *pPage, u8 *pCell){
CellInfo info; CellInfo info;
parseCellPtr(pPage, pCell, &info); sqlite3BtreeParseCellPtr(pPage, pCell, &info);
return info.nSize; return info.nSize;
} }
@@ -553,7 +555,7 @@ static int cellSizePtr(MemPage *pPage, u8 *pCell){
static int ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell){ static int ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell){
if( pCell ){ if( pCell ){
CellInfo info; CellInfo info;
parseCellPtr(pPage, pCell, &info); sqlite3BtreeParseCellPtr(pPage, pCell, &info);
assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload ); assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload );
if( (info.nData+(pPage->intKey?0:info.nKey))>info.nLocal ){ if( (info.nData+(pPage->intKey?0:info.nKey))>info.nLocal ){
Pgno ovfl = get4byte(&pCell[info.iOverflow]); Pgno ovfl = get4byte(&pCell[info.iOverflow]);
@@ -802,7 +804,7 @@ static void decodeFlags(MemPage *pPage, int flagByte){
** guarantee that the page is well-formed. It only shows that ** guarantee that the page is well-formed. It only shows that
** we failed to detect any corruption. ** we failed to detect any corruption.
*/ */
static int initPage( int sqlite3BtreeInitPage(
MemPage *pPage, /* The page to be initialized */ MemPage *pPage, /* The page to be initialized */
MemPage *pParent /* The parent. Might be NULL */ MemPage *pParent /* The parent. Might be NULL */
){ ){
@@ -915,7 +917,12 @@ static void zeroPage(MemPage *pPage, int flags){
** means we have started to be concerned about content and the disk ** means we have started to be concerned about content and the disk
** read should occur at that point. ** read should occur at that point.
*/ */
static int getPage(BtShared *pBt, Pgno pgno, MemPage **ppPage, int noContent){ int sqlite3BtreeGetPage(
BtShared *pBt, /* The btree */
Pgno pgno, /* Number of the page to fetch */
MemPage **ppPage, /* Return the page in this parameter */
int noContent /* Do not load page content if true */
){
int rc; int rc;
MemPage *pPage; MemPage *pPage;
DbPage *pDbPage; DbPage *pDbPage;
@@ -935,7 +942,7 @@ static int getPage(BtShared *pBt, Pgno pgno, MemPage **ppPage, int noContent){
/* /*
** Get a page from the pager and initialize it. This routine ** Get a page from the pager and initialize it. This routine
** is just a convenience wrapper around separate calls to ** is just a convenience wrapper around separate calls to
** getPage() and initPage(). ** sqlite3BtreeGetPage() and sqlite3BtreeInitPage().
*/ */
static int getAndInitPage( static int getAndInitPage(
BtShared *pBt, /* The database file */ BtShared *pBt, /* The database file */
@@ -947,16 +954,16 @@ static int getAndInitPage(
if( pgno==0 ){ if( pgno==0 ){
return SQLITE_CORRUPT_BKPT; return SQLITE_CORRUPT_BKPT;
} }
rc = getPage(pBt, pgno, ppPage, 0); rc = sqlite3BtreeGetPage(pBt, pgno, ppPage, 0);
if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){ if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){
rc = initPage(*ppPage, pParent); rc = sqlite3BtreeInitPage(*ppPage, pParent);
} }
return rc; return rc;
} }
/* /*
** Release a MemPage. This should be called once for each prior ** Release a MemPage. This should be called once for each prior
** call to getPage. ** call to sqlite3BtreeGetPage.
*/ */
static void releasePage(MemPage *pPage){ static void releasePage(MemPage *pPage){
if( pPage ){ if( pPage ){
@@ -998,7 +1005,7 @@ static void pageReinit(DbPage *pData, int pageSize){
pPage = (MemPage *)sqlite3PagerGetExtra(pData); pPage = (MemPage *)sqlite3PagerGetExtra(pData);
if( pPage->isInit ){ if( pPage->isInit ){
pPage->isInit = 0; pPage->isInit = 0;
initPage(pPage, pPage->pParent); sqlite3BtreeInitPage(pPage, pPage->pParent);
} }
} }
@@ -1379,7 +1386,7 @@ static int lockBtree(BtShared *pBt){
int rc, pageSize; int rc, pageSize;
MemPage *pPage1; MemPage *pPage1;
if( pBt->pPage1 ) return SQLITE_OK; if( pBt->pPage1 ) return SQLITE_OK;
rc = getPage(pBt, 1, &pPage1, 0); rc = sqlite3BtreeGetPage(pBt, 1, &pPage1, 0);
if( rc!=SQLITE_OK ) return rc; if( rc!=SQLITE_OK ) return rc;
@@ -1641,11 +1648,11 @@ static int setChildPtrmaps(MemPage *pPage){
int isInitOrig = pPage->isInit; int isInitOrig = pPage->isInit;
Pgno pgno = pPage->pgno; Pgno pgno = pPage->pgno;
initPage(pPage, 0); sqlite3BtreeInitPage(pPage, 0);
nCell = pPage->nCell; nCell = pPage->nCell;
for(i=0; i<nCell; i++){ for(i=0; i<nCell; i++){
u8 *pCell = findCell(pPage, i); u8 *pCell = sqlite3BtreeFindCell(pPage, i);
rc = ptrmapPutOvflPtr(pPage, pCell); rc = ptrmapPutOvflPtr(pPage, pCell);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@@ -1696,14 +1703,14 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
int i; int i;
int nCell; int nCell;
initPage(pPage, 0); sqlite3BtreeInitPage(pPage, 0);
nCell = pPage->nCell; nCell = pPage->nCell;
for(i=0; i<nCell; i++){ for(i=0; i<nCell; i++){
u8 *pCell = findCell(pPage, i); u8 *pCell = sqlite3BtreeFindCell(pPage, i);
if( eType==PTRMAP_OVERFLOW1 ){ if( eType==PTRMAP_OVERFLOW1 ){
CellInfo info; CellInfo info;
parseCellPtr(pPage, pCell, &info); sqlite3BtreeParseCellPtr(pPage, pCell, &info);
if( info.iOverflow ){ if( info.iOverflow ){
if( iFrom==get4byte(&pCell[info.iOverflow]) ){ if( iFrom==get4byte(&pCell[info.iOverflow]) ){
put4byte(&pCell[info.iOverflow], iTo); put4byte(&pCell[info.iOverflow], iTo);
@@ -1788,7 +1795,7 @@ static int relocatePage(
** iPtrPage. ** iPtrPage.
*/ */
if( eType!=PTRMAP_ROOTPAGE ){ if( eType!=PTRMAP_ROOTPAGE ){
rc = getPage(pBt, iPtrPage, &pPtrPage, 0); rc = sqlite3BtreeGetPage(pBt, iPtrPage, &pPtrPage, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
@@ -1871,7 +1878,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin){
Pgno iFreePg; /* Index of free page to move pLastPg to */ Pgno iFreePg; /* Index of free page to move pLastPg to */
MemPage *pLastPg; MemPage *pLastPg;
rc = getPage(pBt, iLastPg, &pLastPg, 0); rc = sqlite3BtreeGetPage(pBt, iLastPg, &pLastPg, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
@@ -2132,25 +2139,6 @@ static int countWriteCursors(BtShared *pBt){
} }
#endif #endif
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
/*
** Print debugging information about all cursors to standard output.
*/
void sqlite3BtreeCursorList(Btree *p){
BtCursor *pCur;
BtShared *pBt = p->pBt;
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
MemPage *pPage = pCur->pPage;
char *zMode = pCur->wrFlag ? "rw" : "ro";
sqlite3DebugPrintf("CURSOR %p rooted at %4d(%s) currently at %d.%d%s\n",
pCur, pCur->pgnoRoot, zMode,
pPage ? pPage->pgno : 0, pCur->idx,
(pCur->eState==CURSOR_VALID) ? "" : " eof"
);
}
}
#endif
/* /*
** Rollback the transaction in progress. All cursors will be ** Rollback the transaction in progress. All cursors will be
** invalided by this operation. Any attempt to use a cursor ** invalided by this operation. Any attempt to use a cursor
@@ -2200,9 +2188,9 @@ int sqlite3BtreeRollback(Btree *p){
} }
/* The rollback may have destroyed the pPage1->aData value. So /* The rollback may have destroyed the pPage1->aData value. So
** call getPage() on page 1 again to make sure pPage1->aData is ** call sqlite3BtreeGetPage() on page 1 again to make
** set correctly. */ ** sure pPage1->aData is set correctly. */
if( getPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){ if( sqlite3BtreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){
releasePage(pPage1); releasePage(pPage1);
} }
assert( countWriteCursors(pBt)==0 ); assert( countWriteCursors(pBt)==0 );
@@ -2452,7 +2440,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
** Make a temporary cursor by filling in the fields of pTempCur. ** Make a temporary cursor by filling in the fields of pTempCur.
** The temporary cursor is not on the cursor list for the Btree. ** The temporary cursor is not on the cursor list for the Btree.
*/ */
static void getTempCursor(BtCursor *pCur, BtCursor *pTempCur){ void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur){
memcpy(pTempCur, pCur, sizeof(*pCur)); memcpy(pTempCur, pCur, sizeof(*pCur));
pTempCur->pNext = 0; pTempCur->pNext = 0;
pTempCur->pPrev = 0; pTempCur->pPrev = 0;
@@ -2465,7 +2453,7 @@ static void getTempCursor(BtCursor *pCur, BtCursor *pTempCur){
** Delete a temporary cursor such as was made by the CreateTemporaryCursor() ** Delete a temporary cursor such as was made by the CreateTemporaryCursor()
** function above. ** function above.
*/ */
static void releaseTempCursor(BtCursor *pCur){ void sqlite3BtreeReleaseTempCursor(BtCursor *pCur){
if( pCur->pPage ){ if( pCur->pPage ){
sqlite3PagerUnref(pCur->pPage->pDbPage); sqlite3PagerUnref(pCur->pPage->pDbPage);
} }
@@ -2473,19 +2461,19 @@ static void releaseTempCursor(BtCursor *pCur){
/* /*
** Make sure the BtCursor.info field of the given cursor is valid. ** Make sure the BtCursor.info field of the given cursor is valid.
** If it is not already valid, call parseCell() to fill it in. ** If it is not already valid, call sqlite3BtreeParseCell() to fill it in.
** **
** BtCursor.info is a cache of the information in the current cell. ** BtCursor.info is a cache of the information in the current cell.
** Using this cache reduces the number of calls to parseCell(). ** Using this cache reduces the number of calls to sqlite3BtreeParseCell().
*/ */
static void getCellInfo(BtCursor *pCur){ static void getCellInfo(BtCursor *pCur){
if( pCur->info.nSize==0 ){ if( pCur->info.nSize==0 ){
parseCell(pCur->pPage, pCur->idx, &pCur->info); sqlite3BtreeParseCell(pCur->pPage, pCur->idx, &pCur->info);
}else{ }else{
#ifndef NDEBUG #ifndef NDEBUG
CellInfo info; CellInfo info;
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
parseCell(pCur->pPage, pCur->idx, &info); sqlite3BtreeParseCell(pCur->pPage, pCur->idx, &info);
assert( memcmp(&info, &pCur->info, sizeof(info))==0 ); assert( memcmp(&info, &pCur->info, sizeof(info))==0 );
#endif #endif
} }
@@ -2568,7 +2556,7 @@ static int getOverflowPage(
** a MemPage* reference only. No page-data is required in this case. ** a MemPage* reference only. No page-data is required in this case.
*/ */
if( !pPgnoNext ){ if( !pPgnoNext ){
return getPage(pBt, ovfl, ppPage, 1); return sqlite3BtreeGetPage(pBt, ovfl, ppPage, 1);
} }
#ifndef SQLITE_OMIT_AUTOVACUUM #ifndef SQLITE_OMIT_AUTOVACUUM
@@ -2602,7 +2590,7 @@ static int getOverflowPage(
if( next==0 || ppPage ){ if( next==0 || ppPage ){
MemPage *pPage = 0; MemPage *pPage = 0;
rc = getPage(pBt, ovfl, &pPage, next!=0); rc = sqlite3BtreeGetPage(pBt, ovfl, &pPage, next!=0);
assert(rc==SQLITE_OK || pPage==0); assert(rc==SQLITE_OK || pPage==0);
if( next==0 && rc==SQLITE_OK ){ if( next==0 && rc==SQLITE_OK ){
next = get4byte(pPage->aData); next = get4byte(pPage->aData);
@@ -2681,7 +2669,6 @@ static int copyPayload(
** * A commit in auto_vacuum="full" mode, ** * A commit in auto_vacuum="full" mode,
** * Creating a table (may require moving an overflow page). ** * Creating a table (may require moving an overflow page).
*/ */
#define getPayload(a,b,c,d,e) accessPayload(a,b,c,d,e,0)
static int accessPayload( static int accessPayload(
BtCursor *pCur, /* Cursor pointing to entry to read from */ BtCursor *pCur, /* Cursor pointing to entry to read from */
int offset, /* Begin reading this far into payload */ int offset, /* Begin reading this far into payload */
@@ -2834,7 +2821,7 @@ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
} }
assert( pCur->pPage->intKey==0 ); assert( pCur->pPage->intKey==0 );
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell ); assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
rc = getPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); rc = accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0, 0);
} }
return rc; return rc;
} }
@@ -2854,7 +2841,7 @@ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
assert( pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_VALID );
assert( pCur->pPage!=0 ); assert( pCur->pPage!=0 );
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell ); assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
rc = getPayload(pCur, offset, amt, pBuf, 1); rc = accessPayload(pCur, offset, amt, pBuf, 1, 0);
} }
return rc; return rc;
} }
@@ -2871,7 +2858,7 @@ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
** and data to fit on the local page and for there to be no overflow ** and data to fit on the local page and for there to be no overflow
** pages. When that is so, this routine can be used to access the ** pages. When that is so, this routine can be used to access the
** key and data without making a copy. If the key and/or data spills ** key and data without making a copy. If the key and/or data spills
** onto overflow pages, then getPayload() must be used to reassembly ** onto overflow pages, then accessPayload() must be used to reassembly
** the key/data and copy it into a preallocated buffer. ** the key/data and copy it into a preallocated buffer.
** **
** The pointer returned by this routine looks directly into the cached ** The pointer returned by this routine looks directly into the cached
@@ -2974,7 +2961,7 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
** virtual root page is the page that the right-pointer of page ** virtual root page is the page that the right-pointer of page
** 1 is pointing to. ** 1 is pointing to.
*/ */
static int isRootPage(MemPage *pPage){ int sqlite3BtreeIsRootPage(MemPage *pPage){
MemPage *pParent = pPage->pParent; MemPage *pParent = pPage->pParent;
if( pParent==0 ) return 1; if( pParent==0 ) return 1;
if( pParent->pgno>1 ) return 0; if( pParent->pgno>1 ) return 0;
@@ -2990,7 +2977,7 @@ static int isRootPage(MemPage *pPage){
** right-most child page then pCur->idx is set to one more than ** right-most child page then pCur->idx is set to one more than
** the largest cell index. ** the largest cell index.
*/ */
static void moveToParent(BtCursor *pCur){ void sqlite3BtreeMoveToParent(BtCursor *pCur){
MemPage *pParent; MemPage *pParent;
MemPage *pPage; MemPage *pPage;
int idxParent; int idxParent;
@@ -2998,7 +2985,7 @@ static void moveToParent(BtCursor *pCur){
assert( pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_VALID );
pPage = pCur->pPage; pPage = pCur->pPage;
assert( pPage!=0 ); assert( pPage!=0 );
assert( !isRootPage(pPage) ); assert( !sqlite3BtreeIsRootPage(pPage) );
pParent = pPage->pParent; pParent = pPage->pParent;
assert( pParent!=0 ); assert( pParent!=0 );
idxParent = pPage->idxParent; idxParent = pPage->idxParent;
@@ -3063,7 +3050,7 @@ static int moveToLeftmost(BtCursor *pCur){
assert( pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_VALID );
while( !(pPage = pCur->pPage)->leaf ){ while( !(pPage = pCur->pPage)->leaf ){
assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
pgno = get4byte(findCell(pPage, pCur->idx)); pgno = get4byte(sqlite3BtreeFindCell(pPage, pCur->idx));
rc = moveToChild(pCur, pgno); rc = moveToChild(pCur, pgno);
if( rc ) return rc; if( rc ) return rc;
} }
@@ -3200,7 +3187,7 @@ int sqlite3BtreeMoveto(
pCur->info.nSize = 0; pCur->info.nSize = 0;
if( pPage->intKey ){ if( pPage->intKey ){
u8 *pCell; u8 *pCell;
pCell = findCell(pPage, pCur->idx) + pPage->childPtrSize; pCell = sqlite3BtreeFindCell(pPage, pCur->idx) + pPage->childPtrSize;
if( pPage->hasData ){ if( pPage->hasData ){
u32 dummy; u32 dummy;
pCell += getVarint32(pCell, &dummy); pCell += getVarint32(pCell, &dummy);
@@ -3255,7 +3242,7 @@ int sqlite3BtreeMoveto(
}else if( lwr>=pPage->nCell ){ }else if( lwr>=pPage->nCell ){
chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]);
}else{ }else{
chldPg = get4byte(findCell(pPage, lwr)); chldPg = get4byte(sqlite3BtreeFindCell(pPage, lwr));
} }
if( chldPg==0 ){ if( chldPg==0 ){
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell ); assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
@@ -3328,12 +3315,12 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
return rc; return rc;
} }
do{ do{
if( isRootPage(pPage) ){ if( sqlite3BtreeIsRootPage(pPage) ){
*pRes = 1; *pRes = 1;
pCur->eState = CURSOR_INVALID; pCur->eState = CURSOR_INVALID;
return SQLITE_OK; return SQLITE_OK;
} }
moveToParent(pCur); sqlite3BtreeMoveToParent(pCur);
pPage = pCur->pPage; pPage = pCur->pPage;
}while( pCur->idx>=pPage->nCell ); }while( pCur->idx>=pPage->nCell );
*pRes = 0; *pRes = 0;
@@ -3382,18 +3369,18 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
assert( pPage->isInit ); assert( pPage->isInit );
assert( pCur->idx>=0 ); assert( pCur->idx>=0 );
if( !pPage->leaf ){ if( !pPage->leaf ){
pgno = get4byte( findCell(pPage, pCur->idx) ); pgno = get4byte( sqlite3BtreeFindCell(pPage, pCur->idx) );
rc = moveToChild(pCur, pgno); rc = moveToChild(pCur, pgno);
if( rc ) return rc; if( rc ) return rc;
rc = moveToRightmost(pCur); rc = moveToRightmost(pCur);
}else{ }else{
while( pCur->idx==0 ){ while( pCur->idx==0 ){
if( isRootPage(pPage) ){ if( sqlite3BtreeIsRootPage(pPage) ){
pCur->eState = CURSOR_INVALID; pCur->eState = CURSOR_INVALID;
*pRes = 1; *pRes = 1;
return SQLITE_OK; return SQLITE_OK;
} }
moveToParent(pCur); sqlite3BtreeMoveToParent(pCur);
pPage = pCur->pPage; pPage = pCur->pPage;
} }
pCur->idx--; pCur->idx--;
@@ -3486,7 +3473,7 @@ static int allocateBtreePage(
}else{ }else{
iTrunk = get4byte(&pPage1->aData[32]); iTrunk = get4byte(&pPage1->aData[32]);
} }
rc = getPage(pBt, iTrunk, &pTrunk, 0); rc = sqlite3BtreeGetPage(pBt, iTrunk, &pTrunk, 0);
if( rc ){ if( rc ){
pTrunk = 0; pTrunk = 0;
goto end_allocate_page; goto end_allocate_page;
@@ -3536,7 +3523,7 @@ static int allocateBtreePage(
*/ */
MemPage *pNewTrunk; MemPage *pNewTrunk;
Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); Pgno iNewTrunk = get4byte(&pTrunk->aData[8]);
rc = getPage(pBt, iNewTrunk, &pNewTrunk, 0); rc = sqlite3BtreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
goto end_allocate_page; goto end_allocate_page;
} }
@@ -3602,7 +3589,7 @@ static int allocateBtreePage(
memcpy(&aData[8+closest*4], &aData[4+k*4], 4); memcpy(&aData[8+closest*4], &aData[4+k*4], 4);
} }
put4byte(&aData[4], k-1); put4byte(&aData[4], k-1);
rc = getPage(pBt, *pPgno, ppPage, 1); rc = sqlite3BtreeGetPage(pBt, *pPgno, ppPage, 1);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
sqlite3PagerDontRollback((*ppPage)->pDbPage); sqlite3PagerDontRollback((*ppPage)->pDbPage);
rc = sqlite3PagerWrite((*ppPage)->pDbPage); rc = sqlite3PagerWrite((*ppPage)->pDbPage);
@@ -3647,7 +3634,7 @@ static int allocateBtreePage(
#endif #endif
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
rc = getPage(pBt, *pPgno, ppPage, 0); rc = sqlite3BtreeGetPage(pBt, *pPgno, ppPage, 0);
if( rc ) return rc; if( rc ) return rc;
rc = sqlite3PagerWrite((*ppPage)->pDbPage); rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@@ -3716,7 +3703,7 @@ static int freePage(MemPage *pPage){
/* Other free pages already exist. Retrive the first trunk page /* Other free pages already exist. Retrive the first trunk page
** of the freelist and find out how many leaves it has. */ ** of the freelist and find out how many leaves it has. */
MemPage *pTrunk; MemPage *pTrunk;
rc = getPage(pBt, get4byte(&pPage1->aData[32]), &pTrunk, 0); rc = sqlite3BtreeGetPage(pBt, get4byte(&pPage1->aData[32]), &pTrunk, 0);
if( rc ) return rc; if( rc ) return rc;
k = get4byte(&pTrunk->aData[4]); k = get4byte(&pTrunk->aData[4]);
if( k>=pBt->usableSize/4 - 8 ){ if( k>=pBt->usableSize/4 - 8 ){
@@ -3757,7 +3744,7 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){
int nOvfl; int nOvfl;
int ovflPageSize; int ovflPageSize;
parseCellPtr(pPage, pCell, &info); sqlite3BtreeParseCellPtr(pPage, pCell, &info);
if( info.iOverflow==0 ){ if( info.iOverflow==0 ){
return SQLITE_OK; /* No overflow pages. Return without doing anything */ return SQLITE_OK; /* No overflow pages. Return without doing anything */
} }
@@ -3824,7 +3811,7 @@ static int fillInCell(
nData = nZero = 0; nData = nZero = 0;
} }
nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey); nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey);
parseCellPtr(pPage, pCell, &info); sqlite3BtreeParseCellPtr(pPage, pCell, &info);
assert( info.nHeader==nHeader ); assert( info.nHeader==nHeader );
assert( info.nKey==nKey ); assert( info.nKey==nKey );
assert( info.nData==nData+nZero ); assert( info.nData==nData+nZero );
@@ -3951,7 +3938,7 @@ static int reparentChildPages(MemPage *pPage){
if( pPage->leaf ) return SQLITE_OK; if( pPage->leaf ) return SQLITE_OK;
for(i=0; i<pPage->nCell; i++){ for(i=0; i<pPage->nCell; i++){
u8 *pCell = findCell(pPage, i); u8 *pCell = sqlite3BtreeFindCell(pPage, i);
if( !pPage->leaf ){ if( !pPage->leaf ){
rc = reparentPage(pBt, get4byte(pCell), pPage, i); rc = reparentPage(pBt, get4byte(pCell), pPage, i);
if( rc!=SQLITE_OK ) return rc; if( rc!=SQLITE_OK ) return rc;
@@ -4077,7 +4064,7 @@ static int insertCell(
** the entry for the overflow page into the pointer map. ** the entry for the overflow page into the pointer map.
*/ */
CellInfo info; CellInfo info;
parseCellPtr(pPage, pCell, &info); sqlite3BtreeParseCellPtr(pPage, pCell, &info);
assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload ); assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload );
if( (info.nData+(pPage->intKey?0:info.nKey))>info.nLocal ){ if( (info.nData+(pPage->intKey?0:info.nKey))>info.nLocal ){
Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]); Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]);
@@ -4205,7 +4192,8 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){
** pPage is the next-to-right child. ** pPage is the next-to-right child.
*/ */
assert( pPage->nCell>0 ); assert( pPage->nCell>0 );
parseCellPtr(pPage, findCell(pPage, pPage->nCell-1), &info); pCell = sqlite3BtreeFindCell(pPage, pPage->nCell-1);
sqlite3BtreeParseCellPtr(pPage, pCell, &info);
rc = fillInCell(pParent, parentCell, 0, info.nKey, 0, 0, 0, &parentSize); rc = fillInCell(pParent, parentCell, 0, info.nKey, 0, 0, 0, &parentSize);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
@@ -4274,7 +4262,7 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){
*/ */
static int balance_nonroot(MemPage *pPage){ static int balance_nonroot(MemPage *pPage){
MemPage *pParent; /* The parent of pPage */ MemPage *pParent; /* The parent of pPage */
BtShared *pBt; /* The whole database */ BtShared *pBt; /* The whole database */
int nCell = 0; /* Number of cells in apCell[] */ int nCell = 0; /* Number of cells in apCell[] */
int nMaxCells = 0; /* Allocated size of apCell, szCell, aFrom. */ int nMaxCells = 0; /* Allocated size of apCell, szCell, aFrom. */
int nOld; /* Number of pages in apOld[] */ int nOld; /* Number of pages in apOld[] */
@@ -4354,7 +4342,7 @@ static int balance_nonroot(MemPage *pPage){
pgno = pPage->pgno; pgno = pPage->pgno;
assert( pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); assert( pgno==sqlite3PagerPagenumber(pPage->pDbPage) );
for(idx=0; idx<pParent->nCell; idx++){ for(idx=0; idx<pParent->nCell; idx++){
if( get4byte(findCell(pParent, idx))==pgno ){ if( get4byte(sqlite3BtreeFindCell(pParent, idx))==pgno ){
break; break;
} }
} }
@@ -4388,7 +4376,7 @@ static int balance_nonroot(MemPage *pPage){
nDiv = 0; nDiv = 0;
for(i=0, k=nxDiv; i<NB; i++, k++){ for(i=0, k=nxDiv; i<NB; i++, k++){
if( k<pParent->nCell ){ if( k<pParent->nCell ){
apDiv[i] = findCell(pParent, k); apDiv[i] = sqlite3BtreeFindCell(pParent, k);
nDiv++; nDiv++;
assert( !pParent->leaf ); assert( !pParent->leaf );
pgnoOld[i] = get4byte(apDiv[i]); pgnoOld[i] = get4byte(apDiv[i]);
@@ -4737,7 +4725,7 @@ static int balance_nonroot(MemPage *pPage){
*/ */
CellInfo info; CellInfo info;
j--; j--;
parseCellPtr(pNew, apCell[j], &info); sqlite3BtreeParseCellPtr(pNew, apCell[j], &info);
pCell = &aSpace[iSpace]; pCell = &aSpace[iSpace];
fillInCell(pParent, pCell, 0, info.nKey, 0, 0, 0, &sz); fillInCell(pParent, pCell, 0, info.nKey, 0, 0, 0, &sz);
iSpace += sz; iSpace += sz;
@@ -4858,10 +4846,10 @@ static int balance_shallower(MemPage *pPage){
pgnoChild = get4byte(&pPage->aData[pPage->hdrOffset+8]); pgnoChild = get4byte(&pPage->aData[pPage->hdrOffset+8]);
assert( pgnoChild>0 ); assert( pgnoChild>0 );
assert( pgnoChild<=sqlite3PagerPagecount(pPage->pBt->pPager) ); assert( pgnoChild<=sqlite3PagerPagecount(pPage->pBt->pPager) );
rc = getPage(pPage->pBt, pgnoChild, &pChild, 0); rc = sqlite3BtreeGetPage(pPage->pBt, pgnoChild, &pChild, 0);
if( rc ) goto end_shallow_balance; if( rc ) goto end_shallow_balance;
if( pPage->pgno==1 ){ if( pPage->pgno==1 ){
rc = initPage(pChild, pPage); rc = sqlite3BtreeInitPage(pChild, pPage);
if( rc ) goto end_shallow_balance; if( rc ) goto end_shallow_balance;
assert( pChild->nOverflow==0 ); assert( pChild->nOverflow==0 );
if( pChild->nFree>=100 ){ if( pChild->nFree>=100 ){
@@ -4870,7 +4858,7 @@ static int balance_shallower(MemPage *pPage){
int i; int i;
zeroPage(pPage, pChild->aData[0]); zeroPage(pPage, pChild->aData[0]);
for(i=0; i<pChild->nCell; i++){ for(i=0; i<pChild->nCell; i++){
apCell[i] = findCell(pChild,i); apCell[i] = sqlite3BtreeFindCell(pChild,i);
szCell[i] = cellSizePtr(pChild, apCell[i]); szCell[i] = cellSizePtr(pChild, apCell[i]);
} }
assemblePage(pPage, pChild->nCell, apCell, szCell); assemblePage(pPage, pChild->nCell, apCell, szCell);
@@ -4888,7 +4876,7 @@ static int balance_shallower(MemPage *pPage){
memcpy(pPage->aData, pChild->aData, pPage->pBt->usableSize); memcpy(pPage->aData, pChild->aData, pPage->pBt->usableSize);
pPage->isInit = 0; pPage->isInit = 0;
pPage->pParent = 0; pPage->pParent = 0;
rc = initPage(pPage, 0); rc = sqlite3BtreeInitPage(pPage, 0);
assert( rc==SQLITE_OK ); assert( rc==SQLITE_OK );
freePage(pChild); freePage(pChild);
TRACE(("BALANCE: transfer child %d into root %d\n", TRACE(("BALANCE: transfer child %d into root %d\n",
@@ -4950,7 +4938,7 @@ static int balance_deeper(MemPage *pPage){
memcpy(cdata, &data[hdr], pPage->cellOffset+2*pPage->nCell-hdr); memcpy(cdata, &data[hdr], pPage->cellOffset+2*pPage->nCell-hdr);
memcpy(&cdata[brk], &data[brk], usableSize-brk); memcpy(&cdata[brk], &data[brk], usableSize-brk);
assert( pChild->isInit==0 ); assert( pChild->isInit==0 );
rc = initPage(pChild, pPage); rc = sqlite3BtreeInitPage(pChild, pPage);
if( rc ) goto balancedeeper_out; if( rc ) goto balancedeeper_out;
memcpy(pChild->aOvfl, pPage->aOvfl, pPage->nOverflow*sizeof(pPage->aOvfl[0])); memcpy(pChild->aOvfl, pPage->aOvfl, pPage->nOverflow*sizeof(pPage->aOvfl[0]));
pChild->nOverflow = pPage->nOverflow; pChild->nOverflow = pPage->nOverflow;
@@ -5013,7 +5001,7 @@ static int balance(MemPage *pPage, int insert){
** **
** In addition to checking for read-locks (where a read-lock ** In addition to checking for read-locks (where a read-lock
** means a cursor opened with wrFlag==0) this routine also moves ** means a cursor opened with wrFlag==0) this routine also moves
** all cursors write cursors so that they are pointing to the ** all write cursors so that they are pointing to the
** first Cell on the root page. This is necessary because an insert ** first Cell on the root page. This is necessary because an insert
** or delete might change the number of cells on a page or delete ** or delete might change the number of cells on a page or delete
** a page entirely and we do not want to leave any cursors ** a page entirely and we do not want to leave any cursors
@@ -5103,7 +5091,7 @@ int sqlite3BtreeInsert(
if( loc==0 && CURSOR_VALID==pCur->eState ){ if( loc==0 && CURSOR_VALID==pCur->eState ){
int szOld; int szOld;
assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
oldCell = findCell(pPage, pCur->idx); oldCell = sqlite3BtreeFindCell(pPage, pCur->idx);
if( !pPage->leaf ){ if( !pPage->leaf ){
memcpy(newCell, oldCell, 4); memcpy(newCell, oldCell, 4);
} }
@@ -5175,7 +5163,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
** data. The clearCell() call frees any overflow pages associated with the ** data. The clearCell() call frees any overflow pages associated with the
** cell. The cell itself is still intact. ** cell. The cell itself is still intact.
*/ */
pCell = findCell(pPage, pCur->idx); pCell = sqlite3BtreeFindCell(pPage, pCur->idx);
if( !pPage->leaf ){ if( !pPage->leaf ){
pgnoChild = get4byte(pCell); pgnoChild = get4byte(pCell);
} }
@@ -5198,7 +5186,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
int notUsed; int notUsed;
unsigned char *tempCell = 0; unsigned char *tempCell = 0;
assert( !pPage->leafData ); assert( !pPage->leafData );
getTempCursor(pCur, &leafCur); sqlite3BtreeGetTempCursor(pCur, &leafCur);
rc = sqlite3BtreeNext(&leafCur, &notUsed); rc = sqlite3BtreeNext(&leafCur, &notUsed);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(leafCur.pPage->pDbPage); rc = sqlite3PagerWrite(leafCur.pPage->pDbPage);
@@ -5207,7 +5195,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
TRACE(("DELETE: table=%d delete internal from %d replace from leaf %d\n", TRACE(("DELETE: table=%d delete internal from %d replace from leaf %d\n",
pCur->pgnoRoot, pPage->pgno, leafCur.pPage->pgno)); pCur->pgnoRoot, pPage->pgno, leafCur.pPage->pgno));
dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell)); dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell));
pNext = findCell(leafCur.pPage, leafCur.idx); pNext = sqlite3BtreeFindCell(leafCur.pPage, leafCur.idx);
szNext = cellSizePtr(leafCur.pPage, pNext); szNext = cellSizePtr(leafCur.pPage, pNext);
assert( MX_CELL_SIZE(pBt)>=szNext+4 ); assert( MX_CELL_SIZE(pBt)>=szNext+4 );
tempCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) ); tempCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) );
@@ -5227,7 +5215,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
rc = balance(leafCur.pPage, 0); rc = balance(leafCur.pPage, 0);
} }
sqliteFree(tempCell); sqliteFree(tempCell);
releaseTempCursor(&leafCur); sqlite3BtreeReleaseTempCursor(&leafCur);
}else{ }else{
TRACE(("DELETE: table=%d delete from leaf %d\n", TRACE(("DELETE: table=%d delete from leaf %d\n",
pCur->pgnoRoot, pPage->pgno)); pCur->pgnoRoot, pPage->pgno));
@@ -5316,7 +5304,7 @@ int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
releasePage(pPageMove); releasePage(pPageMove);
/* Move the page currently at pgnoRoot to pgnoMove. */ /* Move the page currently at pgnoRoot to pgnoMove. */
rc = getPage(pBt, pgnoRoot, &pRoot, 0); rc = sqlite3BtreeGetPage(pBt, pgnoRoot, &pRoot, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
@@ -5339,7 +5327,7 @@ int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
rc = getPage(pBt, pgnoRoot, &pRoot, 0); rc = sqlite3BtreeGetPage(pBt, pgnoRoot, &pRoot, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
@@ -5398,7 +5386,7 @@ static int clearDatabasePage(
rc = getAndInitPage(pBt, pgno, &pPage, pParent); rc = getAndInitPage(pBt, pgno, &pPage, pParent);
if( rc ) goto cleardatabasepage_out; if( rc ) goto cleardatabasepage_out;
for(i=0; i<pPage->nCell; i++){ for(i=0; i<pPage->nCell; i++){
pCell = findCell(pPage, i); pCell = sqlite3BtreeFindCell(pPage, i);
if( !pPage->leaf ){ if( !pPage->leaf ){
rc = clearDatabasePage(pBt, get4byte(pCell), pPage->pParent, 1); rc = clearDatabasePage(pBt, get4byte(pCell), pPage->pParent, 1);
if( rc ) goto cleardatabasepage_out; if( rc ) goto cleardatabasepage_out;
@@ -5488,7 +5476,7 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
return SQLITE_LOCKED; return SQLITE_LOCKED;
} }
rc = getPage(pBt, (Pgno)iTable, &pPage, 0); rc = sqlite3BtreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
if( rc ) return rc; if( rc ) return rc;
rc = sqlite3BtreeClearTable(p, iTable); rc = sqlite3BtreeClearTable(p, iTable);
if( rc ){ if( rc ){
@@ -5527,7 +5515,7 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
*/ */
MemPage *pMove; MemPage *pMove;
releasePage(pPage); releasePage(pPage);
rc = getPage(pBt, maxRootPgno, &pMove, 0); rc = sqlite3BtreeGetPage(pBt, maxRootPgno, &pMove, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
@@ -5536,7 +5524,7 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
rc = getPage(pBt, maxRootPgno, &pMove, 0); rc = sqlite3BtreeGetPage(pBt, maxRootPgno, &pMove, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
@@ -5654,185 +5642,6 @@ int sqlite3BtreeFlags(BtCursor *pCur){
return pPage ? pPage->aData[pPage->hdrOffset] : 0; return pPage ? pPage->aData[pPage->hdrOffset] : 0;
} }
#ifdef SQLITE_DEBUG
/*
** Print a disassembly of the given page on standard output. This routine
** is used for debugging and testing only.
*/
static int btreePageDump(BtShared *pBt, int pgno, int recursive, MemPage *pParent){
int rc;
MemPage *pPage;
int i, j, c;
int nFree;
u16 idx;
int hdr;
int nCell;
int isInit;
unsigned char *data;
char range[20];
unsigned char payload[20];
rc = getPage(pBt, (Pgno)pgno, &pPage, 0);
isInit = pPage->isInit;
if( pPage->isInit==0 ){
initPage(pPage, pParent);
}
if( rc ){
return rc;
}
hdr = pPage->hdrOffset;
data = pPage->aData;
c = data[hdr];
pPage->intKey = (c & (PTF_INTKEY|PTF_LEAFDATA))!=0;
pPage->zeroData = (c & PTF_ZERODATA)!=0;
pPage->leafData = (c & PTF_LEAFDATA)!=0;
pPage->leaf = (c & PTF_LEAF)!=0;
pPage->hasData = !(pPage->zeroData || (!pPage->leaf && pPage->leafData));
nCell = get2byte(&data[hdr+3]);
sqlite3DebugPrintf("PAGE %d: flags=0x%02x frag=%d parent=%d\n", pgno,
data[hdr], data[hdr+7],
(pPage->isInit && pPage->pParent) ? pPage->pParent->pgno : 0);
assert( hdr == (pgno==1 ? 100 : 0) );
idx = hdr + 12 - pPage->leaf*4;
for(i=0; i<nCell; i++){
CellInfo info;
Pgno child;
unsigned char *pCell;
int sz;
int addr;
addr = get2byte(&data[idx + 2*i]);
pCell = &data[addr];
parseCellPtr(pPage, pCell, &info);
sz = info.nSize;
sqlite3_snprintf(sizeof(range),range,"%d..%d", addr, addr+sz-1);
if( pPage->leaf ){
child = 0;
}else{
child = get4byte(pCell);
}
sz = info.nData;
if( !pPage->intKey ) sz += info.nKey;
if( sz>sizeof(payload)-1 ) sz = sizeof(payload)-1;
memcpy(payload, &pCell[info.nHeader], sz);
for(j=0; j<sz; j++){
if( payload[j]<0x20 || payload[j]>0x7f ) payload[j] = '.';
}
payload[sz] = 0;
sqlite3DebugPrintf(
"cell %2d: i=%-10s chld=%-4d nk=%-4lld nd=%-4d payload=%s\n",
i, range, child, info.nKey, info.nData, payload
);
}
if( !pPage->leaf ){
sqlite3DebugPrintf("right_child: %d\n", get4byte(&data[hdr+8]));
}
nFree = 0;
i = 0;
idx = get2byte(&data[hdr+1]);
while( idx>0 && idx<pPage->pBt->usableSize ){
int sz = get2byte(&data[idx+2]);
sqlite3_snprintf(sizeof(range),range,"%d..%d", idx, idx+sz-1);
nFree += sz;
sqlite3DebugPrintf("freeblock %2d: i=%-10s size=%-4d total=%d\n",
i, range, sz, nFree);
idx = get2byte(&data[idx]);
i++;
}
if( idx!=0 ){
sqlite3DebugPrintf("ERROR: next freeblock index out of range: %d\n", idx);
}
if( recursive && !pPage->leaf ){
for(i=0; i<nCell; i++){
unsigned char *pCell = findCell(pPage, i);
btreePageDump(pBt, get4byte(pCell), 1, pPage);
idx = get2byte(pCell);
}
btreePageDump(pBt, get4byte(&data[hdr+8]), 1, pPage);
}
pPage->isInit = isInit;
sqlite3PagerUnref(pPage->pDbPage);
fflush(stdout);
return SQLITE_OK;
}
int sqlite3BtreePageDump(Btree *p, int pgno, int recursive){
return btreePageDump(p->pBt, pgno, recursive, 0);
}
#endif
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
/*
** Fill aResult[] with information about the entry and page that the
** cursor is pointing to.
**
** aResult[0] = The page number
** aResult[1] = The entry number
** aResult[2] = Total number of entries on this page
** aResult[3] = Cell size (local payload + header)
** aResult[4] = Number of free bytes on this page
** aResult[5] = Number of free blocks on the page
** aResult[6] = Total payload size (local + overflow)
** aResult[7] = Header size in bytes
** aResult[8] = Local payload size
** aResult[9] = Parent page number
** aResult[10]= Page number of the first overflow page
**
** This routine is used for testing and debugging only.
*/
int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){
int cnt, idx;
MemPage *pPage = pCur->pPage;
BtCursor tmpCur;
int rc = restoreOrClearCursorPosition(pCur);
if( rc!=SQLITE_OK ){
return rc;
}
assert( pPage->isInit );
getTempCursor(pCur, &tmpCur);
while( upCnt-- ){
moveToParent(&tmpCur);
}
pPage = tmpCur.pPage;
aResult[0] = sqlite3PagerPagenumber(pPage->pDbPage);
assert( aResult[0]==pPage->pgno );
aResult[1] = tmpCur.idx;
aResult[2] = pPage->nCell;
if( tmpCur.idx>=0 && tmpCur.idx<pPage->nCell ){
getCellInfo(&tmpCur);
aResult[3] = tmpCur.info.nSize;
aResult[6] = tmpCur.info.nData;
aResult[7] = tmpCur.info.nHeader;
aResult[8] = tmpCur.info.nLocal;
}else{
aResult[3] = 0;
aResult[6] = 0;
aResult[7] = 0;
aResult[8] = 0;
}
aResult[4] = pPage->nFree;
cnt = 0;
idx = get2byte(&pPage->aData[pPage->hdrOffset+1]);
while( idx>0 && idx<pPage->pBt->usableSize ){
cnt++;
idx = get2byte(&pPage->aData[idx]);
}
aResult[5] = cnt;
if( pPage->pParent==0 || isRootPage(pPage) ){
aResult[9] = 0;
}else{
aResult[9] = pPage->pParent->pgno;
}
if( tmpCur.info.iOverflow ){
aResult[10] = get4byte(&tmpCur.info.pCell[tmpCur.info.iOverflow]);
}else{
aResult[10] = 0;
}
releaseTempCursor(&tmpCur);
return SQLITE_OK;
}
#endif
/* /*
** Return the pager associated with a BTree. This routine is used for ** Return the pager associated with a BTree. This routine is used for
@@ -6040,13 +5849,14 @@ static int checkTreePage(
usableSize = pBt->usableSize; usableSize = pBt->usableSize;
if( iPage==0 ) return 0; if( iPage==0 ) return 0;
if( checkRef(pCheck, iPage, zParentContext) ) return 0; if( checkRef(pCheck, iPage, zParentContext) ) return 0;
if( (rc = getPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){ if( (rc = sqlite3BtreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
checkAppendMsg(pCheck, zContext, checkAppendMsg(pCheck, zContext,
"unable to get the page. error code=%d", rc); "unable to get the page. error code=%d", rc);
return 0; return 0;
} }
if( (rc = initPage(pPage, pParent))!=0 ){ if( (rc = sqlite3BtreeInitPage(pPage, pParent))!=0 ){
checkAppendMsg(pCheck, zContext, "initPage() returns error code %d", rc); checkAppendMsg(pCheck, zContext,
"sqlite3BtreeInitPage() returns error code %d", rc);
releasePage(pPage); releasePage(pPage);
return 0; return 0;
} }
@@ -6063,8 +5873,8 @@ static int checkTreePage(
*/ */
sqlite3_snprintf(sizeof(zContext), zContext, sqlite3_snprintf(sizeof(zContext), zContext,
"On tree page %d cell %d: ", iPage, i); "On tree page %d cell %d: ", iPage, i);
pCell = findCell(pPage,i); pCell = sqlite3BtreeFindCell(pPage,i);
parseCellPtr(pPage, pCell, &info); sqlite3BtreeParseCellPtr(pPage, pCell, &info);
sz = info.nData; sz = info.nData;
if( !pPage->intKey ) sz += info.nKey; if( !pPage->intKey ) sz += info.nKey;
assert( sz==info.nPayload ); assert( sz==info.nPayload );
@@ -6485,33 +6295,3 @@ void sqlite3BtreeCacheOverflow(BtCursor *pCur){
pCur->isIncrblobHandle = 1; pCur->isIncrblobHandle = 1;
} }
#endif #endif
/*
** The following debugging interface has to be in this file (rather
** than in, for example, test1.c) so that it can get access to
** the definition of BtShared.
*/
#if defined(SQLITE_DEBUG) && defined(TCLSH)
#include <tcl.h>
int sqlite3_shared_cache_report(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
#ifndef SQLITE_OMIT_SHARED_CACHE
const ThreadData *pTd = sqlite3ThreadDataReadOnly();
if( pTd->useSharedData ){
BtShared *pBt;
Tcl_Obj *pRet = Tcl_NewObj();
for(pBt=pTd->pBtree; pBt; pBt=pBt->pNext){
const char *zFile = sqlite3PagerFilename(pBt->pPager);
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(zFile, -1));
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(pBt->nRef));
}
Tcl_SetObjResult(interp, pRet);
}
#endif
return TCL_OK;
}
#endif

View File

@@ -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: btreeInt.h,v 1.1 2007/05/05 11:48:54 drh Exp $ ** $Id: btreeInt.h,v 1.2 2007/05/05 18:39:25 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
@@ -574,3 +574,17 @@ struct IntegrityCk {
#define get4byte sqlite3Get4byte #define get4byte sqlite3Get4byte
#define put2byte sqlite3Put2byte #define put2byte sqlite3Put2byte
#define put4byte sqlite3Put4byte #define put4byte sqlite3Put4byte
/*
** Internal routines that should be accessed by the btree layer only.
*/
int sqlite3BtreeGetPage(BtShared*, Pgno, MemPage**, int);
int sqlite3BtreeInitPage(MemPage *pPage, MemPage *pParent);
void sqlite3BtreeParseCellPtr(MemPage*, u8*, CellInfo*);
void sqlite3BtreeParseCell(MemPage*, int, CellInfo*);
u8 *sqlite3BtreeFindCell(MemPage *pPage, int iCell);
int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur);
void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur);
void sqlite3BtreeReleaseTempCursor(BtCursor *pCur);
int sqlite3BtreeIsRootPage(MemPage *pPage);
void sqlite3BtreeMoveToParent(BtCursor *pCur);

View File

@@ -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: test1.c,v 1.245 2007/05/05 11:48:54 drh Exp $ ** $Id: test1.c,v 1.246 2007/05/05 18:39:25 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "tcl.h" #include "tcl.h"
@@ -1410,6 +1410,8 @@ static int test_enable_shared(
} }
#endif #endif
/* /*
** Usage: sqlite3_extended_result_codes DB BOOLEAN ** Usage: sqlite3_extended_result_codes DB BOOLEAN
** **
@@ -4486,6 +4488,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
extern int sqlite3_sort_count; extern int sqlite3_sort_count;
extern int sqlite3_current_time; extern int sqlite3_current_time;
extern int sqlite3_max_blobsize; extern int sqlite3_max_blobsize;
extern int sqlite3BtreeSharedCacheReport(void*,
Tcl_Interp*,int,Tcl_Obj*CONST*);
static struct { static struct {
char *zName; char *zName;
Tcl_CmdProc *xProc; Tcl_CmdProc *xProc;
@@ -4632,6 +4636,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "tcl_variable_type", tcl_variable_type, 0 }, { "tcl_variable_type", tcl_variable_type, 0 },
#ifndef SQLITE_OMIT_SHARED_CACHE #ifndef SQLITE_OMIT_SHARED_CACHE
{ "sqlite3_enable_shared_cache", test_enable_shared, 0 }, { "sqlite3_enable_shared_cache", test_enable_shared, 0 },
{ "sqlite3_shared_cache_report", sqlite3BtreeSharedCacheReport, 0},
#endif #endif
{ "sqlite3_libversion_number", test_libversion_number, 0 }, { "sqlite3_libversion_number", test_libversion_number, 0 },
#ifdef SQLITE_ENABLE_COLUMN_METADATA #ifdef SQLITE_ENABLE_COLUMN_METADATA
@@ -4763,13 +4768,5 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
#endif /* OS_UNIX */ #endif /* OS_UNIX */
set_options(interp); set_options(interp);
{
#ifdef SQLITE_DEBUG
extern int sqlite3_shared_cache_report(void *, Tcl_Interp *,
int, Tcl_Obj *CONST[]);
Tcl_CreateObjCommand(interp, "sqlite_shared_cache_report",
sqlite3_shared_cache_report, 0, 0);
#endif
}
return TCL_OK; return TCL_OK;
} }

246
src/test_btree.c Normal file
View File

@@ -0,0 +1,246 @@
/*
** 2007 May 05
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the btree.c module in SQLite. This code
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
** $Id: test_btree.c,v 1.1 2007/05/05 18:39:25 drh Exp $
*/
#include "btreeInt.h"
#include <tcl.h>
/*
** Print a disassembly of the given page on standard output. This routine
** is used for debugging and testing only.
*/
static int btreePageDump(
BtShared *pBt, /* The Btree to be dumped */
int pgno, /* The page to be dumped */
int recursive, /* True to decend into child pages */
MemPage *pParent /* Parent page */
){
int rc;
MemPage *pPage;
int i, j, c;
int nFree;
u16 idx;
int hdr;
int nCell;
int isInit;
unsigned char *data;
char range[20];
unsigned char payload[20];
rc = sqlite3BtreeGetPage(pBt, (Pgno)pgno, &pPage, 0);
isInit = pPage->isInit;
if( pPage->isInit==0 ){
sqlite3BtreeInitPage(pPage, pParent);
}
if( rc ){
return rc;
}
hdr = pPage->hdrOffset;
data = pPage->aData;
c = data[hdr];
pPage->intKey = (c & (PTF_INTKEY|PTF_LEAFDATA))!=0;
pPage->zeroData = (c & PTF_ZERODATA)!=0;
pPage->leafData = (c & PTF_LEAFDATA)!=0;
pPage->leaf = (c & PTF_LEAF)!=0;
pPage->hasData = !(pPage->zeroData || (!pPage->leaf && pPage->leafData));
nCell = get2byte(&data[hdr+3]);
sqlite3DebugPrintf("PAGE %d: flags=0x%02x frag=%d parent=%d\n", pgno,
data[hdr], data[hdr+7],
(pPage->isInit && pPage->pParent) ? pPage->pParent->pgno : 0);
assert( hdr == (pgno==1 ? 100 : 0) );
idx = hdr + 12 - pPage->leaf*4;
for(i=0; i<nCell; i++){
CellInfo info;
Pgno child;
unsigned char *pCell;
int sz;
int addr;
addr = get2byte(&data[idx + 2*i]);
pCell = &data[addr];
sqlite3BtreeParseCellPtr(pPage, pCell, &info);
sz = info.nSize;
sqlite3_snprintf(sizeof(range),range,"%d..%d", addr, addr+sz-1);
if( pPage->leaf ){
child = 0;
}else{
child = get4byte(pCell);
}
sz = info.nData;
if( !pPage->intKey ) sz += info.nKey;
if( sz>sizeof(payload)-1 ) sz = sizeof(payload)-1;
memcpy(payload, &pCell[info.nHeader], sz);
for(j=0; j<sz; j++){
if( payload[j]<0x20 || payload[j]>0x7f ) payload[j] = '.';
}
payload[sz] = 0;
sqlite3DebugPrintf(
"cell %2d: i=%-10s chld=%-4d nk=%-4lld nd=%-4d payload=%s\n",
i, range, child, info.nKey, info.nData, payload
);
}
if( !pPage->leaf ){
sqlite3DebugPrintf("right_child: %d\n", get4byte(&data[hdr+8]));
}
nFree = 0;
i = 0;
idx = get2byte(&data[hdr+1]);
while( idx>0 && idx<pPage->pBt->usableSize ){
int sz = get2byte(&data[idx+2]);
sqlite3_snprintf(sizeof(range),range,"%d..%d", idx, idx+sz-1);
nFree += sz;
sqlite3DebugPrintf("freeblock %2d: i=%-10s size=%-4d total=%d\n",
i, range, sz, nFree);
idx = get2byte(&data[idx]);
i++;
}
if( idx!=0 ){
sqlite3DebugPrintf("ERROR: next freeblock index out of range: %d\n", idx);
}
if( recursive && !pPage->leaf ){
for(i=0; i<nCell; i++){
unsigned char *pCell = sqlite3BtreeFindCell(pPage, i);
btreePageDump(pBt, get4byte(pCell), 1, pPage);
idx = get2byte(pCell);
}
btreePageDump(pBt, get4byte(&data[hdr+8]), 1, pPage);
}
pPage->isInit = isInit;
sqlite3PagerUnref(pPage->pDbPage);
fflush(stdout);
return SQLITE_OK;
}
int sqlite3BtreePageDump(Btree *p, int pgno, int recursive){
return btreePageDump(p->pBt, pgno, recursive, 0);
}
/*
** Usage: sqlite3_shared_cache_report
**
** Return a list of file that are shared and the number of
** references to each file.
*/
int sqlite3BtreeSharedCacheReport(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
#ifndef SQLITE_OMIT_SHARED_CACHE
const ThreadData *pTd = sqlite3ThreadDataReadOnly();
if( pTd->useSharedData ){
BtShared *pBt;
Tcl_Obj *pRet = Tcl_NewObj();
for(pBt=pTd->pBtree; pBt; pBt=pBt->pNext){
const char *zFile = sqlite3PagerFilename(pBt->pPager);
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(zFile, -1));
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(pBt->nRef));
}
Tcl_SetObjResult(interp, pRet);
}
#endif
return TCL_OK;
}
/*
** Print debugging information about all cursors to standard output.
*/
void sqlite3BtreeCursorList(Btree *p){
BtCursor *pCur;
BtShared *pBt = p->pBt;
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
MemPage *pPage = pCur->pPage;
char *zMode = pCur->wrFlag ? "rw" : "ro";
sqlite3DebugPrintf("CURSOR %p rooted at %4d(%s) currently at %d.%d%s\n",
pCur, pCur->pgnoRoot, zMode,
pPage ? pPage->pgno : 0, pCur->idx,
(pCur->eState==CURSOR_VALID) ? "" : " eof"
);
}
}
/*
** Fill aResult[] with information about the entry and page that the
** cursor is pointing to.
**
** aResult[0] = The page number
** aResult[1] = The entry number
** aResult[2] = Total number of entries on this page
** aResult[3] = Cell size (local payload + header)
** aResult[4] = Number of free bytes on this page
** aResult[5] = Number of free blocks on the page
** aResult[6] = Total payload size (local + overflow)
** aResult[7] = Header size in bytes
** aResult[8] = Local payload size
** aResult[9] = Parent page number
** aResult[10]= Page number of the first overflow page
**
** This routine is used for testing and debugging only.
*/
int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){
int cnt, idx;
MemPage *pPage = pCur->pPage;
BtCursor tmpCur;
int rc = sqlite3BtreeRestoreOrClearCursorPosition(pCur);
if( rc!=SQLITE_OK ){
return rc;
}
assert( pPage->isInit );
sqlite3BtreeGetTempCursor(pCur, &tmpCur);
while( upCnt-- ){
sqlite3BtreeMoveToParent(&tmpCur);
}
pPage = tmpCur.pPage;
aResult[0] = sqlite3PagerPagenumber(pPage->pDbPage);
assert( aResult[0]==pPage->pgno );
aResult[1] = tmpCur.idx;
aResult[2] = pPage->nCell;
if( tmpCur.idx>=0 && tmpCur.idx<pPage->nCell ){
sqlite3BtreeParseCell(tmpCur.pPage, tmpCur.idx, &tmpCur.info);
aResult[3] = tmpCur.info.nSize;
aResult[6] = tmpCur.info.nData;
aResult[7] = tmpCur.info.nHeader;
aResult[8] = tmpCur.info.nLocal;
}else{
aResult[3] = 0;
aResult[6] = 0;
aResult[7] = 0;
aResult[8] = 0;
}
aResult[4] = pPage->nFree;
cnt = 0;
idx = get2byte(&pPage->aData[pPage->hdrOffset+1]);
while( idx>0 && idx<pPage->pBt->usableSize ){
cnt++;
idx = get2byte(&pPage->aData[idx]);
}
aResult[5] = cnt;
if( pPage->pParent==0 || sqlite3BtreeIsRootPage(pPage) ){
aResult[9] = 0;
}else{
aResult[9] = pPage->pParent->pgno;
}
if( tmpCur.info.iOverflow ){
aResult[10] = get4byte(&tmpCur.info.pCell[tmpCur.info.iOverflow]);
}else{
aResult[10] = 0;
}
sqlite3BtreeReleaseTempCursor(&tmpCur);
return SQLITE_OK;
}

View File

@@ -10,7 +10,9 @@
** **
************************************************************************* *************************************************************************
** **
** $Id: vdbeblob.c,v 1.8 2007/05/04 18:36:45 danielk1977 Exp $ ** This file contains code used to implement incremental BLOB I/O.
**
** $Id: vdbeblob.c,v 1.9 2007/05/05 18:39:25 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@@ -22,7 +24,6 @@
** Valid sqlite3_blob* handles point to Incrblob structures. ** Valid sqlite3_blob* handles point to Incrblob structures.
*/ */
typedef struct Incrblob Incrblob; typedef struct Incrblob Incrblob;
struct Incrblob { struct Incrblob {
int flags; /* Copy of "flags" passed to sqlite3_blob_open() */ int flags; /* Copy of "flags" passed to sqlite3_blob_open() */
int nByte; /* Size of open blob, in bytes */ int nByte; /* Size of open blob, in bytes */
@@ -35,13 +36,13 @@ struct Incrblob {
** Open a blob handle. ** Open a blob handle.
*/ */
int sqlite3_blob_open( int sqlite3_blob_open(
sqlite3* db, sqlite3* db, /* The database connection */
const char *zDb, const char *zDb, /* The attached database containing the blob */
const char *zTable, const char *zTable, /* The table containing the blob */
const char *zColumn, const char *zColumn, /* The column containing the blob */
sqlite_int64 iRow, sqlite_int64 iRow, /* The row containing the glob */
int flags, /* True -> read/write access, false -> read-only */ int flags, /* True -> read/write access, false -> read-only */
sqlite3_blob **ppBlob sqlite3_blob **ppBlob /* Handle for accessing the blob returned here */
){ ){
int nAttempt = 0; int nAttempt = 0;
int iCol; /* Index of zColumn in row-record */ int iCol; /* Index of zColumn in row-record */
@@ -235,7 +236,8 @@ blob_open_out:
} }
/* /*
** Close a blob handle. ** Close a blob handle that was previously created using
** sqlite3_blob_open().
*/ */
int sqlite3_blob_close(sqlite3_blob *pBlob){ int sqlite3_blob_close(sqlite3_blob *pBlob){
Incrblob *p = (Incrblob *)pBlob; Incrblob *p = (Incrblob *)pBlob;

View File

@@ -9,7 +9,7 @@
# #
#*********************************************************************** #***********************************************************************
# #
# $Id: shared.test,v 1.23 2007/04/05 11:25:59 drh Exp $ # $Id: shared.test,v 1.24 2007/05/05 18:39:25 drh Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@@ -848,9 +848,9 @@ do_test shared-$av.11.8 {
} }
set res set res
} {1 4 {} 7} } {1 4 {} 7}
if {[llength [info command sqlite_shared_cache_report]]==1} { if {[llength [info command sqlite3_shared_cache_report]]==1} {
do_test shared-$av.11.9 { do_test shared-$av.11.9 {
sqlite_shared_cache_report sqlite3_shared_cache_report
} [list [file normalize test.db] 2] } [list [file normalize test.db] 2]
} }