]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Move btree_rb.c into the attic. (CVS 1442)
authordrh <drh@noemail.net>
Sat, 22 May 2004 17:46:37 +0000 (17:46 +0000)
committerdrh <drh@noemail.net>
Sat, 22 May 2004 17:46:37 +0000 (17:46 +0000)
FossilOrigin-Name: 4159ef235d780ec941677439e77c6fa96e24997c

manifest
manifest.uuid
src/btree_rb.c [deleted file]

index ac021341e276dc70c6693882c45ed1f6f1ee6161..db80390615ca073b903a9716386574711be70b8e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Split\sup\sos.c\sinto\sseparate\sfiles,\sone\sfor\seach\splatform.\s(CVS\s1441)
-D 2004-05-22T17:41:59
+C Move\sbtree_rb.c\sinto\sthe\sattic.\s(CVS\s1442)
+D 2004-05-22T17:46:37
 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -26,7 +26,6 @@ F src/attach.c c315c58cb16fd6e913b3bfa6412aedecb4567fa5
 F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
 F src/btree.c 51dfa34da5f42762b228d7360cf3273ee403bce8
 F src/btree.h b65140b5ae891f30d2a39e64b9f0343225553545
-F src/btree_rb.c 9d7973e266ee6f9c61ce592f68742ce9cd5b10e5
 F src/build.c 35cbeb439b49cca5eb5e8a1de010a5194f4523e8
 F src/copy.c 4d2038602fd0549d80c59bda27d96f13ea9b5e29
 F src/date.c 0eb0a89960bb45c7f7e768748605a7a97b0c8064
@@ -203,7 +202,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P c36203de22f673691783529e06ce5a58bcebeedc
-R 2c92275d417e436955c48e131db4f92e
+P 5c61be1c47ac960fba2a642e69a98436ce1cd725
+R 895a23f6e8990fb83852de59938ec75c
 U drh
-Z f6cdae699efac8ed1a9148f3d6e06cad
+Z 284f15852c16971e78cc98172c48c47f
index 0681ac5d9481c4a51663a234ea3722482f622e6c..a6c0d10056230e5aa0a9227b87f19dce0a2063ea 100644 (file)
@@ -1 +1 @@
-5c61be1c47ac960fba2a642e69a98436ce1cd725
\ No newline at end of file
+4159ef235d780ec941677439e77c6fa96e24997c
\ No newline at end of file
diff --git a/src/btree_rb.c b/src/btree_rb.c
deleted file mode 100644 (file)
index 34a0509..0000000
+++ /dev/null
@@ -1,1491 +0,0 @@
-/*
-** 2003 Feb 4
-**
-** 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.
-**
-*************************************************************************
-** $Id: btree_rb.c,v 1.26 2004/05/10 10:34:35 danielk1977 Exp $
-**
-** This file implements an in-core database using Red-Black balanced
-** binary trees.
-** 
-** It was contributed to SQLite by anonymous on 2003-Feb-04 23:24:49 UTC.
-*/
-#include "btree.h"
-#include "sqliteInt.h"
-#include <assert.h>
-
-/*
-** Omit this whole file if the SQLITE_OMIT_INMEMORYDB macro is
-** defined.  This allows a lot of code to be omitted for installations
-** that do not need it.
-*/
-#ifndef SQLITE_OMIT_INMEMORYDB
-
-
-typedef struct BtRbTree BtRbTree;
-typedef struct BtRbNode BtRbNode;
-typedef struct BtRollbackOp BtRollbackOp;
-typedef struct Rbtree Rbtree;
-typedef struct RbtCursor RbtCursor;
-
-/* Forward declarations */
-static BtOps sqliteRbtreeOps;
-static BtCursorOps sqliteRbtreeCursorOps;
-
-/*
- * During each transaction (or checkpoint), a linked-list of
- * "rollback-operations" is accumulated. If the transaction is rolled back,
- * then the list of operations must be executed (to restore the database to
- * it's state before the transaction started). If the transaction is to be
- * committed, just delete the list.
- *
- * Each operation is represented as follows, depending on the value of eOp:
- *
- * ROLLBACK_INSERT  ->  Need to insert (pKey, pData) into table iTab.
- * ROLLBACK_DELETE  ->  Need to delete the record (pKey) into table iTab.
- * ROLLBACK_CREATE  ->  Need to create table iTab.
- * ROLLBACK_DROP    ->  Need to drop table iTab.
- */
-struct BtRollbackOp {
-  u8 eOp;
-  int iTab;
-  int nKey; 
-  void *pKey;
-  int nData;
-  void *pData;
-  BtRollbackOp *pNext;
-};
-
-/*
-** Legal values for BtRollbackOp.eOp:
-*/
-#define ROLLBACK_INSERT 1 /* Insert a record */
-#define ROLLBACK_DELETE 2 /* Delete a record */
-#define ROLLBACK_CREATE 3 /* Create a table */
-#define ROLLBACK_DROP   4 /* Drop a table */
-
-struct Rbtree {
-  BtOps *pOps;    /* Function table */
-  int aMetaData[SQLITE_N_BTREE_META];
-
-  int next_idx;   /* next available table index */
-  Hash tblHash;   /* All created tables, by index */
-  u8 isAnonymous; /* True if this Rbtree is to be deleted when closed */
-  u8 eTransState; /* State of this Rbtree wrt transactions */
-
-  BtRollbackOp *pTransRollback; 
-  BtRollbackOp *pCheckRollback;
-  BtRollbackOp *pCheckRollbackTail;
-};
-
-/*
-** Legal values for Rbtree.eTransState.
-*/
-#define TRANS_NONE           0  /* No transaction is in progress */
-#define TRANS_INTRANSACTION  1  /* A transaction is in progress */
-#define TRANS_INCHECKPOINT   2  /* A checkpoint is in progress  */
-#define TRANS_ROLLBACK       3  /* We are currently rolling back a checkpoint or
-                                 * transaction. */
-
-struct RbtCursor {
-  BtCursorOps *pOps;        /* Function table */
-  Rbtree    *pRbtree;
-  BtRbTree *pTree;
-  int       iTree;          /* Index of pTree in pRbtree */
-  BtRbNode *pNode;
-  RbtCursor *pShared;       /* List of all cursors on the same Rbtree */
-  u8 eSkip;                 /* Determines if next step operation is a no-op */
-  u8 wrFlag;                /* True if this cursor is open for writing */
-};
-
-/*
-** Legal values for RbtCursor.eSkip.
-*/
-#define SKIP_NONE     0   /* Always step the cursor */
-#define SKIP_NEXT     1   /* The next sqliteRbtreeNext() is a no-op */
-#define SKIP_PREV     2   /* The next sqliteRbtreePrevious() is a no-op */
-#define SKIP_INVALID  3   /* Calls to Next() and Previous() are invalid */
-
-struct BtRbTree {
-  RbtCursor *pCursors;     /* All cursors pointing to this tree */
-  BtRbNode *pHead;         /* Head of the tree, or NULL */
-};
-
-struct BtRbNode {
-  int nKey;
-  void *pKey;
-  int nData;
-  void *pData;
-  u8 isBlack;        /* true for a black node, 0 for a red node */
-  BtRbNode *pParent; /* Nodes parent node, NULL for the tree head */
-  BtRbNode *pLeft;   /* Nodes left child, or NULL */
-  BtRbNode *pRight;  /* Nodes right child, or NULL */
-
-  int nBlackHeight;  /* Only used during the red-black integrity check */
-};
-
-/* Forward declarations */
-static int memRbtreeMoveto(
-  RbtCursor* pCur,
-  const void *pKey,
-  int nKey,
-  int *pRes
-);
-static int memRbtreeClearTable(Rbtree* tree, int n);
-static int memRbtreeNext(RbtCursor* pCur, int *pRes);
-static int memRbtreeLast(RbtCursor* pCur, int *pRes);
-static int memRbtreePrevious(RbtCursor* pCur, int *pRes);
-
-
-/*
-** This routine checks all cursors that point to the same table
-** as pCur points to.  If any of those cursors were opened with
-** wrFlag==0 then this routine returns SQLITE_LOCKED.  If all
-** cursors point to the same table were opened with wrFlag==1
-** then this routine returns SQLITE_OK.
-**
-** In addition to checking for read-locks (where a read-lock 
-** means a cursor opened with wrFlag==0) this routine also NULLs
-** out the pNode field of all other cursors.
-** This is necessary because an insert 
-** or delete might change erase the node out from under
-** another cursor.
-*/
-static int checkReadLocks(RbtCursor *pCur){
-  RbtCursor *p;
-  assert( pCur->wrFlag );
-  for(p=pCur->pTree->pCursors; p; p=p->pShared){
-    if( p!=pCur ){
-      if( p->wrFlag==0 ) return SQLITE_LOCKED;
-      p->pNode = 0;
-    }
-  }
-  return SQLITE_OK;
-}
-
-/*
- * The key-compare function for the red-black trees. Returns as follows:
- *
- * (key1 < key2)             -1
- * (key1 == key2)             0 
- * (key1 > key2)              1
- *
- * Keys are compared using memcmp(). If one key is an exact prefix of the
- * other, then the shorter key is less than the longer key.
- */
-static int key_compare(void const*pKey1, int nKey1, void const*pKey2, int nKey2)
-{
-  int mcmp = memcmp(pKey1, pKey2, (nKey1 <= nKey2)?nKey1:nKey2);
-  if( mcmp == 0){
-    if( nKey1 == nKey2 ) return 0;
-    return ((nKey1 < nKey2)?-1:1);
-  }
-  return ((mcmp>0)?1:-1);
-}
-
-/*
- * Perform the LEFT-rotate transformation on node X of tree pTree. This
- * transform is part of the red-black balancing code.
- *
- *        |                   |
- *        X                   Y
- *       / \                 / \
- *      a   Y               X   c
- *         / \             / \
- *        b   c           a   b
- *
- *      BEFORE              AFTER
- */
-static void leftRotate(BtRbTree *pTree, BtRbNode *pX)
-{
-  BtRbNode *pY;
-  BtRbNode *pb;
-  pY = pX->pRight;
-  pb = pY->pLeft;
-
-  pY->pParent = pX->pParent;
-  if( pX->pParent ){
-    if( pX->pParent->pLeft == pX ) pX->pParent->pLeft = pY;
-    else pX->pParent->pRight = pY;
-  }
-  pY->pLeft = pX;
-  pX->pParent = pY;
-  pX->pRight = pb;
-  if( pb ) pb->pParent = pX;
-  if( pTree->pHead == pX ) pTree->pHead = pY;
-}
-
-/*
- * Perform the RIGHT-rotate transformation on node X of tree pTree. This
- * transform is part of the red-black balancing code.
- *
- *        |                   |
- *        X                   Y
- *       / \                 / \
- *      Y   c               a   X
- *     / \                     / \
- *    a   b                   b   c
- *
- *      BEFORE              AFTER
- */
-static void rightRotate(BtRbTree *pTree, BtRbNode *pX)
-{
-  BtRbNode *pY;
-  BtRbNode *pb;
-  pY = pX->pLeft;
-  pb = pY->pRight;
-
-  pY->pParent = pX->pParent;
-  if( pX->pParent ){
-    if( pX->pParent->pLeft == pX ) pX->pParent->pLeft = pY;
-    else pX->pParent->pRight = pY;
-  }
-  pY->pRight = pX;
-  pX->pParent = pY;
-  pX->pLeft = pb;
-  if( pb ) pb->pParent = pX;
-  if( pTree->pHead == pX ) pTree->pHead = pY;
-}
-
-/*
- * A string-manipulation helper function for check_redblack_tree(). If (orig ==
- * NULL) a copy of val is returned. If (orig != NULL) then a copy of the *
- * concatenation of orig and val is returned. The original orig is deleted
- * (using sqliteFree()).
- */
-static char *append_val(char * orig, char const * val){
-  char *z;
-  if( !orig ){
-    z = sqliteStrDup( val );
-  } else{
-    z = 0;
-    sqlite3SetString(&z, orig, val, (char*)0);
-    sqliteFree( orig );
-  }
-  return z;
-}
-
-/*
- * Append a string representation of the entire node to orig and return it.
- * This is used to produce debugging information if check_redblack_tree() finds
- * a problem with a red-black binary tree.
- */
-static char *append_node(char * orig, BtRbNode *pNode, int indent)
-{
-  char buf[128];
-  int i;
-
-  for( i=0; i<indent; i++ ){
-      orig = append_val(orig, " ");
-  }
-
-  sprintf(buf, "%p", pNode);
-  orig = append_val(orig, buf);
-
-  if( pNode ){
-    indent += 3;
-    if( pNode->isBlack ){
-      orig = append_val(orig, " B \n");
-    }else{
-      orig = append_val(orig, " R \n");
-    }
-    orig = append_node( orig, pNode->pLeft, indent );
-    orig = append_node( orig, pNode->pRight, indent );
-  }else{
-    orig = append_val(orig, "\n");
-  }
-  return orig;
-}
-
-/*
- * Print a representation of a node to stdout. This function is only included
- * so you can call it from within a debugger if things get really bad.  It
- * is not called from anyplace in the code.
- */
-static void print_node(BtRbNode *pNode)
-{
-    char * str = append_node(0, pNode, 0);
-    printf(str);
-
-    /* Suppress a warning message about print_node() being unused */
-    (void)print_node;
-}
-
-/* 
- * Check the following properties of the red-black tree:
- * (1) - If a node is red, both of it's children are black
- * (2) - Each path from a given node to a leaf (NULL) node passes thru the
- *       same number of black nodes 
- *
- * If there is a problem, append a description (using append_val() ) to *msg.
- */
-static void check_redblack_tree(BtRbTree * tree, char ** msg)
-{
-  BtRbNode *pNode;
-
-  /* 0 -> came from parent 
-   * 1 -> came from left
-   * 2 -> came from right */
-  int prev_step = 0;
-
-  pNode = tree->pHead;
-  while( pNode ){
-    switch( prev_step ){
-      case 0:
-        if( pNode->pLeft ){
-          pNode = pNode->pLeft;
-        }else{ 
-          prev_step = 1;
-        }
-        break;
-      case 1:
-        if( pNode->pRight ){
-          pNode = pNode->pRight;
-          prev_step = 0;
-        }else{
-          prev_step = 2;
-        }
-        break;
-      case 2:
-        /* Check red-black property (1) */
-        if( !pNode->isBlack &&
-            ( (pNode->pLeft && !pNode->pLeft->isBlack) ||
-              (pNode->pRight && !pNode->pRight->isBlack) )
-          ){
-          char buf[128];
-          sprintf(buf, "Red node with red child at %p\n", pNode);
-          *msg = append_val(*msg, buf);
-          *msg = append_node(*msg, tree->pHead, 0);
-          *msg = append_val(*msg, "\n");
-        }
-
-        /* Check red-black property (2) */
-        { 
-          int leftHeight = 0;
-          int rightHeight = 0;
-          if( pNode->pLeft ){
-            leftHeight += pNode->pLeft->nBlackHeight;
-            leftHeight += (pNode->pLeft->isBlack?1:0);
-          }
-          if( pNode->pRight ){
-            rightHeight += pNode->pRight->nBlackHeight;
-            rightHeight += (pNode->pRight->isBlack?1:0);
-          }
-          if( leftHeight != rightHeight ){
-            char buf[128];
-            sprintf(buf, "Different black-heights at %p\n", pNode);
-            *msg = append_val(*msg, buf);
-            *msg = append_node(*msg, tree->pHead, 0);
-            *msg = append_val(*msg, "\n");
-          }
-          pNode->nBlackHeight = leftHeight;
-        }
-
-        if( pNode->pParent ){
-          if( pNode == pNode->pParent->pLeft ) prev_step = 1;
-          else prev_step = 2;
-        }
-        pNode = pNode->pParent;
-        break;
-      default: assert(0);
-    }
-  }
-} 
-
-/*
- * Node pX has just been inserted into pTree (by code in sqliteRbtreeInsert()).
- * It is possible that pX is a red node with a red parent, which is a violation
- * of the red-black tree properties. This function performs rotations and 
- * color changes to rebalance the tree
- */
-static void do_insert_balancing(BtRbTree *pTree, BtRbNode *pX)
-{
-  /* In the first iteration of this loop, pX points to the red node just
-   * inserted in the tree. If the parent of pX exists (pX is not the root
-   * node) and is red, then the properties of the red-black tree are
-   * violated.
-   *
-   * At the start of any subsequent iterations, pX points to a red node
-   * with a red parent. In all other respects the tree is a legal red-black
-   * binary tree. */
-  while( pX != pTree->pHead && !pX->pParent->isBlack ){
-    BtRbNode *pUncle;
-    BtRbNode *pGrandparent;
-
-    /* Grandparent of pX must exist and must be black. */
-    pGrandparent = pX->pParent->pParent;
-    assert( pGrandparent );
-    assert( pGrandparent->isBlack );
-
-    /* Uncle of pX may or may not exist. */
-    if( pX->pParent == pGrandparent->pLeft ) 
-      pUncle = pGrandparent->pRight;
-    else 
-      pUncle = pGrandparent->pLeft;
-
-    /* If the uncle of pX exists and is red, we do the following:
-     *       |                 |
-     *      G(b)              G(r)
-     *      /  \              /  \        
-     *   U(r)   P(r)       U(b)  P(b)
-     *            \                \
-     *           X(r)              X(r)
-     *
-     *     BEFORE             AFTER
-     * pX is then set to G. If the parent of G is red, then the while loop
-     * will run again.  */
-    if( pUncle && !pUncle->isBlack ){
-      pGrandparent->isBlack = 0;
-      pUncle->isBlack = 1;
-      pX->pParent->isBlack = 1;
-      pX = pGrandparent;
-    }else{
-
-      if( pX->pParent == pGrandparent->pLeft ){
-        if( pX == pX->pParent->pRight ){
-          /* If pX is a right-child, do the following transform, essentially
-           * to change pX into a left-child: 
-           *       |                  | 
-           *      G(b)               G(b)
-           *      /  \               /  \        
-           *   P(r)   U(b)        X(r)  U(b)
-           *      \                /
-           *     X(r)            P(r) <-- new X
-           *
-           *     BEFORE             AFTER
-           */
-          pX = pX->pParent;
-          leftRotate(pTree, pX);
-        }
-
-        /* Do the following transform, which balances the tree :) 
-         *       |                  | 
-         *      G(b)               P(b)
-         *      /  \               /  \        
-         *   P(r)   U(b)        X(r)  G(r)
-         *    /                         \
-         *  X(r)                        U(b)
-         *
-         *     BEFORE             AFTER
-         */
-        assert( pGrandparent == pX->pParent->pParent );
-        pGrandparent->isBlack = 0;
-        pX->pParent->isBlack = 1;
-        rightRotate( pTree, pGrandparent );
-
-      }else{
-        /* This code is symetric to the illustrated case above. */
-        if( pX == pX->pParent->pLeft ){
-          pX = pX->pParent;
-          rightRotate(pTree, pX);
-        }
-        assert( pGrandparent == pX->pParent->pParent );
-        pGrandparent->isBlack = 0;
-        pX->pParent->isBlack = 1;
-        leftRotate( pTree, pGrandparent );
-      }
-    }
-  }
-  pTree->pHead->isBlack = 1;
-}
-
-/*
- * A child of pParent, which in turn had child pX, has just been removed from 
- * pTree (the figure below depicts the operation, Z is being removed). pParent
- * or pX, or both may be NULL.  
- *                |           |
- *                P           P
- *               / \         / \
- *              Z           X
- *             / \
- *            X  nil
- *
- * This function is only called if Z was black. In this case the red-black tree
- * properties have been violated, and pX has an "extra black". This function 
- * performs rotations and color-changes to re-balance the tree.
- */
-static 
-void do_delete_balancing(BtRbTree *pTree, BtRbNode *pX, BtRbNode *pParent)
-{
-  BtRbNode *pSib; 
-
-  /* TODO: Comment this code! */
-  while( pX != pTree->pHead && (!pX || pX->isBlack) ){
-    if( pX == pParent->pLeft ){
-      pSib = pParent->pRight;
-      if( pSib && !(pSib->isBlack) ){
-        pSib->isBlack = 1;
-        pParent->isBlack = 0;
-        leftRotate(pTree, pParent);
-        pSib = pParent->pRight;
-      }
-      if( !pSib ){
-        pX = pParent;
-      }else if( 
-          (!pSib->pLeft  || pSib->pLeft->isBlack) &&
-          (!pSib->pRight || pSib->pRight->isBlack) ) {
-        pSib->isBlack = 0;
-        pX = pParent;
-      }else{
-        if( (!pSib->pRight || pSib->pRight->isBlack) ){
-          if( pSib->pLeft ) pSib->pLeft->isBlack = 1;
-          pSib->isBlack = 0;
-          rightRotate( pTree, pSib );
-          pSib = pParent->pRight;
-        }
-        pSib->isBlack = pParent->isBlack;
-        pParent->isBlack = 1;
-        if( pSib->pRight ) pSib->pRight->isBlack = 1;
-        leftRotate(pTree, pParent);
-        pX = pTree->pHead;
-      }
-    }else{
-      pSib = pParent->pLeft;
-      if( pSib && !(pSib->isBlack) ){
-        pSib->isBlack = 1;
-        pParent->isBlack = 0;
-        rightRotate(pTree, pParent);
-        pSib = pParent->pLeft;
-      }
-      if( !pSib ){
-        pX = pParent;
-      }else if( 
-          (!pSib->pLeft  || pSib->pLeft->isBlack) &&
-          (!pSib->pRight || pSib->pRight->isBlack) ){
-        pSib->isBlack = 0;
-        pX = pParent;
-      }else{
-        if( (!pSib->pLeft || pSib->pLeft->isBlack) ){
-          if( pSib->pRight ) pSib->pRight->isBlack = 1;
-          pSib->isBlack = 0;
-          leftRotate( pTree, pSib );
-          pSib = pParent->pLeft;
-        }
-        pSib->isBlack = pParent->isBlack;
-        pParent->isBlack = 1;
-        if( pSib->pLeft ) pSib->pLeft->isBlack = 1;
-        rightRotate(pTree, pParent);
-        pX = pTree->pHead;
-      }
-    }
-    pParent = pX->pParent;
-  }
-  if( pX ) pX->isBlack = 1;
-}
-
-/*
- * Create table n in tree pRbtree. Table n must not exist.
- */
-static void btreeCreateTable(Rbtree* pRbtree, int n)
-{
-  BtRbTree *pNewTbl = sqliteMalloc(sizeof(BtRbTree));
-  sqlite3HashInsert(&pRbtree->tblHash, 0, n, pNewTbl);
-}
-
-/*
- * Log a single "rollback-op" for the given Rbtree. See comments for struct
- * BtRollbackOp.
- */
-static void btreeLogRollbackOp(Rbtree* pRbtree, BtRollbackOp *pRollbackOp)
-{
-  assert( pRbtree->eTransState == TRANS_INCHECKPOINT ||
-      pRbtree->eTransState == TRANS_INTRANSACTION );
-  if( pRbtree->eTransState == TRANS_INTRANSACTION ){
-    pRollbackOp->pNext = pRbtree->pTransRollback;
-    pRbtree->pTransRollback = pRollbackOp;
-  }
-  if( pRbtree->eTransState == TRANS_INCHECKPOINT ){
-    if( !pRbtree->pCheckRollback ){
-      pRbtree->pCheckRollbackTail = pRollbackOp;
-    }
-    pRollbackOp->pNext = pRbtree->pCheckRollback;
-    pRbtree->pCheckRollback = pRollbackOp;
-  }
-}
-
-int sqliteRbtreeOpen(
-  const char *zFilename,
-  int mode,
-  int nPg,
-  Btree **ppBtree
-){
-  Rbtree **ppRbtree = (Rbtree**)ppBtree;
-  *ppRbtree = (Rbtree *)sqliteMalloc(sizeof(Rbtree));
-  if( sqlite3_malloc_failed ) goto open_no_mem;
-  sqlite3HashInit(&(*ppRbtree)->tblHash, SQLITE_HASH_INT, 0);
-
-  /* Create a binary tree for the SQLITE_MASTER table at location 2 */
-  btreeCreateTable(*ppRbtree, 2);
-  if( sqlite3_malloc_failed ) goto open_no_mem;
-  (*ppRbtree)->next_idx = 3;
-  (*ppRbtree)->pOps = &sqliteRbtreeOps;
-  /* Set file type to 4; this is so that "attach ':memory:' as ...."  does not
-  ** think that the database in uninitialised and refuse to attach
-  */
-  (*ppRbtree)->aMetaData[2] = 4;
-  
-  return SQLITE_OK;
-
-open_no_mem:
-  *ppBtree = 0;
-  return SQLITE_NOMEM;
-}
-
-/*
- * Create a new table in the supplied Rbtree. Set *n to the new table number.
- * Return SQLITE_OK if the operation is a success.
- */
-static int memRbtreeCreateTable(Rbtree* tree, int* n)
-{
-  assert( tree->eTransState != TRANS_NONE );
-
-  *n = tree->next_idx++;
-  btreeCreateTable(tree, *n);
-  if( sqlite3_malloc_failed ) return SQLITE_NOMEM;
-
-  /* Set up the rollback structure (if we are not doing this as part of a
-   * rollback) */
-  if( tree->eTransState != TRANS_ROLLBACK ){
-    BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp));
-    if( pRollbackOp==0 ) return SQLITE_NOMEM;
-    pRollbackOp->eOp = ROLLBACK_DROP;
-    pRollbackOp->iTab = *n;
-    btreeLogRollbackOp(tree, pRollbackOp);
-  }
-
-  return SQLITE_OK;
-}
-
-/*
- * Delete table n from the supplied Rbtree. 
- */
-static int memRbtreeDropTable(Rbtree* tree, int n)
-{
-  BtRbTree *pTree;
-  assert( tree->eTransState != TRANS_NONE );
-
-  memRbtreeClearTable(tree, n);
-  pTree = sqlite3HashInsert(&tree->tblHash, 0, n, 0);
-  assert(pTree);
-  assert( pTree->pCursors==0 );
-  sqliteFree(pTree);
-
-  if( tree->eTransState != TRANS_ROLLBACK ){
-    BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp));
-    if( pRollbackOp==0 ) return SQLITE_NOMEM;
-    pRollbackOp->eOp = ROLLBACK_CREATE;
-    pRollbackOp->iTab = n;
-    btreeLogRollbackOp(tree, pRollbackOp);
-  }
-
-  return SQLITE_OK;
-}
-
-static int memRbtreeKeyCompare(RbtCursor* pCur, const void *pKey, int nKey,
-                                 int nIgnore, int *pRes)
-{
-  assert(pCur);
-
-  if( !pCur->pNode ) {
-    *pRes = -1;
-  } else {
-    if( (pCur->pNode->nKey - nIgnore) < 0 ){
-      *pRes = -1;
-    }else{
-      *pRes = key_compare(pCur->pNode->pKey, pCur->pNode->nKey-nIgnore, 
-          pKey, nKey);
-    }
-  }
-  return SQLITE_OK;
-}
-
-/*
- * Get a new cursor for table iTable of the supplied Rbtree. The wrFlag
- * parameter indicates that the cursor is open for writing.
- *
- * Note that RbtCursor.eSkip and RbtCursor.pNode both initialize to 0.
- */
-static int memRbtreeCursor(
-  Rbtree* tree,
-  int iTable,
-  int wrFlag,
-  RbtCursor **ppCur
-){
-  RbtCursor *pCur;
-  assert(tree);
-  pCur = *ppCur = sqliteMalloc(sizeof(RbtCursor));
-  if( sqlite3_malloc_failed ) return SQLITE_NOMEM;
-  pCur->pTree  = sqlite3HashFind(&tree->tblHash, 0, iTable);
-  assert( pCur->pTree );
-  pCur->pRbtree = tree;
-  pCur->iTree  = iTable;
-  pCur->pOps = &sqliteRbtreeCursorOps;
-  pCur->wrFlag = wrFlag;
-  pCur->pShared = pCur->pTree->pCursors;
-  pCur->pTree->pCursors = pCur;
-
-  assert( (*ppCur)->pTree );
-  return SQLITE_OK;
-}
-
-/*
- * Insert a new record into the Rbtree.  The key is given by (pKey,nKey)
- * and the data is given by (pData,nData).  The cursor is used only to
- * define what database the record should be inserted into.  The cursor
- * is left pointing at the new record.
- *
- * If the key exists already in the tree, just replace the data. 
- */
-static int memRbtreeInsert(
-  RbtCursor* pCur,
-  const void *pKey,
-  int nKey,
-  const void *pDataInput,
-  int nData
-){
-  void * pData;
-  int match;
-
-  /* It is illegal to call sqliteRbtreeInsert() if we are
-  ** not in a transaction */
-  assert( pCur->pRbtree->eTransState != TRANS_NONE );
-
-  /* Make sure some other cursor isn't trying to read this same table */
-  if( checkReadLocks(pCur) ){
-    return SQLITE_LOCKED; /* The table pCur points to has a read lock */
-  }
-
-  /* Take a copy of the input data now, in case we need it for the 
-   * replace case */
-  pData = sqliteMallocRaw(nData);
-  if( sqlite3_malloc_failed ) return SQLITE_NOMEM;
-  memcpy(pData, pDataInput, nData);
-
-  /* Move the cursor to a node near the key to be inserted. If the key already
-   * exists in the table, then (match == 0). In this case we can just replace
-   * the data associated with the entry, we don't need to manipulate the tree.
-   * 
-   * If there is no exact match, then the cursor points at what would be either
-   * the predecessor (match == -1) or successor (match == 1) of the
-   * searched-for key, were it to be inserted. The new node becomes a child of
-   * this node.
-   * 
-   * The new node is initially red.
-   */
-  memRbtreeMoveto( pCur, pKey, nKey, &match);
-  if( match ){
-    BtRbNode *pNode = sqliteMalloc(sizeof(BtRbNode));
-    if( pNode==0 ) return SQLITE_NOMEM;
-    pNode->nKey = nKey;
-    pNode->pKey = sqliteMallocRaw(nKey);
-    if( sqlite3_malloc_failed ) return SQLITE_NOMEM;
-    memcpy(pNode->pKey, pKey, nKey);
-    pNode->nData = nData;
-    pNode->pData = pData; 
-    if( pCur->pNode ){
-      switch( match ){
-        case -1:
-          assert( !pCur->pNode->pRight );
-          pNode->pParent = pCur->pNode;
-          pCur->pNode->pRight = pNode;
-          break;
-        case 1:
-          assert( !pCur->pNode->pLeft );
-          pNode->pParent = pCur->pNode;
-          pCur->pNode->pLeft = pNode;
-          break;
-        default:
-          assert(0);
-      }
-    }else{
-      pCur->pTree->pHead = pNode;
-    }
-
-    /* Point the cursor at the node just inserted, as per SQLite requirements */
-    pCur->pNode = pNode;
-
-    /* A new node has just been inserted, so run the balancing code */
-    do_insert_balancing(pCur->pTree, pNode);
-
-    /* Set up a rollback-op in case we have to roll this operation back */
-    if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
-      BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
-      if( pOp==0 ) return SQLITE_NOMEM;
-      pOp->eOp = ROLLBACK_DELETE;
-      pOp->iTab = pCur->iTree;
-      pOp->nKey = pNode->nKey;
-      pOp->pKey = sqliteMallocRaw( pOp->nKey );
-      if( sqlite3_malloc_failed ) return SQLITE_NOMEM;
-      memcpy( pOp->pKey, pNode->pKey, pOp->nKey );
-      btreeLogRollbackOp(pCur->pRbtree, pOp);
-    }
-
-  }else{ 
-    /* No need to insert a new node in the tree, as the key already exists.
-     * Just clobber the current nodes data. */
-
-    /* Set up a rollback-op in case we have to roll this operation back */
-    if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
-      BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
-      if( pOp==0 ) return SQLITE_NOMEM;
-      pOp->iTab = pCur->iTree;
-      pOp->nKey = pCur->pNode->nKey;
-      pOp->pKey = sqliteMallocRaw( pOp->nKey );
-      if( sqlite3_malloc_failed ) return SQLITE_NOMEM;
-      memcpy( pOp->pKey, pCur->pNode->pKey, pOp->nKey );
-      pOp->nData = pCur->pNode->nData;
-      pOp->pData = pCur->pNode->pData;
-      pOp->eOp = ROLLBACK_INSERT;
-      btreeLogRollbackOp(pCur->pRbtree, pOp);
-    }else{
-      sqliteFree( pCur->pNode->pData );
-    }
-
-    /* Actually clobber the nodes data */
-    pCur->pNode->pData = pData;
-    pCur->pNode->nData = nData;
-  }
-
-  return SQLITE_OK;
-}
-
-/* Move the cursor so that it points to an entry near pKey.
-** Return a success code.
-**
-**     *pRes<0      The cursor is left pointing at an entry that
-**                  is smaller than pKey or if the table is empty
-**                  and the cursor is therefore left point to nothing.
-**
-**     *pRes==0     The cursor is left pointing at an entry that
-**                  exactly matches pKey.
-**
-**     *pRes>0      The cursor is left pointing at an entry that
-**                  is larger than pKey.
-*/
-static int memRbtreeMoveto(
-  RbtCursor* pCur,
-  const void *pKey,
-  int nKey,
-  int *pRes
-){
-  BtRbNode *pTmp = 0;
-
-  pCur->pNode = pCur->pTree->pHead;
-  *pRes = -1;
-  while( pCur->pNode && *pRes ) {
-    *pRes = key_compare(pCur->pNode->pKey, pCur->pNode->nKey, pKey, nKey);
-    pTmp = pCur->pNode;
-    switch( *pRes ){
-      case 1:    /* cursor > key */
-        pCur->pNode = pCur->pNode->pLeft;
-        break;
-      case -1:   /* cursor < key */
-        pCur->pNode = pCur->pNode->pRight;
-        break;
-    }
-  } 
-
-  /* If (pCur->pNode == NULL), then we have failed to find a match. Set
-   * pCur->pNode to pTmp, which is either NULL (if the tree is empty) or the
-   * last node traversed in the search. In either case the relation ship
-   * between pTmp and the searched for key is already stored in *pRes. pTmp is
-   * either the successor or predecessor of the key we tried to move to. */
-  if( !pCur->pNode ) pCur->pNode = pTmp;
-  pCur->eSkip = SKIP_NONE;
-
-  return SQLITE_OK;
-}
-
-
-/*
-** Delete the entry that the cursor is pointing to.
-**
-** The cursor is left pointing at either the next or the previous
-** entry.  If the cursor is left pointing to the next entry, then 
-** the pCur->eSkip flag is set to SKIP_NEXT which forces the next call to 
-** sqliteRbtreeNext() to be a no-op.  That way, you can always call
-** sqliteRbtreeNext() after a delete and the cursor will be left
-** pointing to the first entry after the deleted entry.  Similarly,
-** pCur->eSkip is set to SKIP_PREV is the cursor is left pointing to
-** the entry prior to the deleted entry so that a subsequent call to
-** sqliteRbtreePrevious() will always leave the cursor pointing at the
-** entry immediately before the one that was deleted.
-*/
-static int memRbtreeDelete(RbtCursor* pCur)
-{
-  BtRbNode *pZ;      /* The one being deleted */
-  BtRbNode *pChild;  /* The child of the spliced out node */
-
-  /* It is illegal to call sqliteRbtreeDelete() if we are
-  ** not in a transaction */
-  assert( pCur->pRbtree->eTransState != TRANS_NONE );
-
-  /* Make sure some other cursor isn't trying to read this same table */
-  if( checkReadLocks(pCur) ){
-    return SQLITE_LOCKED; /* The table pCur points to has a read lock */
-  }
-
-  pZ = pCur->pNode;
-  if( !pZ ){
-    return SQLITE_OK;
-  }
-
-  /* If we are not currently doing a rollback, set up a rollback op for this 
-   * deletion */
-  if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
-    BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
-    if( pOp==0 ) return SQLITE_NOMEM;
-    pOp->iTab = pCur->iTree;
-    pOp->nKey = pZ->nKey;
-    pOp->pKey = pZ->pKey;
-    pOp->nData = pZ->nData;
-    pOp->pData = pZ->pData;
-    pOp->eOp = ROLLBACK_INSERT;
-    btreeLogRollbackOp(pCur->pRbtree, pOp);
-  }
-
-  /* First do a standard binary-tree delete (node pZ is to be deleted). How
-   * to do this depends on how many children pZ has:
-   *
-   * If pZ has no children or one child, then splice out pZ.  If pZ has two
-   * children, splice out the successor of pZ and replace the key and data of
-   * pZ with the key and data of the spliced out successor.  */
-  if( pZ->pLeft && pZ->pRight ){
-    BtRbNode *pTmp;
-    int dummy;
-    pCur->eSkip = SKIP_NONE;
-    memRbtreeNext(pCur, &dummy);
-    assert( dummy == 0 );
-    if( pCur->pRbtree->eTransState == TRANS_ROLLBACK ){
-      sqliteFree(pZ->pKey);
-      sqliteFree(pZ->pData);
-    }
-    pZ->pData = pCur->pNode->pData;
-    pZ->nData = pCur->pNode->nData;
-    pZ->pKey = pCur->pNode->pKey;
-    pZ->nKey = pCur->pNode->nKey;
-    pTmp = pZ;
-    pZ = pCur->pNode;
-    pCur->pNode = pTmp;
-    pCur->eSkip = SKIP_NEXT;
-  }else{
-    int res;
-    pCur->eSkip = SKIP_NONE;
-    memRbtreeNext(pCur, &res);
-    pCur->eSkip = SKIP_NEXT;
-    if( res ){
-      memRbtreeLast(pCur, &res);
-      memRbtreePrevious(pCur, &res);
-      pCur->eSkip = SKIP_PREV;
-    }
-    if( pCur->pRbtree->eTransState == TRANS_ROLLBACK ){
-        sqliteFree(pZ->pKey);
-        sqliteFree(pZ->pData);
-    }
-  }
-
-  /* pZ now points at the node to be spliced out. This block does the 
-   * splicing. */
-  {
-    BtRbNode **ppParentSlot = 0;
-    assert( !pZ->pLeft || !pZ->pRight ); /* pZ has at most one child */
-    pChild = ((pZ->pLeft)?pZ->pLeft:pZ->pRight);
-    if( pZ->pParent ){
-      assert( pZ == pZ->pParent->pLeft || pZ == pZ->pParent->pRight );
-      ppParentSlot = ((pZ == pZ->pParent->pLeft)
-          ?&pZ->pParent->pLeft:&pZ->pParent->pRight);
-      *ppParentSlot = pChild;
-    }else{
-      pCur->pTree->pHead = pChild;
-    }
-    if( pChild ) pChild->pParent = pZ->pParent;
-  }
-
-  /* pZ now points at the spliced out node. pChild is the only child of pZ, or
-   * NULL if pZ has no children. If pZ is black, and not the tree root, then we
-   * will have violated the "same number of black nodes in every path to a
-   * leaf" property of the red-black tree. The code in do_delete_balancing()
-   * repairs this. */
-  if( pZ->isBlack ){ 
-    do_delete_balancing(pCur->pTree, pChild, pZ->pParent);
-  }
-
-  sqliteFree(pZ);
-  return SQLITE_OK;
-}
-
-/*
- * Empty table n of the Rbtree.
- */
-static int memRbtreeClearTable(Rbtree* tree, int n)
-{
-  BtRbTree *pTree;
-  BtRbNode *pNode;
-
-  pTree = sqlite3HashFind(&tree->tblHash, 0, n);
-  assert(pTree);
-
-  pNode = pTree->pHead;
-  while( pNode ){
-    if( pNode->pLeft ){
-      pNode = pNode->pLeft;
-    }
-    else if( pNode->pRight ){
-      pNode = pNode->pRight;
-    }
-    else {
-      BtRbNode *pTmp = pNode->pParent;
-      if( tree->eTransState == TRANS_ROLLBACK ){
-        sqliteFree( pNode->pKey );
-        sqliteFree( pNode->pData );
-      }else{
-        BtRollbackOp *pRollbackOp = sqliteMallocRaw(sizeof(BtRollbackOp));
-        if( pRollbackOp==0 ) return SQLITE_NOMEM;
-        pRollbackOp->eOp = ROLLBACK_INSERT;
-        pRollbackOp->iTab = n;
-        pRollbackOp->nKey = pNode->nKey;
-        pRollbackOp->pKey = pNode->pKey;
-        pRollbackOp->nData = pNode->nData;
-        pRollbackOp->pData = pNode->pData;
-        btreeLogRollbackOp(tree, pRollbackOp);
-      }
-      sqliteFree( pNode );
-      if( pTmp ){
-        if( pTmp->pLeft == pNode ) pTmp->pLeft = 0;
-        else if( pTmp->pRight == pNode ) pTmp->pRight = 0;
-      }
-      pNode = pTmp;
-    }
-  }
-
-  pTree->pHead = 0;
-  return SQLITE_OK;
-}
-
-static int memRbtreeFirst(RbtCursor* pCur, int *pRes)
-{
-  if( pCur->pTree->pHead ){
-    pCur->pNode = pCur->pTree->pHead;
-    while( pCur->pNode->pLeft ){
-      pCur->pNode = pCur->pNode->pLeft;
-    }
-  }
-  if( pCur->pNode ){
-    *pRes = 0;
-  }else{
-    *pRes = 1;
-  }
-  pCur->eSkip = SKIP_NONE;
-  return SQLITE_OK;
-}
-
-static int memRbtreeLast(RbtCursor* pCur, int *pRes)
-{
-  if( pCur->pTree->pHead ){
-    pCur->pNode = pCur->pTree->pHead;
-    while( pCur->pNode->pRight ){
-      pCur->pNode = pCur->pNode->pRight;
-    }
-  }
-  if( pCur->pNode ){
-    *pRes = 0;
-  }else{
-    *pRes = 1;
-  }
-  pCur->eSkip = SKIP_NONE;
-  return SQLITE_OK;
-}
-
-/*
-** Advance the cursor to the next entry in the database.  If
-** successful then set *pRes=0.  If the cursor
-** was already pointing to the last entry in the database before
-** this routine was called, then set *pRes=1.
-*/
-static int memRbtreeNext(RbtCursor* pCur, int *pRes)
-{
-  if( pCur->pNode && pCur->eSkip != SKIP_NEXT ){
-    if( pCur->pNode->pRight ){
-      pCur->pNode = pCur->pNode->pRight;
-      while( pCur->pNode->pLeft )
-        pCur->pNode = pCur->pNode->pLeft;
-    }else{
-      BtRbNode * pX = pCur->pNode;
-      pCur->pNode = pX->pParent;
-      while( pCur->pNode && (pCur->pNode->pRight == pX) ){
-        pX = pCur->pNode;
-        pCur->pNode = pX->pParent;
-      }
-    }
-  }
-  pCur->eSkip = SKIP_NONE;
-
-  if( !pCur->pNode ){
-    *pRes = 1;
-  }else{
-    *pRes = 0;
-  }
-
-  return SQLITE_OK;
-}
-
-static int memRbtreePrevious(RbtCursor* pCur, int *pRes)
-{
-  if( pCur->pNode && pCur->eSkip != SKIP_PREV ){
-    if( pCur->pNode->pLeft ){
-      pCur->pNode = pCur->pNode->pLeft;
-      while( pCur->pNode->pRight )
-        pCur->pNode = pCur->pNode->pRight;
-    }else{
-      BtRbNode * pX = pCur->pNode;
-      pCur->pNode = pX->pParent;
-      while( pCur->pNode && (pCur->pNode->pLeft == pX) ){
-        pX = pCur->pNode;
-        pCur->pNode = pX->pParent;
-      }
-    }
-  }
-  pCur->eSkip = SKIP_NONE;
-
-  if( !pCur->pNode ){
-    *pRes = 1;
-  }else{
-    *pRes = 0;
-  }
-
-  return SQLITE_OK;
-}
-
-static int memRbtreeKeySize(RbtCursor* pCur, int *pSize)
-{
-  if( pCur->pNode ){
-    *pSize = pCur->pNode->nKey;
-  }else{
-    *pSize = 0;
-  }
-  return SQLITE_OK;
-}
-
-static int memRbtreeKey(RbtCursor* pCur, int offset, int amt, char *zBuf)
-{
-  if( !pCur->pNode ) return 0;
-  if( !pCur->pNode->pKey || ((amt + offset) <= pCur->pNode->nKey) ){
-    memcpy(zBuf, ((char*)pCur->pNode->pKey)+offset, amt);
-  }else{
-    memcpy(zBuf, ((char*)pCur->pNode->pKey)+offset, pCur->pNode->nKey-offset);
-    amt = pCur->pNode->nKey-offset;
-  }
-  return amt;
-}
-
-static int memRbtreeDataSize(RbtCursor* pCur, int *pSize)
-{
-  if( pCur->pNode ){
-    *pSize = pCur->pNode->nData;
-  }else{
-    *pSize = 0;
-  }
-  return SQLITE_OK;
-}
-
-static int memRbtreeData(RbtCursor *pCur, int offset, int amt, char *zBuf)
-{
-  if( !pCur->pNode ) return 0;
-  if( (amt + offset) <= pCur->pNode->nData ){
-    memcpy(zBuf, ((char*)pCur->pNode->pData)+offset, amt);
-  }else{
-    memcpy(zBuf, ((char*)pCur->pNode->pData)+offset ,pCur->pNode->nData-offset);
-    amt = pCur->pNode->nData-offset;
-  }
-  return amt;
-}
-
-static int memRbtreeCloseCursor(RbtCursor* pCur)
-{
-  if( pCur->pTree->pCursors==pCur ){
-    pCur->pTree->pCursors = pCur->pShared;
-  }else{
-    RbtCursor *p = pCur->pTree->pCursors;
-    while( p && p->pShared!=pCur ){ p = p->pShared; }
-    assert( p!=0 );
-    if( p ){
-      p->pShared = pCur->pShared;
-    }
-  }
-  sqliteFree(pCur);
-  return SQLITE_OK;
-}
-
-static int memRbtreeGetMeta(Rbtree* tree, int* aMeta)
-{
-  memcpy( aMeta, tree->aMetaData, sizeof(int) * SQLITE_N_BTREE_META );
-  return SQLITE_OK;
-}
-
-static int memRbtreeUpdateMeta(Rbtree* tree, int* aMeta)
-{
-  memcpy( tree->aMetaData, aMeta, sizeof(int) * SQLITE_N_BTREE_META );
-  return SQLITE_OK;
-}
-
-/*
- * Check that each table in the Rbtree meets the requirements for a red-black
- * binary tree. If an error is found, return an explanation of the problem in 
- * memory obtained from sqliteMalloc(). Parameters aRoot and nRoot are ignored. 
- */
-static char *memRbtreeIntegrityCheck(Rbtree* tree, int* aRoot, int nRoot)
-{
-  char * msg = 0;
-  HashElem *p;
-
-  for(p=sqliteHashFirst(&tree->tblHash); p; p=sqliteHashNext(p)){
-    BtRbTree *pTree = sqliteHashData(p);
-    check_redblack_tree(pTree, &msg);
-  }
-
-  return msg;
-}
-
-static int memRbtreeSetCacheSize(Rbtree* tree, int sz)
-{
-  return SQLITE_OK;
-}
-
-static int memRbtreeSetSafetyLevel(Rbtree *pBt, int level){
-  return SQLITE_OK;
-}
-
-static int memRbtreeBeginTrans(Rbtree* tree)
-{
-  if( tree->eTransState != TRANS_NONE ) 
-    return SQLITE_ERROR;
-
-  assert( tree->pTransRollback == 0 );
-  tree->eTransState = TRANS_INTRANSACTION;
-  return SQLITE_OK;
-}
-
-/*
-** Delete a linked list of BtRollbackOp structures.
-*/
-static void deleteRollbackList(BtRollbackOp *pOp){
-  while( pOp ){
-    BtRollbackOp *pTmp = pOp->pNext;
-    sqliteFree(pOp->pData);
-    sqliteFree(pOp->pKey);
-    sqliteFree(pOp);
-    pOp = pTmp;
-  }
-}
-
-static int memRbtreeCommit(Rbtree* tree){
-  /* Just delete pTransRollback and pCheckRollback */
-  deleteRollbackList(tree->pCheckRollback);
-  deleteRollbackList(tree->pTransRollback);
-  tree->pTransRollback = 0;
-  tree->pCheckRollback = 0;
-  tree->pCheckRollbackTail = 0;
-  tree->eTransState = TRANS_NONE;
-  return SQLITE_OK;
-}
-
-/*
- * Close the supplied Rbtree. Delete everything associated with it.
- */
-static int memRbtreeClose(Rbtree* tree)
-{
-  HashElem *p;
-  memRbtreeCommit(tree);
-  while( (p=sqliteHashFirst(&tree->tblHash))!=0 ){
-    tree->eTransState = TRANS_ROLLBACK;
-    memRbtreeDropTable(tree, sqliteHashKeysize(p));
-  }
-  sqlite3HashClear(&tree->tblHash);
-  sqliteFree(tree);
-  return SQLITE_OK;
-}
-
-/*
- * Execute and delete the supplied rollback-list on pRbtree.
- */
-static void execute_rollback_list(Rbtree *pRbtree, BtRollbackOp *pList)
-{
-  BtRollbackOp *pTmp;
-  RbtCursor cur;
-  int res;
-
-  cur.pRbtree = pRbtree;
-  cur.wrFlag = 1;
-  while( pList ){
-    switch( pList->eOp ){
-      case ROLLBACK_INSERT:
-        cur.pTree  = sqlite3HashFind( &pRbtree->tblHash, 0, pList->iTab );
-        assert(cur.pTree);
-        cur.iTree  = pList->iTab;
-        cur.eSkip  = SKIP_NONE;
-        memRbtreeInsert( &cur, pList->pKey,
-            pList->nKey, pList->pData, pList->nData );
-        break;
-      case ROLLBACK_DELETE:
-        cur.pTree  = sqlite3HashFind( &pRbtree->tblHash, 0, pList->iTab );
-        assert(cur.pTree);
-        cur.iTree  = pList->iTab;
-        cur.eSkip  = SKIP_NONE;
-        memRbtreeMoveto(&cur, pList->pKey, pList->nKey, &res);
-        assert(res == 0);
-        memRbtreeDelete( &cur );
-        break;
-      case ROLLBACK_CREATE:
-        btreeCreateTable(pRbtree, pList->iTab);
-        break;
-      case ROLLBACK_DROP:
-        memRbtreeDropTable(pRbtree, pList->iTab);
-        break;
-      default:
-        assert(0);
-    }
-    sqliteFree(pList->pKey);
-    sqliteFree(pList->pData);
-    pTmp = pList->pNext;
-    sqliteFree(pList);
-    pList = pTmp;
-  }
-}
-
-static int memRbtreeRollback(Rbtree* tree)
-{
-  tree->eTransState = TRANS_ROLLBACK;
-  execute_rollback_list(tree, tree->pCheckRollback);
-  execute_rollback_list(tree, tree->pTransRollback);
-  tree->pTransRollback = 0;
-  tree->pCheckRollback = 0;
-  tree->pCheckRollbackTail = 0;
-  tree->eTransState = TRANS_NONE;
-  return SQLITE_OK;
-}
-
-static int memRbtreeBeginCkpt(Rbtree* tree)
-{
-  if( tree->eTransState != TRANS_INTRANSACTION ) 
-    return SQLITE_ERROR;
-
-  assert( tree->pCheckRollback == 0 );
-  assert( tree->pCheckRollbackTail == 0 );
-  tree->eTransState = TRANS_INCHECKPOINT;
-  return SQLITE_OK;
-}
-
-static int memRbtreeCommitCkpt(Rbtree* tree)
-{
-  if( tree->eTransState == TRANS_INCHECKPOINT ){ 
-    if( tree->pCheckRollback ){
-      tree->pCheckRollbackTail->pNext = tree->pTransRollback;
-      tree->pTransRollback = tree->pCheckRollback;
-      tree->pCheckRollback = 0;
-      tree->pCheckRollbackTail = 0;
-    }
-    tree->eTransState = TRANS_INTRANSACTION;
-  }
-  return SQLITE_OK;
-}
-
-static int memRbtreeRollbackCkpt(Rbtree* tree)
-{
-  if( tree->eTransState != TRANS_INCHECKPOINT ) return SQLITE_OK;
-  tree->eTransState = TRANS_ROLLBACK;
-  execute_rollback_list(tree, tree->pCheckRollback);
-  tree->pCheckRollback = 0;
-  tree->pCheckRollbackTail = 0;
-  tree->eTransState = TRANS_INTRANSACTION;
-  return SQLITE_OK;
-}
-
-#ifdef SQLITE_TEST
-static int memRbtreePageDump(Rbtree* tree, int pgno, int rec)
-{
-  assert(!"Cannot call sqliteRbtreePageDump");
-  return SQLITE_OK;
-}
-
-static int memRbtreeCursorDump(RbtCursor* pCur, int* aRes)
-{
-  assert(!"Cannot call sqliteRbtreeCursorDump");
-  return SQLITE_OK;
-}
-#endif
-
-static struct Pager *memRbtreePager(Rbtree* tree)
-{
-  return 0;
-}
-
-/*
-** Return the full pathname of the underlying database file.
-*/
-static const char *memRbtreeGetFilename(Rbtree *pBt){
-  return 0;  /* A NULL return indicates there is no underlying file */
-}
-
-/*
-** The copy file function is not implemented for the in-memory database
-*/
-static int memRbtreeCopyFile(Rbtree *pBt, Rbtree *pBt2){
-  return SQLITE_INTERNAL;  /* Not implemented */
-}
-
-static BtOps sqliteRbtreeOps = {
-    (int(*)(Btree*)) memRbtreeClose,
-    (int(*)(Btree*,int)) memRbtreeSetCacheSize,
-    (int(*)(Btree*,int)) memRbtreeSetSafetyLevel,
-    (int(*)(Btree*)) memRbtreeBeginTrans,
-    (int(*)(Btree*)) memRbtreeCommit,
-    (int(*)(Btree*)) memRbtreeRollback,
-    (int(*)(Btree*)) memRbtreeBeginCkpt,
-    (int(*)(Btree*)) memRbtreeCommitCkpt,
-    (int(*)(Btree*)) memRbtreeRollbackCkpt,
-    (int(*)(Btree*,int*)) memRbtreeCreateTable,
-    (int(*)(Btree*,int*)) memRbtreeCreateTable,
-    (int(*)(Btree*,int)) memRbtreeDropTable,
-    (int(*)(Btree*,int)) memRbtreeClearTable,
-    (int(*)(Btree*,int,int,BtCursor**)) memRbtreeCursor,
-    (int(*)(Btree*,int*)) memRbtreeGetMeta,
-    (int(*)(Btree*,int*)) memRbtreeUpdateMeta,
-    (char*(*)(Btree*,int*,int)) memRbtreeIntegrityCheck,
-    (const char*(*)(Btree*)) memRbtreeGetFilename,
-    (int(*)(Btree*,Btree*)) memRbtreeCopyFile,
-    (struct Pager*(*)(Btree*)) memRbtreePager,
-#ifdef SQLITE_TEST
-    (int(*)(Btree*,int,int)) memRbtreePageDump,
-#endif
-};
-
-static BtCursorOps sqliteRbtreeCursorOps = {
-    (int(*)(BtCursor*,const void*,int,int*)) memRbtreeMoveto,
-    (int(*)(BtCursor*)) memRbtreeDelete,
-    (int(*)(BtCursor*,const void*,int,const void*,int)) memRbtreeInsert,
-    (int(*)(BtCursor*,int*)) memRbtreeFirst,
-    (int(*)(BtCursor*,int*)) memRbtreeLast,
-    (int(*)(BtCursor*,int*)) memRbtreeNext,
-    (int(*)(BtCursor*,int*)) memRbtreePrevious,
-    (int(*)(BtCursor*,int*)) memRbtreeKeySize,
-    (int(*)(BtCursor*,int,int,char*)) memRbtreeKey,
-    (int(*)(BtCursor*,const void*,int,int,int*)) memRbtreeKeyCompare,
-    (int(*)(BtCursor*,int*)) memRbtreeDataSize,
-    (int(*)(BtCursor*,int,int,char*)) memRbtreeData,
-    (int(*)(BtCursor*)) memRbtreeCloseCursor,
-#ifdef SQLITE_TEST
-    (int(*)(BtCursor*,int*)) memRbtreeCursorDump,
-#endif
-
-};
-
-#endif /* SQLITE_OMIT_INMEMORYDB */
-
-
-