]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add infrastructure to suport multiple btree implementations (CVS 894)
authorpaul <paul@noemail.net>
Tue, 1 Apr 2003 21:16:41 +0000 (21:16 +0000)
committerpaul <paul@noemail.net>
Tue, 1 Apr 2003 21:16:41 +0000 (21:16 +0000)
FossilOrigin-Name: 79b3aed2a74a67cbad631c4e2e4a43469d80c162

manifest
manifest.uuid
src/btree.c
src/btree.h

index 369995868acb54c972c367d80b2573d1dfa91b92..f99a0d3469c3aea8a83c5ff130a6daede2189ce9 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Minor\sfollow-on\schanges\sto\sthe\srecent\sATTACH\spatch.\s(CVS\s893)
-D 2003-03-31T13:36:09
+C Add\sinfrastructure\sto\ssuport\smultiple\sbtree\simplementations\s(CVS\s894)
+D 2003-04-01T21:16:42
 F Makefile.in 3c4ba24253e61c954d67adbbb4245e7117c5357e
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -20,8 +20,8 @@ F spec.template 238f7db425a78dc1bb7682e56e3834c7270a3f5e
 F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
 F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
 F src/auth.c f37bfc9451b8c1fa52f34adff474560018892729
-F src/btree.c dba4d12945228dd7e94de7da0e1d8638b70d99f2
-F src/btree.h 8209bfadf5845d4fdaa60f471bb360f894cd4095
+F src/btree.c 7eae5413a7f957bb0733bcab6fab31c6943c51d2
+F src/btree.h 024d2dd21310c202d648c6244dec885e48efa9ad
 F src/build.c 81d31f2e63d51683ee653df6399acc3c3a2e3672
 F src/delete.c 58d698779a6b7f819718ecd45b310a9de8537088
 F src/encode.c faf03741efe921755ec371cf4a6984536de00042
@@ -155,7 +155,7 @@ F www/speed.tcl cb4c10a722614aea76d2c51f32ee43400d5951be
 F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P e80afe75b33d4eacb40ef6128cf688f7c3253984
-R 8452f551322a2a47e2174b852766e085
-U drh
-Z 7162b736d28f6cc7cea678e58590971b
+P 11378c5bf988412f8564cdc0314fc241793b292e
+R cc8e4c3807eb9ac6929fb512790ca871
+U paul
+Z 048b3196e99f227ca8551c2b49ca1411
index 26292d89141ac49eed6d1d2d50054155be1e3adb..43967b3e83ae652128675f0f0112c8d917cd86e4 100644 (file)
@@ -1 +1 @@
-11378c5bf988412f8564cdc0314fc241793b292e
\ No newline at end of file
+79b3aed2a74a67cbad631c4e2e4a43469d80c162
\ No newline at end of file
index 2779aef027f0ddcaa73847c353db2b6af5f0c9d9..cd9f13dc5f2b7a83cdccef12f4e967f4ffe8cca6 100644 (file)
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.85 2003/03/30 18:41:22 drh Exp $
+** $Id: btree.c,v 1.86 2003/04/01 21:16:42 paul Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
 ** BTree begins on page 2 of the file.  (Pages are numbered beginning with
 ** 1, not 0.)  Thus a minimum database contains 2 pages.
 */
+/* We don't want the btree function macros */
+#define SQLITE_NO_BTREE_DEFS
+
 #include "sqliteInt.h"
 #include "pager.h"
 #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
@@ -340,6 +347,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 +364,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 +384,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 sqliteBtreeCloseCursor(BtCursor *pCur);
+
 /*
 ** Routines for byte swapping.
 */
@@ -709,6 +721,7 @@ int sqliteBtreeOpen(
   pBt->pCursor = 0;
   pBt->page1 = 0;
   pBt->readOnly = sqlitepager_isreadonly(pBt->pPager);
+  pBt->pOps = &sqliteBtreeOps;
   *ppBtree = pBt;
   return SQLITE_OK;
 }
@@ -716,7 +729,7 @@ int sqliteBtreeOpen(
 /*
 ** Close an open database and invalidate all cursors.
 */
-int sqliteBtreeClose(Btree *pBt){
+static int sqliteBtreeClose(Btree *pBt){
   while( pBt->pCursor ){
     sqliteBtreeCloseCursor(pBt->pCursor);
   }
@@ -740,7 +753,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 sqliteBtreeSetCacheSize(Btree *pBt, int mxPage){
   sqlitepager_set_cachesize(pBt->pPager, mxPage);
   return SQLITE_OK;
 }
@@ -753,7 +766,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 sqliteBtreeSetSafetyLevel(Btree *pBt, int level){
   sqlitepager_set_safety_level(pBt->pPager, level);
   return SQLITE_OK;
 }
@@ -860,7 +873,7 @@ static int newDatabase(Btree *pBt){
 **      sqliteBtreeDelete()
 **      sqliteBtreeUpdateMeta()
 */
-int sqliteBtreeBeginTrans(Btree *pBt){
+static int sqliteBtreeBeginTrans(Btree *pBt){
   int rc;
   if( pBt->inTrans ) return SQLITE_ERROR;
   if( pBt->readOnly ) return SQLITE_READONLY;
@@ -889,7 +902,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 sqliteBtreeCommit(Btree *pBt){
   int rc;
   rc = pBt->readOnly ? SQLITE_OK : sqlitepager_commit(pBt->pPager);
   pBt->inTrans = 0;
@@ -907,7 +920,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 sqliteBtreeRollback(Btree *pBt){
   int rc;
   BtCursor *pCur;
   if( pBt->inTrans==0 ) return SQLITE_OK;
@@ -934,7 +947,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 sqliteBtreeBeginCkpt(Btree *pBt){
   int rc;
   if( !pBt->inTrans || pBt->inCkpt ){
     return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
@@ -949,7 +962,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 sqliteBtreeCommitCkpt(Btree *pBt){
   int rc;
   if( pBt->inCkpt && !pBt->readOnly ){
     rc = sqlitepager_ckpt_commit(pBt->pPager);
@@ -968,7 +981,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 sqliteBtreeRollbackCkpt(Btree *pBt){
   int rc;
   BtCursor *pCur;
   if( pBt->inCkpt==0 || pBt->readOnly ) return SQLITE_OK;
@@ -1019,7 +1032,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 sqliteBtreeCursor(Btree *pBt, int iTable, int wrFlag, BtCursor **ppCur){
   int rc;
   BtCursor *pCur, *pRing;
 
@@ -1044,6 +1057,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 +1093,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 sqliteBtreeCloseCursor(BtCursor *pCur){
   Btree *pBt = pCur->pBt;
   if( pCur->pPrev ){
     pCur->pPrev->pNext = pCur->pNext;
@@ -1132,7 +1146,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 sqliteBtreeKeySize(BtCursor *pCur, int *pSize){
   Cell *pCell;
   MemPage *pPage;
 
@@ -1221,7 +1235,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 sqliteBtreeKey(BtCursor *pCur, int offset, int amt, char *zBuf){
   MemPage *pPage;
 
   assert( amt>=0 );
@@ -1243,7 +1257,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 sqliteBtreeDataSize(BtCursor *pCur, int *pSize){
   Cell *pCell;
   MemPage *pPage;
 
@@ -1266,7 +1280,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 sqliteBtreeData(BtCursor *pCur, int offset, int amt, char *zBuf){
   Cell *pCell;
   MemPage *pPage;
 
@@ -1304,7 +1318,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 sqliteBtreeKeyCompare(
   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 */
@@ -1503,7 +1517,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 sqliteBtreeFirst(BtCursor *pCur, int *pRes){
   int rc;
   if( pCur->pPage==0 ) return SQLITE_ABORT;
   rc = moveToRoot(pCur);
@@ -1522,7 +1536,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 sqliteBtreeLast(BtCursor *pCur, int *pRes){
   int rc;
   if( pCur->pPage==0 ) return SQLITE_ABORT;
   rc = moveToRoot(pCur);
@@ -1561,7 +1575,7 @@ 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 sqliteBtreeMoveto(BtCursor *pCur, const void *pKey, int nKey, int *pRes){
   int rc;
   if( pCur->pPage==0 ) return SQLITE_ABORT;
   pCur->eSkip = SKIP_NONE;
@@ -1614,7 +1628,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 sqliteBtreeNext(BtCursor *pCur, int *pRes){
   int rc;
   MemPage *pPage = pCur->pPage;
   assert( pRes!=0 );
@@ -1669,7 +1683,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 sqliteBtreePrevious(BtCursor *pCur, int *pRes){
   int rc;
   Pgno pgno;
   MemPage *pPage;
@@ -2595,7 +2609,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 sqliteBtreeInsert(
   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 */
@@ -2663,7 +2677,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 sqliteBtreeDelete(BtCursor *pCur){
   MemPage *pPage = pCur->pPage;
   Cell *pCell;
   int rc;
@@ -2750,7 +2764,7 @@ int sqliteBtreeDelete(BtCursor *pCur){
 ** 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 sqliteBtreeCreateTable(Btree *pBt, int *piTable){
+static int sqliteBtreeCreateTable(Btree *pBt, int *piTable){
   MemPage *pRoot;
   Pgno pgnoRoot;
   int rc;
@@ -2779,7 +2793,7 @@ int sqliteBtreeCreateTable(Btree *pBt, int *piTable){
 ** 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){
+static int sqliteBtreeCreateIndex(Btree *pBt, int *piIndex){
   return sqliteBtreeCreateTable(pBt, piIndex);
 }
 
@@ -2826,7 +2840,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 sqliteBtreeClearTable(Btree *pBt, int iTable){
   int rc;
   BtCursor *pCur;
   if( !pBt->inTrans ){
@@ -2850,7 +2864,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 sqliteBtreeDropTable(Btree *pBt, int iTable){
   int rc;
   MemPage *pPage;
   BtCursor *pCur;
@@ -2977,7 +2991,7 @@ static int copyDatabasePage(
 /*
 ** Read the meta-information out of a database file.
 */
-int sqliteBtreeGetMeta(Btree *pBt, int *aMeta){
+static int sqliteBtreeGetMeta(Btree *pBt, int *aMeta){
   PageOne *pP1;
   int rc;
   int i;
@@ -2995,7 +3009,7 @@ int sqliteBtreeGetMeta(Btree *pBt, int *aMeta){
 /*
 ** Write meta-information back into the database.
 */
-int sqliteBtreeUpdateMeta(Btree *pBt, int *aMeta){
+static int sqliteBtreeUpdateMeta(Btree *pBt, int *aMeta){
   PageOne *pP1;
   int rc, i;
   if( !pBt->inTrans ){
@@ -3021,7 +3035,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 sqliteBtreePageDump(Btree *pBt, int pgno, int recursive){
   int rc;
   MemPage *pPage;
   int i, j;
@@ -3108,7 +3122,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 sqliteBtreeCursorDump(BtCursor *pCur, int *aResult){
   int cnt, idx;
   MemPage *pPage = pCur->pPage;
   Btree *pBt = pCur->pBt;
@@ -3140,7 +3154,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 *sqliteBtreePager(Btree *pBt){
   return pBt->pPager;
 }
 #endif
@@ -3480,3 +3494,47 @@ char *sqliteBtreeIntegrityCheck(Btree *pBt, int *aRoot, int nRoot){
   sqliteFree(sCheck.anRef);
   return sCheck.zErrMsg;
 }
+
+static BtOps sqliteBtreeOps = {
+    sqliteBtreeClose,
+    sqliteBtreeSetCacheSize,
+    sqliteBtreeSetSafetyLevel,
+    sqliteBtreeBeginTrans,
+    sqliteBtreeCommit,
+    sqliteBtreeRollback,
+    sqliteBtreeBeginCkpt,
+    sqliteBtreeCommitCkpt,
+    sqliteBtreeRollbackCkpt,
+    sqliteBtreeCreateTable,
+    sqliteBtreeCreateIndex,
+    sqliteBtreeDropTable,
+    sqliteBtreeClearTable,
+    sqliteBtreeCursor,
+    sqliteBtreeGetMeta,
+    sqliteBtreeUpdateMeta,
+    sqliteBtreeIntegrityCheck,
+
+#ifdef SQLITE_TEST
+    sqliteBtreePageDump,
+    sqliteBtreePager
+#endif
+};
+
+static BtCursorOps sqliteBtreeCursorOps = {
+    sqliteBtreeMoveto,
+    sqliteBtreeDelete,
+    sqliteBtreeInsert,
+    sqliteBtreeFirst,
+    sqliteBtreeLast,
+    sqliteBtreeNext,
+    sqliteBtreePrevious,
+    sqliteBtreeKeySize,
+    sqliteBtreeKey,
+    sqliteBtreeKeyCompare,
+    sqliteBtreeDataSize,
+    sqliteBtreeData,
+    sqliteBtreeCloseCursor,
+#ifdef SQLITE_TEST
+    sqliteBtreeCursorDump,
+#endif
+};
index ef6f781277af289888536abee7ba7ae82b2051ec..52c23d7759da944894ea02bc3e21f933acb60927 100644 (file)
@@ -13,7 +13,7 @@
 ** subsystem.  See comments in the source code for a detailed description
 ** of what each interface routine does.
 **
-** @(#) $Id: btree.h,v 1.28 2003/03/19 03:14:01 drh Exp $
+** @(#) $Id: btree.h,v 1.29 2003/04/01 21:16:43 paul Exp $
 */
 #ifndef _BTREE_H_
 #define _BTREE_H_
 typedef struct Btree Btree;
 typedef struct BtCursor BtCursor;
 
-int sqliteBtreeOpen(const char *zFilename, int mode, int nPg, Btree **ppBtree);
-int sqliteBtreeClose(Btree*);
-int sqliteBtreeSetCacheSize(Btree*, int);
-int sqliteBtreeSetSafetyLevel(Btree*, int);
-
-int sqliteBtreeBeginTrans(Btree*);
-int sqliteBtreeCommit(Btree*);
-int sqliteBtreeRollback(Btree*);
-int sqliteBtreeBeginCkpt(Btree*);
-int sqliteBtreeCommitCkpt(Btree*);
-int sqliteBtreeRollbackCkpt(Btree*);
-
-int sqliteBtreeCreateTable(Btree*, int*);
-int sqliteBtreeCreateIndex(Btree*, int*);
-int sqliteBtreeDropTable(Btree*, int);
-int sqliteBtreeClearTable(Btree*, int);
-int sqliteBtreeCopyTable(Btree *pFrom, int iFrom, Btree *pTo, int iTo);
-
-int sqliteBtreeCursor(Btree*, int iTable, int wrFlag, BtCursor **ppCur);
-int sqliteBtreeMoveto(BtCursor*, const void *pKey, int nKey, int *pRes);
-int sqliteBtreeDelete(BtCursor*);
-int sqliteBtreeInsert(BtCursor*, const void *pKey, int nKey,
-                                 const void *pData, int nData);
-int sqliteBtreeFirst(BtCursor*, int *pRes);
-int sqliteBtreeLast(BtCursor*, int *pRes);
-int sqliteBtreeNext(BtCursor*, int *pRes);
-int sqliteBtreePrevious(BtCursor*, int *pRes);
-int sqliteBtreeKeySize(BtCursor*, int *pSize);
-int sqliteBtreeKey(BtCursor*, int offset, int amt, char *zBuf);
-int sqliteBtreeKeyCompare(BtCursor*, const void *pKey, int nKey,
-                          int nIgnore, int *pRes);
-int sqliteBtreeDataSize(BtCursor*, int *pSize);
-int sqliteBtreeData(BtCursor*, int offset, int amt, char *zBuf);
-int sqliteBtreeCloseCursor(BtCursor*);
+struct BtOps {
+    int (*sqliteBtreeClose)(Btree*);
+    int (*sqliteBtreeSetCacheSize)(Btree*, int);
+    int (*sqliteBtreeSetSafetyLevel)(Btree*, int);
+
+    int (*sqliteBtreeBeginTrans)(Btree*);
+    int (*sqliteBtreeCommit)(Btree*);
+    int (*sqliteBtreeRollback)(Btree*);
+    int (*sqliteBtreeBeginCkpt)(Btree*);
+    int (*sqliteBtreeCommitCkpt)(Btree*);
+    int (*sqliteBtreeRollbackCkpt)(Btree*);
+
+    int (*sqliteBtreeCreateTable)(Btree*, int*);
+    int (*sqliteBtreeCreateIndex)(Btree*, int*);
+    int (*sqliteBtreeDropTable)(Btree*, int);
+    int (*sqliteBtreeClearTable)(Btree*, int);
+
+    int (*sqliteBtreeCursor)(Btree*, int iTable, int wrFlag, BtCursor **ppCur);
+
+    int (*sqliteBtreeGetMeta)(Btree*, int*);
+    int (*sqliteBtreeUpdateMeta)(Btree*, int*);
+
+    char *(*sqliteBtreeIntegrityCheck)(Btree*, int*, int);
+
+#ifdef SQLITE_TEST
+    int (*sqliteBtreePageDump)(Btree*, int, int);
+    struct Pager * (*sqliteBtreePager)(Btree*);
+#endif
+};
+
+typedef struct BtOps BtOps;
+
+struct BtCursorOps {
+    int (*sqliteBtreeMoveto)(BtCursor*, const void *pKey, int nKey, int *pRes);
+    int (*sqliteBtreeDelete)(BtCursor*);
+    int (*sqliteBtreeInsert)(BtCursor*, const void *pKey, int nKey,
+                             const void *pData, int nData);
+    int (*sqliteBtreeFirst)(BtCursor*, int *pRes);
+    int (*sqliteBtreeLast)(BtCursor*, int *pRes);
+    int (*sqliteBtreeNext)(BtCursor*, int *pRes);
+    int (*sqliteBtreePrevious)(BtCursor*, int *pRes);
+    int (*sqliteBtreeKeySize)(BtCursor*, int *pSize);
+    int (*sqliteBtreeKey)(BtCursor*, int offset, int amt, char *zBuf);
+    int (*sqliteBtreeKeyCompare)(BtCursor*, const void *pKey, int nKey,
+                                 int nIgnore, int *pRes);
+    int (*sqliteBtreeDataSize)(BtCursor*, int *pSize);
+    int (*sqliteBtreeData)(BtCursor*, int offset, int amt, char *zBuf);
+    int (*sqliteBtreeCloseCursor)(BtCursor*);
+#ifdef SQLITE_TEST
+    int (*sqliteBtreeCursorDump)(BtCursor*, int*);
+#endif
+};
+    
+typedef struct BtCursorOps BtCursorOps;
 
 #define SQLITE_N_BTREE_META 10
-int sqliteBtreeGetMeta(Btree*, int*);
-int sqliteBtreeUpdateMeta(Btree*, int*);
 
-char *sqliteBtreeIntegrityCheck(Btree*, int*, int);
+int sqliteBtreeOpen(const char *zFilename, int mode, int nPg, Btree **ppBtree);
+
+#if !defined(SQLITE_NO_BTREE_DEFS)
+#define btOps(pBt) (*((BtOps **)(pBt)))
+#define btCOps(pCur) (*((BtCursorOps **)(pCur)))
+
+#define sqliteBtreeClose(pBt)\
+                (btOps(pBt)->sqliteBtreeClose(pBt))
+#define sqliteBtreeSetCacheSize(pBt, sz)\
+                (btOps(pBt)->sqliteBtreeSetCacheSize(pBt, sz))
+#define sqliteBtreeSetSafetyLevel(pBt, sl)\
+                (btOps(pBt)->sqliteBtreeSetSafetyLevel(pBt, sl))
+#define sqliteBtreeBeginTrans(pBt)\
+                (btOps(pBt)->sqliteBtreeBeginTrans(pBt))
+#define sqliteBtreeCommit(pBt)\
+                (btOps(pBt)->sqliteBtreeCommit(pBt))
+#define sqliteBtreeRollback(pBt)\
+                (btOps(pBt)->sqliteBtreeRollback(pBt))
+#define sqliteBtreeBeginCkpt(pBt)\
+                (btOps(pBt)->sqliteBtreeBeginCkpt(pBt))
+#define sqliteBtreeCommitCkpt(pBt)\
+                (btOps(pBt)->sqliteBtreeCommitCkpt(pBt))
+#define sqliteBtreeRollbackCkpt(pBt)\
+                (btOps(pBt)->sqliteBtreeRollbackCkpt(pBt))
+#define sqliteBtreeCreateTable(pBt, piTable)\
+                (btOps(pBt)->sqliteBtreeCreateTable(pBt, piTable))
+#define sqliteBtreeCreateIndex(pBt, piIndex)\
+                (btOps(pBt)->sqliteBtreeCreateIndex(pBt, piIndex))
+#define sqliteBtreeDropTable(pBt, iTable)\
+                (btOps(pBt)->sqliteBtreeDropTable(pBt, iTable))
+#define sqliteBtreeClearTable(pBt, iTable)\
+                (btOps(pBt)->sqliteBtreeClearTable(pBt, iTable))
+#define sqliteBtreeCursor(pBt, iTable, wrFlag, ppCur)\
+                (btOps(pBt)->sqliteBtreeCursor(pBt, iTable, wrFlag, ppCur))
+#define sqliteBtreeMoveto(pCur, pKey, nKey, pRes)\
+                (btCOps(pCur)->sqliteBtreeMoveto(pCur, pKey, nKey, pRes))
+#define sqliteBtreeDelete(pCur)\
+                (btCOps(pCur)->sqliteBtreeDelete(pCur))
+#define sqliteBtreeInsert(pCur, pKey, nKey, pData, nData) \
+                (btCOps(pCur)->sqliteBtreeInsert(pCur, pKey, nKey, pData, nData))
+#define sqliteBtreeFirst(pCur, pRes)\
+                (btCOps(pCur)->sqliteBtreeFirst(pCur, pRes))
+#define sqliteBtreeLast(pCur, pRes)\
+                (btCOps(pCur)->sqliteBtreeLast(pCur, pRes))
+#define sqliteBtreeNext(pCur, pRes)\
+                (btCOps(pCur)->sqliteBtreeNext(pCur, pRes))
+#define sqliteBtreePrevious(pCur, pRes)\
+                (btCOps(pCur)->sqliteBtreePrevious(pCur, pRes))
+#define sqliteBtreeKeySize(pCur, pSize)\
+                (btCOps(pCur)->sqliteBtreeKeySize(pCur, pSize) )
+#define sqliteBtreeKey(pCur, offset, amt, zBuf)\
+                (btCOps(pCur)->sqliteBtreeKey(pCur, offset, amt, zBuf))
+#define sqliteBtreeKeyCompare(pCur, pKey, nKey, nIgnore, pRes)\
+                (btCOps(pCur)->sqliteBtreeKeyCompare(pCur, pKey, nKey, nIgnore, pRes))
+#define sqliteBtreeDataSize(pCur, pSize)\
+                (btCOps(pCur)->sqliteBtreeDataSize(pCur, pSize))
+#define sqliteBtreeData(pCur, offset, amt, zBuf)\
+                (btCOps(pCur)->sqliteBtreeData(pCur, offset, amt, zBuf))
+#define sqliteBtreeCloseCursor(pCur)\
+                (btCOps(pCur)->sqliteBtreeCloseCursor(pCur))
+#define sqliteBtreeGetMeta(pBt, aMeta)\
+                (btOps(pBt)->sqliteBtreeGetMeta(pBt, aMeta))
+#define sqliteBtreeUpdateMeta(pBt, aMeta)\
+                (btOps(pBt)->sqliteBtreeUpdateMeta(pBt, aMeta))
+#define sqliteBtreeIntegrityCheck(pBt, aRoot, nRoot)\
+                (btOps(pBt)->sqliteBtreeIntegrityCheck(pBt, aRoot, nRoot))
+#endif
 
 #ifdef SQLITE_TEST
-int sqliteBtreePageDump(Btree*, int, int);
-int sqliteBtreeCursorDump(BtCursor*, int*);
-struct Pager *sqliteBtreePager(Btree*);
+#if !defined(SQLITE_NO_BTREE_DEFS)
+#define sqliteBtreePageDump(pBt, pgno, recursive)\
+                (btOps(pBt)->sqliteBtreePageDump(pBt, pgno, recursive))
+#define sqliteBtreeCursorDump(pCur, aResult)\
+                (btCOps(pCur)->sqliteBtreeCursorDump(pCur, aResult))
+#define sqliteBtreePager(pBt)\
+                (btOps(pBt)->sqliteBtreePager(pBt))
+#endif
+
 int btree_native_byte_order;
 #endif