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 */
checkReadLocks(RbtCursor * pCur)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 */
key_compare(void const * pKey1,int nKey1,void const * pKey2,int nKey2)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 */
leftRotate(BtRbTree * pTree,BtRbNode * pX)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 */
rightRotate(BtRbTree * pTree,BtRbNode * pX)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 */
append_val(char * orig,char const * val)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 */
append_node(char * orig,BtRbNode * pNode,int indent)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 */
print_node(BtRbNode * pNode)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 */
check_redblack_tree(BtRbTree * tree,char ** msg)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 */
do_insert_balancing(BtRbTree * pTree,BtRbNode * pX)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
do_delete_balancing(BtRbTree * pTree,BtRbNode * pX,BtRbNode * pParent)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 */
btreeCreateTable(Rbtree * pRbtree,int n)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 */
btreeLogRollbackOp(Rbtree * pRbtree,BtRollbackOp * pRollbackOp)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
sqliteRbtreeOpen(const char * zFilename,int mode,int nPg,Btree ** ppBtree)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 */
memRbtreeCreateTable(Rbtree * tree,int * n)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 */
memRbtreeDropTable(Rbtree * tree,int n)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
memRbtreeKeyCompare(RbtCursor * pCur,const void * pKey,int nKey,int nIgnore,int * pRes)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 */
memRbtreeCursor(Rbtree * tree,int iTable,int wrFlag,RbtCursor ** ppCur)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 */
memRbtreeInsert(RbtCursor * pCur,const void * pKey,int nKey,const void * pDataInput,int nData)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 */
memRbtreeMoveto(RbtCursor * pCur,const void * pKey,int nKey,int * pRes)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 */
memRbtreeDelete(RbtCursor * pCur)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 */
memRbtreeClearTable(Rbtree * tree,int n)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
memRbtreeFirst(RbtCursor * pCur,int * pRes)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
memRbtreeLast(RbtCursor * pCur,int * pRes)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 */
memRbtreeNext(RbtCursor * pCur,int * pRes)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
memRbtreePrevious(RbtCursor * pCur,int * pRes)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
memRbtreeKeySize(RbtCursor * pCur,int * pSize)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
memRbtreeKey(RbtCursor * pCur,int offset,int amt,char * zBuf)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
memRbtreeDataSize(RbtCursor * pCur,int * pSize)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
memRbtreeData(RbtCursor * pCur,int offset,int amt,char * zBuf)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
memRbtreeCloseCursor(RbtCursor * pCur)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
memRbtreeGetMeta(Rbtree * tree,int * aMeta)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
memRbtreeUpdateMeta(Rbtree * tree,int * aMeta)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 */
memRbtreeIntegrityCheck(Rbtree * tree,int * aRoot,int nRoot)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
memRbtreeSetCacheSize(Rbtree * tree,int sz)1258 static int memRbtreeSetCacheSize(Rbtree* tree, int sz)
1259 {
1260 return SQLITE_OK;
1261 }
1262
memRbtreeSetSafetyLevel(Rbtree * pBt,int level)1263 static int memRbtreeSetSafetyLevel(Rbtree *pBt, int level){
1264 return SQLITE_OK;
1265 }
1266
memRbtreeBeginTrans(Rbtree * tree)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 */
deleteRollbackList(BtRollbackOp * pOp)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
memRbtreeCommit(Rbtree * tree)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 */
memRbtreeClose(Rbtree * tree)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 */
execute_rollback_list(Rbtree * pRbtree,BtRollbackOp * pList)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
memRbtreeRollback(Rbtree * tree)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
memRbtreeBeginCkpt(Rbtree * tree)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
memRbtreeCommitCkpt(Rbtree * tree)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
memRbtreeRollbackCkpt(Rbtree * tree)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
memRbtreePageDump(Rbtree * tree,int pgno,int rec)1413 static int memRbtreePageDump(Rbtree* tree, int pgno, int rec)
1414 {
1415 assert(!"Cannot call sqliteRbtreePageDump");
1416 return SQLITE_OK;
1417 }
1418
memRbtreeCursorDump(RbtCursor * pCur,int * aRes)1419 static int memRbtreeCursorDump(RbtCursor* pCur, int* aRes)
1420 {
1421 assert(!"Cannot call sqliteRbtreeCursorDump");
1422 return SQLITE_OK;
1423 }
1424 #endif
1425
memRbtreePager(Rbtree * tree)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 */
memRbtreeGetFilename(Rbtree * pBt)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 */
memRbtreeCopyFile(Rbtree * pBt,Rbtree * pBt2)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