From 16a9b8363d124e8761f1c8aa330644bc1d4f17bb Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 5 May 2007 18:39:25 +0000 Subject: [PATCH] Factor out btree test logic into a separate test_btree.c file. (CVS 3928) FossilOrigin-Name: d51274f1cc3a75f6a03e90259ce829ac1dacf78f --- Makefile.in | 1 + main.mk | 1 + manifest | 25 +-- manifest.uuid | 2 +- src/btree.c | 420 +++++++++++------------------------------------ src/btreeInt.h | 16 +- src/test1.c | 15 +- src/test_btree.c | 246 +++++++++++++++++++++++++++ src/vdbeblob.c | 20 ++- test/shared.test | 6 +- 10 files changed, 397 insertions(+), 355 deletions(-) create mode 100644 src/test_btree.c diff --git a/Makefile.in b/Makefile.in index d36e86681b..23839370f9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -224,6 +224,7 @@ TESTSRC = \ $(TOP)/src/test9.c \ $(TOP)/src/test_autoext.c \ $(TOP)/src/test_async.c \ + $(TOP)/src/test_btree.c \ $(TOP)/src/test_hexio.c \ $(TOP)/src/test_md5.c \ $(TOP)/src/test_schema.c \ diff --git a/main.mk b/main.mk index c8b72d44b7..671366b4f1 100644 --- a/main.mk +++ b/main.mk @@ -180,6 +180,7 @@ TESTSRC = \ $(TOP)/src/test9.c \ $(TOP)/src/test_autoext.c \ $(TOP)/src/test_async.c \ + $(TOP)/src/test_btree.c \ $(TOP)/src/test_hexio.c \ $(TOP)/src/test_md5.c \ $(TOP)/src/test_schema.c \ diff --git a/manifest b/manifest index 1566a6e3f7..03a2f3d546 100644 --- a/manifest +++ b/manifest @@ -1,6 +1,6 @@ -C Fix\sa\ssprintf()\sproblem\sintroduced\sby\s(3916).\s(CVS\s3927) -D 2007-05-05T12:06:24 -F Makefile.in 80d63bf2c61619ae0e29795948ec19e79f91acc3 +C Factor\sout\sbtree\stest\slogic\sinto\sa\sseparate\stest_btree.c\sfile.\s(CVS\s3928) +D 2007-05-05T18:39:25 +F Makefile.in ea8888bdcf53313d26576fcabcb6d0a10ecd35cd F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F VERSION 6de5e9812c227f00155cb59af3535017aef3e258 @@ -44,7 +44,7 @@ F ext/fts2/fts2_tokenizer1.c 5c979fe8815f95396beb22b627571da895a025af F ext/fts2/mkfts2amal.tcl 2a9ec76b0760fe7f3669dca5bc0d60728bc1c977 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F ltmain.sh 56abb507100ed2d4261f6dd1653dec3cf4066387 -F main.mk b9fd506a8ff3abd83b01dff9abdb98948a207f26 +F main.mk a7522a769f2fe70c9bebd6bd8a36bed79be0e5cb F mkdll.sh ed62756baf44babf562a7843588790c02fee2106 F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d F mkopcodeh.awk cde995d269aa06c94adbf6455bea0acedb913fa5 @@ -59,9 +59,9 @@ F src/alter.c 2c79ec40f65e33deaf90ca493422c74586e481a3 F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651 F src/attach.c f088f8155541ff75542239ec40cf05f3d81390ba F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f -F src/btree.c 7311696faf137cb37421c8e1d0e22e2d3a15de51 +F src/btree.c 6d3db6416c71f678a4dd4719ce6d754ad5927c46 F src/btree.h a9cd72b05a14f6be22e057daf954ae548d2bcbe4 -F src/btreeInt.h 2de5f19abb59fcc5e87474fe59ef8110cfa0d343 +F src/btreeInt.h cb3c0e9eb842d06079a62cdf3492c90c5db7ba75 F src/build.c 0dd6f0d0a5d304be91374f4c7228a3e9b00ff7f1 F src/callback.c 6414ed32d55859d0f65067aa5b88d2da27b3af9e F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675 @@ -104,7 +104,7 @@ F src/sqlite3ext.h 7d0d363ea7327e817ef0dfe1b7eee1f171b72890 F src/sqliteInt.h 3ffe2f9c801575e315451e7d2831c4a90a165aa8 F src/table.c a8de75bcedf84d4060d804264b067ab3b1a3561d F src/tclsqlite.c f3414b2d6bc37e6760b49c9abd3504ff69f4441b -F src/test1.c 9fb5a4300897c01add79ff8691114e54e5a83ff0 +F src/test1.c 515a91ed7ee95a6fa5b40873aa4f5aa9c858080e F src/test2.c 24458b17ab2f3c90cbc1c8446bd7ffe69be62f88 F src/test3.c 946ea9d1a8c928656e3c70f0a2fcb8e733a15e86 F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25 @@ -115,6 +115,7 @@ F src/test8.c c3c4aeea4e3d70966306d6eca1b77ce7eee2f059 F src/test9.c c0f38f7795cc51d37db6c63874d90f40f10d0f0e F src/test_async.c 9d326ceda4306bcab252b8f7e8e480ed45d7ccb6 F src/test_autoext.c 855157d97aa28cf84233847548bfacda21807436 +F src/test_btree.c 893030a3c49ea36e9b15b01f1609727dfb11c81e F src/test_hexio.c 32204b5ce281ebc85f789c69c4ec725129e7e7f5 F src/test_loadext.c 22065d601a18878e5542191001f0eaa5d77c0ed8 F src/test_md5.c 6c42bc0a3c0b54be34623ff77a0eec32b2fa96e3 @@ -132,7 +133,7 @@ F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691 F src/vdbeInt.h cb02cbbceddf3b40d49012e9f41576f17bcbec97 F src/vdbeapi.c 37d793559390bec8a00c556f651f21b5f9e589af F src/vdbeaux.c c432e17fef6efaf102d507e979cee4e47f6ceac4 -F src/vdbeblob.c 6a25e9bbb874a7dcee4cf8f37d8dd635c129002e +F src/vdbeblob.c 57127dc9fd01f3fded2eab30b5842f5f96b1c42b F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f F src/vdbemem.c ba98f8572ec4609846b368fa7580db178022f1bb F src/vtab.c c5ebebf615b2f29499fbe97a584c4bb342632aa0 @@ -326,7 +327,7 @@ F test/select5.test 0b47058d3e916c1fc9fe81f44b438e02bade21ce F test/select6.test 399f14b9ba37b768afe5d2cd8c12e4f340a69db8 F test/select7.test 95697d8e8355ef7538e2fe768da16838bbd0fcde F test/server1.test e328b8e641ba8fe9273132cfef497383185dc1f5 -F test/shared.test 315934fecff5ecb884449eaa5bae9876961f2f22 +F test/shared.test 5c39f216ce85d723eda5875804bbf5ef8a03fcfc F test/shared2.test 8b48f8d33494413ef4cf250110d89403e2bf6b23 F test/shared3.test 01e3e124dbb3859788aabc7cfb82f7ea04421749 F test/shared_err.test cc528f6e78665787e93d9ce3a782a2ce5179d821 @@ -477,7 +478,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P ad549a40ed3500fb3d552ed19ff791d1280e0b62 -R 8e70c7a5e1bfad9e41e67f958c0c12ec +P 54a1d275aa0154a88d433a3c4df538d52c2c3ecb +R b1bb50d4a308744ac562ad6378a81905 U drh -Z 58284854439e023cfa44a554bd182ac1 +Z 79b62501eb7362c290096e8263df6144 diff --git a/manifest.uuid b/manifest.uuid index 92064bc0d4..b6727c4032 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -54a1d275aa0154a88d433a3c4df538d52c2c3ecb \ No newline at end of file +d51274f1cc3a75f6a03e90259ce829ac1dacf78f \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 025fbf35dd..97cd84a43e 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** 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. ** 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 ** and the cursor state set to CURSOR_INVALID. */ -static int restoreOrClearCursorPositionX(BtCursor *pCur){ +int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur){ int rc; assert( pCur->eState==CURSOR_REQUIRESEEK ); #ifndef SQLITE_OMIT_INCRBLOB @@ -317,7 +317,9 @@ static int restoreOrClearCursorPositionX(BtCursor *pCur){ } #define restoreOrClearCursorPosition(p) \ - (p->eState==CURSOR_REQUIRESEEK?restoreOrClearCursorPositionX(p):SQLITE_OK) + (p->eState==CURSOR_REQUIRESEEK ? \ + sqlite3BtreeRestoreOrClearCursorPosition(p) : \ + SQLITE_OK) #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. */ -static u8 *findCell(MemPage *pPage, int iCell){ +u8 *sqlite3BtreeFindCell(MemPage *pPage, int iCell){ u8 *data = pPage->aData; assert( iCell>=0 ); assert( iCellhdrOffset+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 */ static u8 *findOverflowCell(MemPage *pPage, int iCell){ @@ -442,16 +444,16 @@ static u8 *findOverflowCell(MemPage *pPage, int iCell){ iCell--; } } - return findCell(pPage, iCell); + return sqlite3BtreeFindCell(pPage, iCell); } /* ** Parse a cell content block and fill in the CellInfo structure. There -** are two versions of this function. parseCell() takes a cell index -** as the second argument and parseCellPtr() takes a pointer to the -** body of the cell as its second argument. +** are two versions of this function. sqlite3BtreeParseCell() takes a +** cell index as the second argument and sqlite3BtreeParseCellPtr() +** takes a pointer to the body of the cell as its second argument. */ -static void parseCellPtr( +void sqlite3BtreeParseCellPtr( MemPage *pPage, /* Page containing the cell */ u8 *pCell, /* Pointer to the cell text. */ CellInfo *pInfo /* Fill in this structure */ @@ -517,12 +519,12 @@ static void parseCellPtr( pInfo->nSize = pInfo->iOverflow + 4; } } -static void parseCell( +void sqlite3BtreeParseCell( MemPage *pPage, /* Page containing the cell */ int iCell, /* The cell index. First cell is 0 */ 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 static int cellSize(MemPage *pPage, int iCell){ CellInfo info; - parseCell(pPage, iCell, &info); + sqlite3BtreeParseCell(pPage, iCell, &info); return info.nSize; } #endif static int cellSizePtr(MemPage *pPage, u8 *pCell){ CellInfo info; - parseCellPtr(pPage, pCell, &info); + sqlite3BtreeParseCellPtr(pPage, pCell, &info); return info.nSize; } @@ -553,7 +555,7 @@ static int cellSizePtr(MemPage *pPage, u8 *pCell){ static int ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell){ if( pCell ){ CellInfo info; - parseCellPtr(pPage, pCell, &info); + sqlite3BtreeParseCellPtr(pPage, pCell, &info); assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload ); if( (info.nData+(pPage->intKey?0:info.nKey))>info.nLocal ){ 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 ** we failed to detect any corruption. */ -static int initPage( +int sqlite3BtreeInitPage( MemPage *pPage, /* The page to be initialized */ 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 ** 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; MemPage *pPage; 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 ** is just a convenience wrapper around separate calls to -** getPage() and initPage(). +** sqlite3BtreeGetPage() and sqlite3BtreeInitPage(). */ static int getAndInitPage( BtShared *pBt, /* The database file */ @@ -947,16 +954,16 @@ static int getAndInitPage( if( pgno==0 ){ return SQLITE_CORRUPT_BKPT; } - rc = getPage(pBt, pgno, ppPage, 0); + rc = sqlite3BtreeGetPage(pBt, pgno, ppPage, 0); if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){ - rc = initPage(*ppPage, pParent); + rc = sqlite3BtreeInitPage(*ppPage, pParent); } return rc; } /* ** Release a MemPage. This should be called once for each prior -** call to getPage. +** call to sqlite3BtreeGetPage. */ static void releasePage(MemPage *pPage){ if( pPage ){ @@ -998,7 +1005,7 @@ static void pageReinit(DbPage *pData, int pageSize){ pPage = (MemPage *)sqlite3PagerGetExtra(pData); if( pPage->isInit ){ pPage->isInit = 0; - initPage(pPage, pPage->pParent); + sqlite3BtreeInitPage(pPage, pPage->pParent); } } @@ -1379,7 +1386,7 @@ static int lockBtree(BtShared *pBt){ int rc, pageSize; MemPage *pPage1; if( pBt->pPage1 ) return SQLITE_OK; - rc = getPage(pBt, 1, &pPage1, 0); + rc = sqlite3BtreeGetPage(pBt, 1, &pPage1, 0); if( rc!=SQLITE_OK ) return rc; @@ -1641,11 +1648,11 @@ static int setChildPtrmaps(MemPage *pPage){ int isInitOrig = pPage->isInit; Pgno pgno = pPage->pgno; - initPage(pPage, 0); + sqlite3BtreeInitPage(pPage, 0); nCell = pPage->nCell; for(i=0; inCell; for(i=0; ipBt; - 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 ** 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 - ** call getPage() on page 1 again to make sure pPage1->aData is - ** set correctly. */ - if( getPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){ + ** call sqlite3BtreeGetPage() on page 1 again to make + ** sure pPage1->aData is set correctly. */ + if( sqlite3BtreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){ releasePage(pPage1); } assert( countWriteCursors(pBt)==0 ); @@ -2452,7 +2440,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){ ** Make a temporary cursor by filling in the fields of pTempCur. ** 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)); pTempCur->pNext = 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() ** function above. */ -static void releaseTempCursor(BtCursor *pCur){ +void sqlite3BtreeReleaseTempCursor(BtCursor *pCur){ if( pCur->pPage ){ 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. -** 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. -** 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){ if( pCur->info.nSize==0 ){ - parseCell(pCur->pPage, pCur->idx, &pCur->info); + sqlite3BtreeParseCell(pCur->pPage, pCur->idx, &pCur->info); }else{ #ifndef NDEBUG CellInfo 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 ); #endif } @@ -2568,7 +2556,7 @@ static int getOverflowPage( ** a MemPage* reference only. No page-data is required in this case. */ if( !pPgnoNext ){ - return getPage(pBt, ovfl, ppPage, 1); + return sqlite3BtreeGetPage(pBt, ovfl, ppPage, 1); } #ifndef SQLITE_OMIT_AUTOVACUUM @@ -2602,7 +2590,7 @@ static int getOverflowPage( if( next==0 || ppPage ){ MemPage *pPage = 0; - rc = getPage(pBt, ovfl, &pPage, next!=0); + rc = sqlite3BtreeGetPage(pBt, ovfl, &pPage, next!=0); assert(rc==SQLITE_OK || pPage==0); if( next==0 && rc==SQLITE_OK ){ next = get4byte(pPage->aData); @@ -2681,7 +2669,6 @@ static int copyPayload( ** * A commit in auto_vacuum="full" mode, ** * 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( BtCursor *pCur, /* Cursor pointing to entry to read from */ 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->idx>=0 && pCur->idxpPage->nCell ); - rc = getPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); + rc = accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0, 0); } return rc; } @@ -2854,7 +2841,7 @@ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ assert( pCur->eState==CURSOR_VALID ); assert( pCur->pPage!=0 ); assert( pCur->idx>=0 && pCur->idxpPage->nCell ); - rc = getPayload(pCur, offset, amt, pBuf, 1); + rc = accessPayload(pCur, offset, amt, pBuf, 1, 0); } 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 ** 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 -** 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 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 ** 1 is pointing to. */ -static int isRootPage(MemPage *pPage){ +int sqlite3BtreeIsRootPage(MemPage *pPage){ MemPage *pParent = pPage->pParent; if( pParent==0 ) return 1; 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 ** the largest cell index. */ -static void moveToParent(BtCursor *pCur){ +void sqlite3BtreeMoveToParent(BtCursor *pCur){ MemPage *pParent; MemPage *pPage; int idxParent; @@ -2998,7 +2985,7 @@ static void moveToParent(BtCursor *pCur){ assert( pCur->eState==CURSOR_VALID ); pPage = pCur->pPage; assert( pPage!=0 ); - assert( !isRootPage(pPage) ); + assert( !sqlite3BtreeIsRootPage(pPage) ); pParent = pPage->pParent; assert( pParent!=0 ); idxParent = pPage->idxParent; @@ -3063,7 +3050,7 @@ static int moveToLeftmost(BtCursor *pCur){ assert( pCur->eState==CURSOR_VALID ); while( !(pPage = pCur->pPage)->leaf ){ assert( pCur->idx>=0 && pCur->idxnCell ); - pgno = get4byte(findCell(pPage, pCur->idx)); + pgno = get4byte(sqlite3BtreeFindCell(pPage, pCur->idx)); rc = moveToChild(pCur, pgno); if( rc ) return rc; } @@ -3200,7 +3187,7 @@ int sqlite3BtreeMoveto( pCur->info.nSize = 0; if( pPage->intKey ){ u8 *pCell; - pCell = findCell(pPage, pCur->idx) + pPage->childPtrSize; + pCell = sqlite3BtreeFindCell(pPage, pCur->idx) + pPage->childPtrSize; if( pPage->hasData ){ u32 dummy; pCell += getVarint32(pCell, &dummy); @@ -3255,7 +3242,7 @@ int sqlite3BtreeMoveto( }else if( lwr>=pPage->nCell ){ chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); }else{ - chldPg = get4byte(findCell(pPage, lwr)); + chldPg = get4byte(sqlite3BtreeFindCell(pPage, lwr)); } if( chldPg==0 ){ assert( pCur->idx>=0 && pCur->idxpPage->nCell ); @@ -3328,12 +3315,12 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ return rc; } do{ - if( isRootPage(pPage) ){ + if( sqlite3BtreeIsRootPage(pPage) ){ *pRes = 1; pCur->eState = CURSOR_INVALID; return SQLITE_OK; } - moveToParent(pCur); + sqlite3BtreeMoveToParent(pCur); pPage = pCur->pPage; }while( pCur->idx>=pPage->nCell ); *pRes = 0; @@ -3382,18 +3369,18 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ assert( pPage->isInit ); assert( pCur->idx>=0 ); if( !pPage->leaf ){ - pgno = get4byte( findCell(pPage, pCur->idx) ); + pgno = get4byte( sqlite3BtreeFindCell(pPage, pCur->idx) ); rc = moveToChild(pCur, pgno); if( rc ) return rc; rc = moveToRightmost(pCur); }else{ while( pCur->idx==0 ){ - if( isRootPage(pPage) ){ + if( sqlite3BtreeIsRootPage(pPage) ){ pCur->eState = CURSOR_INVALID; *pRes = 1; return SQLITE_OK; } - moveToParent(pCur); + sqlite3BtreeMoveToParent(pCur); pPage = pCur->pPage; } pCur->idx--; @@ -3486,7 +3473,7 @@ static int allocateBtreePage( }else{ iTrunk = get4byte(&pPage1->aData[32]); } - rc = getPage(pBt, iTrunk, &pTrunk, 0); + rc = sqlite3BtreeGetPage(pBt, iTrunk, &pTrunk, 0); if( rc ){ pTrunk = 0; goto end_allocate_page; @@ -3536,7 +3523,7 @@ static int allocateBtreePage( */ MemPage *pNewTrunk; Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); - rc = getPage(pBt, iNewTrunk, &pNewTrunk, 0); + rc = sqlite3BtreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0); if( rc!=SQLITE_OK ){ goto end_allocate_page; } @@ -3602,7 +3589,7 @@ static int allocateBtreePage( memcpy(&aData[8+closest*4], &aData[4+k*4], 4); } put4byte(&aData[4], k-1); - rc = getPage(pBt, *pPgno, ppPage, 1); + rc = sqlite3BtreeGetPage(pBt, *pPgno, ppPage, 1); if( rc==SQLITE_OK ){ sqlite3PagerDontRollback((*ppPage)->pDbPage); rc = sqlite3PagerWrite((*ppPage)->pDbPage); @@ -3647,7 +3634,7 @@ static int allocateBtreePage( #endif assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); - rc = getPage(pBt, *pPgno, ppPage, 0); + rc = sqlite3BtreeGetPage(pBt, *pPgno, ppPage, 0); if( rc ) return rc; rc = sqlite3PagerWrite((*ppPage)->pDbPage); if( rc!=SQLITE_OK ){ @@ -3716,7 +3703,7 @@ static int freePage(MemPage *pPage){ /* Other free pages already exist. Retrive the first trunk page ** of the freelist and find out how many leaves it has. */ MemPage *pTrunk; - rc = getPage(pBt, get4byte(&pPage1->aData[32]), &pTrunk, 0); + rc = sqlite3BtreeGetPage(pBt, get4byte(&pPage1->aData[32]), &pTrunk, 0); if( rc ) return rc; k = get4byte(&pTrunk->aData[4]); if( k>=pBt->usableSize/4 - 8 ){ @@ -3757,7 +3744,7 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){ int nOvfl; int ovflPageSize; - parseCellPtr(pPage, pCell, &info); + sqlite3BtreeParseCellPtr(pPage, pCell, &info); if( info.iOverflow==0 ){ return SQLITE_OK; /* No overflow pages. Return without doing anything */ } @@ -3824,7 +3811,7 @@ static int fillInCell( nData = nZero = 0; } nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey); - parseCellPtr(pPage, pCell, &info); + sqlite3BtreeParseCellPtr(pPage, pCell, &info); assert( info.nHeader==nHeader ); assert( info.nKey==nKey ); assert( info.nData==nData+nZero ); @@ -3951,7 +3938,7 @@ static int reparentChildPages(MemPage *pPage){ if( pPage->leaf ) return SQLITE_OK; for(i=0; inCell; i++){ - u8 *pCell = findCell(pPage, i); + u8 *pCell = sqlite3BtreeFindCell(pPage, i); if( !pPage->leaf ){ rc = reparentPage(pBt, get4byte(pCell), pPage, i); if( rc!=SQLITE_OK ) return rc; @@ -4077,7 +4064,7 @@ static int insertCell( ** the entry for the overflow page into the pointer map. */ CellInfo info; - parseCellPtr(pPage, pCell, &info); + sqlite3BtreeParseCellPtr(pPage, pCell, &info); assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload ); if( (info.nData+(pPage->intKey?0:info.nKey))>info.nLocal ){ 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. */ 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); if( rc!=SQLITE_OK ){ return rc; @@ -4274,7 +4262,7 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){ */ static int balance_nonroot(MemPage *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 nMaxCells = 0; /* Allocated size of apCell, szCell, aFrom. */ int nOld; /* Number of pages in apOld[] */ @@ -4354,7 +4342,7 @@ static int balance_nonroot(MemPage *pPage){ pgno = pPage->pgno; assert( pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); for(idx=0; idxnCell; idx++){ - if( get4byte(findCell(pParent, idx))==pgno ){ + if( get4byte(sqlite3BtreeFindCell(pParent, idx))==pgno ){ break; } } @@ -4388,7 +4376,7 @@ static int balance_nonroot(MemPage *pPage){ nDiv = 0; for(i=0, k=nxDiv; inCell ){ - apDiv[i] = findCell(pParent, k); + apDiv[i] = sqlite3BtreeFindCell(pParent, k); nDiv++; assert( !pParent->leaf ); pgnoOld[i] = get4byte(apDiv[i]); @@ -4737,7 +4725,7 @@ static int balance_nonroot(MemPage *pPage){ */ CellInfo info; j--; - parseCellPtr(pNew, apCell[j], &info); + sqlite3BtreeParseCellPtr(pNew, apCell[j], &info); pCell = &aSpace[iSpace]; fillInCell(pParent, pCell, 0, info.nKey, 0, 0, 0, &sz); iSpace += sz; @@ -4858,10 +4846,10 @@ static int balance_shallower(MemPage *pPage){ pgnoChild = get4byte(&pPage->aData[pPage->hdrOffset+8]); assert( pgnoChild>0 ); 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( pPage->pgno==1 ){ - rc = initPage(pChild, pPage); + rc = sqlite3BtreeInitPage(pChild, pPage); if( rc ) goto end_shallow_balance; assert( pChild->nOverflow==0 ); if( pChild->nFree>=100 ){ @@ -4870,7 +4858,7 @@ static int balance_shallower(MemPage *pPage){ int i; zeroPage(pPage, pChild->aData[0]); for(i=0; inCell; i++){ - apCell[i] = findCell(pChild,i); + apCell[i] = sqlite3BtreeFindCell(pChild,i); szCell[i] = cellSizePtr(pChild, apCell[i]); } assemblePage(pPage, pChild->nCell, apCell, szCell); @@ -4888,7 +4876,7 @@ static int balance_shallower(MemPage *pPage){ memcpy(pPage->aData, pChild->aData, pPage->pBt->usableSize); pPage->isInit = 0; pPage->pParent = 0; - rc = initPage(pPage, 0); + rc = sqlite3BtreeInitPage(pPage, 0); assert( rc==SQLITE_OK ); freePage(pChild); 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[brk], &data[brk], usableSize-brk); assert( pChild->isInit==0 ); - rc = initPage(pChild, pPage); + rc = sqlite3BtreeInitPage(pChild, pPage); if( rc ) goto balancedeeper_out; memcpy(pChild->aOvfl, pPage->aOvfl, pPage->nOverflow*sizeof(pPage->aOvfl[0])); 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 ** 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 ** 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 @@ -5103,7 +5091,7 @@ int sqlite3BtreeInsert( if( loc==0 && CURSOR_VALID==pCur->eState ){ int szOld; assert( pCur->idx>=0 && pCur->idxnCell ); - oldCell = findCell(pPage, pCur->idx); + oldCell = sqlite3BtreeFindCell(pPage, pCur->idx); if( !pPage->leaf ){ memcpy(newCell, oldCell, 4); } @@ -5175,7 +5163,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){ ** data. The clearCell() call frees any overflow pages associated with the ** cell. The cell itself is still intact. */ - pCell = findCell(pPage, pCur->idx); + pCell = sqlite3BtreeFindCell(pPage, pCur->idx); if( !pPage->leaf ){ pgnoChild = get4byte(pCell); } @@ -5198,7 +5186,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){ int notUsed; unsigned char *tempCell = 0; assert( !pPage->leafData ); - getTempCursor(pCur, &leafCur); + sqlite3BtreeGetTempCursor(pCur, &leafCur); rc = sqlite3BtreeNext(&leafCur, ¬Used); if( rc==SQLITE_OK ){ 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", pCur->pgnoRoot, pPage->pgno, leafCur.pPage->pgno)); dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell)); - pNext = findCell(leafCur.pPage, leafCur.idx); + pNext = sqlite3BtreeFindCell(leafCur.pPage, leafCur.idx); szNext = cellSizePtr(leafCur.pPage, pNext); assert( MX_CELL_SIZE(pBt)>=szNext+4 ); tempCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) ); @@ -5227,7 +5215,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){ rc = balance(leafCur.pPage, 0); } sqliteFree(tempCell); - releaseTempCursor(&leafCur); + sqlite3BtreeReleaseTempCursor(&leafCur); }else{ TRACE(("DELETE: table=%d delete from leaf %d\n", pCur->pgnoRoot, pPage->pgno)); @@ -5316,7 +5304,7 @@ int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){ releasePage(pPageMove); /* Move the page currently at pgnoRoot to pgnoMove. */ - rc = getPage(pBt, pgnoRoot, &pRoot, 0); + rc = sqlite3BtreeGetPage(pBt, pgnoRoot, &pRoot, 0); if( rc!=SQLITE_OK ){ return rc; } @@ -5339,7 +5327,7 @@ int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){ if( rc!=SQLITE_OK ){ return rc; } - rc = getPage(pBt, pgnoRoot, &pRoot, 0); + rc = sqlite3BtreeGetPage(pBt, pgnoRoot, &pRoot, 0); if( rc!=SQLITE_OK ){ return rc; } @@ -5398,7 +5386,7 @@ static int clearDatabasePage( rc = getAndInitPage(pBt, pgno, &pPage, pParent); if( rc ) goto cleardatabasepage_out; for(i=0; inCell; i++){ - pCell = findCell(pPage, i); + pCell = sqlite3BtreeFindCell(pPage, i); if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(pCell), pPage->pParent, 1); if( rc ) goto cleardatabasepage_out; @@ -5488,7 +5476,7 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ return SQLITE_LOCKED; } - rc = getPage(pBt, (Pgno)iTable, &pPage, 0); + rc = sqlite3BtreeGetPage(pBt, (Pgno)iTable, &pPage, 0); if( rc ) return rc; rc = sqlite3BtreeClearTable(p, iTable); if( rc ){ @@ -5527,7 +5515,7 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ */ MemPage *pMove; releasePage(pPage); - rc = getPage(pBt, maxRootPgno, &pMove, 0); + rc = sqlite3BtreeGetPage(pBt, maxRootPgno, &pMove, 0); if( rc!=SQLITE_OK ){ return rc; } @@ -5536,7 +5524,7 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ if( rc!=SQLITE_OK ){ return rc; } - rc = getPage(pBt, maxRootPgno, &pMove, 0); + rc = sqlite3BtreeGetPage(pBt, maxRootPgno, &pMove, 0); if( rc!=SQLITE_OK ){ return rc; } @@ -5654,185 +5642,6 @@ int sqlite3BtreeFlags(BtCursor *pCur){ 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; ileaf ){ - 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; j0x7f ) 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 && idxpBt->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; iisInit = 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.idxnCell ){ - 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 && idxpBt->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 @@ -6040,13 +5849,14 @@ static int checkTreePage( usableSize = pBt->usableSize; if( iPage==0 ) 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, "unable to get the page. error code=%d", rc); return 0; } - if( (rc = initPage(pPage, pParent))!=0 ){ - checkAppendMsg(pCheck, zContext, "initPage() returns error code %d", rc); + if( (rc = sqlite3BtreeInitPage(pPage, pParent))!=0 ){ + checkAppendMsg(pCheck, zContext, + "sqlite3BtreeInitPage() returns error code %d", rc); releasePage(pPage); return 0; } @@ -6063,8 +5873,8 @@ static int checkTreePage( */ sqlite3_snprintf(sizeof(zContext), zContext, "On tree page %d cell %d: ", iPage, i); - pCell = findCell(pPage,i); - parseCellPtr(pPage, pCell, &info); + pCell = sqlite3BtreeFindCell(pPage,i); + sqlite3BtreeParseCellPtr(pPage, pCell, &info); sz = info.nData; if( !pPage->intKey ) sz += info.nKey; assert( sz==info.nPayload ); @@ -6485,33 +6295,3 @@ void sqlite3BtreeCacheOverflow(BtCursor *pCur){ pCur->isIncrblobHandle = 1; } #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 -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 diff --git a/src/btreeInt.h b/src/btreeInt.h index 90c8a872ea..84f823d88c 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -9,7 +9,7 @@ ** 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. ** For a detailed discussion of BTrees, refer to @@ -574,3 +574,17 @@ struct IntegrityCk { #define get4byte sqlite3Get4byte #define put2byte sqlite3Put2byte #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); diff --git a/src/test1.c b/src/test1.c index bb303ee9df..f7db1e5987 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** 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 "tcl.h" @@ -1410,6 +1410,8 @@ static int test_enable_shared( } #endif + + /* ** 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_current_time; extern int sqlite3_max_blobsize; + extern int sqlite3BtreeSharedCacheReport(void*, + Tcl_Interp*,int,Tcl_Obj*CONST*); static struct { char *zName; Tcl_CmdProc *xProc; @@ -4632,6 +4636,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "tcl_variable_type", tcl_variable_type, 0 }, #ifndef SQLITE_OMIT_SHARED_CACHE { "sqlite3_enable_shared_cache", test_enable_shared, 0 }, + { "sqlite3_shared_cache_report", sqlite3BtreeSharedCacheReport, 0}, #endif { "sqlite3_libversion_number", test_libversion_number, 0 }, #ifdef SQLITE_ENABLE_COLUMN_METADATA @@ -4763,13 +4768,5 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ #endif /* OS_UNIX */ 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; } diff --git a/src/test_btree.c b/src/test_btree.c new file mode 100644 index 0000000000..b1de027108 --- /dev/null +++ b/src/test_btree.c @@ -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 + +/* +** 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; ileaf ){ + 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; j0x7f ) 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 && idxpBt->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; iisInit = 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.idxnCell ){ + 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 && idxpBt->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; +} diff --git a/src/vdbeblob.c b/src/vdbeblob.c index 8624180602..8f52ca08d5 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -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" @@ -22,7 +24,6 @@ ** Valid sqlite3_blob* handles point to Incrblob structures. */ typedef struct Incrblob Incrblob; - struct Incrblob { int flags; /* Copy of "flags" passed to sqlite3_blob_open() */ int nByte; /* Size of open blob, in bytes */ @@ -35,13 +36,13 @@ struct Incrblob { ** Open a blob handle. */ int sqlite3_blob_open( - sqlite3* db, - const char *zDb, - const char *zTable, - const char *zColumn, - sqlite_int64 iRow, + sqlite3* db, /* The database connection */ + const char *zDb, /* The attached database containing the blob */ + const char *zTable, /* The table containing the blob */ + const char *zColumn, /* The column containing the blob */ + sqlite_int64 iRow, /* The row containing the glob */ 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 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){ Incrblob *p = (Incrblob *)pBlob; diff --git a/test/shared.test b/test/shared.test index 8d57a4e595..7e84a89986 100644 --- a/test/shared.test +++ b/test/shared.test @@ -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] source $testdir/tester.tcl @@ -848,9 +848,9 @@ do_test shared-$av.11.8 { } set res } {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 { - sqlite_shared_cache_report + sqlite3_shared_cache_report } [list [file normalize test.db] 2] }