diff options
author | Wez Furlong <wez@php.net> | 2003-06-04 22:40:00 +0000 |
---|---|---|
committer | Wez Furlong <wez@php.net> | 2003-06-04 22:40:00 +0000 |
commit | 80e7f7001d39add9010ba78be636245410b79c24 (patch) | |
tree | 23ae7f9f01ea9bb1add35b1ff85efa2421d05142 /ext/sqlite/libsqlite/src/btree.c | |
parent | 82a1818fdec3afe8e3a5cc8aa7171f4472ea1e4a (diff) | |
download | php-git-80e7f7001d39add9010ba78be636245410b79c24.tar.gz |
Update bundled library to version 2.8.2.
Make OnUpdateInt compatible with ZE2.
Fix the makefile fragment for non-gnu makes
Diffstat (limited to 'ext/sqlite/libsqlite/src/btree.c')
-rw-r--r-- | ext/sqlite/libsqlite/src/btree.c | 315 |
1 files changed, 258 insertions, 57 deletions
diff --git a/ext/sqlite/libsqlite/src/btree.c b/ext/sqlite/libsqlite/src/btree.c index 41913fc551..30979d0e31 100644 --- a/ext/sqlite/libsqlite/src/btree.c +++ b/ext/sqlite/libsqlite/src/btree.c @@ -54,6 +54,10 @@ #include "btree.h" #include <assert.h> +/* Forward declarations */ +static BtOps sqliteBtreeOps; +static BtCursorOps sqliteBtreeCursorOps; + /* ** Macros used for byteswapping. B is a pointer to the Btree ** structure. This is needed to access the Btree.needSwab boolean @@ -61,7 +65,7 @@ ** X is an unsigned integer. SWAB16 byte swaps a 16-bit integer. ** SWAB32 byteswaps a 32-bit integer. */ -#define SWAB16(B,X) ((B)->needSwab? swab16(X) : (X)) +#define SWAB16(B,X) ((B)->needSwab? swab16((u16)X) : ((u16)X)) #define SWAB32(B,X) ((B)->needSwab? swab32(X) : (X)) #define SWAB_ADD(B,X,A) \ if((B)->needSwab){ X=swab32(swab32(X)+A); }else{ X += (A); } @@ -340,6 +344,7 @@ struct MemPage { ** Everything we need to know about an open database */ struct Btree { + BtOps *pOps; /* Function table */ Pager *pPager; /* The page cache */ BtCursor *pCursor; /* A list of all open cursors */ PageOne *page1; /* First page of the database */ @@ -356,6 +361,7 @@ typedef Btree Bt; ** MemPage.apCell[] of the entry. */ struct BtCursor { + BtCursorOps *pOps; /* Function table */ Btree *pBt; /* The Btree to which this cursor belongs */ BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */ BtCursor *pShared; /* Loop of cursors with the same root page */ @@ -375,6 +381,9 @@ struct BtCursor { #define SKIP_PREV 2 /* The next sqliteBtreePrevious() is a no-op */ #define SKIP_INVALID 3 /* Calls to Next() and Previous() are invalid */ +/* Forward declarations */ +static int fileBtreeCloseCursor(BtCursor *pCur); + /* ** Routines for byte swapping. */ @@ -527,7 +536,7 @@ static void freeSpace(Btree *pBt, MemPage *pPage, int start, int size){ if( idx + iSize + size == SWAB16(pBt, pFBlk->iNext) ){ pNext = (FreeBlk*)&pPage->u.aDisk[idx + iSize + size]; if( pBt->needSwab ){ - pFBlk->iSize = swab16(swab16(pNext->iSize)+iSize+size); + pFBlk->iSize = swab16((u16)swab16(pNext->iSize)+iSize+size); }else{ pFBlk->iSize += pNext->iSize; } @@ -709,6 +718,7 @@ int sqliteBtreeOpen( pBt->pCursor = 0; pBt->page1 = 0; pBt->readOnly = sqlitepager_isreadonly(pBt->pPager); + pBt->pOps = &sqliteBtreeOps; *ppBtree = pBt; return SQLITE_OK; } @@ -716,9 +726,9 @@ int sqliteBtreeOpen( /* ** Close an open database and invalidate all cursors. */ -int sqliteBtreeClose(Btree *pBt){ +static int fileBtreeClose(Btree *pBt){ while( pBt->pCursor ){ - sqliteBtreeCloseCursor(pBt->pCursor); + fileBtreeCloseCursor(pBt->pCursor); } sqlitepager_close(pBt->pPager); sqliteFree(pBt); @@ -740,7 +750,7 @@ int sqliteBtreeClose(Btree *pBt){ ** Synchronous is on by default so database corruption is not ** normally a worry. */ -int sqliteBtreeSetCacheSize(Btree *pBt, int mxPage){ +static int fileBtreeSetCacheSize(Btree *pBt, int mxPage){ sqlitepager_set_cachesize(pBt->pPager, mxPage); return SQLITE_OK; } @@ -753,7 +763,7 @@ int sqliteBtreeSetCacheSize(Btree *pBt, int mxPage){ ** is a very low but non-zero probability of damage. Level 3 reduces the ** probability of damage to near zero but with a write performance reduction. */ -int sqliteBtreeSetSafetyLevel(Btree *pBt, int level){ +static int fileBtreeSetSafetyLevel(Btree *pBt, int level){ sqlitepager_set_safety_level(pBt->pPager, level); return SQLITE_OK; } @@ -860,7 +870,7 @@ static int newDatabase(Btree *pBt){ ** sqliteBtreeDelete() ** sqliteBtreeUpdateMeta() */ -int sqliteBtreeBeginTrans(Btree *pBt){ +static int fileBtreeBeginTrans(Btree *pBt){ int rc; if( pBt->inTrans ) return SQLITE_ERROR; if( pBt->readOnly ) return SQLITE_READONLY; @@ -889,7 +899,7 @@ int sqliteBtreeBeginTrans(Btree *pBt){ ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ -int sqliteBtreeCommit(Btree *pBt){ +static int fileBtreeCommit(Btree *pBt){ int rc; rc = pBt->readOnly ? SQLITE_OK : sqlitepager_commit(pBt->pPager); pBt->inTrans = 0; @@ -907,7 +917,7 @@ int sqliteBtreeCommit(Btree *pBt){ ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ -int sqliteBtreeRollback(Btree *pBt){ +static int fileBtreeRollback(Btree *pBt){ int rc; BtCursor *pCur; if( pBt->inTrans==0 ) return SQLITE_OK; @@ -934,7 +944,7 @@ int sqliteBtreeRollback(Btree *pBt){ ** Only one checkpoint may be active at a time. It is an error to try ** to start a new checkpoint if another checkpoint is already active. */ -int sqliteBtreeBeginCkpt(Btree *pBt){ +static int fileBtreeBeginCkpt(Btree *pBt){ int rc; if( !pBt->inTrans || pBt->inCkpt ){ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; @@ -949,7 +959,7 @@ int sqliteBtreeBeginCkpt(Btree *pBt){ ** Commit a checkpoint to transaction currently in progress. If no ** checkpoint is active, this is a no-op. */ -int sqliteBtreeCommitCkpt(Btree *pBt){ +static int fileBtreeCommitCkpt(Btree *pBt){ int rc; if( pBt->inCkpt && !pBt->readOnly ){ rc = sqlitepager_ckpt_commit(pBt->pPager); @@ -968,7 +978,7 @@ int sqliteBtreeCommitCkpt(Btree *pBt){ ** to use a cursor that was open at the beginning of this operation ** will result in an error. */ -int sqliteBtreeRollbackCkpt(Btree *pBt){ +static int fileBtreeRollbackCkpt(Btree *pBt){ int rc; BtCursor *pCur; if( pBt->inCkpt==0 || pBt->readOnly ) return SQLITE_OK; @@ -1019,7 +1029,7 @@ int sqliteBtreeRollbackCkpt(Btree *pBt){ ** root page of a b-tree. If it is not, then the cursor acquired ** will not work correctly. */ -int sqliteBtreeCursor(Btree *pBt, int iTable, int wrFlag, BtCursor **ppCur){ +static int fileBtreeCursor(Btree *pBt, int iTable, int wrFlag, BtCursor **ppCur){ int rc; BtCursor *pCur, *pRing; @@ -1044,6 +1054,7 @@ int sqliteBtreeCursor(Btree *pBt, int iTable, int wrFlag, BtCursor **ppCur){ if( rc!=SQLITE_OK ){ goto create_cursor_exception; } + pCur->pOps = &sqliteBtreeCursorOps; pCur->pBt = pBt; pCur->wrFlag = wrFlag; pCur->idx = 0; @@ -1079,7 +1090,7 @@ create_cursor_exception: ** Close a cursor. The read lock on the database file is released ** when the last cursor is closed. */ -int sqliteBtreeCloseCursor(BtCursor *pCur){ +static int fileBtreeCloseCursor(BtCursor *pCur){ Btree *pBt = pCur->pBt; if( pCur->pPrev ){ pCur->pPrev->pNext = pCur->pNext; @@ -1132,7 +1143,7 @@ static void releaseTempCursor(BtCursor *pCur){ ** pointing to an entry (which can happen, for example, if ** the database is empty) then *pSize is set to 0. */ -int sqliteBtreeKeySize(BtCursor *pCur, int *pSize){ +static int fileBtreeKeySize(BtCursor *pCur, int *pSize){ Cell *pCell; MemPage *pPage; @@ -1221,7 +1232,7 @@ static int getPayload(BtCursor *pCur, int offset, int amt, char *zBuf){ ** is raised. The change was made in an effort to boost performance ** by eliminating unneeded tests. */ -int sqliteBtreeKey(BtCursor *pCur, int offset, int amt, char *zBuf){ +static int fileBtreeKey(BtCursor *pCur, int offset, int amt, char *zBuf){ MemPage *pPage; assert( amt>=0 ); @@ -1243,7 +1254,7 @@ int sqliteBtreeKey(BtCursor *pCur, int offset, int amt, char *zBuf){ ** pointing to an entry (which can happen, for example, if ** the database is empty) then *pSize is set to 0. */ -int sqliteBtreeDataSize(BtCursor *pCur, int *pSize){ +static int fileBtreeDataSize(BtCursor *pCur, int *pSize){ Cell *pCell; MemPage *pPage; @@ -1266,7 +1277,7 @@ int sqliteBtreeDataSize(BtCursor *pCur, int *pSize){ ** amount requested if there are not enough bytes in the data ** to satisfy the request. */ -int sqliteBtreeData(BtCursor *pCur, int offset, int amt, char *zBuf){ +static int fileBtreeData(BtCursor *pCur, int offset, int amt, char *zBuf){ Cell *pCell; MemPage *pPage; @@ -1304,7 +1315,7 @@ int sqliteBtreeData(BtCursor *pCur, int offset, int amt, char *zBuf){ ** keys must be exactly the same length. (The length of the pCur key ** is the actual key length minus nIgnore bytes.) */ -int sqliteBtreeKeyCompare( +static int fileBtreeKeyCompare( BtCursor *pCur, /* Pointer to entry to compare against */ const void *pKey, /* Key to compare against entry that pCur points to */ int nKey, /* Number of bytes in pKey */ @@ -1389,6 +1400,7 @@ static int moveToChild(BtCursor *pCur, int newPgno){ sqlitepager_unref(pCur->pPage); pCur->pPage = pNewPage; pCur->idx = 0; + if( pNewPage->nCell<1 ) return SQLITE_CORRUPT; return SQLITE_OK; } @@ -1502,7 +1514,7 @@ static int moveToRightmost(BtCursor *pCur){ ** on success. Set *pRes to 0 if the cursor actually points to something ** or set *pRes to 1 if the table is empty. */ -int sqliteBtreeFirst(BtCursor *pCur, int *pRes){ +static int fileBtreeFirst(BtCursor *pCur, int *pRes){ int rc; if( pCur->pPage==0 ) return SQLITE_ABORT; rc = moveToRoot(pCur); @@ -1521,7 +1533,7 @@ int sqliteBtreeFirst(BtCursor *pCur, int *pRes){ ** on success. Set *pRes to 0 if the cursor actually points to something ** or set *pRes to 1 if the table is empty. */ -int sqliteBtreeLast(BtCursor *pCur, int *pRes){ +static int fileBtreeLast(BtCursor *pCur, int *pRes){ int rc; if( pCur->pPage==0 ) return SQLITE_ABORT; rc = moveToRoot(pCur); @@ -1560,7 +1572,8 @@ int sqliteBtreeLast(BtCursor *pCur, int *pRes){ ** *pRes>0 The cursor is left pointing at an entry that ** is larger than pKey. */ -int sqliteBtreeMoveto(BtCursor *pCur, const void *pKey, int nKey, int *pRes){ +static +int fileBtreeMoveto(BtCursor *pCur, const void *pKey, int nKey, int *pRes){ int rc; if( pCur->pPage==0 ) return SQLITE_ABORT; pCur->eSkip = SKIP_NONE; @@ -1575,7 +1588,7 @@ int sqliteBtreeMoveto(BtCursor *pCur, const void *pKey, int nKey, int *pRes){ upr = pPage->nCell-1; while( lwr<=upr ){ pCur->idx = (lwr+upr)/2; - rc = sqliteBtreeKeyCompare(pCur, pKey, nKey, 0, &c); + rc = fileBtreeKeyCompare(pCur, pKey, nKey, 0, &c); if( rc ) return rc; if( c==0 ){ pCur->iMatch = c; @@ -1613,7 +1626,7 @@ int sqliteBtreeMoveto(BtCursor *pCur, const void *pKey, int nKey, int *pRes){ ** was already pointing to the last entry in the database before ** this routine was called, then set *pRes=1. */ -int sqliteBtreeNext(BtCursor *pCur, int *pRes){ +static int fileBtreeNext(BtCursor *pCur, int *pRes){ int rc; MemPage *pPage = pCur->pPage; assert( pRes!=0 ); @@ -1668,7 +1681,7 @@ int sqliteBtreeNext(BtCursor *pCur, int *pRes){ ** was already pointing to the first entry in the database before ** this routine was called, then set *pRes=1. */ -int sqliteBtreePrevious(BtCursor *pCur, int *pRes){ +static int fileBtreePrevious(BtCursor *pCur, int *pRes){ int rc; Pgno pgno; MemPage *pPage; @@ -2594,7 +2607,7 @@ static int checkReadLocks(BtCursor *pCur){ ** define what database the record should be inserted into. The cursor ** is left pointing at the new record. */ -int sqliteBtreeInsert( +static int fileBtreeInsert( BtCursor *pCur, /* Insert data into the table of this cursor */ const void *pKey, int nKey, /* The key of the new record */ const void *pData, int nData /* The data of the new record */ @@ -2620,7 +2633,7 @@ int sqliteBtreeInsert( if( checkReadLocks(pCur) ){ return SQLITE_LOCKED; /* The table pCur points to has a read lock */ } - rc = sqliteBtreeMoveto(pCur, pKey, nKey, &loc); + rc = fileBtreeMoveto(pCur, pKey, nKey, &loc); if( rc ) return rc; pPage = pCur->pPage; assert( pPage->isInit ); @@ -2662,7 +2675,7 @@ int sqliteBtreeInsert( ** sqliteBtreePrevious() will always leave the cursor pointing at the ** entry immediately before the one that was deleted. */ -int sqliteBtreeDelete(BtCursor *pCur){ +static int fileBtreeDelete(BtCursor *pCur){ MemPage *pPage = pCur->pPage; Cell *pCell; int rc; @@ -2705,7 +2718,7 @@ int sqliteBtreeDelete(BtCursor *pCur){ int szNext; int notUsed; getTempCursor(pCur, &leafCur); - rc = sqliteBtreeNext(&leafCur, ¬Used); + rc = fileBtreeNext(&leafCur, ¬Used); if( rc!=SQLITE_OK ){ return SQLITE_CORRUPT; } @@ -2745,11 +2758,12 @@ int sqliteBtreeDelete(BtCursor *pCur){ ** number for the root page of the new table. ** ** In the current implementation, BTree tables and BTree indices are the -** the same. But in the future, we may change this so that BTree tables +** the same. In the future, we may change this so that BTree tables ** are restricted to having a 4-byte integer key and arbitrary data and ** BTree indices are restricted to having an arbitrary key and no data. +** But for now, this routine also serves to create indices. */ -int sqliteBtreeCreateTable(Btree *pBt, int *piTable){ +static int fileBtreeCreateTable(Btree *pBt, int *piTable){ MemPage *pRoot; Pgno pgnoRoot; int rc; @@ -2770,19 +2784,6 @@ int sqliteBtreeCreateTable(Btree *pBt, int *piTable){ } /* -** Create a new BTree index. Write into *piTable the page -** number for the root page of the new index. -** -** In the current implementation, BTree tables and BTree indices are the -** the same. But in the future, we may change this so that BTree tables -** are restricted to having a 4-byte integer key and arbitrary data and -** BTree indices are restricted to having an arbitrary key and no data. -*/ -int sqliteBtreeCreateIndex(Btree *pBt, int *piIndex){ - return sqliteBtreeCreateTable(pBt, piIndex); -} - -/* ** Erase the given database page and all its children. Return ** the page to the freelist. */ @@ -2825,7 +2826,7 @@ static int clearDatabasePage(Btree *pBt, Pgno pgno, int freePageFlag){ /* ** Delete all information from a single table in the database. */ -int sqliteBtreeClearTable(Btree *pBt, int iTable){ +static int fileBtreeClearTable(Btree *pBt, int iTable){ int rc; BtCursor *pCur; if( !pBt->inTrans ){ @@ -2839,7 +2840,7 @@ int sqliteBtreeClearTable(Btree *pBt, int iTable){ } rc = clearDatabasePage(pBt, (Pgno)iTable, 0); if( rc ){ - sqliteBtreeRollback(pBt); + fileBtreeRollback(pBt); } return rc; } @@ -2849,7 +2850,7 @@ int sqliteBtreeClearTable(Btree *pBt, int iTable){ ** the freelist. Except, the root of the principle table (the one on ** page 2) is never added to the freelist. */ -int sqliteBtreeDropTable(Btree *pBt, int iTable){ +static int fileBtreeDropTable(Btree *pBt, int iTable){ int rc; MemPage *pPage; BtCursor *pCur; @@ -2863,7 +2864,7 @@ int sqliteBtreeDropTable(Btree *pBt, int iTable){ } rc = sqlitepager_get(pBt->pPager, (Pgno)iTable, (void**)&pPage); if( rc ) return rc; - rc = sqliteBtreeClearTable(pBt, iTable); + rc = fileBtreeClearTable(pBt, iTable); if( rc ) return rc; if( iTable>2 ){ rc = freePage(pBt, pPage, iTable); @@ -2874,10 +2875,109 @@ int sqliteBtreeDropTable(Btree *pBt, int iTable){ return rc; } +#if 0 /* UNTESTED */ +/* +** Copy all cell data from one database file into another. +** pages back the freelist. +*/ +static int copyCell(Btree *pBtFrom, BTree *pBtTo, Cell *pCell){ + Pager *pFromPager = pBtFrom->pPager; + OverflowPage *pOvfl; + Pgno ovfl, nextOvfl; + Pgno *pPrev; + int rc = SQLITE_OK; + MemPage *pNew, *pPrevPg; + Pgno new; + + if( NKEY(pBtTo, pCell->h) + NDATA(pBtTo, pCell->h) <= MX_LOCAL_PAYLOAD ){ + return SQLITE_OK; + } + pPrev = &pCell->ovfl; + pPrevPg = 0; + ovfl = SWAB32(pBtTo, pCell->ovfl); + while( ovfl && rc==SQLITE_OK ){ + rc = sqlitepager_get(pFromPager, ovfl, (void**)&pOvfl); + if( rc ) return rc; + nextOvfl = SWAB32(pBtFrom, pOvfl->iNext); + rc = allocatePage(pBtTo, &pNew, &new, 0); + if( rc==SQLITE_OK ){ + rc = sqlitepager_write(pNew); + if( rc==SQLITE_OK ){ + memcpy(pNew, pOvfl, SQLITE_PAGE_SIZE); + *pPrev = SWAB32(pBtTo, new); + if( pPrevPg ){ + sqlitepager_unref(pPrevPg); + } + pPrev = &pOvfl->iNext; + pPrevPg = pNew; + } + } + sqlitepager_unref(pOvfl); + ovfl = nextOvfl; + } + if( pPrevPg ){ + sqlitepager_unref(pPrevPg); + } + return rc; +} +#endif + + +#if 0 /* UNTESTED */ +/* +** Copy a page of data from one database over to another. +*/ +static int copyDatabasePage( + Btree *pBtFrom, + Pgno pgnoFrom, + Btree *pBtTo, + Pgno *pTo +){ + MemPage *pPageFrom, *pPage; + Pgno to; + int rc; + Cell *pCell; + int idx; + + rc = sqlitepager_get(pBtFrom->pPager, pgno, (void**)&pPageFrom); + if( rc ) return rc; + rc = allocatePage(pBt, &pPage, pTo, 0); + if( rc==SQLITE_OK ){ + rc = sqlitepager_write(pPage); + } + if( rc==SQLITE_OK ){ + memcpy(pPage, pPageFrom, SQLITE_PAGE_SIZE); + idx = SWAB16(pBt, pPage->u.hdr.firstCell); + while( idx>0 ){ + pCell = (Cell*)&pPage->u.aDisk[idx]; + idx = SWAB16(pBt, pCell->h.iNext); + if( pCell->h.leftChild ){ + Pgno newChld; + rc = copyDatabasePage(pBtFrom, SWAB32(pBtFrom, pCell->h.leftChild), + pBtTo, &newChld); + if( rc ) return rc; + pCell->h.leftChild = SWAB32(pBtFrom, newChld); + } + rc = copyCell(pBtFrom, pBtTo, pCell); + if( rc ) return rc; + } + if( pPage->u.hdr.rightChild ){ + Pgno newChld; + rc = copyDatabasePage(pBtFrom, SWAB32(pBtFrom, pPage->u.hdr.rightChild), + pBtTo, &newChld); + if( rc ) return rc; + pPage->u.hdr.rightChild = SWAB32(pBtTo, newChild); + } + } + sqlitepager_unref(pPage); + return rc; +} +#endif + /* ** Read the meta-information out of a database file. */ -int sqliteBtreeGetMeta(Btree *pBt, int *aMeta){ +static int fileBtreeGetMeta(Btree *pBt, int *aMeta){ PageOne *pP1; int rc; int i; @@ -2895,7 +2995,7 @@ int sqliteBtreeGetMeta(Btree *pBt, int *aMeta){ /* ** Write meta-information back into the database. */ -int sqliteBtreeUpdateMeta(Btree *pBt, int *aMeta){ +static int fileBtreeUpdateMeta(Btree *pBt, int *aMeta){ PageOne *pP1; int rc, i; if( !pBt->inTrans ){ @@ -2921,7 +3021,7 @@ int sqliteBtreeUpdateMeta(Btree *pBt, int *aMeta){ ** is used for debugging and testing only. */ #ifdef SQLITE_TEST -int sqliteBtreePageDump(Btree *pBt, int pgno, int recursive){ +static int fileBtreePageDump(Btree *pBt, int pgno, int recursive){ int rc; MemPage *pPage; int i, j; @@ -2982,10 +3082,10 @@ int sqliteBtreePageDump(Btree *pBt, int pgno, int recursive){ idx = SWAB16(pBt, pPage->u.hdr.firstCell); while( idx>0 && idx<SQLITE_PAGE_SIZE-MIN_CELL_SIZE ){ Cell *pCell = (Cell*)&pPage->u.aDisk[idx]; - sqliteBtreePageDump(pBt, SWAB32(pBt, pCell->h.leftChild), 1); + fileBtreePageDump(pBt, SWAB32(pBt, pCell->h.leftChild), 1); idx = SWAB16(pBt, pCell->h.iNext); } - sqliteBtreePageDump(pBt, SWAB32(pBt, pPage->u.hdr.rightChild), 1); + fileBtreePageDump(pBt, SWAB32(pBt, pPage->u.hdr.rightChild), 1); } sqlitepager_unref(pPage); return SQLITE_OK; @@ -3008,7 +3108,7 @@ int sqliteBtreePageDump(Btree *pBt, int pgno, int recursive){ ** ** This routine is used for testing and debugging only. */ -int sqliteBtreeCursorDump(BtCursor *pCur, int *aResult){ +static int fileBtreeCursorDump(BtCursor *pCur, int *aResult){ int cnt, idx; MemPage *pPage = pCur->pPage; Btree *pBt = pCur->pBt; @@ -3040,7 +3140,7 @@ int sqliteBtreeCursorDump(BtCursor *pCur, int *aResult){ ** Return the pager associated with a BTree. This routine is used for ** testing and debugging only. */ -Pager *sqliteBtreePager(Btree *pBt){ +static Pager *fileBtreePager(Btree *pBt){ return pBt->pPager; } #endif @@ -3129,7 +3229,7 @@ static void checkList( FreelistInfo *pInfo = (FreelistInfo*)pOvfl->aPayload; int n = SWAB32(pCheck->pBt, pInfo->nFree); for(i=0; i<n; i++){ - checkRef(pCheck, SWAB32(pCheck->pBt, pInfo->aFree[i]), zMsg); + checkRef(pCheck, SWAB32(pCheck->pBt, pInfo->aFree[i]), zContext); } N -= n; } @@ -3320,7 +3420,7 @@ static int checkTreePage( ** and a pointer to that error message is returned. The calling function ** is responsible for freeing the error message when it is done. */ -char *sqliteBtreeIntegrityCheck(Btree *pBt, int *aRoot, int nRoot){ +char *fileBtreeIntegrityCheck(Btree *pBt, int *aRoot, int nRoot){ int i; int nRef; IntegrityCk sCheck; @@ -3380,3 +3480,104 @@ char *sqliteBtreeIntegrityCheck(Btree *pBt, int *aRoot, int nRoot){ sqliteFree(sCheck.anRef); return sCheck.zErrMsg; } + +/* +** Return the full pathname of the underlying database file. +*/ +static const char *fileBtreeGetFilename(Btree *pBt){ + assert( pBt->pPager!=0 ); + return sqlitepager_filename(pBt->pPager); +} + +/* +** Copy the complete content of pBtFrom into pBtTo. A transaction +** must be active for both files. +** +** The size of file pBtFrom may be reduced by this operation. +** If anything goes wrong, the transaction on pBtFrom is rolled back. +*/ +static int fileBtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){ + int rc = SQLITE_OK; + Pgno i, nPage, nToPage; + + if( !pBtTo->inTrans || !pBtFrom->inTrans ) return SQLITE_ERROR; + if( pBtTo->needSwab!=pBtFrom->needSwab ) return SQLITE_ERROR; + if( pBtTo->pCursor ) return SQLITE_BUSY; + memcpy(pBtTo->page1, pBtFrom->page1, SQLITE_PAGE_SIZE); + rc = sqlitepager_overwrite(pBtTo->pPager, 1, pBtFrom->page1); + nToPage = sqlitepager_pagecount(pBtTo->pPager); + nPage = sqlitepager_pagecount(pBtFrom->pPager); + for(i=2; rc==SQLITE_OK && i<=nPage; i++){ + void *pPage; + rc = sqlitepager_get(pBtFrom->pPager, i, &pPage); + if( rc ) break; + rc = sqlitepager_overwrite(pBtTo->pPager, i, pPage); + if( rc ) break; + sqlitepager_unref(pPage); + } + for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){ + void *pPage; + rc = sqlitepager_get(pBtTo->pPager, i, &pPage); + if( rc ) break; + rc = sqlitepager_write(pPage); + sqlitepager_unref(pPage); + sqlitepager_dont_write(pBtTo->pPager, i); + } + if( !rc && nPage<nToPage ){ + rc = sqlitepager_truncate(pBtTo->pPager, nPage); + } + if( rc ){ + fileBtreeRollback(pBtTo); + } + return rc; +} + +/* +** The following tables contain pointers to all of the interface +** routines for this implementation of the B*Tree backend. To +** substitute a different implemention of the backend, one has merely +** to provide pointers to alternative functions in similar tables. +*/ +static BtOps sqliteBtreeOps = { + fileBtreeClose, + fileBtreeSetCacheSize, + fileBtreeSetSafetyLevel, + fileBtreeBeginTrans, + fileBtreeCommit, + fileBtreeRollback, + fileBtreeBeginCkpt, + fileBtreeCommitCkpt, + fileBtreeRollbackCkpt, + fileBtreeCreateTable, + fileBtreeCreateTable, /* Really sqliteBtreeCreateIndex() */ + fileBtreeDropTable, + fileBtreeClearTable, + fileBtreeCursor, + fileBtreeGetMeta, + fileBtreeUpdateMeta, + fileBtreeIntegrityCheck, + fileBtreeGetFilename, + fileBtreeCopyFile, +#ifdef SQLITE_TEST + fileBtreePageDump, + fileBtreePager +#endif +}; +static BtCursorOps sqliteBtreeCursorOps = { + fileBtreeMoveto, + fileBtreeDelete, + fileBtreeInsert, + fileBtreeFirst, + fileBtreeLast, + fileBtreeNext, + fileBtreePrevious, + fileBtreeKeySize, + fileBtreeKey, + fileBtreeKeyCompare, + fileBtreeDataSize, + fileBtreeData, + fileBtreeCloseCursor, +#ifdef SQLITE_TEST + fileBtreeCursorDump, +#endif +}; |