Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Factor out btree test logic into a separate test_btree.c file. (CVS 3928) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
d51274f1cc3a75f6a03e90259ce829ac |
User & Date: | drh 2007-05-05 18:39:25.000 |
Context
2007-05-05
| ||
18:49 | Fix a header problem introduced in the previous check-in. (CVS 3929) (check-in: bece7a6bae user: drh tags: trunk) | |
18:39 | Factor out btree test logic into a separate test_btree.c file. (CVS 3928) (check-in: d51274f1cc user: drh tags: trunk) | |
12:06 | Fix a sprintf() problem introduced by (3916). (CVS 3927) (check-in: 54a1d275aa user: drh tags: trunk) | |
Changes
Changes to Makefile.in.
︙ | ︙ | |||
220 221 222 223 224 225 226 227 228 229 230 231 232 233 | $(TOP)/src/test5.c \ $(TOP)/src/test6.c \ $(TOP)/src/test7.c \ $(TOP)/src/test8.c \ $(TOP)/src/test9.c \ $(TOP)/src/test_autoext.c \ $(TOP)/src/test_async.c \ $(TOP)/src/test_hexio.c \ $(TOP)/src/test_md5.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/utf.c \ $(TOP)/src/util.c \ | > | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | $(TOP)/src/test5.c \ $(TOP)/src/test6.c \ $(TOP)/src/test7.c \ $(TOP)/src/test8.c \ $(TOP)/src/test9.c \ $(TOP)/src/test_autoext.c \ $(TOP)/src/test_async.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_hexio.c \ $(TOP)/src/test_md5.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/utf.c \ $(TOP)/src/util.c \ |
︙ | ︙ |
Changes to main.mk.
︙ | ︙ | |||
176 177 178 179 180 181 182 183 184 185 186 187 188 189 | $(TOP)/src/test5.c \ $(TOP)/src/test6.c \ $(TOP)/src/test7.c \ $(TOP)/src/test8.c \ $(TOP)/src/test9.c \ $(TOP)/src/test_autoext.c \ $(TOP)/src/test_async.c \ $(TOP)/src/test_hexio.c \ $(TOP)/src/test_md5.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/utf.c \ $(TOP)/src/util.c \ | > | 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | $(TOP)/src/test5.c \ $(TOP)/src/test6.c \ $(TOP)/src/test7.c \ $(TOP)/src/test8.c \ $(TOP)/src/test9.c \ $(TOP)/src/test_autoext.c \ $(TOP)/src/test_async.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_hexio.c \ $(TOP)/src/test_md5.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/utf.c \ $(TOP)/src/util.c \ |
︙ | ︙ |
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** $Id: btree.c,v 1.377 2007/05/05 18:39:25 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. ** Including a description of file format and an overview of operation. */ #include "btreeInt.h" |
︙ | ︙ | |||
294 295 296 297 298 299 300 | ** at most one effective restoreOrClearCursorPosition() call after each ** saveCursorPosition(). ** ** If the second argument argument - doSeek - is false, then instead of ** returning the cursor to it's saved position, any saved position is deleted ** and the cursor state set to CURSOR_INVALID. */ | | | > > | 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | ** at most one effective restoreOrClearCursorPosition() call after each ** saveCursorPosition(). ** ** If the second argument argument - doSeek - is false, then instead of ** returning the cursor to it's saved position, any saved position is deleted ** and the cursor state set to CURSOR_INVALID. */ int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur){ int rc; assert( pCur->eState==CURSOR_REQUIRESEEK ); #ifndef SQLITE_OMIT_INCRBLOB if( pCur->isIncrblobHandle ){ return SQLITE_ABORT; } #endif pCur->eState = CURSOR_INVALID; rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &pCur->skip); if( rc==SQLITE_OK ){ sqliteFree(pCur->pKey); pCur->pKey = 0; assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID ); } return rc; } #define restoreOrClearCursorPosition(p) \ (p->eState==CURSOR_REQUIRESEEK ? \ sqlite3BtreeRestoreOrClearCursorPosition(p) : \ SQLITE_OK) #ifndef SQLITE_OMIT_AUTOVACUUM /* ** Given a page number of a regular database page, return the page ** number for the pointer-map page that contains the entry for the ** input page number. */ |
︙ | ︙ | |||
413 414 415 416 417 418 419 | /* ** Given a btree page and a cell index (0 means the first cell on ** the page, 1 means the second cell, and so forth) return a pointer ** to the cell content. ** ** This routine works only for pages that do not contain overflow cells. */ | | | | | | | | | 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 | /* ** Given a btree page and a cell index (0 means the first cell on ** the page, 1 means the second cell, and so forth) return a pointer ** to the cell content. ** ** This routine works only for pages that do not contain overflow cells. */ u8 *sqlite3BtreeFindCell(MemPage *pPage, int iCell){ u8 *data = pPage->aData; assert( iCell>=0 ); assert( iCell<get2byte(&data[pPage->hdrOffset+3]) ); return data + get2byte(&data[pPage->cellOffset+2*iCell]); } /* ** This a more complex version of sqlite3BtreeFindCell() that works for ** pages that do contain overflow cells. See insert */ static u8 *findOverflowCell(MemPage *pPage, int iCell){ int i; for(i=pPage->nOverflow-1; i>=0; i--){ int k; struct _OvflCell *pOvfl; pOvfl = &pPage->aOvfl[i]; k = pOvfl->idx; if( k<=iCell ){ if( k==iCell ){ return pOvfl->pCell; } iCell--; } } return sqlite3BtreeFindCell(pPage, iCell); } /* ** Parse a cell content block and fill in the CellInfo structure. There ** are two versions of this function. sqlite3BtreeParseCell() takes a ** cell index as the second argument and sqlite3BtreeParseCellPtr() ** takes a pointer to the body of the cell as its second argument. */ void sqlite3BtreeParseCellPtr( MemPage *pPage, /* Page containing the cell */ u8 *pCell, /* Pointer to the cell text. */ CellInfo *pInfo /* Fill in this structure */ ){ int n; /* Number bytes in cell content header */ u32 nPayload; /* Number of bytes of cell payload */ |
︙ | ︙ | |||
513 514 515 516 517 518 519 | }else{ pInfo->nLocal = minLocal; } pInfo->iOverflow = pInfo->nLocal + n; pInfo->nSize = pInfo->iOverflow + 4; } } | | | | | | | 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 | }else{ pInfo->nLocal = minLocal; } pInfo->iOverflow = pInfo->nLocal + n; pInfo->nSize = pInfo->iOverflow + 4; } } void sqlite3BtreeParseCell( MemPage *pPage, /* Page containing the cell */ int iCell, /* The cell index. First cell is 0 */ CellInfo *pInfo /* Fill in this structure */ ){ sqlite3BtreeParseCellPtr(pPage, sqlite3BtreeFindCell(pPage, iCell), pInfo); } /* ** Compute the total number of bytes that a Cell needs in the cell ** data area of the btree-page. The return number includes the cell ** data header and the local payload, but not any overflow page or ** the space used by the cell pointer. */ #ifndef NDEBUG static int cellSize(MemPage *pPage, int iCell){ CellInfo info; sqlite3BtreeParseCell(pPage, iCell, &info); return info.nSize; } #endif static int cellSizePtr(MemPage *pPage, u8 *pCell){ CellInfo info; sqlite3BtreeParseCellPtr(pPage, pCell, &info); return info.nSize; } #ifndef SQLITE_OMIT_AUTOVACUUM /* ** If the cell pCell, part of page pPage contains a pointer ** to an overflow page, insert an entry into the pointer-map ** for the overflow page. */ static int ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell){ if( pCell ){ CellInfo info; sqlite3BtreeParseCellPtr(pPage, pCell, &info); assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload ); if( (info.nData+(pPage->intKey?0:info.nKey))>info.nLocal ){ Pgno ovfl = get4byte(&pCell[info.iOverflow]); return ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno); } } return SQLITE_OK; |
︙ | ︙ | |||
798 799 800 801 802 803 804 | ** ** Return SQLITE_OK on success. If we see that the page does ** not contain a well-formed database page, then return ** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not ** guarantee that the page is well-formed. It only shows that ** we failed to detect any corruption. */ | | | 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 | ** ** Return SQLITE_OK on success. If we see that the page does ** not contain a well-formed database page, then return ** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not ** guarantee that the page is well-formed. It only shows that ** we failed to detect any corruption. */ int sqlite3BtreeInitPage( MemPage *pPage, /* The page to be initialized */ MemPage *pParent /* The parent. Might be NULL */ ){ int pc; /* Address of a freeblock within pPage->aData[] */ int hdr; /* Offset to beginning of page header */ u8 *data; /* Equal to pPage->aData */ BtShared *pBt; /* The main btree structure */ |
︙ | ︙ | |||
911 912 913 914 915 916 917 | ** If the noContent flag is set, it means that we do not care about ** the content of the page at this time. So do not go to the disk ** to fetch the content. Just fill in the content with zeros for now. ** If in the future we call sqlite3PagerWrite() on this page, that ** means we have started to be concerned about content and the disk ** read should occur at that point. */ | > | > > > > | | | | | 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 | ** If the noContent flag is set, it means that we do not care about ** the content of the page at this time. So do not go to the disk ** to fetch the content. Just fill in the content with zeros for now. ** If in the future we call sqlite3PagerWrite() on this page, that ** means we have started to be concerned about content and the disk ** read should occur at that point. */ int sqlite3BtreeGetPage( BtShared *pBt, /* The btree */ Pgno pgno, /* Number of the page to fetch */ MemPage **ppPage, /* Return the page in this parameter */ int noContent /* Do not load page content if true */ ){ int rc; MemPage *pPage; DbPage *pDbPage; rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, noContent); if( rc ) return rc; pPage = (MemPage *)sqlite3PagerGetExtra(pDbPage); pPage->aData = sqlite3PagerGetData(pDbPage); pPage->pDbPage = pDbPage; pPage->pBt = pBt; pPage->pgno = pgno; pPage->hdrOffset = pPage->pgno==1 ? 100 : 0; *ppPage = pPage; return SQLITE_OK; } /* ** Get a page from the pager and initialize it. This routine ** is just a convenience wrapper around separate calls to ** sqlite3BtreeGetPage() and sqlite3BtreeInitPage(). */ static int getAndInitPage( BtShared *pBt, /* The database file */ Pgno pgno, /* Number of the page to get */ MemPage **ppPage, /* Write the page pointer here */ MemPage *pParent /* Parent of the page */ ){ int rc; if( pgno==0 ){ return SQLITE_CORRUPT_BKPT; } rc = sqlite3BtreeGetPage(pBt, pgno, ppPage, 0); if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){ rc = sqlite3BtreeInitPage(*ppPage, pParent); } return rc; } /* ** Release a MemPage. This should be called once for each prior ** call to sqlite3BtreeGetPage. */ static void releasePage(MemPage *pPage){ if( pPage ){ assert( pPage->aData ); assert( pPage->pBt ); assert( &pPage->aData[pPage->pBt->pageSize]==(unsigned char*)pPage ); sqlite3PagerUnref(pPage->pDbPage); |
︙ | ︙ | |||
994 995 996 997 998 999 1000 | */ static void pageReinit(DbPage *pData, int pageSize){ MemPage *pPage; assert( (pageSize & 7)==0 ); pPage = (MemPage *)sqlite3PagerGetExtra(pData); if( pPage->isInit ){ pPage->isInit = 0; | | | 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 | */ static void pageReinit(DbPage *pData, int pageSize){ MemPage *pPage; assert( (pageSize & 7)==0 ); pPage = (MemPage *)sqlite3PagerGetExtra(pData); if( pPage->isInit ){ pPage->isInit = 0; sqlite3BtreeInitPage(pPage, pPage->pParent); } } /* ** Open a database file. ** ** zFilename is the name of the database file. If zFilename is NULL |
︙ | ︙ | |||
1375 1376 1377 1378 1379 1380 1381 | ** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM ** is returned if we run out of memory. */ static int lockBtree(BtShared *pBt){ int rc, pageSize; MemPage *pPage1; if( pBt->pPage1 ) return SQLITE_OK; | | | 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 | ** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM ** is returned if we run out of memory. */ static int lockBtree(BtShared *pBt){ int rc, pageSize; MemPage *pPage1; if( pBt->pPage1 ) return SQLITE_OK; rc = sqlite3BtreeGetPage(pBt, 1, &pPage1, 0); if( rc!=SQLITE_OK ) return rc; /* Do some checking to help insure the file we opened really is ** a valid database file. */ rc = SQLITE_NOTADB; |
︙ | ︙ | |||
1637 1638 1639 1640 1641 1642 1643 | int i; /* Counter variable */ int nCell; /* Number of cells in page pPage */ int rc = SQLITE_OK; /* Return code */ BtShared *pBt = pPage->pBt; int isInitOrig = pPage->isInit; Pgno pgno = pPage->pgno; | | | | 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 | int i; /* Counter variable */ int nCell; /* Number of cells in page pPage */ int rc = SQLITE_OK; /* Return code */ BtShared *pBt = pPage->pBt; int isInitOrig = pPage->isInit; Pgno pgno = pPage->pgno; sqlite3BtreeInitPage(pPage, 0); nCell = pPage->nCell; for(i=0; i<nCell; i++){ u8 *pCell = sqlite3BtreeFindCell(pPage, i); rc = ptrmapPutOvflPtr(pPage, pCell); if( rc!=SQLITE_OK ){ goto set_child_ptrmaps_out; } if( !pPage->leaf ){ |
︙ | ︙ | |||
1692 1693 1694 1695 1696 1697 1698 | } put4byte(pPage->aData, iTo); }else{ int isInitOrig = pPage->isInit; int i; int nCell; | | | | | 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 | } put4byte(pPage->aData, iTo); }else{ int isInitOrig = pPage->isInit; int i; int nCell; sqlite3BtreeInitPage(pPage, 0); nCell = pPage->nCell; for(i=0; i<nCell; i++){ u8 *pCell = sqlite3BtreeFindCell(pPage, i); if( eType==PTRMAP_OVERFLOW1 ){ CellInfo info; sqlite3BtreeParseCellPtr(pPage, pCell, &info); if( info.iOverflow ){ if( iFrom==get4byte(&pCell[info.iOverflow]) ){ put4byte(&pCell[info.iOverflow], iTo); break; } } }else{ |
︙ | ︙ | |||
1784 1785 1786 1787 1788 1789 1790 | } /* Fix the database pointer on page iPtrPage that pointed at iDbPage so ** that it points at iFreePage. Also fix the pointer map entry for ** iPtrPage. */ if( eType!=PTRMAP_ROOTPAGE ){ | | | 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 | } /* Fix the database pointer on page iPtrPage that pointed at iDbPage so ** that it points at iFreePage. Also fix the pointer map entry for ** iPtrPage. */ if( eType!=PTRMAP_ROOTPAGE ){ rc = sqlite3BtreeGetPage(pBt, iPtrPage, &pPtrPage, 0); if( rc!=SQLITE_OK ){ return rc; } rc = sqlite3PagerWrite(pPtrPage->pDbPage); if( rc!=SQLITE_OK ){ releasePage(pPtrPage); return rc; |
︙ | ︙ | |||
1867 1868 1869 1870 1871 1872 1873 | assert( iFreePg==iLastPg ); releasePage(pFreePg); } } else { Pgno iFreePg; /* Index of free page to move pLastPg to */ MemPage *pLastPg; | | | 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 | assert( iFreePg==iLastPg ); releasePage(pFreePg); } } else { Pgno iFreePg; /* Index of free page to move pLastPg to */ MemPage *pLastPg; rc = sqlite3BtreeGetPage(pBt, iLastPg, &pLastPg, 0); if( rc!=SQLITE_OK ){ return rc; } /* If nFin is zero, this loop runs exactly once and page pLastPg ** is swapped with the first free page pulled off the free list. ** |
︙ | ︙ | |||
2128 2129 2130 2131 2132 2133 2134 | for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ if( pCur->wrFlag ) r++; } return r; } #endif | < < < < < < < < < < < < < < < < < < < | 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 | for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ if( pCur->wrFlag ) r++; } return r; } #endif /* ** Rollback the transaction in progress. All cursors will be ** invalided by this operation. Any attempt to use a cursor ** that was open at the beginning of this operation will result ** in an error. ** ** This will release the write lock on the database file. If there |
︙ | ︙ | |||
2196 2197 2198 2199 2200 2201 2202 | assert( TRANS_WRITE==pBt->inTransaction ); rc2 = sqlite3PagerRollback(pBt->pPager); if( rc2!=SQLITE_OK ){ rc = rc2; } /* The rollback may have destroyed the pPage1->aData value. So | | | | | 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 | assert( TRANS_WRITE==pBt->inTransaction ); rc2 = sqlite3PagerRollback(pBt->pPager); if( rc2!=SQLITE_OK ){ rc = rc2; } /* The rollback may have destroyed the pPage1->aData value. So ** call sqlite3BtreeGetPage() on page 1 again to make ** sure pPage1->aData is set correctly. */ if( sqlite3BtreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){ releasePage(pPage1); } assert( countWriteCursors(pBt)==0 ); pBt->inTransaction = TRANS_READ; } if( p->inTrans!=TRANS_NONE ){ |
︙ | ︙ | |||
2448 2449 2450 2451 2452 2453 2454 | return SQLITE_OK; } /* ** Make a temporary cursor by filling in the fields of pTempCur. ** The temporary cursor is not on the cursor list for the Btree. */ | | | | | | | | 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 | return SQLITE_OK; } /* ** Make a temporary cursor by filling in the fields of pTempCur. ** The temporary cursor is not on the cursor list for the Btree. */ void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur){ memcpy(pTempCur, pCur, sizeof(*pCur)); pTempCur->pNext = 0; pTempCur->pPrev = 0; if( pTempCur->pPage ){ sqlite3PagerRef(pTempCur->pPage->pDbPage); } } /* ** Delete a temporary cursor such as was made by the CreateTemporaryCursor() ** function above. */ void sqlite3BtreeReleaseTempCursor(BtCursor *pCur){ if( pCur->pPage ){ sqlite3PagerUnref(pCur->pPage->pDbPage); } } /* ** Make sure the BtCursor.info field of the given cursor is valid. ** If it is not already valid, call sqlite3BtreeParseCell() to fill it in. ** ** BtCursor.info is a cache of the information in the current cell. ** Using this cache reduces the number of calls to sqlite3BtreeParseCell(). */ static void getCellInfo(BtCursor *pCur){ if( pCur->info.nSize==0 ){ sqlite3BtreeParseCell(pCur->pPage, pCur->idx, &pCur->info); }else{ #ifndef NDEBUG CellInfo info; memset(&info, 0, sizeof(info)); sqlite3BtreeParseCell(pCur->pPage, pCur->idx, &info); assert( memcmp(&info, &pCur->info, sizeof(info))==0 ); #endif } } /* ** Set *pSize to the size of the buffer needed to hold the value of |
︙ | ︙ | |||
2564 2565 2566 2567 2568 2569 2570 | /* One of these must not be NULL. Otherwise, why call this function? */ assert(ppPage || pPgnoNext); /* If pPgnoNext is NULL, then this function is being called to obtain ** a MemPage* reference only. No page-data is required in this case. */ if( !pPgnoNext ){ | | | 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 | /* One of these must not be NULL. Otherwise, why call this function? */ assert(ppPage || pPgnoNext); /* If pPgnoNext is NULL, then this function is being called to obtain ** a MemPage* reference only. No page-data is required in this case. */ if( !pPgnoNext ){ return sqlite3BtreeGetPage(pBt, ovfl, ppPage, 1); } #ifndef SQLITE_OMIT_AUTOVACUUM /* Try to find the next page in the overflow list using the ** autovacuum pointer-map pages. Guess that the next page in ** the overflow list is page number (ovfl+1). If that guess turns ** out to be wrong, fall back to loading the data of page |
︙ | ︙ | |||
2598 2599 2600 2601 2602 2603 2604 | } } #endif if( next==0 || ppPage ){ MemPage *pPage = 0; | | | 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 | } } #endif if( next==0 || ppPage ){ MemPage *pPage = 0; rc = sqlite3BtreeGetPage(pBt, ovfl, &pPage, next!=0); assert(rc==SQLITE_OK || pPage==0); if( next==0 && rc==SQLITE_OK ){ next = get4byte(pPage->aData); } if( ppPage ){ *ppPage = pPage; |
︙ | ︙ | |||
2677 2678 2679 2680 2681 2682 2683 | ** the cursor is moved to a different row. Additionally, in auto-vacuum ** mode, the following events may invalidate an overflow page-list cache. ** ** * An incremental vacuum, ** * A commit in auto_vacuum="full" mode, ** * Creating a table (may require moving an overflow page). */ | < | 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 | ** the cursor is moved to a different row. Additionally, in auto-vacuum ** mode, the following events may invalidate an overflow page-list cache. ** ** * An incremental vacuum, ** * A commit in auto_vacuum="full" mode, ** * Creating a table (may require moving an overflow page). */ static int accessPayload( BtCursor *pCur, /* Cursor pointing to entry to read from */ int offset, /* Begin reading this far into payload */ int amt, /* Read this many bytes */ unsigned char *pBuf, /* Write the bytes into this buffer */ int skipKey, /* offset begins at data if this is true */ int eOp /* zero to read. non-zero to write. */ |
︙ | ︙ | |||
2830 2831 2832 2833 2834 2835 2836 | assert( pCur->eState==CURSOR_VALID ); assert( pCur->pPage!=0 ); if( pCur->pPage->intKey ){ return SQLITE_CORRUPT_BKPT; } assert( pCur->pPage->intKey==0 ); assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell ); | | | | | 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 | assert( pCur->eState==CURSOR_VALID ); assert( pCur->pPage!=0 ); if( pCur->pPage->intKey ){ return SQLITE_CORRUPT_BKPT; } assert( pCur->pPage->intKey==0 ); assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell ); rc = accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0, 0); } return rc; } /* ** Read part of the data associated with cursor pCur. Exactly ** "amt" bytes will be transfered into pBuf[]. The transfer ** begins at "offset". ** ** Return SQLITE_OK on success or an error code if anything goes ** wrong. An error is returned if "offset+amt" is larger than ** the available payload. */ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ int rc = restoreOrClearCursorPosition(pCur); if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_VALID ); assert( pCur->pPage!=0 ); assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell ); rc = accessPayload(pCur, offset, amt, pBuf, 1, 0); } return rc; } /* ** Return a pointer to payload information from the entry that the ** pCur cursor is pointing to. The pointer is to the beginning of ** the key if skipKey==0 and it points to the beginning of data if ** skipKey==1. The number of bytes of available key/data is written ** into *pAmt. If *pAmt==0, then the value returned will not be ** a valid pointer. ** ** This routine is an optimization. It is common for the entire key ** and data to fit on the local page and for there to be no overflow ** pages. When that is so, this routine can be used to access the ** key and data without making a copy. If the key and/or data spills ** onto overflow pages, then accessPayload() must be used to reassembly ** the key/data and copy it into a preallocated buffer. ** ** The pointer returned by this routine looks directly into the cached ** page of the database. The data might change or move the next time ** any btree routine is called. */ static const unsigned char *fetchPayload( |
︙ | ︙ | |||
2970 2971 2972 2973 2974 2975 2976 | ** ** The virtual root page is the root page for most tables. But ** for the table rooted on page 1, sometime the real root page ** is empty except for the right-pointer. In such cases the ** virtual root page is the page that the right-pointer of page ** 1 is pointing to. */ | | | | | 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 | ** ** The virtual root page is the root page for most tables. But ** for the table rooted on page 1, sometime the real root page ** is empty except for the right-pointer. In such cases the ** virtual root page is the page that the right-pointer of page ** 1 is pointing to. */ int sqlite3BtreeIsRootPage(MemPage *pPage){ MemPage *pParent = pPage->pParent; if( pParent==0 ) return 1; if( pParent->pgno>1 ) return 0; if( get2byte(&pParent->aData[pParent->hdrOffset+3])==0 ) return 1; return 0; } /* ** Move the cursor up to the parent page. ** ** pCur->idx is set to the cell index that contains the pointer ** to the page we are coming from. If we are coming from the ** right-most child page then pCur->idx is set to one more than ** the largest cell index. */ void sqlite3BtreeMoveToParent(BtCursor *pCur){ MemPage *pParent; MemPage *pPage; int idxParent; assert( pCur->eState==CURSOR_VALID ); pPage = pCur->pPage; assert( pPage!=0 ); assert( !sqlite3BtreeIsRootPage(pPage) ); pParent = pPage->pParent; assert( pParent!=0 ); idxParent = pPage->idxParent; sqlite3PagerRef(pParent->pDbPage); releasePage(pPage); pCur->pPage = pParent; pCur->info.nSize = 0; |
︙ | ︙ | |||
3059 3060 3061 3062 3063 3064 3065 | Pgno pgno; int rc; MemPage *pPage; assert( pCur->eState==CURSOR_VALID ); while( !(pPage = pCur->pPage)->leaf ){ assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); | | | 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 | Pgno pgno; int rc; MemPage *pPage; assert( pCur->eState==CURSOR_VALID ); while( !(pPage = pCur->pPage)->leaf ){ assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); pgno = get4byte(sqlite3BtreeFindCell(pPage, pCur->idx)); rc = moveToChild(pCur, pgno); if( rc ) return rc; } return SQLITE_OK; } /* |
︙ | ︙ | |||
3196 3197 3198 3199 3200 3201 3202 | } if( lwr<=upr ) for(;;){ void *pCellKey; i64 nCellKey; pCur->info.nSize = 0; if( pPage->intKey ){ u8 *pCell; | | | 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 | } if( lwr<=upr ) for(;;){ void *pCellKey; i64 nCellKey; pCur->info.nSize = 0; if( pPage->intKey ){ u8 *pCell; pCell = sqlite3BtreeFindCell(pPage, pCur->idx) + pPage->childPtrSize; if( pPage->hasData ){ u32 dummy; pCell += getVarint32(pCell, &dummy); } getVarint(pCell, (u64 *)&nCellKey); if( nCellKey<nKey ){ c = -1; |
︙ | ︙ | |||
3251 3252 3253 3254 3255 3256 3257 | assert( lwr==upr+1 ); assert( pPage->isInit ); if( pPage->leaf ){ chldPg = 0; }else if( lwr>=pPage->nCell ){ chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); }else{ | | | 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 | assert( lwr==upr+1 ); assert( pPage->isInit ); if( pPage->leaf ){ chldPg = 0; }else if( lwr>=pPage->nCell ){ chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); }else{ chldPg = get4byte(sqlite3BtreeFindCell(pPage, lwr)); } if( chldPg==0 ){ assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell ); if( pRes ) *pRes = c; return SQLITE_OK; } pCur->idx = lwr; |
︙ | ︙ | |||
3324 3325 3326 3327 3328 3329 3330 | rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); if( rc ) return rc; rc = moveToLeftmost(pCur); *pRes = 0; return rc; } do{ | | | | 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 | rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); if( rc ) return rc; rc = moveToLeftmost(pCur); *pRes = 0; return rc; } do{ if( sqlite3BtreeIsRootPage(pPage) ){ *pRes = 1; pCur->eState = CURSOR_INVALID; return SQLITE_OK; } sqlite3BtreeMoveToParent(pCur); pPage = pCur->pPage; }while( pCur->idx>=pPage->nCell ); *pRes = 0; if( pPage->leafData ){ rc = sqlite3BtreeNext(pCur, pRes); }else{ rc = SQLITE_OK; |
︙ | ︙ | |||
3378 3379 3380 3381 3382 3383 3384 | } pCur->skip = 0; pPage = pCur->pPage; assert( pPage->isInit ); assert( pCur->idx>=0 ); if( !pPage->leaf ){ | | | | | 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 | } pCur->skip = 0; pPage = pCur->pPage; assert( pPage->isInit ); assert( pCur->idx>=0 ); if( !pPage->leaf ){ pgno = get4byte( sqlite3BtreeFindCell(pPage, pCur->idx) ); rc = moveToChild(pCur, pgno); if( rc ) return rc; rc = moveToRightmost(pCur); }else{ while( pCur->idx==0 ){ if( sqlite3BtreeIsRootPage(pPage) ){ pCur->eState = CURSOR_INVALID; *pRes = 1; return SQLITE_OK; } sqlite3BtreeMoveToParent(pCur); pPage = pCur->pPage; } pCur->idx--; pCur->info.nSize = 0; if( pPage->leafData && !pPage->leaf ){ rc = sqlite3BtreePrevious(pCur, pRes); }else{ |
︙ | ︙ | |||
3482 3483 3484 3485 3486 3487 3488 | do { pPrevTrunk = pTrunk; if( pPrevTrunk ){ iTrunk = get4byte(&pPrevTrunk->aData[0]); }else{ iTrunk = get4byte(&pPage1->aData[32]); } | | | 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 | do { pPrevTrunk = pTrunk; if( pPrevTrunk ){ iTrunk = get4byte(&pPrevTrunk->aData[0]); }else{ iTrunk = get4byte(&pPage1->aData[32]); } rc = sqlite3BtreeGetPage(pBt, iTrunk, &pTrunk, 0); if( rc ){ pTrunk = 0; goto end_allocate_page; } k = get4byte(&pTrunk->aData[4]); if( k==0 && !searchList ){ |
︙ | ︙ | |||
3532 3533 3534 3535 3536 3537 3538 | }else{ /* The trunk page is required by the caller but it contains ** pointers to free-list leaves. The first leaf becomes a trunk ** page in this case. */ MemPage *pNewTrunk; Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); | | | 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 | }else{ /* The trunk page is required by the caller but it contains ** pointers to free-list leaves. The first leaf becomes a trunk ** page in this case. */ MemPage *pNewTrunk; Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); rc = sqlite3BtreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0); if( rc!=SQLITE_OK ){ goto end_allocate_page; } rc = sqlite3PagerWrite(pNewTrunk->pDbPage); if( rc!=SQLITE_OK ){ releasePage(pNewTrunk); goto end_allocate_page; |
︙ | ︙ | |||
3598 3599 3600 3601 3602 3603 3604 | TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d" ": %d more free pages\n", *pPgno, closest+1, k, pTrunk->pgno, n-1)); if( closest<k-1 ){ memcpy(&aData[8+closest*4], &aData[4+k*4], 4); } put4byte(&aData[4], k-1); | | | 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 | TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d" ": %d more free pages\n", *pPgno, closest+1, k, pTrunk->pgno, n-1)); if( closest<k-1 ){ memcpy(&aData[8+closest*4], &aData[4+k*4], 4); } put4byte(&aData[4], k-1); rc = sqlite3BtreeGetPage(pBt, *pPgno, ppPage, 1); if( rc==SQLITE_OK ){ sqlite3PagerDontRollback((*ppPage)->pDbPage); rc = sqlite3PagerWrite((*ppPage)->pDbPage); if( rc!=SQLITE_OK ){ releasePage(*ppPage); } } |
︙ | ︙ | |||
3643 3644 3645 3646 3647 3648 3649 | } if( pBt->nTrunc ){ pBt->nTrunc = *pPgno; } #endif assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); | | | 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 | } if( pBt->nTrunc ){ pBt->nTrunc = *pPgno; } #endif assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); rc = sqlite3BtreeGetPage(pBt, *pPgno, ppPage, 0); if( rc ) return rc; rc = sqlite3PagerWrite((*ppPage)->pDbPage); if( rc!=SQLITE_OK ){ releasePage(*ppPage); } TRACE(("ALLOCATE: %d from end of file\n", *pPgno)); } |
︙ | ︙ | |||
3712 3713 3714 3715 3716 3717 3718 | memset(pPage->aData, 0, 8); put4byte(&pPage1->aData[32], pPage->pgno); TRACE(("FREE-PAGE: %d first\n", pPage->pgno)); }else{ /* Other free pages already exist. Retrive the first trunk page ** of the freelist and find out how many leaves it has. */ MemPage *pTrunk; | | | 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 | memset(pPage->aData, 0, 8); put4byte(&pPage1->aData[32], pPage->pgno); TRACE(("FREE-PAGE: %d first\n", pPage->pgno)); }else{ /* Other free pages already exist. Retrive the first trunk page ** of the freelist and find out how many leaves it has. */ MemPage *pTrunk; rc = sqlite3BtreeGetPage(pBt, get4byte(&pPage1->aData[32]), &pTrunk, 0); if( rc ) return rc; k = get4byte(&pTrunk->aData[4]); if( k>=pBt->usableSize/4 - 8 ){ /* The trunk is full. Turn the page being freed into a new ** trunk page with no leaves. */ rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ) return rc; |
︙ | ︙ | |||
3753 3754 3755 3756 3757 3758 3759 | BtShared *pBt = pPage->pBt; CellInfo info; Pgno ovflPgno; int rc; int nOvfl; int ovflPageSize; | | | 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 | BtShared *pBt = pPage->pBt; CellInfo info; Pgno ovflPgno; int rc; int nOvfl; int ovflPageSize; sqlite3BtreeParseCellPtr(pPage, pCell, &info); if( info.iOverflow==0 ){ return SQLITE_OK; /* No overflow pages. Return without doing anything */ } ovflPgno = get4byte(&pCell[info.iOverflow]); ovflPageSize = pBt->usableSize - 4; nOvfl = (info.nPayload - info.nLocal + ovflPageSize - 1)/ovflPageSize; assert( ovflPgno==0 || nOvfl>0 ); |
︙ | ︙ | |||
3820 3821 3822 3823 3824 3825 3826 | } if( pPage->hasData ){ nHeader += putVarint(&pCell[nHeader], nData+nZero); }else{ nData = nZero = 0; } nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey); | | | 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 | } if( pPage->hasData ){ nHeader += putVarint(&pCell[nHeader], nData+nZero); }else{ nData = nZero = 0; } nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey); sqlite3BtreeParseCellPtr(pPage, pCell, &info); assert( info.nHeader==nHeader ); assert( info.nKey==nKey ); assert( info.nData==nData+nZero ); /* Fill in the payload */ nPayload = nData + nZero; if( pPage->intKey ){ |
︙ | ︙ | |||
3947 3948 3949 3950 3951 3952 3953 | int i; BtShared *pBt = pPage->pBt; int rc = SQLITE_OK; if( pPage->leaf ) return SQLITE_OK; for(i=0; i<pPage->nCell; i++){ | | | 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 | int i; BtShared *pBt = pPage->pBt; int rc = SQLITE_OK; if( pPage->leaf ) return SQLITE_OK; for(i=0; i<pPage->nCell; i++){ u8 *pCell = sqlite3BtreeFindCell(pPage, i); if( !pPage->leaf ){ rc = reparentPage(pBt, get4byte(pCell), pPage, i); if( rc!=SQLITE_OK ) return rc; } } if( !pPage->leaf ){ rc = reparentPage(pBt, get4byte(&pPage->aData[pPage->hdrOffset+8]), |
︙ | ︙ | |||
4073 4074 4075 4076 4077 4078 4079 | pPage->idxShift = 1; #ifndef SQLITE_OMIT_AUTOVACUUM if( pPage->pBt->autoVacuum ){ /* The cell may contain a pointer to an overflow page. If so, write ** the entry for the overflow page into the pointer map. */ CellInfo info; | | | 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 | pPage->idxShift = 1; #ifndef SQLITE_OMIT_AUTOVACUUM if( pPage->pBt->autoVacuum ){ /* The cell may contain a pointer to an overflow page. If so, write ** the entry for the overflow page into the pointer map. */ CellInfo info; sqlite3BtreeParseCellPtr(pPage, pCell, &info); assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload ); if( (info.nData+(pPage->intKey?0:info.nKey))>info.nLocal ){ Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]); int rc = ptrmapPut(pPage->pBt, pgnoOvfl, PTRMAP_OVERFLOW1, pPage->pgno); if( rc!=SQLITE_OK ) return rc; } } |
︙ | ︙ | |||
4201 4202 4203 4204 4205 4206 4207 | sqlite3PagerRef(pParent->pDbPage); /* pPage is currently the right-child of pParent. Change this ** so that the right-child is the new page allocated above and ** pPage is the next-to-right child. */ assert( pPage->nCell>0 ); | | > | 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 | sqlite3PagerRef(pParent->pDbPage); /* pPage is currently the right-child of pParent. Change this ** so that the right-child is the new page allocated above and ** pPage is the next-to-right child. */ assert( pPage->nCell>0 ); pCell = sqlite3BtreeFindCell(pPage, pPage->nCell-1); sqlite3BtreeParseCellPtr(pPage, pCell, &info); rc = fillInCell(pParent, parentCell, 0, info.nKey, 0, 0, 0, &parentSize); if( rc!=SQLITE_OK ){ return rc; } assert( parentSize<64 ); rc = insertCell(pParent, parentIdx, parentCell, parentSize, 0, 4); if( rc!=SQLITE_OK ){ |
︙ | ︙ | |||
4270 4271 4272 4273 4274 4275 4276 | ** ** If this routine fails for any reason, it might leave the database ** in a corrupted state. So if this routine fails, the database should ** be rolled back. */ static int balance_nonroot(MemPage *pPage){ MemPage *pParent; /* The parent of pPage */ | | | 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 | ** ** If this routine fails for any reason, it might leave the database ** in a corrupted state. So if this routine fails, the database should ** be rolled back. */ static int balance_nonroot(MemPage *pPage){ MemPage *pParent; /* The parent of pPage */ BtShared *pBt; /* The whole database */ int nCell = 0; /* Number of cells in apCell[] */ int nMaxCells = 0; /* Allocated size of apCell, szCell, aFrom. */ int nOld; /* Number of pages in apOld[] */ int nNew; /* Number of pages in apNew[] */ int nDiv; /* Number of cells in apDiv[] */ int i, j, k; /* Loop counters */ int idx; /* Index of pPage in pParent->aCell[] */ |
︙ | ︙ | |||
4350 4351 4352 4353 4354 4355 4356 | ** is the rightmost child of pParent then set idx to pParent->nCell */ if( pParent->idxShift ){ Pgno pgno; pgno = pPage->pgno; assert( pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); for(idx=0; idx<pParent->nCell; idx++){ | | | 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 | ** is the rightmost child of pParent then set idx to pParent->nCell */ if( pParent->idxShift ){ Pgno pgno; pgno = pPage->pgno; assert( pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); for(idx=0; idx<pParent->nCell; idx++){ if( get4byte(sqlite3BtreeFindCell(pParent, idx))==pgno ){ break; } } assert( idx<pParent->nCell || get4byte(&pParent->aData[pParent->hdrOffset+8])==pgno ); }else{ idx = pPage->idxParent; |
︙ | ︙ | |||
4384 4385 4386 4387 4388 4389 4390 | } if( nxDiv<0 ){ nxDiv = 0; } nDiv = 0; for(i=0, k=nxDiv; i<NB; i++, k++){ if( k<pParent->nCell ){ | | | 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 | } if( nxDiv<0 ){ nxDiv = 0; } nDiv = 0; for(i=0, k=nxDiv; i<NB; i++, k++){ if( k<pParent->nCell ){ apDiv[i] = sqlite3BtreeFindCell(pParent, k); nDiv++; assert( !pParent->leaf ); pgnoOld[i] = get4byte(apDiv[i]); }else if( k==pParent->nCell ){ pgnoOld[i] = get4byte(&pParent->aData[pParent->hdrOffset+8]); }else{ break; |
︙ | ︙ | |||
4733 4734 4735 4736 4737 4738 4739 | /* If the tree is a leaf-data tree, and the siblings are leaves, ** then there is no divider cell in apCell[]. Instead, the divider ** cell consists of the integer key for the right-most cell of ** the sibling-page assembled above only. */ CellInfo info; j--; | | | 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 | /* If the tree is a leaf-data tree, and the siblings are leaves, ** then there is no divider cell in apCell[]. Instead, the divider ** cell consists of the integer key for the right-most cell of ** the sibling-page assembled above only. */ CellInfo info; j--; sqlite3BtreeParseCellPtr(pNew, apCell[j], &info); pCell = &aSpace[iSpace]; fillInCell(pParent, pCell, 0, info.nKey, 0, 0, 0, &sz); iSpace += sz; assert( iSpace<=pBt->pageSize*5 ); pTemp = 0; }else{ pCell -= 4; |
︙ | ︙ | |||
4854 4855 4856 4857 4858 4859 4860 | ** case, then do not do the transfer. Leave page 1 empty except ** for the right-pointer to the child page. The child page becomes ** the virtual root of the tree. */ pgnoChild = get4byte(&pPage->aData[pPage->hdrOffset+8]); assert( pgnoChild>0 ); assert( pgnoChild<=sqlite3PagerPagecount(pPage->pBt->pPager) ); | | | | | | 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 | ** case, then do not do the transfer. Leave page 1 empty except ** for the right-pointer to the child page. The child page becomes ** the virtual root of the tree. */ pgnoChild = get4byte(&pPage->aData[pPage->hdrOffset+8]); assert( pgnoChild>0 ); assert( pgnoChild<=sqlite3PagerPagecount(pPage->pBt->pPager) ); rc = sqlite3BtreeGetPage(pPage->pBt, pgnoChild, &pChild, 0); if( rc ) goto end_shallow_balance; if( pPage->pgno==1 ){ rc = sqlite3BtreeInitPage(pChild, pPage); if( rc ) goto end_shallow_balance; assert( pChild->nOverflow==0 ); if( pChild->nFree>=100 ){ /* The child information will fit on the root page, so do the ** copy */ int i; zeroPage(pPage, pChild->aData[0]); for(i=0; i<pChild->nCell; i++){ apCell[i] = sqlite3BtreeFindCell(pChild,i); szCell[i] = cellSizePtr(pChild, apCell[i]); } assemblePage(pPage, pChild->nCell, apCell, szCell); /* Copy the right-pointer of the child to the parent. */ put4byte(&pPage->aData[pPage->hdrOffset+8], get4byte(&pChild->aData[pChild->hdrOffset+8])); freePage(pChild); TRACE(("BALANCE: child %d transfer to page 1\n", pChild->pgno)); }else{ /* The child has more information that will fit on the root. ** The tree is already balanced. Do nothing. */ TRACE(("BALANCE: child %d will not fit on page 1\n", pChild->pgno)); } }else{ memcpy(pPage->aData, pChild->aData, pPage->pBt->usableSize); pPage->isInit = 0; pPage->pParent = 0; rc = sqlite3BtreeInitPage(pPage, 0); assert( rc==SQLITE_OK ); freePage(pChild); TRACE(("BALANCE: transfer child %d into root %d\n", pChild->pgno, pPage->pgno)); } rc = reparentChildPages(pPage); assert( pPage->nOverflow==0 ); |
︙ | ︙ | |||
4946 4947 4948 4949 4950 4951 4952 | data = pPage->aData; hdr = pPage->hdrOffset; brk = get2byte(&data[hdr+5]); cdata = pChild->aData; memcpy(cdata, &data[hdr], pPage->cellOffset+2*pPage->nCell-hdr); memcpy(&cdata[brk], &data[brk], usableSize-brk); assert( pChild->isInit==0 ); | | | 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 | data = pPage->aData; hdr = pPage->hdrOffset; brk = get2byte(&data[hdr+5]); cdata = pChild->aData; memcpy(cdata, &data[hdr], pPage->cellOffset+2*pPage->nCell-hdr); memcpy(&cdata[brk], &data[brk], usableSize-brk); assert( pChild->isInit==0 ); rc = sqlite3BtreeInitPage(pChild, pPage); if( rc ) goto balancedeeper_out; memcpy(pChild->aOvfl, pPage->aOvfl, pPage->nOverflow*sizeof(pPage->aOvfl[0])); pChild->nOverflow = pPage->nOverflow; if( pChild->nOverflow ){ pChild->nFree = 0; } assert( pChild->nCell==pPage->nCell ); |
︙ | ︙ | |||
5009 5010 5011 5012 5013 5014 5015 | ** database connection (a database connection that shares the pager ** cache with the current connection) and that other connection ** is not in the ReadUncommmitted state, then this routine returns ** SQLITE_LOCKED. ** ** In addition to checking for read-locks (where a read-lock ** means a cursor opened with wrFlag==0) this routine also moves | | | 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 | ** database connection (a database connection that shares the pager ** cache with the current connection) and that other connection ** is not in the ReadUncommmitted state, then this routine returns ** SQLITE_LOCKED. ** ** In addition to checking for read-locks (where a read-lock ** means a cursor opened with wrFlag==0) this routine also moves ** all write cursors so that they are pointing to the ** first Cell on the root page. This is necessary because an insert ** or delete might change the number of cells on a page or delete ** a page entirely and we do not want to leave any cursors ** pointing to non-existant pages or cells. */ static int checkReadLocks(Btree *pBtree, Pgno pgnoRoot, BtCursor *pExclude){ BtCursor *p; |
︙ | ︙ | |||
5099 5100 5101 5102 5103 5104 5105 | rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew); if( rc ) goto end_insert; assert( szNew==cellSizePtr(pPage, newCell) ); assert( szNew<=MX_CELL_SIZE(pBt) ); if( loc==0 && CURSOR_VALID==pCur->eState ){ int szOld; assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); | | | 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 | rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew); if( rc ) goto end_insert; assert( szNew==cellSizePtr(pPage, newCell) ); assert( szNew<=MX_CELL_SIZE(pBt) ); if( loc==0 && CURSOR_VALID==pCur->eState ){ int szOld; assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); oldCell = sqlite3BtreeFindCell(pPage, pCur->idx); if( !pPage->leaf ){ memcpy(newCell, oldCell, 4); } szOld = cellSizePtr(pPage, oldCell); rc = clearCell(pPage, oldCell); if( rc ) goto end_insert; dropCell(pPage, pCur->idx, szOld); |
︙ | ︙ | |||
5171 5172 5173 5174 5175 5176 5177 | return rc; } /* Locate the cell within it's page and leave pCell pointing to the ** data. The clearCell() call frees any overflow pages associated with the ** cell. The cell itself is still intact. */ | | | 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 | return rc; } /* Locate the cell within it's page and leave pCell pointing to the ** data. The clearCell() call frees any overflow pages associated with the ** cell. The cell itself is still intact. */ pCell = sqlite3BtreeFindCell(pPage, pCur->idx); if( !pPage->leaf ){ pgnoChild = get4byte(pCell); } rc = clearCell(pPage, pCell); if( rc ) return rc; if( !pPage->leaf ){ |
︙ | ︙ | |||
5194 5195 5196 5197 5198 5199 5200 | unsigned char *pNext; int szNext; /* The compiler warning is wrong: szNext is always ** initialized before use. Adding an extra initialization ** to silence the compiler slows down the code. */ int notUsed; unsigned char *tempCell = 0; assert( !pPage->leafData ); | | | | | 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 | unsigned char *pNext; int szNext; /* The compiler warning is wrong: szNext is always ** initialized before use. Adding an extra initialization ** to silence the compiler slows down the code. */ int notUsed; unsigned char *tempCell = 0; assert( !pPage->leafData ); sqlite3BtreeGetTempCursor(pCur, &leafCur); rc = sqlite3BtreeNext(&leafCur, ¬Used); if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(leafCur.pPage->pDbPage); } if( rc==SQLITE_OK ){ TRACE(("DELETE: table=%d delete internal from %d replace from leaf %d\n", pCur->pgnoRoot, pPage->pgno, leafCur.pPage->pgno)); dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell)); pNext = sqlite3BtreeFindCell(leafCur.pPage, leafCur.idx); szNext = cellSizePtr(leafCur.pPage, pNext); assert( MX_CELL_SIZE(pBt)>=szNext+4 ); tempCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) ); if( tempCell==0 ){ rc = SQLITE_NOMEM; } } if( rc==SQLITE_OK ){ rc = insertCell(pPage, pCur->idx, pNext-4, szNext+4, tempCell, 0); } if( rc==SQLITE_OK ){ put4byte(findOverflowCell(pPage, pCur->idx), pgnoChild); rc = balance(pPage, 0); } if( rc==SQLITE_OK ){ dropCell(leafCur.pPage, leafCur.idx, szNext); rc = balance(leafCur.pPage, 0); } sqliteFree(tempCell); sqlite3BtreeReleaseTempCursor(&leafCur); }else{ TRACE(("DELETE: table=%d delete from leaf %d\n", pCur->pgnoRoot, pPage->pgno)); dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell)); rc = balance(pPage, 0); } if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
5312 5313 5314 5315 5316 5317 5318 | */ u8 eType; Pgno iPtrPage; releasePage(pPageMove); /* Move the page currently at pgnoRoot to pgnoMove. */ | | | 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 | */ u8 eType; Pgno iPtrPage; releasePage(pPageMove); /* Move the page currently at pgnoRoot to pgnoMove. */ rc = sqlite3BtreeGetPage(pBt, pgnoRoot, &pRoot, 0); if( rc!=SQLITE_OK ){ return rc; } rc = ptrmapGet(pBt, pgnoRoot, &eType, &iPtrPage); if( rc!=SQLITE_OK || eType==PTRMAP_ROOTPAGE || eType==PTRMAP_FREEPAGE ){ releasePage(pRoot); return rc; |
︙ | ︙ | |||
5335 5336 5337 5338 5339 5340 5341 | rc = relocatePage(pBt, pRoot, eType, iPtrPage, pgnoMove); releasePage(pRoot); /* Obtain the page at pgnoRoot */ if( rc!=SQLITE_OK ){ return rc; } | | | 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 | rc = relocatePage(pBt, pRoot, eType, iPtrPage, pgnoMove); releasePage(pRoot); /* Obtain the page at pgnoRoot */ if( rc!=SQLITE_OK ){ return rc; } rc = sqlite3BtreeGetPage(pBt, pgnoRoot, &pRoot, 0); if( rc!=SQLITE_OK ){ return rc; } rc = sqlite3PagerWrite(pRoot->pDbPage); if( rc!=SQLITE_OK ){ releasePage(pRoot); return rc; |
︙ | ︙ | |||
5394 5395 5396 5397 5398 5399 5400 | if( pgno>sqlite3PagerPagecount(pBt->pPager) ){ return SQLITE_CORRUPT_BKPT; } rc = getAndInitPage(pBt, pgno, &pPage, pParent); if( rc ) goto cleardatabasepage_out; for(i=0; i<pPage->nCell; i++){ | | | 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 | if( pgno>sqlite3PagerPagecount(pBt->pPager) ){ return SQLITE_CORRUPT_BKPT; } rc = getAndInitPage(pBt, pgno, &pPage, pParent); if( rc ) goto cleardatabasepage_out; for(i=0; i<pPage->nCell; i++){ pCell = sqlite3BtreeFindCell(pPage, i); if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(pCell), pPage->pParent, 1); if( rc ) goto cleardatabasepage_out; } rc = clearCell(pPage, pCell); if( rc ) goto cleardatabasepage_out; } |
︙ | ︙ | |||
5484 5485 5486 5487 5488 5489 5490 | ** root page. If an open cursor was using this page a problem would ** occur. */ if( pBt->pCursor ){ return SQLITE_LOCKED; } | | | 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 | ** root page. If an open cursor was using this page a problem would ** occur. */ if( pBt->pCursor ){ return SQLITE_LOCKED; } rc = sqlite3BtreeGetPage(pBt, (Pgno)iTable, &pPage, 0); if( rc ) return rc; rc = sqlite3BtreeClearTable(p, iTable); if( rc ){ releasePage(pPage); return rc; } |
︙ | ︙ | |||
5523 5524 5525 5526 5527 5528 5529 | }else{ /* The table being dropped does not have the largest root-page ** number in the database. So move the page that does into the ** gap left by the deleted root-page. */ MemPage *pMove; releasePage(pPage); | | | | 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 | }else{ /* The table being dropped does not have the largest root-page ** number in the database. So move the page that does into the ** gap left by the deleted root-page. */ MemPage *pMove; releasePage(pPage); rc = sqlite3BtreeGetPage(pBt, maxRootPgno, &pMove, 0); if( rc!=SQLITE_OK ){ return rc; } rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable); releasePage(pMove); if( rc!=SQLITE_OK ){ return rc; } rc = sqlite3BtreeGetPage(pBt, maxRootPgno, &pMove, 0); if( rc!=SQLITE_OK ){ return rc; } rc = freePage(pMove); releasePage(pMove); if( rc!=SQLITE_OK ){ return rc; |
︙ | ︙ | |||
5650 5651 5652 5653 5654 5655 5656 | /* TODO: What about CURSOR_REQUIRESEEK state? Probably need to call ** restoreOrClearCursorPosition() here. */ MemPage *pPage = pCur->pPage; return pPage ? pPage->aData[pPage->hdrOffset] : 0; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 | /* TODO: What about CURSOR_REQUIRESEEK state? Probably need to call ** restoreOrClearCursorPosition() here. */ MemPage *pPage = pCur->pPage; return pPage ? pPage->aData[pPage->hdrOffset] : 0; } /* ** Return the pager associated with a BTree. This routine is used for ** testing and debugging only. */ Pager *sqlite3BtreePager(Btree *p){ return p->pBt->pPager; |
︙ | ︙ | |||
6036 6037 6038 6039 6040 6041 6042 | /* Check that the page exists */ pBt = pCheck->pBt; usableSize = pBt->usableSize; if( iPage==0 ) return 0; if( checkRef(pCheck, iPage, zParentContext) ) return 0; | | | | > | | | 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 | /* Check that the page exists */ pBt = pCheck->pBt; usableSize = pBt->usableSize; if( iPage==0 ) return 0; if( checkRef(pCheck, iPage, zParentContext) ) return 0; if( (rc = sqlite3BtreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){ checkAppendMsg(pCheck, zContext, "unable to get the page. error code=%d", rc); return 0; } if( (rc = sqlite3BtreeInitPage(pPage, pParent))!=0 ){ checkAppendMsg(pCheck, zContext, "sqlite3BtreeInitPage() returns error code %d", rc); releasePage(pPage); return 0; } /* Check out all the cells. */ depth = 0; for(i=0; i<pPage->nCell && pCheck->mxErr; i++){ u8 *pCell; int sz; CellInfo info; /* Check payload overflow pages */ sqlite3_snprintf(sizeof(zContext), zContext, "On tree page %d cell %d: ", iPage, i); pCell = sqlite3BtreeFindCell(pPage,i); sqlite3BtreeParseCellPtr(pPage, pCell, &info); sz = info.nData; if( !pPage->intKey ) sz += info.nKey; assert( sz==info.nPayload ); if( sz>info.nLocal ){ int nPage = (sz - info.nLocal + usableSize - 5)/(usableSize - 4); Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]); #ifndef SQLITE_OMIT_AUTOVACUUM |
︙ | ︙ | |||
6480 6481 6482 6483 6484 6485 6486 6487 | ** sqlite3BtreePutData()). */ void sqlite3BtreeCacheOverflow(BtCursor *pCur){ assert(!pCur->isIncrblobHandle); assert(!pCur->aOverflow); pCur->isIncrblobHandle = 1; } #endif | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 6290 6291 6292 6293 6294 6295 6296 6297 | ** sqlite3BtreePutData()). */ void sqlite3BtreeCacheOverflow(BtCursor *pCur){ assert(!pCur->isIncrblobHandle); assert(!pCur->aOverflow); pCur->isIncrblobHandle = 1; } #endif |
Changes to src/btreeInt.h.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** $Id: btreeInt.h,v 1.2 2007/05/05 18:39:25 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: ** "Sorting And Searching", pages 473-480. Addison-Wesley ** Publishing Company, Reading, Massachusetts. |
︙ | ︙ | |||
570 571 572 573 574 575 576 | /* ** Read or write a two- and four-byte big-endian integer values. */ #define get2byte sqlite3Get2byte #define get4byte sqlite3Get4byte #define put2byte sqlite3Put2byte #define put4byte sqlite3Put4byte | > > > > > > > > > > > > > > | 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 | /* ** Read or write a two- and four-byte big-endian integer values. */ #define get2byte sqlite3Get2byte #define get4byte sqlite3Get4byte #define put2byte sqlite3Put2byte #define put4byte sqlite3Put4byte /* ** Internal routines that should be accessed by the btree layer only. */ int sqlite3BtreeGetPage(BtShared*, Pgno, MemPage**, int); int sqlite3BtreeInitPage(MemPage *pPage, MemPage *pParent); void sqlite3BtreeParseCellPtr(MemPage*, u8*, CellInfo*); void sqlite3BtreeParseCell(MemPage*, int, CellInfo*); u8 *sqlite3BtreeFindCell(MemPage *pPage, int iCell); int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur); void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur); void sqlite3BtreeReleaseTempCursor(BtCursor *pCur); int sqlite3BtreeIsRootPage(MemPage *pPage); void sqlite3BtreeMoveToParent(BtCursor *pCur); |
Changes to src/test1.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test1.c,v 1.246 2007/05/05 18:39:25 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" #include "os.h" #include <stdlib.h> #include <string.h> |
︙ | ︙ | |||
1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 | Tcl_SetResult(interp, (char *)sqlite3ErrStr(rc), TCL_STATIC); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewBooleanObj(ret)); return TCL_OK; } #endif /* ** Usage: sqlite3_extended_result_codes DB BOOLEAN ** */ static int test_extended_result_codes( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ | > > | 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 | Tcl_SetResult(interp, (char *)sqlite3ErrStr(rc), TCL_STATIC); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewBooleanObj(ret)); return TCL_OK; } #endif /* ** Usage: sqlite3_extended_result_codes DB BOOLEAN ** */ static int test_extended_result_codes( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ |
︙ | ︙ | |||
4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 | int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_search_count; extern int sqlite3_interrupt_count; extern int sqlite3_open_file_count; extern int sqlite3_sort_count; extern int sqlite3_current_time; extern int sqlite3_max_blobsize; static struct { char *zName; Tcl_CmdProc *xProc; } aCmd[] = { { "sqlite3_mprintf_int", (Tcl_CmdProc*)sqlite3_mprintf_int }, { "sqlite3_mprintf_int64", (Tcl_CmdProc*)sqlite3_mprintf_int64 }, { "sqlite3_mprintf_str", (Tcl_CmdProc*)sqlite3_mprintf_str }, | > > | 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 | int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_search_count; extern int sqlite3_interrupt_count; extern int sqlite3_open_file_count; extern int sqlite3_sort_count; extern int sqlite3_current_time; extern int sqlite3_max_blobsize; extern int sqlite3BtreeSharedCacheReport(void*, Tcl_Interp*,int,Tcl_Obj*CONST*); static struct { char *zName; Tcl_CmdProc *xProc; } aCmd[] = { { "sqlite3_mprintf_int", (Tcl_CmdProc*)sqlite3_mprintf_int }, { "sqlite3_mprintf_int64", (Tcl_CmdProc*)sqlite3_mprintf_int64 }, { "sqlite3_mprintf_str", (Tcl_CmdProc*)sqlite3_mprintf_str }, |
︙ | ︙ | |||
4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 | #ifdef SQLITE_MEMDEBUG { "sqlite_malloc_outstanding", sqlite_malloc_outstanding, 0}, #endif { "sqlite3_test_errstr", test_errstr, 0 }, { "tcl_variable_type", tcl_variable_type, 0 }, #ifndef SQLITE_OMIT_SHARED_CACHE { "sqlite3_enable_shared_cache", test_enable_shared, 0 }, #endif { "sqlite3_libversion_number", test_libversion_number, 0 }, #ifdef SQLITE_ENABLE_COLUMN_METADATA { "sqlite3_table_column_metadata", test_table_column_metadata, 0 }, #endif #ifndef SQLITE_OMIT_INCRBLOB { "sqlite3_blob_read", test_blob_read, 0 }, | > | 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 | #ifdef SQLITE_MEMDEBUG { "sqlite_malloc_outstanding", sqlite_malloc_outstanding, 0}, #endif { "sqlite3_test_errstr", test_errstr, 0 }, { "tcl_variable_type", tcl_variable_type, 0 }, #ifndef SQLITE_OMIT_SHARED_CACHE { "sqlite3_enable_shared_cache", test_enable_shared, 0 }, { "sqlite3_shared_cache_report", sqlite3BtreeSharedCacheReport, 0}, #endif { "sqlite3_libversion_number", test_libversion_number, 0 }, #ifdef SQLITE_ENABLE_COLUMN_METADATA { "sqlite3_table_column_metadata", test_table_column_metadata, 0 }, #endif #ifndef SQLITE_OMIT_INCRBLOB { "sqlite3_blob_read", test_blob_read, 0 }, |
︙ | ︙ | |||
4759 4760 4761 4762 4763 4764 4765 | Tcl_LinkVar(interp, "sqlite_sync_count", (char*)&sqlite3_sync_count, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_fullsync_count", (char*)&sqlite3_fullsync_count, TCL_LINK_INT); #endif /* OS_UNIX */ set_options(interp); | < < < < < < < < | 4764 4765 4766 4767 4768 4769 4770 4771 4772 | Tcl_LinkVar(interp, "sqlite_sync_count", (char*)&sqlite3_sync_count, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_fullsync_count", (char*)&sqlite3_fullsync_count, TCL_LINK_INT); #endif /* OS_UNIX */ set_options(interp); return TCL_OK; } |
Added src/test_btree.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | /* ** 2007 May 05 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the btree.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test_btree.c,v 1.1 2007/05/05 18:39:25 drh Exp $ */ #include "btreeInt.h" #include <tcl.h> /* ** Print a disassembly of the given page on standard output. This routine ** is used for debugging and testing only. */ static int btreePageDump( BtShared *pBt, /* The Btree to be dumped */ int pgno, /* The page to be dumped */ int recursive, /* True to decend into child pages */ MemPage *pParent /* Parent page */ ){ int rc; MemPage *pPage; int i, j, c; int nFree; u16 idx; int hdr; int nCell; int isInit; unsigned char *data; char range[20]; unsigned char payload[20]; rc = sqlite3BtreeGetPage(pBt, (Pgno)pgno, &pPage, 0); isInit = pPage->isInit; if( pPage->isInit==0 ){ sqlite3BtreeInitPage(pPage, pParent); } if( rc ){ return rc; } hdr = pPage->hdrOffset; data = pPage->aData; c = data[hdr]; pPage->intKey = (c & (PTF_INTKEY|PTF_LEAFDATA))!=0; pPage->zeroData = (c & PTF_ZERODATA)!=0; pPage->leafData = (c & PTF_LEAFDATA)!=0; pPage->leaf = (c & PTF_LEAF)!=0; pPage->hasData = !(pPage->zeroData || (!pPage->leaf && pPage->leafData)); nCell = get2byte(&data[hdr+3]); sqlite3DebugPrintf("PAGE %d: flags=0x%02x frag=%d parent=%d\n", pgno, data[hdr], data[hdr+7], (pPage->isInit && pPage->pParent) ? pPage->pParent->pgno : 0); assert( hdr == (pgno==1 ? 100 : 0) ); idx = hdr + 12 - pPage->leaf*4; for(i=0; i<nCell; i++){ CellInfo info; Pgno child; unsigned char *pCell; int sz; int addr; addr = get2byte(&data[idx + 2*i]); pCell = &data[addr]; sqlite3BtreeParseCellPtr(pPage, pCell, &info); sz = info.nSize; sqlite3_snprintf(sizeof(range),range,"%d..%d", addr, addr+sz-1); if( pPage->leaf ){ child = 0; }else{ child = get4byte(pCell); } sz = info.nData; if( !pPage->intKey ) sz += info.nKey; if( sz>sizeof(payload)-1 ) sz = sizeof(payload)-1; memcpy(payload, &pCell[info.nHeader], sz); for(j=0; j<sz; j++){ if( payload[j]<0x20 || payload[j]>0x7f ) payload[j] = '.'; } payload[sz] = 0; sqlite3DebugPrintf( "cell %2d: i=%-10s chld=%-4d nk=%-4lld nd=%-4d payload=%s\n", i, range, child, info.nKey, info.nData, payload ); } if( !pPage->leaf ){ sqlite3DebugPrintf("right_child: %d\n", get4byte(&data[hdr+8])); } nFree = 0; i = 0; idx = get2byte(&data[hdr+1]); while( idx>0 && idx<pPage->pBt->usableSize ){ int sz = get2byte(&data[idx+2]); sqlite3_snprintf(sizeof(range),range,"%d..%d", idx, idx+sz-1); nFree += sz; sqlite3DebugPrintf("freeblock %2d: i=%-10s size=%-4d total=%d\n", i, range, sz, nFree); idx = get2byte(&data[idx]); i++; } if( idx!=0 ){ sqlite3DebugPrintf("ERROR: next freeblock index out of range: %d\n", idx); } if( recursive && !pPage->leaf ){ for(i=0; i<nCell; i++){ unsigned char *pCell = sqlite3BtreeFindCell(pPage, i); btreePageDump(pBt, get4byte(pCell), 1, pPage); idx = get2byte(pCell); } btreePageDump(pBt, get4byte(&data[hdr+8]), 1, pPage); } pPage->isInit = isInit; sqlite3PagerUnref(pPage->pDbPage); fflush(stdout); return SQLITE_OK; } int sqlite3BtreePageDump(Btree *p, int pgno, int recursive){ return btreePageDump(p->pBt, pgno, recursive, 0); } /* ** Usage: sqlite3_shared_cache_report ** ** Return a list of file that are shared and the number of ** references to each file. */ int sqlite3BtreeSharedCacheReport( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_SHARED_CACHE const ThreadData *pTd = sqlite3ThreadDataReadOnly(); if( pTd->useSharedData ){ BtShared *pBt; Tcl_Obj *pRet = Tcl_NewObj(); for(pBt=pTd->pBtree; pBt; pBt=pBt->pNext){ const char *zFile = sqlite3PagerFilename(pBt->pPager); Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(zFile, -1)); Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(pBt->nRef)); } Tcl_SetObjResult(interp, pRet); } #endif return TCL_OK; } /* ** Print debugging information about all cursors to standard output. */ void sqlite3BtreeCursorList(Btree *p){ BtCursor *pCur; BtShared *pBt = p->pBt; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ MemPage *pPage = pCur->pPage; char *zMode = pCur->wrFlag ? "rw" : "ro"; sqlite3DebugPrintf("CURSOR %p rooted at %4d(%s) currently at %d.%d%s\n", pCur, pCur->pgnoRoot, zMode, pPage ? pPage->pgno : 0, pCur->idx, (pCur->eState==CURSOR_VALID) ? "" : " eof" ); } } /* ** Fill aResult[] with information about the entry and page that the ** cursor is pointing to. ** ** aResult[0] = The page number ** aResult[1] = The entry number ** aResult[2] = Total number of entries on this page ** aResult[3] = Cell size (local payload + header) ** aResult[4] = Number of free bytes on this page ** aResult[5] = Number of free blocks on the page ** aResult[6] = Total payload size (local + overflow) ** aResult[7] = Header size in bytes ** aResult[8] = Local payload size ** aResult[9] = Parent page number ** aResult[10]= Page number of the first overflow page ** ** This routine is used for testing and debugging only. */ int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){ int cnt, idx; MemPage *pPage = pCur->pPage; BtCursor tmpCur; int rc = sqlite3BtreeRestoreOrClearCursorPosition(pCur); if( rc!=SQLITE_OK ){ return rc; } assert( pPage->isInit ); sqlite3BtreeGetTempCursor(pCur, &tmpCur); while( upCnt-- ){ sqlite3BtreeMoveToParent(&tmpCur); } pPage = tmpCur.pPage; aResult[0] = sqlite3PagerPagenumber(pPage->pDbPage); assert( aResult[0]==pPage->pgno ); aResult[1] = tmpCur.idx; aResult[2] = pPage->nCell; if( tmpCur.idx>=0 && tmpCur.idx<pPage->nCell ){ sqlite3BtreeParseCell(tmpCur.pPage, tmpCur.idx, &tmpCur.info); aResult[3] = tmpCur.info.nSize; aResult[6] = tmpCur.info.nData; aResult[7] = tmpCur.info.nHeader; aResult[8] = tmpCur.info.nLocal; }else{ aResult[3] = 0; aResult[6] = 0; aResult[7] = 0; aResult[8] = 0; } aResult[4] = pPage->nFree; cnt = 0; idx = get2byte(&pPage->aData[pPage->hdrOffset+1]); while( idx>0 && idx<pPage->pBt->usableSize ){ cnt++; idx = get2byte(&pPage->aData[idx]); } aResult[5] = cnt; if( pPage->pParent==0 || sqlite3BtreeIsRootPage(pPage) ){ aResult[9] = 0; }else{ aResult[9] = pPage->pParent->pgno; } if( tmpCur.info.iOverflow ){ aResult[10] = get4byte(&tmpCur.info.pCell[tmpCur.info.iOverflow]); }else{ aResult[10] = 0; } sqlite3BtreeReleaseTempCursor(&tmpCur); return SQLITE_OK; } |
Changes to src/vdbeblob.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2007 May 1 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** | > > | < | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | /* ** 2007 May 1 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains code used to implement incremental BLOB I/O. ** ** $Id: vdbeblob.c,v 1.9 2007/05/05 18:39:25 drh Exp $ */ #include "sqliteInt.h" #include "vdbeInt.h" #ifndef SQLITE_OMIT_INCRBLOB /* ** Valid sqlite3_blob* handles point to Incrblob structures. */ typedef struct Incrblob Incrblob; struct Incrblob { int flags; /* Copy of "flags" passed to sqlite3_blob_open() */ int nByte; /* Size of open blob, in bytes */ int iOffset; /* Byte offset of blob in cursor data */ BtCursor *pCsr; /* Cursor pointing at blob row */ sqlite3_stmt *pStmt; /* Statement holding cursor open */ }; /* ** Open a blob handle. */ int sqlite3_blob_open( sqlite3* db, /* The database connection */ const char *zDb, /* The attached database containing the blob */ const char *zTable, /* The table containing the blob */ const char *zColumn, /* The column containing the blob */ sqlite_int64 iRow, /* The row containing the glob */ int flags, /* True -> read/write access, false -> read-only */ sqlite3_blob **ppBlob /* Handle for accessing the blob returned here */ ){ int nAttempt = 0; int iCol; /* Index of zColumn in row-record */ /* This VDBE program seeks a btree cursor to the identified ** db/table/row entry. The reason for using a vdbe program instead ** of writing code to use the b-tree layer directly is that the |
︙ | ︙ | |||
231 232 233 234 235 236 237 | sqlite3_finalize((sqlite3_stmt *)v); } sqlite3Error(db, rc, (rc==SQLITE_OK?0:zErr)); return sqlite3ApiExit(db, rc); } /* | | > | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | sqlite3_finalize((sqlite3_stmt *)v); } sqlite3Error(db, rc, (rc==SQLITE_OK?0:zErr)); return sqlite3ApiExit(db, rc); } /* ** Close a blob handle that was previously created using ** sqlite3_blob_open(). */ int sqlite3_blob_close(sqlite3_blob *pBlob){ Incrblob *p = (Incrblob *)pBlob; sqlite3_stmt *pStmt = p->pStmt; sqliteFree(p); return sqlite3_finalize(pStmt); } |
︙ | ︙ |
Changes to test/shared.test.
1 2 3 4 5 6 7 8 9 10 11 | # 2005 December 30 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # 2005 December 30 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # $Id: shared.test,v 1.24 2007/05/05 18:39:25 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl db close ifcapable !shared_cache { finish_test |
︙ | ︙ | |||
844 845 846 847 848 849 850 | execsql { DELETE FROM abc WHERE 1; } lappend res $I $II } set res } {1 4 {} 7} | | | | 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 | execsql { DELETE FROM abc WHERE 1; } lappend res $I $II } set res } {1 4 {} 7} if {[llength [info command sqlite3_shared_cache_report]]==1} { do_test shared-$av.11.9 { sqlite3_shared_cache_report } [list [file normalize test.db] 2] } do_test shared-$av.11.11 { db close db2 close } {} } sqlite3_enable_shared_cache $::enable_shared_cache finish_test |