From 8c42ca93667cd678ae873f054ed6bec9b6a39137 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 22 Jun 2001 19:15:00 +0000 Subject: [PATCH] The BTree code compiles and links now, but it does not work yet. (CVS 226) FossilOrigin-Name: b31c49021c260a67b7848bc077b75a7146e31c71 --- Makefile.in | 13 +- manifest | 24 +-- manifest.uuid | 2 +- src/btree.c | 324 ++++++++++++++++++++++++++------------ src/btree.h | 10 +- src/pager.c | 6 +- src/pager.h | 5 +- src/tclsqlite.c | 4 +- src/test3.c | 409 +++++++++++++++++++++++++++++++++++++++++++++++- 9 files changed, 667 insertions(+), 130 deletions(-) diff --git a/Makefile.in b/Makefile.in index a1362aa016..9c6a497b90 100644 --- a/Makefile.in +++ b/Makefile.in @@ -47,13 +47,14 @@ LIBREADLINE = @TARGET_READLINE_LIBS@ # Object files for the SQLite library. # -LIBOBJ = build.o dbbe.o dbbegdbm.o dbbemem.o delete.o expr.o insert.o \ +LIBOBJ = btree.o build.o dbbe.o dbbegdbm.o dbbemem.o delete.o expr.o insert.o \ main.o pager.o parse.o printf.o random.o select.o table.o \ tokenize.o update.o util.o vdbe.o where.o tclsqlite.o # All of the source code files. # SRC = \ + $(TOP)/src/btree.c \ $(TOP)/src/build.c \ $(TOP)/src/dbbe.c \ $(TOP)/src/dbbe.h \ @@ -84,7 +85,8 @@ SRC = \ # TESTSRC = \ $(TOP)/src/test1.c \ - $(TOP)/src/test2.c + $(TOP)/src/test2.c \ + $(TOP)/src/test3.c # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. @@ -117,10 +119,15 @@ lemon: $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c HDR = \ sqlite.h \ $(TOP)/src/sqliteInt.h \ + $(TOP)/src/btree.h \ $(TOP)/src/dbbe.h \ + $(TOP)/src/pager.h \ $(TOP)/src/vdbe.h \ parse.h +btree.o: $(TOP)/src/btree.c $(HDR) + $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/btree.c + build.o: $(TOP)/src/build.c $(HDR) $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/build.c @@ -201,7 +208,7 @@ tclsqlite: $(TOP)/src/tclsqlite.c libsqlite.a testfixture: $(TOP)/src/tclsqlite.c libsqlite.a $(TESTSRC) $(TCC) $(TCL_FLAGS) -DTCLSH=1 -DSQLITE_TEST=1 -o testfixture \ - $(TESTSRC) $(TOP)/src/tclsqlite.c \ + $(TESTSRC) $(TOP)/src/tclsqlite.c $(TOP)/src/btree.c \ libsqlite.a $(LIBGDBM) $(LIBTCL) test: testfixture sqlite diff --git a/manifest b/manifest index 8c45637ac1..7694481396 100644 --- a/manifest +++ b/manifest @@ -1,7 +1,7 @@ -C All\sBTree\scode\sis\sin\splace.\sNow\swe\sjust\shave\sto\smake\sit\swork.\s(CVS\s225) -D 2001-06-10T19:56:59 +C The\sBTree\scode\scompiles\sand\slinks\snow,\sbut\sit\sdoes\snot\swork\syet.\s(CVS\s226) +D 2001-06-22T19:15:00 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4 -F Makefile.in acef0f0275a5ca8e68bda165f7f05d810a207664 +F Makefile.in 65862a30703b070209b5f5e565d75cc870962b3c F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958 F VERSION 71874cb7e2a53c2bd22bb6affa7d223dd94a7a13 F configure d2051345f49f7e48604423da26e086a745c86a47 x @@ -12,8 +12,8 @@ F notes/notes1.txt b7c0812b704a022e88c621146ae50955c923d464 F notes/notes2.txt 7e3fafd5e25906c1fe1e95f13b089aa398ca403e F notes/notes3.txt 985bf688b59f1f52bfe6e4b1f896efdeffac1432 F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4 -F src/btree.c 788e18f3c668732fc4f228fd24912bb5181b055f -F src/btree.h f9adc22e8414402c176d71088e76afa89cc0d4b1 +F src/btree.c 0a2b66ce90f0bee87f0449235060529b96cc96e4 +F src/btree.h 40ae2c9b6d2ba8feb03461a589ccab9afc04ec29 F src/build.c 4f6a2d551c56342cd4a0420654835be3ad179651 F src/dbbe.c b18259f99d87240cbe751021cf14dd3aa83a48af F src/dbbe.h 7235b15c6c5d8be0c4da469cef9620cee70b1cc8 @@ -31,8 +31,8 @@ F src/ex/sizes.tcl f54bad4a2ac567624be59131a6ee42d71b41a3d7 F src/expr.c c4c24c3af1eba094a816522eb0e085bed518ee16 F src/insert.c aa528e20a787af85432a61daaea6df394bd251d7 F src/main.c 0a13c7a2beb8ce36aee43daf8c95989b200727a7 -F src/pager.c 5224dc4b7f678af2b7e9affb933eb1cee5e7977e -F src/pager.h e527411d88e31085f07eba6776dc337b8b027921 +F src/pager.c 30c6f10a3c0cdfca3314c07d34375dbc19a48c2f +F src/pager.h 724ac5a79b5fa704a1e1a87e421e421b3da9c1e4 F src/parse.y 8fc096948994a7ffbf61ba13129cc589f794a9cb F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9 F src/random.c b36c3f57dc80c8f354e6bfbf39cf1e1de021d54a @@ -42,10 +42,10 @@ F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/sqlite.h.in 3e5906f72608f0fd4394dfbb1d7e8d35b8353677 F src/sqliteInt.h 47845c60e2e196b5409d774936a56700b1611f00 F src/table.c adcaf074f6c1075e86359174e68701fa2acfc4d6 -F src/tclsqlite.c 1f2bf4691a6bd81fbff1856ae4a12db24d1265f7 +F src/tclsqlite.c af29a45cb4c2244a6fd032568a22d26516472b2c F src/test1.c abb3cb427e735ae87e6533f5b3b7164b7da91bc4 F src/test2.c 0183625225a860397b4fd3041aefb48f77e4630a -F src/test3.c a1868c55e03776f2e59f713247e77c734d8badfe +F src/test3.c 405ea28287faeefc108ca362eca527731421e6bb F src/tokenize.c 0118b57702cb6550769316e8443b06760b067acf F src/update.c 0cf789656a936d4356668393267692fa4b03ffc6 F src/util.c 1b396ac34e30dd6222d82e996c17b161bbc906bc @@ -107,7 +107,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2 F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad -P d1e211fad9d787a0fdbcd11fb364d6c592c07a05 -R 3aa8278a253756473c3d6ce9ea5ba81d +P d4be4709ee32bab6e78104861ed4e02d153779aa +R 0a720e1f17d26fb5cb5699a653f8a269 U drh -Z 55b535f0434199de5eef13cb7d2b84b8 +Z 4c2d9d4e753474964194e60669402b32 diff --git a/manifest.uuid b/manifest.uuid index 7659d1305d..536496be0a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d4be4709ee32bab6e78104861ed4e02d153779aa \ No newline at end of file +b31c49021c260a67b7848bc077b75a7146e31c71 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 7a0ff65f25..eee60492ba 100644 --- a/src/btree.c +++ b/src/btree.c @@ -21,7 +21,7 @@ ** http://www.hwaci.com/drh/ ** ************************************************************************* -** $Id: btree.c,v 1.12 2001/06/10 19:56:59 drh Exp $ +** $Id: btree.c,v 1.13 2001/06/22 19:15:00 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -73,10 +73,16 @@ ** Change these typedefs when porting to new architectures. */ typedef unsigned int uptr; -typedef unsigned int u32; +/* typedef unsigned int u32; -- already defined in sqliteInt.h */ typedef unsigned short int u16; typedef unsigned char u8; +/* +** This macro casts a pointer to an integer. Useful for doing +** pointer arithmetic. +*/ +#define addr(X) ((uptr)X) + /* ** Forward declarations of structures used only in this file. */ @@ -99,12 +105,24 @@ typedef struct OverflowPage OverflowPage; /* ** This is a magic string that appears at the beginning of every -** SQLite database in order to identify the fail as a real database. +** SQLite database in order to identify the file as a real database. */ static const char zMagicHeader[] = - "** This file contains an SQLite 2.0 database **" + "** This file contains an SQLite 2.0 database **"; #define MAGIC_SIZE (sizeof(zMagicHeader)) +/* +** This is a magic integer also used to the integrety of the database +** file. This integer is used in addition to the string above so that +** if the file is written on a little-endian architecture and read +** on a big-endian architectures (or vice versa) we can detect the +** problem. +** +** The number used was obtained at random and has no special +** significance. +*/ +#define MAGIC 0xdae37528 + /* ** The first page of the database file contains a magic header string ** to identify the file as an SQLite database file. It also contains @@ -121,7 +139,8 @@ static const char zMagicHeader[] = */ struct PageOne { char zMagic[MAGIC_SIZE]; /* String that identifies the file as a database */ - Pgno firstList; /* First free page in a list of all free pages */ + int iMagic; /* Integer to verify correct byte order */ + Pgno freeList; /* First free page in a list of all free pages */ int aMeta[SQLITE_N_BTREE_META]; /* User defined integers */ }; @@ -156,7 +175,7 @@ struct PageHdr { ** the database page. ** ** A definition of the complete Cell structure is given below. The -** header for the cell must be defined separately in order to do some +** header for the cell must be defined first in order to do some ** of the sizing #defines that follow. */ struct CellHdr { @@ -164,7 +183,7 @@ struct CellHdr { u16 nKey; /* Number of bytes in the key */ u16 iNext; /* Index in MemPage.u.aDisk[] of next cell in sorted order */ u32 nData; /* Number of bytes of data */ -} +}; /* ** The minimum size of a complete Cell. The Cell must contain a header @@ -179,8 +198,8 @@ struct CellHdr { #define MX_CELL ((SQLITE_PAGE_SIZE-sizeof(PageHdr))/MIN_CELL_SIZE) /* -** The maximum amount of data (in bytes) that can be stored locally for a -** database entry. If the entry contains more data than this, the +** The maximum amount of payload (in bytes) that can be stored locally for +** a database entry. If the entry contains more data than this, the ** extra goes onto overflow pages. ** ** This number is chosen so that at least 4 cells will fit on every page. @@ -226,7 +245,7 @@ struct FreeBlk { /* ** When the key and data for a single entry in the BTree will not fit in -** the MX_LOACAL_PAYLOAD bytes of space available on the database page, +** the MX_LOCAL_PAYLOAD bytes of space available on the database page, ** then all extra bytes are written to a linked list of overflow pages. ** Each overflow page is an instance of the following structure. ** @@ -278,7 +297,7 @@ struct MemPage { int nCell; /* Number of entries on this page */ int isOverfull; /* Some apCell[] points outside u.aDisk[] */ Cell *apCell[MX_CELL+2]; /* All data entires in sorted order */ -} +}; /* ** The in-memory image of a disk page has the auxiliary information appended @@ -308,7 +327,7 @@ struct BtCursor { BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */ Pgno pgnoRoot; /* The root page of this tree */ MemPage *pPage; /* Page that contains the entry */ - u16 idx; /* Index of the entry in pPage->apCell[] */ + int idx; /* Index of the entry in pPage->apCell[] */ u8 bSkipNext; /* sqliteBtreeNext() is no-op if true */ u8 iMatch; /* compare result from last sqliteBtreeMoveto() */ }; @@ -317,7 +336,7 @@ struct BtCursor { ** Compute the total number of bytes that a Cell needs on the main ** database page. The number returned includes the Cell header, ** local payload storage, and the pointer to overflow pages (if -** applicable). Additional spaced allocated on overflow pages +** applicable). Additional space allocated on overflow pages ** is NOT included in the value returned from this routine. */ static int cellSize(Cell *pCell){ @@ -345,7 +364,13 @@ static void defragmentPage(MemPage *pPage){ pPage->u.hdr.firstCell = pc; memcpy(newPage, pPage->u.aDisk, pc); for(i=0; inCell; i++){ - Cell *pCell = &pPage->apCell[i]; + Cell *pCell = (Cell*)&pPage->apCell[i]; + + /* This routine should never be called on an overfull page. The + ** following asserts verify that constraint. */ + assert( addr(pCell) > addr(pPage) ); + assert( addr(pCell) < addr(pPage) + SQLITE_PAGE_SIZE ); + n = cellSize(pCell); pCell->h.iNext = inCell-1 ? pc + n : 0; memcpy(&newPage[pc], pCell, n); @@ -354,7 +379,7 @@ static void defragmentPage(MemPage *pPage){ } assert( pPage->nFree==SQLITE_PAGE_SIZE-pc ); memcpy(pPage->u.aDisk, newPage, pc); - pFBlk = &pPage->u.aDisk[pc]; + pFBlk = (FreeBlk*)&pPage->u.aDisk[pc]; pFBlk->iSize = SQLITE_PAGE_SIZE - pc; pFBlk->iNext = 0; pPage->u.hdr.firstFree = pc; @@ -378,12 +403,14 @@ static int allocateSpace(MemPage *pPage, int nByte){ FreeBlk *p; u16 *pIdx; int start; + int cnt = 0; assert( nByte==ROUNDUP(nByte) ); if( pPage->nFreeisOverfull ) return 0; pIdx = &pPage->u.hdr.firstFree; p = (FreeBlk*)&pPage->u.aDisk[*pIdx]; while( p->iSizeiNext==0 ){ defragmentPage(pPage); pIdx = &pPage->u.hdr.firstFree; @@ -396,8 +423,9 @@ static int allocateSpace(MemPage *pPage, int nByte){ start = *pIdx; *pIdx = p->iNext; }else{ + FreeBlk *pNew; start = *pIdx; - FreeBlk *pNew = (FreeBlk*)&pPage->u.aDisk[start + nByte]; + pNew = (FreeBlk*)&pPage->u.aDisk[start + nByte]; pNew->iNext = p->iNext; pNew->iSize = p->iSize - nByte; *pIdx = start + nByte; @@ -431,7 +459,7 @@ static void freeSpace(MemPage *pPage, int start, int size){ if( idx + pFBlk->iSize == start ){ pFBlk->iSize += size; if( idx + pFBlk->iSize == pFBlk->iNext ){ - pNext = (FreeBlk*)&pPage->u.aDisk[pFblk->iNext]; + pNext = (FreeBlk*)&pPage->u.aDisk[pFBlk->iNext]; pFBlk->iSize += pNext->iSize; pFBlk->iNext = pNext->iNext; } @@ -489,8 +517,9 @@ static int initPage(MemPage *pPage, Pgno pgnoThis, MemPage *pParent){ freeSpace = SQLITE_PAGE_SIZE - sizeof(PageHdr); idx = pPage->u.hdr.firstCell; while( idx!=0 ){ - if( idx>SQLITE_PAGE_SIZE-MN_CELL_SIZE ) goto page_format_error; + if( idx>SQLITE_PAGE_SIZE-MIN_CELL_SIZE ) goto page_format_error; if( idxu.aDisk[idx]; sz = cellSize(pCell); if( idx+sz > SQLITE_PAGE_SIZE ) goto page_format_error; @@ -534,6 +563,9 @@ static void zeroPage(MemPage *pPage){ pFBlk = (FreeBlk*)&pHdr[1]; pFBlk->iNext = 0; pFBlk->iSize = SQLITE_PAGE_SIZE - sizeof(*pHdr); + pPage->nFree = pFBlk->iSize; + pPage->nCell = 0; + pPage->isOverfull = 0; } /* @@ -559,13 +591,14 @@ static void pageDestructor(void *pData){ */ int sqliteBtreeOpen(const char *zFilename, int mode, Btree **ppBtree){ Btree *pBt; + int rc; pBt = sqliteMalloc( sizeof(*pBt) ); if( pBt==0 ){ - **ppBtree = 0; + *ppBtree = 0; return SQLITE_NOMEM; } - rc = sqlitepager_open(&pBt->pPager, zFilename, 100, EXTRA_SPACE); + rc = sqlitepager_open(&pBt->pPager, zFilename, 100, EXTRA_SIZE); if( rc!=SQLITE_OK ){ if( pBt->pPager ) sqlitepager_close(pBt->pPager); sqliteFree(pBt); @@ -604,7 +637,7 @@ int sqliteBtreeClose(Btree *pBt){ static int lockBtree(Btree *pBt){ int rc; if( pBt->page1 ) return SQLITE_OK; - rc = sqlitepager_get(pBt->pPager, 1, &pBt->page1); + rc = sqlitepager_get(pBt->pPager, 1, (void**)&pBt->page1); if( rc!=SQLITE_OK ) return rc; /* Do some checking to help insure the file we opened really is @@ -612,7 +645,7 @@ static int lockBtree(Btree *pBt){ */ if( sqlitepager_pagecount(pBt->pPager)>0 ){ PageOne *pP1 = pBt->page1; - if( strcmp(pP1->zMagic1,zMagicHeader)!=0 ){ + if( strcmp(pP1->zMagic,zMagicHeader)!=0 || pP1->iMagic!=MAGIC ){ rc = SQLITE_CORRUPT; goto page1_init_failed; } @@ -626,16 +659,18 @@ page1_init_failed: } /* -** Create a new database by initializing the first two pages. +** Create a new database by initializing the first two pages of the +** file. */ static int newDatabase(Btree *pBt){ MemPage *pRoot; PageOne *pP1; + int rc; if( sqlitepager_pagecount(pBt->pPager)>0 ) return SQLITE_OK; pP1 = pBt->page1; rc = sqlitepager_write(pBt->page1); if( rc ) return rc; - rc = sqlitepager_get(pBt->pPager, 2, &pRoot); + rc = sqlitepager_get(pBt->pPager, 2, (void**)&pRoot); if( rc ) return rc; rc = sqlitepager_write(pRoot); if( rc ){ @@ -643,6 +678,7 @@ static int newDatabase(Btree *pBt){ return rc; } strcpy(pP1->zMagic, zMagicHeader); + pP1->iMagic = MAGIC; zeroPage(pRoot); sqlitepager_unref(pRoot); return SQLITE_OK; @@ -664,17 +700,20 @@ static int newDatabase(Btree *pBt){ */ int sqliteBtreeBeginTrans(Btree *pBt){ int rc; - PageOne *pP1; if( pBt->inTrans ) return SQLITE_ERROR; if( pBt->page1==0 ){ rc = lockBtree(pBt); - if( rc!=SQLITE_OK ) return rc; + if( rc!=SQLITE_OK ){ + return rc; + } } rc = sqlitepager_write(pBt->page1); - if( rc==SQLITE_OK ){ - pBt->inTrans = 1; + if( rc!=SQLITE_OK ){ + return rc; } - return newDatabase(pBt); + pBt->inTrans = 1; + rc = newDatabase(pBt); + return rc; } /* @@ -734,7 +773,7 @@ int sqliteBtreeCursor(Btree *pBt, int iTable, BtCursor **ppCur){ goto create_cursor_exception; } pCur->pgnoRoot = (Pgno)iTable; - rc = sqlitepager_get(pBt->pPager, pCur->pgnoRoot, &pCur->pPage); + rc = sqlitepager_get(pBt->pPager, pCur->pgnoRoot, (void**)&pCur->pPage); if( rc!=SQLITE_OK ){ goto create_cursor_exception; } @@ -759,7 +798,7 @@ create_cursor_exception: if( pCur->pPage ) sqlitepager_unref(pCur->pPage); sqliteFree(pCur); } - unlinkBtree(pBt); + unlockBtree(pBt); return rc; } @@ -769,7 +808,6 @@ create_cursor_exception: */ int sqliteBtreeCloseCursor(BtCursor *pCur){ Btree *pBt = pCur->pBt; - int i; if( pCur->pPrev ){ pCur->pPrev->pNext = pCur->pNext; }else{ @@ -781,6 +819,7 @@ int sqliteBtreeCloseCursor(BtCursor *pCur){ sqlitepager_unref(pCur->pPage); unlockBtree(pBt); sqliteFree(pCur); + return SQLITE_OK; } /* @@ -819,7 +858,7 @@ int sqliteBtreeKeySize(BtCursor *pCur, int *pSize){ *pSize = 0; }else{ pCell = pPage->apCell[pCur->idx]; - *psize = pCell->h.nKey; + *pSize = pCell->h.nKey; } return SQLITE_OK; } @@ -835,9 +874,10 @@ int sqliteBtreeKeySize(BtCursor *pCur, int *pSize){ static int getPayload(BtCursor *pCur, int offset, int amt, char *zBuf){ char *aPayload; Pgno nextPage; + int rc; assert( pCur!=0 && pCur->pPage!=0 ); - assert( pCur->idx>=0 && pCur->idxnCell ); - aPayload = pCur->pPage->apCell[pCur->idx].aPayload; + assert( pCur->idx>=0 && pCur->idxpPage->nCell ); + aPayload = pCur->pPage->apCell[pCur->idx]->aPayload; if( offsetMX_LOCAL_PAYLOAD ){ @@ -852,11 +892,11 @@ static int getPayload(BtCursor *pCur, int offset, int amt, char *zBuf){ amt -= a; } if( amt>0 ){ - nextPage = pCur->pPage->apCell[pCur->idx].ovfl; + nextPage = pCur->pPage->apCell[pCur->idx]->ovfl; } while( amt>0 && nextPage ){ OverflowPage *pOvfl; - rc = sqlitepager_get(pCur->pBt->pPager, nextPage, &pOvfl); + rc = sqlitepager_get(pCur->pBt->pPager, nextPage, (void**)&pOvfl); if( rc!=0 ){ return rc; } @@ -964,7 +1004,7 @@ int sqliteBtreeData(BtCursor *pCur, int offset, int amt, char *zBuf){ static int compareKey(BtCursor *pCur, char *pKey, int nKeyOrig, int *pResult){ Pgno nextPage; int nKey = nKeyOrig; - int n; + int n, c, rc; Cell *pCell; assert( pCur->pPage ); @@ -990,7 +1030,7 @@ static int compareKey(BtCursor *pCur, char *pKey, int nKeyOrig, int *pResult){ if( nextPage==0 ){ return SQLITE_CORRUPT; } - rc = sqlitepager_get(pCur->pBt->pPager, nextPage, &pOvfl); + rc = sqlitepager_get(pCur->pBt->pPager, nextPage, (void**)&pOvfl); if( rc ){ return rc; } @@ -1020,7 +1060,7 @@ static int moveToChild(BtCursor *pCur, int newPgno){ int rc; MemPage *pNewPage; - rc = sqlitepager_get(pCur->pBt->pPager, newPgno, &pNewPage); + rc = sqlitepager_get(pCur->pBt->pPager, newPgno, (void**)&pNewPage); if( rc ){ return rc; } @@ -1042,16 +1082,16 @@ static int moveToChild(BtCursor *pCur, int newPgno){ static int moveToParent(BtCursor *pCur){ Pgno oldPgno; MemPage *pParent; - + int i; pParent = pCur->pPage->pParent; if( pParent==0 ) return SQLITE_INTERNAL; oldPgno = sqlitepager_pagenumber(pCur->pPage); sqlitepager_ref(pParent); sqlitepager_unref(pCur->pPage); pCur->pPage = pParent; - pCur->idx = pPage->nCell; - for(i=0; inCell; i++){ - if( pPage->apCell[i].h.leftChild==oldPgno ){ + pCur->idx = pParent->nCell; + for(i=0; inCell; i++){ + if( pParent->apCell[i]->h.leftChild==oldPgno ){ pCur->idx = i; break; } @@ -1066,7 +1106,7 @@ static int moveToRoot(BtCursor *pCur){ MemPage *pNew; int rc; - rc = sqlitepager_get(pCur->pBt->pPager, pCur->pgnoRoot, &pNew); + rc = sqlitepager_get(pCur->pBt->pPager, pCur->pgnoRoot, (void**)&pNew); if( rc ) return rc; sqlitepager_unref(pCur->pPage); pCur->pPage = pNew; @@ -1170,8 +1210,8 @@ int sqliteBtreeNext(BtCursor *pCur, int *pRes){ } pCur->idx++; if( pCur->idx>=pCur->pPage->nCell ){ - if( pPage->u.hdr.rightChild ){ - rc = moveToChild(pCur, pPage->u.hdr.rightChild); + if( pCur->pPage->u.hdr.rightChild ){ + rc = moveToChild(pCur, pCur->pPage->u.hdr.rightChild); if( rc ) return rc; rc = moveToLeftmost(pCur); if( rc ) return rc; @@ -1179,7 +1219,7 @@ int sqliteBtreeNext(BtCursor *pCur, int *pRes){ return SQLITE_OK; } do{ - if( pCur->pParent==0 ){ + if( pCur->pPage->pParent==0 ){ if( pRes ) *pRes = 1; return SQLITE_OK; } @@ -1209,12 +1249,13 @@ int sqliteBtreeNext(BtCursor *pCur, int *pRes){ */ static int allocatePage(Btree *pBt, MemPage **ppPage, Pgno *pPgno){ PageOne *pPage1 = pBt->page1; + int rc; if( pPage1->freeList ){ OverflowPage *pOvfl; rc = sqlitepager_write(pPage1); if( rc ) return rc; *pPgno = pPage1->freeList; - rc = sqlitepager_get(pBt->pPager, pPage1->freeList, &pOvfl); + rc = sqlitepager_get(pBt->pPager, pPage1->freeList, (void**)&pOvfl); if( rc ) return rc; rc = sqlitepager_write(pOvfl); if( rc ){ @@ -1225,7 +1266,7 @@ static int allocatePage(Btree *pBt, MemPage **ppPage, Pgno *pPgno){ *ppPage = (MemPage*)pOvfl; }else{ *pPgno = sqlitepager_pagecount(pBt->pPager); - rc = sqlitepager_get(pBt->pPager, *pPgno, ppPage); + rc = sqlitepager_get(pBt->pPager, *pPgno, (void**)ppPage); if( rc ) return rc; rc = sqlitepager_write(*ppPage); } @@ -1255,7 +1296,7 @@ static int freePage(Btree *pBt, void *pPage, Pgno pgno){ } if( pOvfl==0 ){ assert( pgno>0 ); - rc = sqlitepager_get(pBt->pPager, pgno, &pOvfl); + rc = sqlitepager_get(pBt->pPager, pgno, (void**)&pOvfl); if( rc ) return rc; needOvflUnref = 1; } @@ -1267,8 +1308,8 @@ static int freePage(Btree *pBt, void *pPage, Pgno pgno){ pOvfl->iNext = pPage1->freeList; pPage1->freeList = pgno; memset(pOvfl->aPayload, 0, OVERFLOW_SIZE); - pPage->isInit = 0; - assert( pPage->pParent==0 ); + ((MemPage*)pPage)->isInit = 0; + assert( ((MemPage*)pPage)->pParent==0 ); rc = sqlitepager_unref(pOvfl); return rc; } @@ -1289,7 +1330,7 @@ static int clearCell(Btree *pBt, Cell *pCell){ ovfl = pCell->ovfl; pCell->ovfl = 0; while( ovfl ){ - rc = sqlitepager_get(pPager, ovfl, &pOvfl); + rc = sqlitepager_get(pPager, ovfl, (void**)&pOvfl); if( rc ) return rc; nextOvfl = pOvfl->iNext; rc = freePage(pBt, pOvfl, ovfl); @@ -1310,10 +1351,10 @@ static int fillInCell( void *pKey, int nKey, /* The key */ void *pData,int nData /* The data */ ){ - int OverflowPage *pOvfl; + OverflowPage *pOvfl; Pgno *pNext; int spaceLeft; - int n; + int n, rc; int nPayload; char *pPayload; char *pSpace; @@ -1331,7 +1372,7 @@ static int fillInCell( nPayload = nKey; while( nPayload>0 ){ if( spaceLeft==0 ){ - rc = allocatePage(pBt, &pOvfl, pNext); + rc = allocatePage(pBt, (MemPage**)&pOvfl, pNext); if( rc ){ *pNext = 0; clearCell(pBt, pCell); @@ -1339,7 +1380,7 @@ static int fillInCell( } spaceLeft = OVERFLOW_SIZE; pSpace = pOvfl->aPayload; - pNextPg = &pOvfl->iNext; + pNext = &pOvfl->iNext; } n = nPayload; if( n>spaceLeft ) n = spaceLeft; @@ -1383,10 +1424,10 @@ static void reparentPage(Pager *pPager, Pgno pgno, MemPage *pNewParent){ ** This routine gets called after you memcpy() one page into ** another. */ -static void reparentChildPages(Pager *pPager, Page *pPage){ +static void reparentChildPages(Pager *pPager, MemPage *pPage){ int i; for(i=0; inCell; i++){ - reparentPage(pPager, pPage->apCell[i]->leftChild, pPage); + reparentPage(pPager, pPage->apCell[i]->h.leftChild, pPage); } reparentPage(pPager, pPage->u.hdr.rightChild, pPage); } @@ -1400,16 +1441,16 @@ static void reparentChildPages(Pager *pPager, Page *pPage){ ** "sz" must be the number of bytes in the cell. ** ** Do not bother maintaining the integrity of the linked list of Cells. -** Only pPage->apCell[] is important. The relinkCellList() routine -** will be called soon after this routine in order to rebuild the -** linked list. +** Only the pPage->apCell[] array is important. The relinkCellList() +** routine will be called soon after this routine in order to rebuild +** the linked list. */ -static void dropCell(MemPage *pPage, int i, int sz){ +static void dropCell(MemPage *pPage, int idx, int sz){ int j; - assert( i>=0 && inCell ); - assert( sz==cellSize(pPage->apCell[i]); + assert( idx>=0 && idxnCell ); + assert( sz==cellSize(pPage->apCell[idx]) ); freeSpace(pPage, idx, sz); - for(j=i, jnCell-2; j++){ + for(j=idx; jnCell-2; j++){ pPage->apCell[j] = pPage->apCell[j+1]; } pPage->nCell--; @@ -1424,9 +1465,9 @@ static void dropCell(MemPage *pPage, int i, int sz){ ** and set pPage->isOverfull. ** ** Do not bother maintaining the integrity of the linked list of Cells. -** Only pPage->apCell[] is important. The relinkCellList() routine -** will be called soon after this routine in order to rebuild the -** linked list. +** Only the pPage->apCell[] array is important. The relinkCellList() +** routine will be called soon after this routine in order to rebuild +** the linked list. */ static void insertCell(MemPage *pPage, int i, Cell *pCell, int sz){ int idx, j; @@ -1442,22 +1483,23 @@ static void insertCell(MemPage *pPage, int i, Cell *pCell, int sz){ pPage->apCell[i] = pCell; }else{ memcpy(&pPage->u.aDisk[idx], pCell, sz); - pPage->apCell[i] = (Cell*)&pPage->u.aDisk[idx]); + pPage->apCell[i] = (Cell*)&pPage->u.aDisk[idx]; } } /* ** Rebuild the linked list of cells on a page so that the cells -** occur in the order specified by pPage->apCell[]. Invoke this -** routine once to repair damage after one or more invocations -** of either insertCell() or dropCell(). +** occur in the order specified by the pPage->apCell[] array. +** Invoke this routine once to repair damage after one or more +** invocations of either insertCell() or dropCell(). */ static void relinkCellList(MemPage *pPage){ int i; u16 *pIdx; pIdx = &pPage->u.hdr.firstCell; for(i=0; inCell; i++){ - int idx = ((uptr)pPage->apCell[i]) - (uptr)pPage; + int idx = addr(pPage->apCell[i]) - addr(pPage); + assert( idx>0 && idxapCell[i]->h.iNext; } @@ -1479,12 +1521,12 @@ static void copyPage(MemPage *pTo, MemPage *pFrom){ pTo->nCell = pFrom->nCell; pTo->nFree = pFrom->nFree; pTo->isOverfull = pFrom->isOverfull; - to = (unsigned int)pTo; - from = (unsigned int)pFrom; + to = addr(pTo); + from = addr(pFrom); for(i=0; inCell; i++){ - uptr addr = (uptr)(pFrom->apCell[i]); - if( addr>from && addrapCell[i]) = addr + to - from; + uptr x = addr(pFrom->apCell[i]); + if( x>from && xapCell[i]) = x + to - from; } } } @@ -1499,8 +1541,9 @@ static void copyPage(MemPage *pTo, MemPage *pFrom){ ** child of root) then all available siblings participate in the balancing. ** ** The number of siblings of pPage might be increased or decreased by -** one in order to keep all pages between 2/3 and completely full. If -** pPage is the root page, then the depth of the tree might be increased +** one in an effort to keep pages between 66% and 100% full. The root page +** is special and is allowed to be less than 66% full. If pPage is +** the root page, then the depth of the tree might be increased ** or decreased by one, as necessary, to keep the root page from being ** overfull or empty. ** @@ -1511,13 +1554,19 @@ static void copyPage(MemPage *pTo, MemPage *pFrom){ ** routines left behind. ** ** pCur is left pointing to the same cell as when this routine was called -** event if that cell gets moved to a different page. pCur may be NULL. +** even if that cell gets moved to a different page. pCur may be NULL. +** Set the pCur parameter to NULL if you do not care about keeping track +** of a cell as that will save this routine the work of keeping track of it. ** ** Note that when this routine is called, some of the Cells on pPage ** might not actually be stored in pPage->u.aDisk[]. This can happen ** if the page is overfull. Part of the job of this routine is to ** make sure all Cells for pPage once again fit in pPage->u.aDisk[]. ** +** In the course of balancing the siblings of pPage, the parent of pPage +** might become overfull or underfull. If that happens, then this routine +** is called recursively on the parent. +** ** If this routine fails for any reason, it means the database may have ** been left in a corrupted state and should be rolled back. */ @@ -1532,7 +1581,6 @@ static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){ int nCell; /* Number of cells in apCell[] */ int nOld; /* Number of pages in apOld[] */ int nNew; /* Number of pages in apNew[] */ - int perPage; /* Approximate number of bytes per page */ int nDiv; /* Number of cells in apDiv[] */ int i, j, k; /* Loop counters */ int idx; /* Index of pPage in pParent->apCell[] */ @@ -1541,6 +1589,8 @@ static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){ int iCur; /* apCell[iCur] is the cell of the cursor */ int usedPerPage; /* Memory needed for each page */ int freePerPage; /* Average free space per page */ + int totalSize; /* Total bytes for all cells */ + Pgno pgno; /* Page number */ Cell *apCell[MX_CELL*3+5]; /* All cells from pages being balanceed */ int szCell[MX_CELL*3+5]; /* Local size of all cells */ Cell aTemp[2]; /* Temporary holding area for apDiv[] */ @@ -1563,7 +1613,7 @@ static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){ pParent = pPage->pParent; if( pParent==0 ){ Pgno pgnoChild; - Page *pChild; + MemPage *pChild; if( pPage->nCell==0 ){ if( pPage->u.hdr.rightChild ){ /* @@ -1574,7 +1624,7 @@ static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){ rc = sqlitepager_write(pPage); if( rc ) return rc; pgnoChild = pPage->u.hdr.rightChild; - rc = sqlitepager_get(pBt, pgnoChild, &pChild); + rc = sqlitepager_get(pBt->pPager, pgnoChild, (void**)&pChild); if( rc ) return rc; memcpy(pPage, pChild, SQLITE_PAGE_SIZE); pPage->isInit = 0; @@ -1668,11 +1718,11 @@ static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){ nDiv++; pgnoOld[i] = apDiv[i]->h.leftChild; }else if( k==pParent->nCell ){ - pgnoOld[i] = pParent->rightChild; + pgnoOld[i] = pParent->u.hdr.rightChild; }else{ break; } - rc = sqlitepager_get(pBt, pgnoOld[i], &apOld[i]); + rc = sqlitepager_get(pBt->pPager, pgnoOld[i], (void**)&apOld[i]); if( rc ) goto balance_cleanup; nOld++; } @@ -1719,7 +1769,7 @@ static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){ } if( ih.leftChild==pgnoOld[i] ); @@ -1878,6 +1928,7 @@ int sqliteBtreeDelete(BtCursor *pCur){ MemPage *pPage = pCur->pPage; Cell *pCell; int rc; + Pgno pgnoChild; if( !pCur->pBt->inTrans ){ return SQLITE_ERROR; /* Must start a transaction first */ @@ -1889,13 +1940,13 @@ int sqliteBtreeDelete(BtCursor *pCur){ if( rc ) return rc; pCell = pPage->apCell[pCur->idx]; pgnoChild = pCell->h.leftChild; - clearCell(pCell); + clearCell(pCur->pBt, pCell); dropCell(pPage, pCur->idx, cellSize(pCell)); if( pgnoChild ){ /* ** If the entry we just deleted is not a leaf, then we've left a - ** whole in an internal page. We have to fill the whole by moving - ** in a page from a leaf. The next Cell after the one just deleted + ** hole in an internal page. We have to fill the hole by moving + ** in a cell from a leaf. The next Cell after the one just deleted ** is guaranteed to exist and to be a leaf so we can use it. */ BtCursor leafCur; @@ -1906,15 +1957,16 @@ int sqliteBtreeDelete(BtCursor *pCur){ if( rc!=SQLITE_OK ){ return SQLITE_CORRUPT; } - pNext = leafCur.pPage->apCell[leafCur.idx] + pNext = leafCur.pPage->apCell[leafCur.idx]; szNext = cellSize(pNext); + pNext->h.leftChild = pgnoChild; insertCell(pPage, pCur->idx, pNext, szNext); rc = balance(pCur->pBt, pPage, pCur); if( rc ) return rc; pCur->bSkipNext = 1; dropCell(leafCur.pPage, leafCur.idx, szNext); rc = balance(pCur->pBt, leafCur.pPage, 0); - releaseTempCur(&leafCur); + releaseTempCursor(&leafCur); }else{ rc = balance(pCur->pBt, pPage, pCur); pCur->bSkipNext = 1; @@ -1949,11 +2001,10 @@ int sqliteBtreeCreateTable(Btree *pBt, int *piTable){ static int clearDatabasePage(Btree *pBt, Pgno pgno){ MemPage *pPage; int rc; - int i; Cell *pCell; int idx; - rc = sqlitepager_get(pBt->pPager, pgno, &pPage); + rc = sqlitepager_get(pBt->pPager, pgno, (void**)&pPage); if( rc ) return rc; idx = pPage->u.hdr.firstCell; while( idx>0 ){ @@ -1963,9 +2014,11 @@ static int clearDatabasePage(Btree *pBt, Pgno pgno){ rc = clearDatabasePage(pBt, pCell->h.leftChild); if( rc ) return rc; } - rc = clearCell(pCell); + rc = clearCell(pBt, pCell); if( rc ) return rc; } + rc = clearDatabasePage(pBt, pPage->u.hdr.rightChild); + if( rc ) return rc; return freePage(pBt, pPage, pgno); } @@ -1980,8 +2033,8 @@ int sqliteBtreeClearTable(Btree *pBt, int iTable){ rc = clearDatabasePage(pBt, (Pgno)iTable); if( rc ){ sqliteBtreeRollback(pBt); - return rc; } + return rc; } /* @@ -1995,7 +2048,7 @@ int sqliteBtreeDropTable(Btree *pBt, int iTable){ if( !pBt->inTrans ){ return SQLITE_ERROR; /* Must start a transaction first */ } - rc = sqlitepager_get(pBt->pPager, (Pgno)iTable, &pPage); + rc = sqlitepager_get(pBt->pPager, (Pgno)iTable, (void**)&pPage); if( rc==SQLITE_OK ){ rc = sqliteBtreeClearTable(pBt, iTable); } @@ -2013,7 +2066,7 @@ int sqliteBtreeGetMeta(Btree *pBt, int *aMeta){ PageOne *pP1; int rc; - rc = sqlitepager_get(pBt->pPager, 1, &pP1); + rc = sqlitepager_get(pBt->pPager, 1, (void**)&pP1); if( rc ) return rc; memcpy(aMeta, pP1->aMeta, sizeof(pP1->aMeta)); sqlitepager_unref(pP1); @@ -2035,3 +2088,74 @@ int sqliteBtreeUpdateMeta(Btree *pBt, int *aMeta){ memcpy(pP1->aMeta, aMeta, sizeof(pP1->aMeta)); return SQLITE_OK; } + +#ifdef SQLITE_TEST +/* +** Print a disassembly of the given page on standard output. This routine +** is used for debugging and testing only. +*/ +int sqliteBtreePageDump(Btree *pBt, int pgno){ + int rc; + MemPage *pPage; + int i, j; + int nFree; + u16 idx; + char range[20]; + unsigned char payload[20]; + rc = sqlitepager_get(pBt->pPager, (Pgno)pgno, (void**)&pPage); + if( rc ){ + return rc; + } + i = 0; + idx = pPage->u.hdr.firstCell; + while( idx>0 && idx<=SQLITE_PAGE_SIZE-MIN_CELL_SIZE ){ + Cell *pCell = (Cell*)&pPage->u.aDisk[idx]; + int sz = cellSize(pCell); + sprintf(range,"%d..%d", idx, idx+sz-1); + if( sz>sizeof(payload)-1 ) sz = sizeof(payload)-1; + memcpy(payload, pCell->aPayload, sz); + for(j=0; j0x7f ) payload[j] = '.'; + } + payload[sz] = 0; + printf( + "cell %2d: i=%-10s chld=%-4d nk=%-3d nd=%-3d payload=%s\n", + i, range, (int)pCell->h.leftChild, pCell->h.nKey, pCell->h.nData, + pCell->aPayload + ); + idx = pCell->h.iNext; + } + if( idx!=0 ){ + printf("ERROR: next cell index out of range: %d\n", idx); + } + printf("right_child: %d\n", pPage->u.hdr.rightChild); + nFree = 0; + i = 0; + idx = pPage->u.hdr.firstFree; + while( idx>0 && idxu.aDisk[idx]; + sprintf(range,"%d..%d", idx, idx+p->iSize-1); + nFree += p->iSize; + printf("freeblock %2d: i=%-10s size=%-4d total=%d\n", + i, range, p->iSize, nFree); + idx = p->iNext; + } + if( idx!=0 ){ + printf("ERROR: next freeblock index out of range: %d\n", idx); + } + sqlitepager_unref(pPage); + return SQLITE_OK; +} +#endif + +#ifdef SQLITE_TEST +/* +** Put the page number and index of a cursor into aResult[0] and aResult[1] +** This routine is used for debugging and testing only. +*/ +int sqliteBtreeCursorDump(BtCursor *pCur, int *aResult){ + aResult[0] = sqlitepager_pagenumber(pCur->pPage); + aResult[1] = pCur->idx; + return SQLITE_OK; +} +#endif diff --git a/src/btree.h b/src/btree.h index f63b198a14..b751c2f843 100644 --- a/src/btree.h +++ b/src/btree.h @@ -24,7 +24,7 @@ ** This header file defines the interface that the sqlite B-Tree file ** subsystem. ** -** @(#) $Id: btree.h,v 1.4 2001/06/08 00:21:53 drh Exp $ +** @(#) $Id: btree.h,v 1.5 2001/06/22 19:15:00 drh Exp $ */ typedef struct Btree Btree; @@ -42,7 +42,7 @@ int sqliteBtreeDropTable(Btree*, int); int sqliteBtreeClearTable(Btree*, int); int sqliteBtreeCursor(Btree*, int iTable, BtCursor **ppCur); -int sqliteBtreeMoveto(BtCursor*, void *pKey, int nKey, *pRes); +int sqliteBtreeMoveto(BtCursor*, void *pKey, int nKey, int *pRes); int sqliteBtreeDelete(BtCursor*); int sqliteBtreeInsert(BtCursor*, void *pKey, int nKey, void *pData, int nData); int sqliteBtreeNext(BtCursor*, int *pRes); @@ -55,3 +55,9 @@ int sqliteBtreeCloseCursor(BtCursor*); #define SQLITE_N_BTREE_META 3 int sqliteBtreeGetMeta(Btree*, int*); int sqliteBtreeUpdateMeta(Btree*, int*); + + +#ifdef SQLITE_TEST +int sqliteBtreePageDump(Btree*, int); +int sqliteBtreeCursorDump(BtCursor*, int*); +#endif diff --git a/src/pager.c b/src/pager.c index 6915ef2776..b102e04868 100644 --- a/src/pager.c +++ b/src/pager.c @@ -27,7 +27,7 @@ ** all writes in order to support rollback. Locking is used to limit ** access to one or more reader or one writer. ** -** @(#) $Id: pager.c,v 1.8 2001/06/02 02:40:57 drh Exp $ +** @(#) $Id: pager.c,v 1.9 2001/06/22 19:15:00 drh Exp $ */ #include "sqliteInt.h" #include "pager.h" @@ -562,7 +562,8 @@ Pgno sqlitepager_pagenumber(void *pData){ ** currently on the freelist (the reference count is zero) then ** remove it from the freelist. */ -static void sqlitepager_ref(PgHdr *pPg){ +int sqlitepager_ref(void *pData){ + PgHdr *pPg = DATA_TO_PGHDR(pData); if( pPg->nRef==0 ){ /* The page is currently on the freelist. Remove it. */ if( pPg->pPrevFree ){ @@ -578,6 +579,7 @@ static void sqlitepager_ref(PgHdr *pPg){ pPg->pPager->nRef++; } pPg->nRef++; + return SQLITE_OK; } /* diff --git a/src/pager.h b/src/pager.h index f12fe09a65..acb7735b8c 100644 --- a/src/pager.h +++ b/src/pager.h @@ -25,7 +25,7 @@ ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. ** -** @(#) $Id: pager.h,v 1.4 2001/05/24 21:06:36 drh Exp $ +** @(#) $Id: pager.h,v 1.5 2001/06/22 19:15:01 drh Exp $ */ /* @@ -45,10 +45,11 @@ typedef unsigned int Pgno; typedef struct Pager Pager; int sqlitepager_open(Pager **ppPager,const char *zFilename,int nPage,int nEx); -void sqiltepager_set_destructor(Pager*, void(*)(void*)); +void sqlitepager_set_destructor(Pager*, void(*)(void*)); int sqlitepager_close(Pager *pPager); int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage); void *sqlitepager_lookup(Pager *pPager, Pgno pgno); +int sqlitepager_ref(void*); int sqlitepager_unref(void*); Pgno sqlitepager_pagenumber(void*); int sqlitepager_write(void*); diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 6d5c2c6b0b..d364cb7b35 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -23,7 +23,7 @@ ************************************************************************* ** A TCL Interface to SQLite ** -** $Id: tclsqlite.c,v 1.18 2001/04/15 00:37:09 drh Exp $ +** $Id: tclsqlite.c,v 1.19 2001/06/22 19:15:01 drh Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ @@ -511,8 +511,10 @@ int TCLSH_MAIN(int argc, char **argv){ { extern int Sqlitetest1_Init(Tcl_Interp*); extern int Sqlitetest2_Init(Tcl_Interp*); + extern int Sqlitetest3_Init(Tcl_Interp*); Sqlitetest1_Init(interp); Sqlitetest2_Init(interp); + Sqlitetest3_Init(interp); } #endif if( argc>=2 ){ diff --git a/src/test3.c b/src/test3.c index 769218e980..87b36e37e5 100644 --- a/src/test3.c +++ b/src/test3.c @@ -25,7 +25,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test3.c,v 1.1 2001/06/02 02:40:57 drh Exp $ +** $Id: test3.c,v 1.2 2001/06/22 19:15:01 drh Exp $ */ #include "sqliteInt.h" #include "pager.h" @@ -71,8 +71,7 @@ static int btree_open( int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ - BTree *pBt; - int nPage; + Btree *pBt; int rc; char zBuf[100]; if( argc!=2 ){ @@ -155,7 +154,7 @@ static int btree_rollback( int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ - Btree *pBt + Btree *pBt; int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], @@ -239,16 +238,16 @@ static int btree_drop_table( int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ - Pager *pPager; + Btree *pBt; int iTable; - char zBuf[100]; + int rc; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID TABLENUM\"", 0); return TCL_ERROR; } if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; - if( Tcl_GetInt(interp, argv[2], &iTable ) return TCL_ERROR; + if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; rc = sqliteBtreeDropTable(pBt, iTable); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); @@ -257,6 +256,390 @@ static int btree_drop_table( return TCL_OK; } +/* +** Usage: btree_get_meta ID +** +** Return meta data +*/ +static int btree_get_meta( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Btree *pBt; + int rc; + int i; + int aMeta[SQLITE_N_BTREE_META]; + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; + rc = sqliteBtreeGetMeta(pBt, aMeta); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + for(i=0; i