/ Check-in [82c3f2ba]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:When an incremental blob cursor is invalidated (occurs when an SQL statement modifies or deletes the row the blob cursor points to) release all page references held by the cursor. Otherwise, the presence of these references may cause other code in btree.c to incorrectly infer that the database is corrupt.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | fts4-incr-merge
Files: files | file ages | folders
SHA1:82c3f2ba42f2c75ba6951cc2743148886a4dc0bc
User & Date: dan 2012-03-23 11:09:59
Context
2012-03-23
13:40
Fix another test case issue in trace2.test. check-in: 02a8e423 user: dan tags: fts4-incr-merge
11:09
When an incremental blob cursor is invalidated (occurs when an SQL statement modifies or deletes the row the blob cursor points to) release all page references held by the cursor. Otherwise, the presence of these references may cause other code in btree.c to incorrectly infer that the database is corrupt. check-in: 82c3f2ba user: dan tags: fts4-incr-merge
11:07
Update a couple of existing test cases. check-in: dcb8fa0f user: dan tags: fts4-incr-merge
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

  6785   6785     /* Assert that the caller has been consistent. If this cursor was opened
  6786   6786     ** expecting an index b-tree, then the caller should be inserting blob
  6787   6787     ** keys with no associated data. If the cursor was opened expecting an
  6788   6788     ** intkey table, the caller should be inserting integer keys with a
  6789   6789     ** blob of associated data.  */
  6790   6790     assert( (pKey==0)==(pCur->pKeyInfo==0) );
  6791   6791   
  6792         -  /* If this is an insert into a table b-tree, invalidate any incrblob 
  6793         -  ** cursors open on the row being replaced (assuming this is a replace
  6794         -  ** operation - if it is not, the following is a no-op).  */
  6795         -  if( pCur->pKeyInfo==0 ){
  6796         -    invalidateIncrblobCursors(p, nKey, 0);
  6797         -  }
  6798         -
  6799   6792     /* Save the positions of any other cursors open on this table.
  6800   6793     **
  6801   6794     ** In some cases, the call to btreeMoveto() below is a no-op. For
  6802   6795     ** example, when inserting data into a table with auto-generated integer
  6803   6796     ** keys, the VDBE layer invokes sqlite3BtreeLast() to figure out the 
  6804   6797     ** integer key to use. It then calls this function to actually insert the 
  6805   6798     ** data into the intkey B-Tree. In this case btreeMoveto() recognizes
  6806   6799     ** that the cursor is already where it needs to be and returns without
  6807   6800     ** doing any work. To avoid thwarting these optimizations, it is important
  6808   6801     ** not to clear the cursor here.
  6809   6802     */
  6810   6803     rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur);
  6811   6804     if( rc ) return rc;
         6805  +
         6806  +  /* If this is an insert into a table b-tree, invalidate any incrblob 
         6807  +  ** cursors open on the row being replaced (assuming this is a replace
         6808  +  ** operation - if it is not, the following is a no-op).  */
         6809  +  if( pCur->pKeyInfo==0 ){
         6810  +    invalidateIncrblobCursors(p, nKey, 0);
         6811  +  }
         6812  +
  6812   6813     if( !loc ){
  6813   6814       rc = btreeMoveto(pCur, pKey, nKey, appendBias, &loc);
  6814   6815       if( rc ) return rc;
  6815   6816     }
  6816   6817     assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) );
  6817   6818   
  6818   6819     pPage = pCur->apPage[pCur->iPage];
................................................................................
  6915   6916   
  6916   6917     if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell) 
  6917   6918      || NEVER(pCur->eState!=CURSOR_VALID)
  6918   6919     ){
  6919   6920       return SQLITE_ERROR;  /* Something has gone awry. */
  6920   6921     }
  6921   6922   
  6922         -  /* If this is a delete operation to remove a row from a table b-tree,
  6923         -  ** invalidate any incrblob cursors open on the row being deleted.  */
  6924         -  if( pCur->pKeyInfo==0 ){
  6925         -    invalidateIncrblobCursors(p, pCur->info.nKey, 0);
  6926         -  }
  6927         -
  6928   6923     iCellDepth = pCur->iPage;
  6929   6924     iCellIdx = pCur->aiIdx[iCellDepth];
  6930   6925     pPage = pCur->apPage[iCellDepth];
  6931   6926     pCell = findCell(pPage, iCellIdx);
  6932   6927   
  6933   6928     /* If the page containing the entry to delete is not a leaf page, move
  6934   6929     ** the cursor to the largest entry in the tree that is smaller than
................................................................................
  6946   6941     /* Save the positions of any other cursors open on this table before
  6947   6942     ** making any modifications. Make the page containing the entry to be 
  6948   6943     ** deleted writable. Then free any overflow pages associated with the 
  6949   6944     ** entry and finally remove the cell itself from within the page.  
  6950   6945     */
  6951   6946     rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur);
  6952   6947     if( rc ) return rc;
         6948  +
         6949  +  /* If this is a delete operation to remove a row from a table b-tree,
         6950  +  ** invalidate any incrblob cursors open on the row being deleted.  */
         6951  +  if( pCur->pKeyInfo==0 ){
         6952  +    invalidateIncrblobCursors(p, pCur->info.nKey, 0);
         6953  +  }
         6954  +
  6953   6955     rc = sqlite3PagerWrite(pPage->pDbPage);
  6954   6956     if( rc ) return rc;
  6955   6957     rc = clearCell(pPage, pCell);
  6956   6958     dropCell(pPage, iCellIdx, cellSizePtr(pPage, pCell), &rc);
  6957   6959     if( rc ) return rc;
  6958   6960   
  6959   6961     /* If the cell deleted was not located on a leaf page, then the cursor
................................................................................
  7227   7229   */
  7228   7230   int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
  7229   7231     int rc;
  7230   7232     BtShared *pBt = p->pBt;
  7231   7233     sqlite3BtreeEnter(p);
  7232   7234     assert( p->inTrans==TRANS_WRITE );
  7233   7235   
  7234         -  /* Invalidate all incrblob cursors open on table iTable (assuming iTable
  7235         -  ** is the root of a table b-tree - if it is not, the following call is
  7236         -  ** a no-op).  */
  7237         -  invalidateIncrblobCursors(p, 0, 1);
  7238         -
  7239   7236     rc = saveAllCursors(pBt, (Pgno)iTable, 0);
         7237  +
  7240   7238     if( SQLITE_OK==rc ){
         7239  +    /* Invalidate all incrblob cursors open on table iTable (assuming iTable
         7240  +    ** is the root of a table b-tree - if it is not, the following call is
         7241  +    ** a no-op).  */
         7242  +    invalidateIncrblobCursors(p, 0, 1);
  7241   7243       rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
  7242   7244     }
  7243   7245     sqlite3BtreeLeave(p);
  7244   7246     return rc;
  7245   7247   }
  7246   7248   
  7247   7249   /*

Added test/incrblob4.test.

            1  +# 2012 March 23
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +#
           12  +#
           13  +set testdir [file dirname $argv0]
           14  +source $testdir/tester.tcl
           15  +ifcapable {!incrblob} { finish_test ; return }
           16  +set testprefix incrblob4
           17  +
           18  +proc create_t1 {} {
           19  +  execsql {
           20  +    PRAGMA page_size = 1024;
           21  +    CREATE TABLE t1(k INTEGER PRIMARY KEY, v);
           22  +  }
           23  +}
           24  +
           25  +proc populate_t1 {} {
           26  +  set data [list a b c d e f g h i j k l m n o p q r s t u v w x y z]
           27  +  foreach d $data {
           28  +    set blob [string repeat $d 900]
           29  +    execsql { INSERT INTO t1(v) VALUES($blob) }
           30  +  }
           31  +}
           32  +
           33  +
           34  +do_test 1.1 { 
           35  +  create_t1
           36  +  populate_t1 
           37  +} {}
           38  +
           39  +do_test 1.2 {
           40  +  set blob [db incrblob t1 v 5]
           41  +  read $blob 10
           42  +} {eeeeeeeeee}
           43  +
           44  +do_test 1.3 {
           45  +  execsql { DELETE FROM t1 }
           46  +  populate_t1
           47  +} {}
           48  +
           49  +
           50  +
           51  +do_test 2.1 { 
           52  +  reset_db
           53  +  create_t1
           54  +  populate_t1 
           55  +} {}
           56  +
           57  +do_test 2.2 {
           58  +  set blob [db incrblob t1 v 10]
           59  +  read $blob 10
           60  +} {jjjjjjjjjj}
           61  +
           62  +do_test 2.3 {
           63  +  set new [string repeat % 900]
           64  +  execsql { DELETE FROM t1 WHERE k=10 }
           65  +  execsql { DELETE FROM t1 WHERE k=9 }
           66  +  execsql { INSERT INTO t1(v) VALUES($new) }
           67  +} {}
           68  +
           69  +
           70  +
           71  +do_test 3.1 {
           72  +  reset_db
           73  +  create_t1
           74  +  populate_t1 
           75  +} {}
           76  +
           77  +do_test 3.2 {
           78  +  set blob [db incrblob t1 v 20]
           79  +  read $blob 10
           80  +} {tttttttttt}
           81  +
           82  +do_test 3.3 {
           83  +  set new [string repeat % 900]
           84  +  execsql { UPDATE t1 SET v = $new WHERE k = 20 }
           85  +  execsql { DELETE FROM t1 WHERE k=19 }
           86  +  execsql { INSERT INTO t1(v) VALUES($new) }
           87  +} {}
           88  +
           89  +finish_test
           90  +