Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix a couple of assert() failures that can occur in btree.c and pager.c. (CVS 6055) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
ae44e7482476478c8eeacfb80b282f17 |
User & Date: | danielk1977 2008-12-23 10:37:47.000 |
Context
2008-12-23
| ||
11:11 | In sqlite3AddColumn(), use local variable 'db' instead of 'pParse->db'. (CVS 6056) (check-in: 0c53a4c2da user: danielk1977 tags: trunk) | |
10:37 | Fix a couple of assert() failures that can occur in btree.c and pager.c. (CVS 6055) (check-in: ae44e74824 user: danielk1977 tags: trunk) | |
2008-12-22
| ||
15:04 | Fix a reference counting bug in rtree. Ticket #3549. (CVS 6054) (check-in: bbdc0e9f24 user: danielk1977 tags: trunk) | |
Changes
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.551 2008/12/23 10:37:47 danielk1977 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" |
︙ | ︙ | |||
4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 | ** back. But here, in balance_quick(), it is possible that pPage has ** not yet been marked dirty or written into the journal file. Therefore ** it will not be rolled back and so it is important to make sure that ** the page data and contents of MemPage are consistent. */ pPage->isInit = 0; sqlite3BtreeInitPage(pPage); /* If everything else succeeded, balance the parent page, in ** case the divider cell inserted caused it to become overfull. */ if( rc==SQLITE_OK ){ releasePage(pPage); pCur->iPage--; | > | 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 | ** back. But here, in balance_quick(), it is possible that pPage has ** not yet been marked dirty or written into the journal file. Therefore ** it will not be rolled back and so it is important to make sure that ** the page data and contents of MemPage are consistent. */ pPage->isInit = 0; sqlite3BtreeInitPage(pPage); assert( pPage->nOverflow==0 ); /* If everything else succeeded, balance the parent page, in ** case the divider cell inserted caused it to become overfull. */ if( rc==SQLITE_OK ){ releasePage(pPage); pCur->iPage--; |
︙ | ︙ | |||
5021 5022 5023 5024 5025 5026 5027 | */ static int balance_nonroot(BtCursor *pCur){ MemPage *pPage; /* The over or underfull page to balance */ 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. */ | | | | 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 | */ static int balance_nonroot(BtCursor *pCur){ MemPage *pPage; /* The over or underfull page to balance */ 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 = 0; /* Number of pages in apOld[] */ int nNew = 0; /* 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[] */ int nxDiv; /* Next divider slot in pParent->aCell[] */ int rc; /* The return code */ int leafCorrection; /* 4 if pPage is a leaf. 0 if not */ int leafData; /* True if pPage is a leaf of a LEAFDATA tree */ |
︙ | ︙ | |||
5065 5066 5067 5068 5069 5070 5071 | assert( pCur->iPage>0 ); assert( pPage->isInit ); assert( sqlite3PagerIswriteable(pPage->pDbPage) || pPage->nOverflow==1 ); pBt = pPage->pBt; pParent = pCur->apPage[pCur->iPage-1]; assert( pParent ); if( SQLITE_OK!=(rc = sqlite3PagerWrite(pParent->pDbPage)) ){ | | | 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 | assert( pCur->iPage>0 ); assert( pPage->isInit ); assert( sqlite3PagerIswriteable(pPage->pDbPage) || pPage->nOverflow==1 ); pBt = pPage->pBt; pParent = pCur->apPage[pCur->iPage-1]; assert( pParent ); if( SQLITE_OK!=(rc = sqlite3PagerWrite(pParent->pDbPage)) ){ goto balance_cleanup; } TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno)); #ifndef SQLITE_OMIT_QUICKBALANCE /* ** A special case: If a new entry has just been inserted into a |
︙ | ︙ | |||
5096 5097 5098 5099 5100 5101 5102 | ** they are not full and no new page is required. */ return balance_quick(pCur); } #endif if( SQLITE_OK!=(rc = sqlite3PagerWrite(pPage->pDbPage)) ){ | | < < < < < < | 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 | ** they are not full and no new page is required. */ return balance_quick(pCur); } #endif if( SQLITE_OK!=(rc = sqlite3PagerWrite(pPage->pDbPage)) ){ goto balance_cleanup; } /* ** Find the cell in the parent page whose left child points back ** to pPage. The "idx" variable is the index of that cell. If pPage ** is the rightmost child of pParent then set idx to pParent->nCell */ idx = pCur->aiIdx[pCur->iPage-1]; assertParentIndex(pParent, idx, pPage->pgno); /* ** Find sibling pages to pPage and the cells in pParent that divide ** the siblings. An attempt is made to find NN siblings on either ** side of pPage. More siblings are taken from one side, however, if ** pPage there are fewer than NN siblings on the other side. If pParent ** has NB or fewer children then all children of pParent are taken. */ |
︙ | ︙ | |||
5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 | ** Balance the parent page. Note that the current page (pPage) might ** have been added to the freelist so it might no longer be initialized. ** But the parent page will always be initialized. */ assert( pParent->isInit ); sqlite3ScratchFree(apCell); apCell = 0; releasePage(pPage); pCur->iPage--; rc = balance(pCur, 0); /* ** Cleanup before returning. */ balance_cleanup: sqlite3PageFree(aSpace2); sqlite3ScratchFree(apCell); for(i=0; i<nOld; i++){ releasePage(apOld[i]); } for(i=0; i<nNew; i++){ releasePage(apNew[i]); } | > > > | < < < < | 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 | ** Balance the parent page. Note that the current page (pPage) might ** have been added to the freelist so it might no longer be initialized. ** But the parent page will always be initialized. */ assert( pParent->isInit ); sqlite3ScratchFree(apCell); apCell = 0; TRACE(("BALANCE: finished with %d: old=%d new=%d cells=%d\n", pPage->pgno, nOld, nNew, nCell)); pPage->nOverflow = 0; releasePage(pPage); pCur->iPage--; rc = balance(pCur, 0); /* ** Cleanup before returning. */ balance_cleanup: sqlite3PageFree(aSpace2); sqlite3ScratchFree(apCell); for(i=0; i<nOld; i++){ releasePage(apOld[i]); } for(i=0; i<nNew; i++){ releasePage(apNew[i]); } pCur->apPage[pCur->iPage]->nOverflow = 0; return rc; } /* ** This routine is called for the root page of a btree when the root ** page contains no cells. This is an opportunity to make the tree |
︙ | ︙ | |||
5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 | MemPage *pPage = pCur->apPage[pCur->iPage]; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); if( pCur->iPage==0 ){ rc = sqlite3PagerWrite(pPage->pDbPage); if( rc==SQLITE_OK && pPage->nOverflow>0 ){ rc = balance_deeper(pCur); assert( pPage->nOverflow==0 || rc!=SQLITE_OK ); } if( rc==SQLITE_OK && pPage->nCell==0 ){ rc = balance_shallower(pCur); assert( pPage->nOverflow==0 || rc!=SQLITE_OK ); } }else{ if( pPage->nOverflow>0 || (!isInsert && pPage->nFree>pPage->pBt->usableSize*2/3) ){ rc = balance_nonroot(pCur); | > > < | 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 | MemPage *pPage = pCur->apPage[pCur->iPage]; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); if( pCur->iPage==0 ){ rc = sqlite3PagerWrite(pPage->pDbPage); if( rc==SQLITE_OK && pPage->nOverflow>0 ){ rc = balance_deeper(pCur); assert( pCur->apPage[0]==pPage ); assert( pPage->nOverflow==0 || rc!=SQLITE_OK ); } if( rc==SQLITE_OK && pPage->nCell==0 ){ rc = balance_shallower(pCur); assert( pCur->apPage[0]==pPage ); assert( pPage->nOverflow==0 || rc!=SQLITE_OK ); } }else{ if( pPage->nOverflow>0 || (!isInsert && pPage->nFree>pPage->pBt->usableSize*2/3) ){ rc = balance_nonroot(pCur); } } return rc; } /* ** This routine checks all cursors that point to table pgnoRoot. |
︙ | ︙ | |||
5973 5974 5975 5976 5977 5978 5979 | rc = insertCell(pPage, idx, newCell, szNew, 0, 0); if( rc==SQLITE_OK ){ rc = balance(pCur, 1); } /* Must make sure nOverflow is reset to zero even if the balance() ** fails. Internal data structure corruption will result otherwise. */ | < | | 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 | rc = insertCell(pPage, idx, newCell, szNew, 0, 0); if( rc==SQLITE_OK ){ rc = balance(pCur, 1); } /* Must make sure nOverflow is reset to zero even if the balance() ** fails. Internal data structure corruption will result otherwise. */ pCur->apPage[pCur->iPage]->nOverflow = 0; if( rc==SQLITE_OK ){ moveToRoot(pCur); } end_insert: return rc; } |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** ** @(#) $Id: pager.c,v 1.522 2008/12/23 10:37:47 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" /* ** Macros for troubleshooting. Normally turned off */ |
︙ | ︙ | |||
3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 | ** Otherwise, when the transaction is rolled back, the logic in ** playback_one_page() will think that the page needs to be restored ** in the database file. And if an IO error occurs while doing so, ** then corruption may follow. */ if( !pPager->noSync ){ pPg->flags |= PGHDR_NEED_SYNC; } /* An error has occured writing to the journal file. The ** transaction will be rolled back by the layer above. */ if( rc!=SQLITE_OK ){ return rc; } pPager->nRec++; assert( pPager->pInJournal!=0 ); sqlite3BitvecSet(pPager->pInJournal, pPg->pgno); addToSavepointBitvecs(pPager, pPg->pgno); }else{ if( !pPager->journalStarted && !pPager->noSync ){ pPg->flags |= PGHDR_NEED_SYNC; } PAGERTRACE4("APPEND %d page %d needSync=%d\n", PAGERID(pPager), pPg->pgno, ((pPg->flags&PGHDR_NEED_SYNC)?1:0)); } | > > < < < | 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 | ** Otherwise, when the transaction is rolled back, the logic in ** playback_one_page() will think that the page needs to be restored ** in the database file. And if an IO error occurs while doing so, ** then corruption may follow. */ if( !pPager->noSync ){ pPg->flags |= PGHDR_NEED_SYNC; pPager->needSync = 1; } /* An error has occured writing to the journal file. The ** transaction will be rolled back by the layer above. */ if( rc!=SQLITE_OK ){ return rc; } pPager->nRec++; assert( pPager->pInJournal!=0 ); sqlite3BitvecSet(pPager->pInJournal, pPg->pgno); addToSavepointBitvecs(pPager, pPg->pgno); }else{ if( !pPager->journalStarted && !pPager->noSync ){ pPg->flags |= PGHDR_NEED_SYNC; pPager->needSync = 1; } PAGERTRACE4("APPEND %d page %d needSync=%d\n", PAGERID(pPager), pPg->pgno, ((pPg->flags&PGHDR_NEED_SYNC)?1:0)); } } /* If the statement journal is open and the page is not in it, ** then write the current page to the statement journal. Note that ** the statement journal format differs from the standard journal format ** in that it omits the checksums and the header. */ |
︙ | ︙ | |||
3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 | if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){ if( pg!=PAGER_MJ_PGNO(pPager) ){ rc = sqlite3PagerGet(pPager, pg, &pPage); if( rc==SQLITE_OK ){ rc = pager_write(pPage); if( pPage->flags&PGHDR_NEED_SYNC ){ needSync = 1; } sqlite3PagerUnref(pPage); } } }else if( (pPage = pager_lookup(pPager, pg))!=0 ){ if( pPage->flags&PGHDR_NEED_SYNC ){ needSync = 1; | > | 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 | if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){ if( pg!=PAGER_MJ_PGNO(pPager) ){ rc = sqlite3PagerGet(pPager, pg, &pPage); if( rc==SQLITE_OK ){ rc = pager_write(pPage); if( pPage->flags&PGHDR_NEED_SYNC ){ needSync = 1; assert(pPager->needSync); } sqlite3PagerUnref(pPage); } } }else if( (pPage = pager_lookup(pPager, pg))!=0 ){ if( pPage->flags&PGHDR_NEED_SYNC ){ needSync = 1; |
︙ | ︙ |
Changes to test/insert3.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2005 January 13 # # 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 implements regression tests for SQLite library. The # focus of this file is testing corner cases of the INSERT statement. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2005 January 13 # # 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 implements regression tests for SQLite library. The # focus of this file is testing corner cases of the INSERT statement. # # $Id: insert3.test,v 1.8 2008/12/23 10:37:47 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # All the tests in this file require trigger support # ifcapable {trigger} { |
︙ | ︙ | |||
163 164 165 166 167 168 169 170 171 | CREATE TABLE t6(x,y DEFAULT 4.3, z DEFAULT x'6869'); INSERT INTO t6 DEFAULT VALUES; SELECT * FROM t6; } } {{} 4.3 hi} } db close finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | CREATE TABLE t6(x,y DEFAULT 4.3, z DEFAULT x'6869'); INSERT INTO t6 DEFAULT VALUES; SELECT * FROM t6; } } {{} 4.3 hi} } db close file delete -force test.db sqlite3 db test.db #------------------------------------------------------------------------- # While developing tests for a different feature (savepoint) the following # sequence was found to cause an assert() in btree.c to fail. These # tests are included to ensure that that bug is fixed. # do_test insert3-4.1 { execsql { CREATE TABLE t1(a, b, c); CREATE INDEX i1 ON t1(a, b); BEGIN; INSERT INTO t1 VALUES(randstr(10,400),randstr(10,400),randstr(10,400)); } set r "randstr(10,400)" for {set ii 0} {$ii < 10} {incr ii} { execsql "INSERT INTO t1 SELECT $r, $r, $r FROM t1" } execsql { COMMIT } } {} do_test insert3-4.2 { execsql { PRAGMA cache_size = 10; BEGIN; UPDATE t1 SET a = randstr(10,10) WHERE (rowid%4)==0; DELETE FROM t1 WHERE rowid%2; INSERT INTO t1 SELECT randstr(10,400), randstr(10,400), c FROM t1; COMMIT; } } {} finish_test |