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