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