xref: /illumos-gate/usr/src/lib/libsqlite/src/btree_rb.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 
2 #pragma ident	"%Z%%M%	%I%	%E% SMI"
3 
4 /*
5 ** 2003 Feb 4
6 **
7 ** The author disclaims copyright to this source code.  In place of
8 ** a legal notice, here is a blessing:
9 **
10 **    May you do good and not evil.
11 **    May you find forgiveness for yourself and forgive others.
12 **    May you share freely, never taking more than you give.
13 **
14 *************************************************************************
15 ** $Id: btree_rb.c,v 1.24.2.1 2004/06/26 14:40:05 drh Exp $
16 **
17 ** This file implements an in-core database using Red-Black balanced
18 ** binary trees.
19 **
20 ** It was contributed to SQLite by anonymous on 2003-Feb-04 23:24:49 UTC.
21 */
22 #include "btree.h"
23 #include "sqliteInt.h"
24 #include <assert.h>
25 
26 /*
27 ** Omit this whole file if the SQLITE_OMIT_INMEMORYDB macro is
28 ** defined.  This allows a lot of code to be omitted for installations
29 ** that do not need it.
30 */
31 #ifndef SQLITE_OMIT_INMEMORYDB
32 
33 
34 typedef struct BtRbTree BtRbTree;
35 typedef struct BtRbNode BtRbNode;
36 typedef struct BtRollbackOp BtRollbackOp;
37 typedef struct Rbtree Rbtree;
38 typedef struct RbtCursor RbtCursor;
39 
40 /* Forward declarations */
41 static BtOps sqliteRbtreeOps;
42 static BtCursorOps sqliteRbtreeCursorOps;
43 
44 /*
45  * During each transaction (or checkpoint), a linked-list of
46  * "rollback-operations" is accumulated. If the transaction is rolled back,
47  * then the list of operations must be executed (to restore the database to
48  * it's state before the transaction started). If the transaction is to be
49  * committed, just delete the list.
50  *
51  * Each operation is represented as follows, depending on the value of eOp:
52  *
53  * ROLLBACK_INSERT  ->  Need to insert (pKey, pData) into table iTab.
54  * ROLLBACK_DELETE  ->  Need to delete the record (pKey) into table iTab.
55  * ROLLBACK_CREATE  ->  Need to create table iTab.
56  * ROLLBACK_DROP    ->  Need to drop table iTab.
57  */
58 struct BtRollbackOp {
59   u8 eOp;
60   int iTab;
61   int nKey;
62   void *pKey;
63   int nData;
64   void *pData;
65   BtRollbackOp *pNext;
66 };
67 
68 /*
69 ** Legal values for BtRollbackOp.eOp:
70 */
71 #define ROLLBACK_INSERT 1 /* Insert a record */
72 #define ROLLBACK_DELETE 2 /* Delete a record */
73 #define ROLLBACK_CREATE 3 /* Create a table */
74 #define ROLLBACK_DROP   4 /* Drop a table */
75 
76 struct Rbtree {
77   BtOps *pOps;    /* Function table */
78   int aMetaData[SQLITE_N_BTREE_META];
79 
80   int next_idx;   /* next available table index */
81   Hash tblHash;   /* All created tables, by index */
82   u8 isAnonymous; /* True if this Rbtree is to be deleted when closed */
83   u8 eTransState; /* State of this Rbtree wrt transactions */
84 
85   BtRollbackOp *pTransRollback;
86   BtRollbackOp *pCheckRollback;
87   BtRollbackOp *pCheckRollbackTail;
88 };
89 
90 /*
91 ** Legal values for Rbtree.eTransState.
92 */
93 #define TRANS_NONE           0  /* No transaction is in progress */
94 #define TRANS_INTRANSACTION  1  /* A transaction is in progress */
95 #define TRANS_INCHECKPOINT   2  /* A checkpoint is in progress  */
96 #define TRANS_ROLLBACK       3  /* We are currently rolling back a checkpoint or
97                                  * transaction. */
98 
99 struct RbtCursor {
100   BtCursorOps *pOps;        /* Function table */
101   Rbtree    *pRbtree;
102   BtRbTree *pTree;
103   int       iTree;          /* Index of pTree in pRbtree */
104   BtRbNode *pNode;
105   RbtCursor *pShared;       /* List of all cursors on the same Rbtree */
106   u8 eSkip;                 /* Determines if next step operation is a no-op */
107   u8 wrFlag;                /* True if this cursor is open for writing */
108 };
109 
110 /*
111 ** Legal values for RbtCursor.eSkip.
112 */
113 #define SKIP_NONE     0   /* Always step the cursor */
114 #define SKIP_NEXT     1   /* The next sqliteRbtreeNext() is a no-op */
115 #define SKIP_PREV     2   /* The next sqliteRbtreePrevious() is a no-op */
116 #define SKIP_INVALID  3   /* Calls to Next() and Previous() are invalid */
117 
118 struct BtRbTree {
119   RbtCursor *pCursors;     /* All cursors pointing to this tree */
120   BtRbNode *pHead;         /* Head of the tree, or NULL */
121 };
122 
123 struct BtRbNode {
124   int nKey;
125   void *pKey;
126   int nData;
127   void *pData;
128   u8 isBlack;        /* true for a black node, 0 for a red node */
129   BtRbNode *pParent; /* Nodes parent node, NULL for the tree head */
130   BtRbNode *pLeft;   /* Nodes left child, or NULL */
131   BtRbNode *pRight;  /* Nodes right child, or NULL */
132 
133   int nBlackHeight;  /* Only used during the red-black integrity check */
134 };
135 
136 /* Forward declarations */
137 static int memRbtreeMoveto(
138   RbtCursor* pCur,
139   const void *pKey,
140   int nKey,
141   int *pRes
142 );
143 static int memRbtreeClearTable(Rbtree* tree, int n);
144 static int memRbtreeNext(RbtCursor* pCur, int *pRes);
145 static int memRbtreeLast(RbtCursor* pCur, int *pRes);
146 static int memRbtreePrevious(RbtCursor* pCur, int *pRes);
147 
148 
149 /*
150 ** This routine checks all cursors that point to the same table
151 ** as pCur points to.  If any of those cursors were opened with
152 ** wrFlag==0 then this routine returns SQLITE_LOCKED.  If all
153 ** cursors point to the same table were opened with wrFlag==1
154 ** then this routine returns SQLITE_OK.
155 **
156 ** In addition to checking for read-locks (where a read-lock
157 ** means a cursor opened with wrFlag==0) this routine also NULLs
158 ** out the pNode field of all other cursors.
159 ** This is necessary because an insert
160 ** or delete might change erase the node out from under
161 ** another cursor.
162 */
163 static int checkReadLocks(RbtCursor *pCur){
164   RbtCursor *p;
165   assert( pCur->wrFlag );
166   for(p=pCur->pTree->pCursors; p; p=p->pShared){
167     if( p!=pCur ){
168       if( p->wrFlag==0 ) return SQLITE_LOCKED;
169       p->pNode = 0;
170     }
171   }
172   return SQLITE_OK;
173 }
174 
175 /*
176  * The key-compare function for the red-black trees. Returns as follows:
177  *
178  * (key1 < key2)             -1
179  * (key1 == key2)             0
180  * (key1 > key2)              1
181  *
182  * Keys are compared using memcmp(). If one key is an exact prefix of the
183  * other, then the shorter key is less than the longer key.
184  */
185 static int key_compare(void const*pKey1, int nKey1, void const*pKey2, int nKey2)
186 {
187   int mcmp = memcmp(pKey1, pKey2, (nKey1 <= nKey2)?nKey1:nKey2);
188   if( mcmp == 0){
189     if( nKey1 == nKey2 ) return 0;
190     return ((nKey1 < nKey2)?-1:1);
191   }
192   return ((mcmp>0)?1:-1);
193 }
194 
195 /*
196  * Perform the LEFT-rotate transformation on node X of tree pTree. This
197  * transform is part of the red-black balancing code.
198  *
199  *        |                   |
200  *        X                   Y
201  *       / \                 / \
202  *      a   Y               X   c
203  *         / \             / \
204  *        b   c           a   b
205  *
206  *      BEFORE              AFTER
207  */
208 static void leftRotate(BtRbTree *pTree, BtRbNode *pX)
209 {
210   BtRbNode *pY;
211   BtRbNode *pb;
212   pY = pX->pRight;
213   pb = pY->pLeft;
214 
215   pY->pParent = pX->pParent;
216   if( pX->pParent ){
217     if( pX->pParent->pLeft == pX ) pX->pParent->pLeft = pY;
218     else pX->pParent->pRight = pY;
219   }
220   pY->pLeft = pX;
221   pX->pParent = pY;
222   pX->pRight = pb;
223   if( pb ) pb->pParent = pX;
224   if( pTree->pHead == pX ) pTree->pHead = pY;
225 }
226 
227 /*
228  * Perform the RIGHT-rotate transformation on node X of tree pTree. This
229  * transform is part of the red-black balancing code.
230  *
231  *        |                   |
232  *        X                   Y
233  *       / \                 / \
234  *      Y   c               a   X
235  *     / \                     / \
236  *    a   b                   b   c
237  *
238  *      BEFORE              AFTER
239  */
240 static void rightRotate(BtRbTree *pTree, BtRbNode *pX)
241 {
242   BtRbNode *pY;
243   BtRbNode *pb;
244   pY = pX->pLeft;
245   pb = pY->pRight;
246 
247   pY->pParent = pX->pParent;
248   if( pX->pParent ){
249     if( pX->pParent->pLeft == pX ) pX->pParent->pLeft = pY;
250     else pX->pParent->pRight = pY;
251   }
252   pY->pRight = pX;
253   pX->pParent = pY;
254   pX->pLeft = pb;
255   if( pb ) pb->pParent = pX;
256   if( pTree->pHead == pX ) pTree->pHead = pY;
257 }
258 
259 /*
260  * A string-manipulation helper function for check_redblack_tree(). If (orig ==
261  * NULL) a copy of val is returned. If (orig != NULL) then a copy of the *
262  * concatenation of orig and val is returned. The original orig is deleted
263  * (using sqliteFree()).
264  */
265 static char *append_val(char * orig, char const * val){
266   char *z;
267   if( !orig ){
268     z = sqliteStrDup( val );
269   } else{
270     z = 0;
271     sqliteSetString(&z, orig, val, (char*)0);
272     sqliteFree( orig );
273   }
274   return z;
275 }
276 
277 /*
278  * Append a string representation of the entire node to orig and return it.
279  * This is used to produce debugging information if check_redblack_tree() finds
280  * a problem with a red-black binary tree.
281  */
282 static char *append_node(char * orig, BtRbNode *pNode, int indent)
283 {
284   char buf[128];
285   int i;
286 
287   for( i=0; i<indent; i++ ){
288       orig = append_val(orig, " ");
289   }
290 
291   sprintf(buf, "%p", pNode);
292   orig = append_val(orig, buf);
293 
294   if( pNode ){
295     indent += 3;
296     if( pNode->isBlack ){
297       orig = append_val(orig, " B \n");
298     }else{
299       orig = append_val(orig, " R \n");
300     }
301     orig = append_node( orig, pNode->pLeft, indent );
302     orig = append_node( orig, pNode->pRight, indent );
303   }else{
304     orig = append_val(orig, "\n");
305   }
306   return orig;
307 }
308 
309 /*
310  * Print a representation of a node to stdout. This function is only included
311  * so you can call it from within a debugger if things get really bad.  It
312  * is not called from anyplace in the code.
313  */
314 static void print_node(BtRbNode *pNode)
315 {
316     char * str = append_node(0, pNode, 0);
317     printf("%s", str);
318 
319     /* Suppress a warning message about print_node() being unused */
320     (void)print_node;
321 }
322 
323 /*
324  * Check the following properties of the red-black tree:
325  * (1) - If a node is red, both of it's children are black
326  * (2) - Each path from a given node to a leaf (NULL) node passes thru the
327  *       same number of black nodes
328  *
329  * If there is a problem, append a description (using append_val() ) to *msg.
330  */
331 static void check_redblack_tree(BtRbTree * tree, char ** msg)
332 {
333   BtRbNode *pNode;
334 
335   /* 0 -> came from parent
336    * 1 -> came from left
337    * 2 -> came from right */
338   int prev_step = 0;
339 
340   pNode = tree->pHead;
341   while( pNode ){
342     switch( prev_step ){
343       case 0:
344         if( pNode->pLeft ){
345           pNode = pNode->pLeft;
346         }else{
347           prev_step = 1;
348         }
349         break;
350       case 1:
351         if( pNode->pRight ){
352           pNode = pNode->pRight;
353           prev_step = 0;
354         }else{
355           prev_step = 2;
356         }
357         break;
358       case 2:
359         /* Check red-black property (1) */
360         if( !pNode->isBlack &&
361             ( (pNode->pLeft && !pNode->pLeft->isBlack) ||
362               (pNode->pRight && !pNode->pRight->isBlack) )
363           ){
364           char buf[128];
365           sprintf(buf, "Red node with red child at %p\n", pNode);
366           *msg = append_val(*msg, buf);
367           *msg = append_node(*msg, tree->pHead, 0);
368           *msg = append_val(*msg, "\n");
369         }
370 
371         /* Check red-black property (2) */
372         {
373           int leftHeight = 0;
374           int rightHeight = 0;
375           if( pNode->pLeft ){
376             leftHeight += pNode->pLeft->nBlackHeight;
377             leftHeight += (pNode->pLeft->isBlack?1:0);
378           }
379           if( pNode->pRight ){
380             rightHeight += pNode->pRight->nBlackHeight;
381             rightHeight += (pNode->pRight->isBlack?1:0);
382           }
383           if( leftHeight != rightHeight ){
384             char buf[128];
385             sprintf(buf, "Different black-heights at %p\n", pNode);
386             *msg = append_val(*msg, buf);
387             *msg = append_node(*msg, tree->pHead, 0);
388             *msg = append_val(*msg, "\n");
389           }
390           pNode->nBlackHeight = leftHeight;
391         }
392 
393         if( pNode->pParent ){
394           if( pNode == pNode->pParent->pLeft ) prev_step = 1;
395           else prev_step = 2;
396         }
397         pNode = pNode->pParent;
398         break;
399       default: assert(0);
400     }
401   }
402 }
403 
404 /*
405  * Node pX has just been inserted into pTree (by code in sqliteRbtreeInsert()).
406  * It is possible that pX is a red node with a red parent, which is a violation
407  * of the red-black tree properties. This function performs rotations and
408  * color changes to rebalance the tree
409  */
410 static void do_insert_balancing(BtRbTree *pTree, BtRbNode *pX)
411 {
412   /* In the first iteration of this loop, pX points to the red node just
413    * inserted in the tree. If the parent of pX exists (pX is not the root
414    * node) and is red, then the properties of the red-black tree are
415    * violated.
416    *
417    * At the start of any subsequent iterations, pX points to a red node
418    * with a red parent. In all other respects the tree is a legal red-black
419    * binary tree. */
420   while( pX != pTree->pHead && !pX->pParent->isBlack ){
421     BtRbNode *pUncle;
422     BtRbNode *pGrandparent;
423 
424     /* Grandparent of pX must exist and must be black. */
425     pGrandparent = pX->pParent->pParent;
426     assert( pGrandparent );
427     assert( pGrandparent->isBlack );
428 
429     /* Uncle of pX may or may not exist. */
430     if( pX->pParent == pGrandparent->pLeft )
431       pUncle = pGrandparent->pRight;
432     else
433       pUncle = pGrandparent->pLeft;
434 
435     /* If the uncle of pX exists and is red, we do the following:
436      *       |                 |
437      *      G(b)              G(r)
438      *      /  \              /  \
439      *   U(r)   P(r)       U(b)  P(b)
440      *            \                \
441      *           X(r)              X(r)
442      *
443      *     BEFORE             AFTER
444      * pX is then set to G. If the parent of G is red, then the while loop
445      * will run again.  */
446     if( pUncle && !pUncle->isBlack ){
447       pGrandparent->isBlack = 0;
448       pUncle->isBlack = 1;
449       pX->pParent->isBlack = 1;
450       pX = pGrandparent;
451     }else{
452 
453       if( pX->pParent == pGrandparent->pLeft ){
454         if( pX == pX->pParent->pRight ){
455           /* If pX is a right-child, do the following transform, essentially
456            * to change pX into a left-child:
457            *       |                  |
458            *      G(b)               G(b)
459            *      /  \               /  \
460            *   P(r)   U(b)        X(r)  U(b)
461            *      \                /
462            *     X(r)            P(r) <-- new X
463            *
464            *     BEFORE             AFTER
465            */
466           pX = pX->pParent;
467           leftRotate(pTree, pX);
468         }
469 
470         /* Do the following transform, which balances the tree :)
471          *       |                  |
472          *      G(b)               P(b)
473          *      /  \               /  \
474          *   P(r)   U(b)        X(r)  G(r)
475          *    /                         \
476          *  X(r)                        U(b)
477          *
478          *     BEFORE             AFTER
479          */
480         assert( pGrandparent == pX->pParent->pParent );
481         pGrandparent->isBlack = 0;
482         pX->pParent->isBlack = 1;
483         rightRotate( pTree, pGrandparent );
484 
485       }else{
486         /* This code is symetric to the illustrated case above. */
487         if( pX == pX->pParent->pLeft ){
488           pX = pX->pParent;
489           rightRotate(pTree, pX);
490         }
491         assert( pGrandparent == pX->pParent->pParent );
492         pGrandparent->isBlack = 0;
493         pX->pParent->isBlack = 1;
494         leftRotate( pTree, pGrandparent );
495       }
496     }
497   }
498   pTree->pHead->isBlack = 1;
499 }
500 
501 /*
502  * A child of pParent, which in turn had child pX, has just been removed from
503  * pTree (the figure below depicts the operation, Z is being removed). pParent
504  * or pX, or both may be NULL.
505  *                |           |
506  *                P           P
507  *               / \         / \
508  *              Z           X
509  *             / \
510  *            X  nil
511  *
512  * This function is only called if Z was black. In this case the red-black tree
513  * properties have been violated, and pX has an "extra black". This function
514  * performs rotations and color-changes to re-balance the tree.
515  */
516 static
517 void do_delete_balancing(BtRbTree *pTree, BtRbNode *pX, BtRbNode *pParent)
518 {
519   BtRbNode *pSib;
520 
521   /* TODO: Comment this code! */
522   while( pX != pTree->pHead && (!pX || pX->isBlack) ){
523     if( pX == pParent->pLeft ){
524       pSib = pParent->pRight;
525       if( pSib && !(pSib->isBlack) ){
526         pSib->isBlack = 1;
527         pParent->isBlack = 0;
528         leftRotate(pTree, pParent);
529         pSib = pParent->pRight;
530       }
531       if( !pSib ){
532         pX = pParent;
533       }else if(
534           (!pSib->pLeft  || pSib->pLeft->isBlack) &&
535           (!pSib->pRight || pSib->pRight->isBlack) ) {
536         pSib->isBlack = 0;
537         pX = pParent;
538       }else{
539         if( (!pSib->pRight || pSib->pRight->isBlack) ){
540           if( pSib->pLeft ) pSib->pLeft->isBlack = 1;
541           pSib->isBlack = 0;
542           rightRotate( pTree, pSib );
543           pSib = pParent->pRight;
544         }
545         pSib->isBlack = pParent->isBlack;
546         pParent->isBlack = 1;
547         if( pSib->pRight ) pSib->pRight->isBlack = 1;
548         leftRotate(pTree, pParent);
549         pX = pTree->pHead;
550       }
551     }else{
552       pSib = pParent->pLeft;
553       if( pSib && !(pSib->isBlack) ){
554         pSib->isBlack = 1;
555         pParent->isBlack = 0;
556         rightRotate(pTree, pParent);
557         pSib = pParent->pLeft;
558       }
559       if( !pSib ){
560         pX = pParent;
561       }else if(
562           (!pSib->pLeft  || pSib->pLeft->isBlack) &&
563           (!pSib->pRight || pSib->pRight->isBlack) ){
564         pSib->isBlack = 0;
565         pX = pParent;
566       }else{
567         if( (!pSib->pLeft || pSib->pLeft->isBlack) ){
568           if( pSib->pRight ) pSib->pRight->isBlack = 1;
569           pSib->isBlack = 0;
570           leftRotate( pTree, pSib );
571           pSib = pParent->pLeft;
572         }
573         pSib->isBlack = pParent->isBlack;
574         pParent->isBlack = 1;
575         if( pSib->pLeft ) pSib->pLeft->isBlack = 1;
576         rightRotate(pTree, pParent);
577         pX = pTree->pHead;
578       }
579     }
580     pParent = pX->pParent;
581   }
582   if( pX ) pX->isBlack = 1;
583 }
584 
585 /*
586  * Create table n in tree pRbtree. Table n must not exist.
587  */
588 static void btreeCreateTable(Rbtree* pRbtree, int n)
589 {
590   BtRbTree *pNewTbl = sqliteMalloc(sizeof(BtRbTree));
591   sqliteHashInsert(&pRbtree->tblHash, 0, n, pNewTbl);
592 }
593 
594 /*
595  * Log a single "rollback-op" for the given Rbtree. See comments for struct
596  * BtRollbackOp.
597  */
598 static void btreeLogRollbackOp(Rbtree* pRbtree, BtRollbackOp *pRollbackOp)
599 {
600   assert( pRbtree->eTransState == TRANS_INCHECKPOINT ||
601       pRbtree->eTransState == TRANS_INTRANSACTION );
602   if( pRbtree->eTransState == TRANS_INTRANSACTION ){
603     pRollbackOp->pNext = pRbtree->pTransRollback;
604     pRbtree->pTransRollback = pRollbackOp;
605   }
606   if( pRbtree->eTransState == TRANS_INCHECKPOINT ){
607     if( !pRbtree->pCheckRollback ){
608       pRbtree->pCheckRollbackTail = pRollbackOp;
609     }
610     pRollbackOp->pNext = pRbtree->pCheckRollback;
611     pRbtree->pCheckRollback = pRollbackOp;
612   }
613 }
614 
615 int sqliteRbtreeOpen(
616   const char *zFilename,
617   int mode,
618   int nPg,
619   Btree **ppBtree
620 ){
621   Rbtree **ppRbtree = (Rbtree**)ppBtree;
622   *ppRbtree = (Rbtree *)sqliteMalloc(sizeof(Rbtree));
623   if( sqlite_malloc_failed ) goto open_no_mem;
624   sqliteHashInit(&(*ppRbtree)->tblHash, SQLITE_HASH_INT, 0);
625 
626   /* Create a binary tree for the SQLITE_MASTER table at location 2 */
627   btreeCreateTable(*ppRbtree, 2);
628   if( sqlite_malloc_failed ) goto open_no_mem;
629   (*ppRbtree)->next_idx = 3;
630   (*ppRbtree)->pOps = &sqliteRbtreeOps;
631   /* Set file type to 4; this is so that "attach ':memory:' as ...."  does not
632   ** think that the database in uninitialised and refuse to attach
633   */
634   (*ppRbtree)->aMetaData[2] = 4;
635 
636   return SQLITE_OK;
637 
638 open_no_mem:
639   *ppBtree = 0;
640   return SQLITE_NOMEM;
641 }
642 
643 /*
644  * Create a new table in the supplied Rbtree. Set *n to the new table number.
645  * Return SQLITE_OK if the operation is a success.
646  */
647 static int memRbtreeCreateTable(Rbtree* tree, int* n)
648 {
649   assert( tree->eTransState != TRANS_NONE );
650 
651   *n = tree->next_idx++;
652   btreeCreateTable(tree, *n);
653   if( sqlite_malloc_failed ) return SQLITE_NOMEM;
654 
655   /* Set up the rollback structure (if we are not doing this as part of a
656    * rollback) */
657   if( tree->eTransState != TRANS_ROLLBACK ){
658     BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp));
659     if( pRollbackOp==0 ) return SQLITE_NOMEM;
660     pRollbackOp->eOp = ROLLBACK_DROP;
661     pRollbackOp->iTab = *n;
662     btreeLogRollbackOp(tree, pRollbackOp);
663   }
664 
665   return SQLITE_OK;
666 }
667 
668 /*
669  * Delete table n from the supplied Rbtree.
670  */
671 static int memRbtreeDropTable(Rbtree* tree, int n)
672 {
673   BtRbTree *pTree;
674   assert( tree->eTransState != TRANS_NONE );
675 
676   memRbtreeClearTable(tree, n);
677   pTree = sqliteHashInsert(&tree->tblHash, 0, n, 0);
678   assert(pTree);
679   assert( pTree->pCursors==0 );
680   sqliteFree(pTree);
681 
682   if( tree->eTransState != TRANS_ROLLBACK ){
683     BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp));
684     if( pRollbackOp==0 ) return SQLITE_NOMEM;
685     pRollbackOp->eOp = ROLLBACK_CREATE;
686     pRollbackOp->iTab = n;
687     btreeLogRollbackOp(tree, pRollbackOp);
688   }
689 
690   return SQLITE_OK;
691 }
692 
693 static int memRbtreeKeyCompare(RbtCursor* pCur, const void *pKey, int nKey,
694                                  int nIgnore, int *pRes)
695 {
696   assert(pCur);
697 
698   if( !pCur->pNode ) {
699     *pRes = -1;
700   } else {
701     if( (pCur->pNode->nKey - nIgnore) < 0 ){
702       *pRes = -1;
703     }else{
704       *pRes = key_compare(pCur->pNode->pKey, pCur->pNode->nKey-nIgnore,
705           pKey, nKey);
706     }
707   }
708   return SQLITE_OK;
709 }
710 
711 /*
712  * Get a new cursor for table iTable of the supplied Rbtree. The wrFlag
713  * parameter indicates that the cursor is open for writing.
714  *
715  * Note that RbtCursor.eSkip and RbtCursor.pNode both initialize to 0.
716  */
717 static int memRbtreeCursor(
718   Rbtree* tree,
719   int iTable,
720   int wrFlag,
721   RbtCursor **ppCur
722 ){
723   RbtCursor *pCur;
724   assert(tree);
725   pCur = *ppCur = sqliteMalloc(sizeof(RbtCursor));
726   if( sqlite_malloc_failed ) return SQLITE_NOMEM;
727   pCur->pTree  = sqliteHashFind(&tree->tblHash, 0, iTable);
728   assert( pCur->pTree );
729   pCur->pRbtree = tree;
730   pCur->iTree  = iTable;
731   pCur->pOps = &sqliteRbtreeCursorOps;
732   pCur->wrFlag = wrFlag;
733   pCur->pShared = pCur->pTree->pCursors;
734   pCur->pTree->pCursors = pCur;
735 
736   assert( (*ppCur)->pTree );
737   return SQLITE_OK;
738 }
739 
740 /*
741  * Insert a new record into the Rbtree.  The key is given by (pKey,nKey)
742  * and the data is given by (pData,nData).  The cursor is used only to
743  * define what database the record should be inserted into.  The cursor
744  * is left pointing at the new record.
745  *
746  * If the key exists already in the tree, just replace the data.
747  */
748 static int memRbtreeInsert(
749   RbtCursor* pCur,
750   const void *pKey,
751   int nKey,
752   const void *pDataInput,
753   int nData
754 ){
755   void * pData;
756   int match;
757 
758   /* It is illegal to call sqliteRbtreeInsert() if we are
759   ** not in a transaction */
760   assert( pCur->pRbtree->eTransState != TRANS_NONE );
761 
762   /* Make sure some other cursor isn't trying to read this same table */
763   if( checkReadLocks(pCur) ){
764     return SQLITE_LOCKED; /* The table pCur points to has a read lock */
765   }
766 
767   /* Take a copy of the input data now, in case we need it for the
768    * replace case */
769   pData = sqliteMallocRaw(nData);
770   if( sqlite_malloc_failed ) return SQLITE_NOMEM;
771   memcpy(pData, pDataInput, nData);
772 
773   /* Move the cursor to a node near the key to be inserted. If the key already
774    * exists in the table, then (match == 0). In this case we can just replace
775    * the data associated with the entry, we don't need to manipulate the tree.
776    *
777    * If there is no exact match, then the cursor points at what would be either
778    * the predecessor (match == -1) or successor (match == 1) of the
779    * searched-for key, were it to be inserted. The new node becomes a child of
780    * this node.
781    *
782    * The new node is initially red.
783    */
784   memRbtreeMoveto( pCur, pKey, nKey, &match);
785   if( match ){
786     BtRbNode *pNode = sqliteMalloc(sizeof(BtRbNode));
787     if( pNode==0 ) return SQLITE_NOMEM;
788     pNode->nKey = nKey;
789     pNode->pKey = sqliteMallocRaw(nKey);
790     if( sqlite_malloc_failed ) return SQLITE_NOMEM;
791     memcpy(pNode->pKey, pKey, nKey);
792     pNode->nData = nData;
793     pNode->pData = pData;
794     if( pCur->pNode ){
795       switch( match ){
796         case -1:
797           assert( !pCur->pNode->pRight );
798           pNode->pParent = pCur->pNode;
799           pCur->pNode->pRight = pNode;
800           break;
801         case 1:
802           assert( !pCur->pNode->pLeft );
803           pNode->pParent = pCur->pNode;
804           pCur->pNode->pLeft = pNode;
805           break;
806         default:
807           assert(0);
808       }
809     }else{
810       pCur->pTree->pHead = pNode;
811     }
812 
813     /* Point the cursor at the node just inserted, as per SQLite requirements */
814     pCur->pNode = pNode;
815 
816     /* A new node has just been inserted, so run the balancing code */
817     do_insert_balancing(pCur->pTree, pNode);
818 
819     /* Set up a rollback-op in case we have to roll this operation back */
820     if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
821       BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
822       if( pOp==0 ) return SQLITE_NOMEM;
823       pOp->eOp = ROLLBACK_DELETE;
824       pOp->iTab = pCur->iTree;
825       pOp->nKey = pNode->nKey;
826       pOp->pKey = sqliteMallocRaw( pOp->nKey );
827       if( sqlite_malloc_failed ) return SQLITE_NOMEM;
828       memcpy( pOp->pKey, pNode->pKey, pOp->nKey );
829       btreeLogRollbackOp(pCur->pRbtree, pOp);
830     }
831 
832   }else{
833     /* No need to insert a new node in the tree, as the key already exists.
834      * Just clobber the current nodes data. */
835 
836     /* Set up a rollback-op in case we have to roll this operation back */
837     if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
838       BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
839       if( pOp==0 ) return SQLITE_NOMEM;
840       pOp->iTab = pCur->iTree;
841       pOp->nKey = pCur->pNode->nKey;
842       pOp->pKey = sqliteMallocRaw( pOp->nKey );
843       if( sqlite_malloc_failed ) return SQLITE_NOMEM;
844       memcpy( pOp->pKey, pCur->pNode->pKey, pOp->nKey );
845       pOp->nData = pCur->pNode->nData;
846       pOp->pData = pCur->pNode->pData;
847       pOp->eOp = ROLLBACK_INSERT;
848       btreeLogRollbackOp(pCur->pRbtree, pOp);
849     }else{
850       sqliteFree( pCur->pNode->pData );
851     }
852 
853     /* Actually clobber the nodes data */
854     pCur->pNode->pData = pData;
855     pCur->pNode->nData = nData;
856   }
857 
858   return SQLITE_OK;
859 }
860 
861 /* Move the cursor so that it points to an entry near pKey.
862 ** Return a success code.
863 **
864 **     *pRes<0      The cursor is left pointing at an entry that
865 **                  is smaller than pKey or if the table is empty
866 **                  and the cursor is therefore left point to nothing.
867 **
868 **     *pRes==0     The cursor is left pointing at an entry that
869 **                  exactly matches pKey.
870 **
871 **     *pRes>0      The cursor is left pointing at an entry that
872 **                  is larger than pKey.
873 */
874 static int memRbtreeMoveto(
875   RbtCursor* pCur,
876   const void *pKey,
877   int nKey,
878   int *pRes
879 ){
880   BtRbNode *pTmp = 0;
881 
882   pCur->pNode = pCur->pTree->pHead;
883   *pRes = -1;
884   while( pCur->pNode && *pRes ) {
885     *pRes = key_compare(pCur->pNode->pKey, pCur->pNode->nKey, pKey, nKey);
886     pTmp = pCur->pNode;
887     switch( *pRes ){
888       case 1:    /* cursor > key */
889         pCur->pNode = pCur->pNode->pLeft;
890         break;
891       case -1:   /* cursor < key */
892         pCur->pNode = pCur->pNode->pRight;
893         break;
894     }
895   }
896 
897   /* If (pCur->pNode == NULL), then we have failed to find a match. Set
898    * pCur->pNode to pTmp, which is either NULL (if the tree is empty) or the
899    * last node traversed in the search. In either case the relation ship
900    * between pTmp and the searched for key is already stored in *pRes. pTmp is
901    * either the successor or predecessor of the key we tried to move to. */
902   if( !pCur->pNode ) pCur->pNode = pTmp;
903   pCur->eSkip = SKIP_NONE;
904 
905   return SQLITE_OK;
906 }
907 
908 
909 /*
910 ** Delete the entry that the cursor is pointing to.
911 **
912 ** The cursor is left pointing at either the next or the previous
913 ** entry.  If the cursor is left pointing to the next entry, then
914 ** the pCur->eSkip flag is set to SKIP_NEXT which forces the next call to
915 ** sqliteRbtreeNext() to be a no-op.  That way, you can always call
916 ** sqliteRbtreeNext() after a delete and the cursor will be left
917 ** pointing to the first entry after the deleted entry.  Similarly,
918 ** pCur->eSkip is set to SKIP_PREV is the cursor is left pointing to
919 ** the entry prior to the deleted entry so that a subsequent call to
920 ** sqliteRbtreePrevious() will always leave the cursor pointing at the
921 ** entry immediately before the one that was deleted.
922 */
923 static int memRbtreeDelete(RbtCursor* pCur)
924 {
925   BtRbNode *pZ;      /* The one being deleted */
926   BtRbNode *pChild;  /* The child of the spliced out node */
927 
928   /* It is illegal to call sqliteRbtreeDelete() if we are
929   ** not in a transaction */
930   assert( pCur->pRbtree->eTransState != TRANS_NONE );
931 
932   /* Make sure some other cursor isn't trying to read this same table */
933   if( checkReadLocks(pCur) ){
934     return SQLITE_LOCKED; /* The table pCur points to has a read lock */
935   }
936 
937   pZ = pCur->pNode;
938   if( !pZ ){
939     return SQLITE_OK;
940   }
941 
942   /* If we are not currently doing a rollback, set up a rollback op for this
943    * deletion */
944   if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
945     BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
946     if( pOp==0 ) return SQLITE_NOMEM;
947     pOp->iTab = pCur->iTree;
948     pOp->nKey = pZ->nKey;
949     pOp->pKey = pZ->pKey;
950     pOp->nData = pZ->nData;
951     pOp->pData = pZ->pData;
952     pOp->eOp = ROLLBACK_INSERT;
953     btreeLogRollbackOp(pCur->pRbtree, pOp);
954   }
955 
956   /* First do a standard binary-tree delete (node pZ is to be deleted). How
957    * to do this depends on how many children pZ has:
958    *
959    * If pZ has no children or one child, then splice out pZ.  If pZ has two
960    * children, splice out the successor of pZ and replace the key and data of
961    * pZ with the key and data of the spliced out successor.  */
962   if( pZ->pLeft && pZ->pRight ){
963     BtRbNode *pTmp;
964     int dummy;
965     pCur->eSkip = SKIP_NONE;
966     memRbtreeNext(pCur, &dummy);
967     assert( dummy == 0 );
968     if( pCur->pRbtree->eTransState == TRANS_ROLLBACK ){
969       sqliteFree(pZ->pKey);
970       sqliteFree(pZ->pData);
971     }
972     pZ->pData = pCur->pNode->pData;
973     pZ->nData = pCur->pNode->nData;
974     pZ->pKey = pCur->pNode->pKey;
975     pZ->nKey = pCur->pNode->nKey;
976     pTmp = pZ;
977     pZ = pCur->pNode;
978     pCur->pNode = pTmp;
979     pCur->eSkip = SKIP_NEXT;
980   }else{
981     int res;
982     pCur->eSkip = SKIP_NONE;
983     memRbtreeNext(pCur, &res);
984     pCur->eSkip = SKIP_NEXT;
985     if( res ){
986       memRbtreeLast(pCur, &res);
987       memRbtreePrevious(pCur, &res);
988       pCur->eSkip = SKIP_PREV;
989     }
990     if( pCur->pRbtree->eTransState == TRANS_ROLLBACK ){
991         sqliteFree(pZ->pKey);
992         sqliteFree(pZ->pData);
993     }
994   }
995 
996   /* pZ now points at the node to be spliced out. This block does the
997    * splicing. */
998   {
999     BtRbNode **ppParentSlot = 0;
1000     assert( !pZ->pLeft || !pZ->pRight ); /* pZ has at most one child */
1001     pChild = ((pZ->pLeft)?pZ->pLeft:pZ->pRight);
1002     if( pZ->pParent ){
1003       assert( pZ == pZ->pParent->pLeft || pZ == pZ->pParent->pRight );
1004       ppParentSlot = ((pZ == pZ->pParent->pLeft)
1005           ?&pZ->pParent->pLeft:&pZ->pParent->pRight);
1006       *ppParentSlot = pChild;
1007     }else{
1008       pCur->pTree->pHead = pChild;
1009     }
1010     if( pChild ) pChild->pParent = pZ->pParent;
1011   }
1012 
1013   /* pZ now points at the spliced out node. pChild is the only child of pZ, or
1014    * NULL if pZ has no children. If pZ is black, and not the tree root, then we
1015    * will have violated the "same number of black nodes in every path to a
1016    * leaf" property of the red-black tree. The code in do_delete_balancing()
1017    * repairs this. */
1018   if( pZ->isBlack ){
1019     do_delete_balancing(pCur->pTree, pChild, pZ->pParent);
1020   }
1021 
1022   sqliteFree(pZ);
1023   return SQLITE_OK;
1024 }
1025 
1026 /*
1027  * Empty table n of the Rbtree.
1028  */
1029 static int memRbtreeClearTable(Rbtree* tree, int n)
1030 {
1031   BtRbTree *pTree;
1032   BtRbNode *pNode;
1033 
1034   pTree = sqliteHashFind(&tree->tblHash, 0, n);
1035   assert(pTree);
1036 
1037   pNode = pTree->pHead;
1038   while( pNode ){
1039     if( pNode->pLeft ){
1040       pNode = pNode->pLeft;
1041     }
1042     else if( pNode->pRight ){
1043       pNode = pNode->pRight;
1044     }
1045     else {
1046       BtRbNode *pTmp = pNode->pParent;
1047       if( tree->eTransState == TRANS_ROLLBACK ){
1048         sqliteFree( pNode->pKey );
1049         sqliteFree( pNode->pData );
1050       }else{
1051         BtRollbackOp *pRollbackOp = sqliteMallocRaw(sizeof(BtRollbackOp));
1052         if( pRollbackOp==0 ) return SQLITE_NOMEM;
1053         pRollbackOp->eOp = ROLLBACK_INSERT;
1054         pRollbackOp->iTab = n;
1055         pRollbackOp->nKey = pNode->nKey;
1056         pRollbackOp->pKey = pNode->pKey;
1057         pRollbackOp->nData = pNode->nData;
1058         pRollbackOp->pData = pNode->pData;
1059         btreeLogRollbackOp(tree, pRollbackOp);
1060       }
1061       sqliteFree( pNode );
1062       if( pTmp ){
1063         if( pTmp->pLeft == pNode ) pTmp->pLeft = 0;
1064         else if( pTmp->pRight == pNode ) pTmp->pRight = 0;
1065       }
1066       pNode = pTmp;
1067     }
1068   }
1069 
1070   pTree->pHead = 0;
1071   return SQLITE_OK;
1072 }
1073 
1074 static int memRbtreeFirst(RbtCursor* pCur, int *pRes)
1075 {
1076   if( pCur->pTree->pHead ){
1077     pCur->pNode = pCur->pTree->pHead;
1078     while( pCur->pNode->pLeft ){
1079       pCur->pNode = pCur->pNode->pLeft;
1080     }
1081   }
1082   if( pCur->pNode ){
1083     *pRes = 0;
1084   }else{
1085     *pRes = 1;
1086   }
1087   pCur->eSkip = SKIP_NONE;
1088   return SQLITE_OK;
1089 }
1090 
1091 static int memRbtreeLast(RbtCursor* pCur, int *pRes)
1092 {
1093   if( pCur->pTree->pHead ){
1094     pCur->pNode = pCur->pTree->pHead;
1095     while( pCur->pNode->pRight ){
1096       pCur->pNode = pCur->pNode->pRight;
1097     }
1098   }
1099   if( pCur->pNode ){
1100     *pRes = 0;
1101   }else{
1102     *pRes = 1;
1103   }
1104   pCur->eSkip = SKIP_NONE;
1105   return SQLITE_OK;
1106 }
1107 
1108 /*
1109 ** Advance the cursor to the next entry in the database.  If
1110 ** successful then set *pRes=0.  If the cursor
1111 ** was already pointing to the last entry in the database before
1112 ** this routine was called, then set *pRes=1.
1113 */
1114 static int memRbtreeNext(RbtCursor* pCur, int *pRes)
1115 {
1116   if( pCur->pNode && pCur->eSkip != SKIP_NEXT ){
1117     if( pCur->pNode->pRight ){
1118       pCur->pNode = pCur->pNode->pRight;
1119       while( pCur->pNode->pLeft )
1120         pCur->pNode = pCur->pNode->pLeft;
1121     }else{
1122       BtRbNode * pX = pCur->pNode;
1123       pCur->pNode = pX->pParent;
1124       while( pCur->pNode && (pCur->pNode->pRight == pX) ){
1125         pX = pCur->pNode;
1126         pCur->pNode = pX->pParent;
1127       }
1128     }
1129   }
1130   pCur->eSkip = SKIP_NONE;
1131 
1132   if( !pCur->pNode ){
1133     *pRes = 1;
1134   }else{
1135     *pRes = 0;
1136   }
1137 
1138   return SQLITE_OK;
1139 }
1140 
1141 static int memRbtreePrevious(RbtCursor* pCur, int *pRes)
1142 {
1143   if( pCur->pNode && pCur->eSkip != SKIP_PREV ){
1144     if( pCur->pNode->pLeft ){
1145       pCur->pNode = pCur->pNode->pLeft;
1146       while( pCur->pNode->pRight )
1147         pCur->pNode = pCur->pNode->pRight;
1148     }else{
1149       BtRbNode * pX = pCur->pNode;
1150       pCur->pNode = pX->pParent;
1151       while( pCur->pNode && (pCur->pNode->pLeft == pX) ){
1152         pX = pCur->pNode;
1153         pCur->pNode = pX->pParent;
1154       }
1155     }
1156   }
1157   pCur->eSkip = SKIP_NONE;
1158 
1159   if( !pCur->pNode ){
1160     *pRes = 1;
1161   }else{
1162     *pRes = 0;
1163   }
1164 
1165   return SQLITE_OK;
1166 }
1167 
1168 static int memRbtreeKeySize(RbtCursor* pCur, int *pSize)
1169 {
1170   if( pCur->pNode ){
1171     *pSize = pCur->pNode->nKey;
1172   }else{
1173     *pSize = 0;
1174   }
1175   return SQLITE_OK;
1176 }
1177 
1178 static int memRbtreeKey(RbtCursor* pCur, int offset, int amt, char *zBuf)
1179 {
1180   if( !pCur->pNode ) return 0;
1181   if( !pCur->pNode->pKey || ((amt + offset) <= pCur->pNode->nKey) ){
1182     memcpy(zBuf, ((char*)pCur->pNode->pKey)+offset, amt);
1183   }else{
1184     memcpy(zBuf, ((char*)pCur->pNode->pKey)+offset, pCur->pNode->nKey-offset);
1185     amt = pCur->pNode->nKey-offset;
1186   }
1187   return amt;
1188 }
1189 
1190 static int memRbtreeDataSize(RbtCursor* pCur, int *pSize)
1191 {
1192   if( pCur->pNode ){
1193     *pSize = pCur->pNode->nData;
1194   }else{
1195     *pSize = 0;
1196   }
1197   return SQLITE_OK;
1198 }
1199 
1200 static int memRbtreeData(RbtCursor *pCur, int offset, int amt, char *zBuf)
1201 {
1202   if( !pCur->pNode ) return 0;
1203   if( (amt + offset) <= pCur->pNode->nData ){
1204     memcpy(zBuf, ((char*)pCur->pNode->pData)+offset, amt);
1205   }else{
1206     memcpy(zBuf, ((char*)pCur->pNode->pData)+offset ,pCur->pNode->nData-offset);
1207     amt = pCur->pNode->nData-offset;
1208   }
1209   return amt;
1210 }
1211 
1212 static int memRbtreeCloseCursor(RbtCursor* pCur)
1213 {
1214   if( pCur->pTree->pCursors==pCur ){
1215     pCur->pTree->pCursors = pCur->pShared;
1216   }else{
1217     RbtCursor *p = pCur->pTree->pCursors;
1218     while( p && p->pShared!=pCur ){ p = p->pShared; }
1219     assert( p!=0 );
1220     if( p ){
1221       p->pShared = pCur->pShared;
1222     }
1223   }
1224   sqliteFree(pCur);
1225   return SQLITE_OK;
1226 }
1227 
1228 static int memRbtreeGetMeta(Rbtree* tree, int* aMeta)
1229 {
1230   memcpy( aMeta, tree->aMetaData, sizeof(int) * SQLITE_N_BTREE_META );
1231   return SQLITE_OK;
1232 }
1233 
1234 static int memRbtreeUpdateMeta(Rbtree* tree, int* aMeta)
1235 {
1236   memcpy( tree->aMetaData, aMeta, sizeof(int) * SQLITE_N_BTREE_META );
1237   return SQLITE_OK;
1238 }
1239 
1240 /*
1241  * Check that each table in the Rbtree meets the requirements for a red-black
1242  * binary tree. If an error is found, return an explanation of the problem in
1243  * memory obtained from sqliteMalloc(). Parameters aRoot and nRoot are ignored.
1244  */
1245 static char *memRbtreeIntegrityCheck(Rbtree* tree, int* aRoot, int nRoot)
1246 {
1247   char * msg = 0;
1248   HashElem *p;
1249 
1250   for(p=sqliteHashFirst(&tree->tblHash); p; p=sqliteHashNext(p)){
1251     BtRbTree *pTree = sqliteHashData(p);
1252     check_redblack_tree(pTree, &msg);
1253   }
1254 
1255   return msg;
1256 }
1257 
1258 static int memRbtreeSetCacheSize(Rbtree* tree, int sz)
1259 {
1260   return SQLITE_OK;
1261 }
1262 
1263 static int memRbtreeSetSafetyLevel(Rbtree *pBt, int level){
1264   return SQLITE_OK;
1265 }
1266 
1267 static int memRbtreeBeginTrans(Rbtree* tree)
1268 {
1269   if( tree->eTransState != TRANS_NONE )
1270     return SQLITE_ERROR;
1271 
1272   assert( tree->pTransRollback == 0 );
1273   tree->eTransState = TRANS_INTRANSACTION;
1274   return SQLITE_OK;
1275 }
1276 
1277 /*
1278 ** Delete a linked list of BtRollbackOp structures.
1279 */
1280 static void deleteRollbackList(BtRollbackOp *pOp){
1281   while( pOp ){
1282     BtRollbackOp *pTmp = pOp->pNext;
1283     sqliteFree(pOp->pData);
1284     sqliteFree(pOp->pKey);
1285     sqliteFree(pOp);
1286     pOp = pTmp;
1287   }
1288 }
1289 
1290 static int memRbtreeCommit(Rbtree* tree){
1291   /* Just delete pTransRollback and pCheckRollback */
1292   deleteRollbackList(tree->pCheckRollback);
1293   deleteRollbackList(tree->pTransRollback);
1294   tree->pTransRollback = 0;
1295   tree->pCheckRollback = 0;
1296   tree->pCheckRollbackTail = 0;
1297   tree->eTransState = TRANS_NONE;
1298   return SQLITE_OK;
1299 }
1300 
1301 /*
1302  * Close the supplied Rbtree. Delete everything associated with it.
1303  */
1304 static int memRbtreeClose(Rbtree* tree)
1305 {
1306   HashElem *p;
1307   memRbtreeCommit(tree);
1308   while( (p=sqliteHashFirst(&tree->tblHash))!=0 ){
1309     tree->eTransState = TRANS_ROLLBACK;
1310     memRbtreeDropTable(tree, sqliteHashKeysize(p));
1311   }
1312   sqliteHashClear(&tree->tblHash);
1313   sqliteFree(tree);
1314   return SQLITE_OK;
1315 }
1316 
1317 /*
1318  * Execute and delete the supplied rollback-list on pRbtree.
1319  */
1320 static void execute_rollback_list(Rbtree *pRbtree, BtRollbackOp *pList)
1321 {
1322   BtRollbackOp *pTmp;
1323   RbtCursor cur;
1324   int res;
1325 
1326   cur.pRbtree = pRbtree;
1327   cur.wrFlag = 1;
1328   while( pList ){
1329     switch( pList->eOp ){
1330       case ROLLBACK_INSERT:
1331         cur.pTree  = sqliteHashFind( &pRbtree->tblHash, 0, pList->iTab );
1332         assert(cur.pTree);
1333         cur.iTree  = pList->iTab;
1334         cur.eSkip  = SKIP_NONE;
1335         memRbtreeInsert( &cur, pList->pKey,
1336             pList->nKey, pList->pData, pList->nData );
1337         break;
1338       case ROLLBACK_DELETE:
1339         cur.pTree  = sqliteHashFind( &pRbtree->tblHash, 0, pList->iTab );
1340         assert(cur.pTree);
1341         cur.iTree  = pList->iTab;
1342         cur.eSkip  = SKIP_NONE;
1343         memRbtreeMoveto(&cur, pList->pKey, pList->nKey, &res);
1344         assert(res == 0);
1345         memRbtreeDelete( &cur );
1346         break;
1347       case ROLLBACK_CREATE:
1348         btreeCreateTable(pRbtree, pList->iTab);
1349         break;
1350       case ROLLBACK_DROP:
1351         memRbtreeDropTable(pRbtree, pList->iTab);
1352         break;
1353       default:
1354         assert(0);
1355     }
1356     sqliteFree(pList->pKey);
1357     sqliteFree(pList->pData);
1358     pTmp = pList->pNext;
1359     sqliteFree(pList);
1360     pList = pTmp;
1361   }
1362 }
1363 
1364 static int memRbtreeRollback(Rbtree* tree)
1365 {
1366   tree->eTransState = TRANS_ROLLBACK;
1367   execute_rollback_list(tree, tree->pCheckRollback);
1368   execute_rollback_list(tree, tree->pTransRollback);
1369   tree->pTransRollback = 0;
1370   tree->pCheckRollback = 0;
1371   tree->pCheckRollbackTail = 0;
1372   tree->eTransState = TRANS_NONE;
1373   return SQLITE_OK;
1374 }
1375 
1376 static int memRbtreeBeginCkpt(Rbtree* tree)
1377 {
1378   if( tree->eTransState != TRANS_INTRANSACTION )
1379     return SQLITE_ERROR;
1380 
1381   assert( tree->pCheckRollback == 0 );
1382   assert( tree->pCheckRollbackTail == 0 );
1383   tree->eTransState = TRANS_INCHECKPOINT;
1384   return SQLITE_OK;
1385 }
1386 
1387 static int memRbtreeCommitCkpt(Rbtree* tree)
1388 {
1389   if( tree->eTransState == TRANS_INCHECKPOINT ){
1390     if( tree->pCheckRollback ){
1391       tree->pCheckRollbackTail->pNext = tree->pTransRollback;
1392       tree->pTransRollback = tree->pCheckRollback;
1393       tree->pCheckRollback = 0;
1394       tree->pCheckRollbackTail = 0;
1395     }
1396     tree->eTransState = TRANS_INTRANSACTION;
1397   }
1398   return SQLITE_OK;
1399 }
1400 
1401 static int memRbtreeRollbackCkpt(Rbtree* tree)
1402 {
1403   if( tree->eTransState != TRANS_INCHECKPOINT ) return SQLITE_OK;
1404   tree->eTransState = TRANS_ROLLBACK;
1405   execute_rollback_list(tree, tree->pCheckRollback);
1406   tree->pCheckRollback = 0;
1407   tree->pCheckRollbackTail = 0;
1408   tree->eTransState = TRANS_INTRANSACTION;
1409   return SQLITE_OK;
1410 }
1411 
1412 #ifdef SQLITE_TEST
1413 static int memRbtreePageDump(Rbtree* tree, int pgno, int rec)
1414 {
1415   assert(!"Cannot call sqliteRbtreePageDump");
1416   return SQLITE_OK;
1417 }
1418 
1419 static int memRbtreeCursorDump(RbtCursor* pCur, int* aRes)
1420 {
1421   assert(!"Cannot call sqliteRbtreeCursorDump");
1422   return SQLITE_OK;
1423 }
1424 #endif
1425 
1426 static struct Pager *memRbtreePager(Rbtree* tree)
1427 {
1428   return 0;
1429 }
1430 
1431 /*
1432 ** Return the full pathname of the underlying database file.
1433 */
1434 static const char *memRbtreeGetFilename(Rbtree *pBt){
1435   return 0;  /* A NULL return indicates there is no underlying file */
1436 }
1437 
1438 /*
1439 ** The copy file function is not implemented for the in-memory database
1440 */
1441 static int memRbtreeCopyFile(Rbtree *pBt, Rbtree *pBt2){
1442   return SQLITE_INTERNAL;  /* Not implemented */
1443 }
1444 
1445 static BtOps sqliteRbtreeOps = {
1446     (int(*)(Btree*)) memRbtreeClose,
1447     (int(*)(Btree*,int)) memRbtreeSetCacheSize,
1448     (int(*)(Btree*,int)) memRbtreeSetSafetyLevel,
1449     (int(*)(Btree*)) memRbtreeBeginTrans,
1450     (int(*)(Btree*)) memRbtreeCommit,
1451     (int(*)(Btree*)) memRbtreeRollback,
1452     (int(*)(Btree*)) memRbtreeBeginCkpt,
1453     (int(*)(Btree*)) memRbtreeCommitCkpt,
1454     (int(*)(Btree*)) memRbtreeRollbackCkpt,
1455     (int(*)(Btree*,int*)) memRbtreeCreateTable,
1456     (int(*)(Btree*,int*)) memRbtreeCreateTable,
1457     (int(*)(Btree*,int)) memRbtreeDropTable,
1458     (int(*)(Btree*,int)) memRbtreeClearTable,
1459     (int(*)(Btree*,int,int,BtCursor**)) memRbtreeCursor,
1460     (int(*)(Btree*,int*)) memRbtreeGetMeta,
1461     (int(*)(Btree*,int*)) memRbtreeUpdateMeta,
1462     (char*(*)(Btree*,int*,int)) memRbtreeIntegrityCheck,
1463     (const char*(*)(Btree*)) memRbtreeGetFilename,
1464     (int(*)(Btree*,Btree*)) memRbtreeCopyFile,
1465     (struct Pager*(*)(Btree*)) memRbtreePager,
1466 #ifdef SQLITE_TEST
1467     (int(*)(Btree*,int,int)) memRbtreePageDump,
1468 #endif
1469 };
1470 
1471 static BtCursorOps sqliteRbtreeCursorOps = {
1472     (int(*)(BtCursor*,const void*,int,int*)) memRbtreeMoveto,
1473     (int(*)(BtCursor*)) memRbtreeDelete,
1474     (int(*)(BtCursor*,const void*,int,const void*,int)) memRbtreeInsert,
1475     (int(*)(BtCursor*,int*)) memRbtreeFirst,
1476     (int(*)(BtCursor*,int*)) memRbtreeLast,
1477     (int(*)(BtCursor*,int*)) memRbtreeNext,
1478     (int(*)(BtCursor*,int*)) memRbtreePrevious,
1479     (int(*)(BtCursor*,int*)) memRbtreeKeySize,
1480     (int(*)(BtCursor*,int,int,char*)) memRbtreeKey,
1481     (int(*)(BtCursor*,const void*,int,int,int*)) memRbtreeKeyCompare,
1482     (int(*)(BtCursor*,int*)) memRbtreeDataSize,
1483     (int(*)(BtCursor*,int,int,char*)) memRbtreeData,
1484     (int(*)(BtCursor*)) memRbtreeCloseCursor,
1485 #ifdef SQLITE_TEST
1486     (int(*)(BtCursor*,int*)) memRbtreeCursorDump,
1487 #endif
1488 
1489 };
1490 
1491 #endif /* SQLITE_OMIT_INMEMORYDB */
1492