/ Check-in [ca2ef8a8]
Login

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

Overview
Comment:Fix the sqlite3BtreeDelete() routine so that it preserves the correct key even when the row being deleted is not on a leaf page. Fix for ticket [a306e56ff68b8fa56]
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: ca2ef8a86cf806cbbcc64db03251b1df5b2c5501
User & Date: drh 2016-04-09 17:04:05
Context
2016-04-18
16:06
Fix the sqlite3BtreeDelete() routine so that it preserves the correct key even when the row being deleted is not on a leaf page. Fix for ticket [a306e56ff68b8fa56] check-in: 368e86c7 user: drh tags: branch-3.12.0
2016-04-09
18:04
Fix a problem in the code generator for joins on virtual tables where the outer loop of the join uses the IN operator. check-in: 6c56b3a0 user: drh tags: trunk
17:04
Fix the sqlite3BtreeDelete() routine so that it preserves the correct key even when the row being deleted is not on a leaf page. Fix for ticket [a306e56ff68b8fa56] check-in: ca2ef8a8 user: drh tags: trunk
14:36
Limit the number of digits shown in the "prereq" mask for ".wheretrace" debugging output. check-in: 3686ed74 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

  8135   8135     assert( pCur->eState==CURSOR_VALID );
  8136   8136     assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 );
  8137   8137   
  8138   8138     iCellDepth = pCur->iPage;
  8139   8139     iCellIdx = pCur->aiIdx[iCellDepth];
  8140   8140     pPage = pCur->apPage[iCellDepth];
  8141   8141     pCell = findCell(pPage, iCellIdx);
         8142  +
         8143  +  /* If the bPreserve flag is set to true, then the cursor position must
         8144  +  ** be preserved following this delete operation. If the current delete
         8145  +  ** will cause a b-tree rebalance, then this is done by saving the cursor
         8146  +  ** key and leaving the cursor in CURSOR_REQUIRESEEK state before 
         8147  +  ** returning. 
         8148  +  **
         8149  +  ** Or, if the current delete will not cause a rebalance, then the cursor
         8150  +  ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
         8151  +  ** before or after the deleted entry. In this case set bSkipnext to true.  */
         8152  +  if( bPreserve ){
         8153  +    if( !pPage->leaf 
         8154  +     || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
         8155  +    ){
         8156  +      /* A b-tree rebalance will be required after deleting this entry.
         8157  +      ** Save the cursor key.  */
         8158  +      rc = saveCursorKey(pCur);
         8159  +      if( rc ) return rc;
         8160  +    }else{
         8161  +      bSkipnext = 1;
         8162  +    }
         8163  +  }
  8142   8164   
  8143   8165     /* If the page containing the entry to delete is not a leaf page, move
  8144   8166     ** the cursor to the largest entry in the tree that is smaller than
  8145   8167     ** the entry being deleted. This cell will replace the cell being deleted
  8146   8168     ** from the internal node. The 'previous' entry is used for this instead
  8147   8169     ** of the 'next' entry, as the previous entry is always a part of the
  8148   8170     ** sub-tree headed by the child page of the cell being deleted. This makes
................................................................................
  8162   8184   
  8163   8185     /* If this is a delete operation to remove a row from a table b-tree,
  8164   8186     ** invalidate any incrblob cursors open on the row being deleted.  */
  8165   8187     if( pCur->pKeyInfo==0 ){
  8166   8188       invalidateIncrblobCursors(p, pCur->info.nKey, 0);
  8167   8189     }
  8168   8190   
  8169         -  /* If the bPreserve flag is set to true, then the cursor position must
  8170         -  ** be preserved following this delete operation. If the current delete
  8171         -  ** will cause a b-tree rebalance, then this is done by saving the cursor
  8172         -  ** key and leaving the cursor in CURSOR_REQUIRESEEK state before 
  8173         -  ** returning. 
  8174         -  **
  8175         -  ** Or, if the current delete will not cause a rebalance, then the cursor
  8176         -  ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
  8177         -  ** before or after the deleted entry. In this case set bSkipnext to true.  */
  8178         -  if( bPreserve ){
  8179         -    if( !pPage->leaf 
  8180         -     || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
  8181         -    ){
  8182         -      /* A b-tree rebalance will be required after deleting this entry.
  8183         -      ** Save the cursor key.  */
  8184         -      rc = saveCursorKey(pCur);
  8185         -      if( rc ) return rc;
  8186         -    }else{
  8187         -      bSkipnext = 1;
  8188         -    }
  8189         -  }
  8190         -
  8191   8191     /* Make the page containing the entry to be deleted writable. Then free any
  8192   8192     ** overflow pages associated with the entry and finally remove the cell
  8193   8193     ** itself from within the page.  */
  8194   8194     rc = sqlite3PagerWrite(pPage->pDbPage);
  8195   8195     if( rc ) return rc;
  8196   8196     rc = clearCell(pPage, pCell, &szCell);
  8197   8197     dropCell(pPage, iCellIdx, szCell, &rc);

Changes to test/delete4.test.

   135    135     INSERT INTO t4 VALUES(14, 'abcde','xyzzy');
   136    136     CREATE INDEX idx_t4_3 ON t4 (col0);
   137    137     CREATE INDEX idx_t4_0 ON t4 (col1, col0);
   138    138     DELETE FROM t4 WHERE col0=69 OR col0>7;
   139    139     PRAGMA integrity_check;
   140    140   } {ok}
   141    141   
   142         -
   143         -
          142  +# 2016-04-09
          143  +# Ticket https://sqlite.org/src/info/a306e56ff68b8fa5
          144  +# Failure to completely delete when reverse_unordered_selects is
          145  +# engaged.
          146  +#
          147  +db close
          148  +forcedelete test.db
          149  +sqlite3 db test.db
          150  +do_execsql_test 5.0 {
          151  +  PRAGMA page_size=1024;
          152  +  CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
          153  +  CREATE INDEX x1 ON t1(b, c);
          154  +  INSERT INTO t1(a,b,c) VALUES(1, 1, zeroblob(80));
          155  +  INSERT INTO t1(a,b,c) SELECT a+1, 1, c FROM t1;
          156  +  INSERT INTO t1(a,b,c) SELECT a+2, 1, c FROM t1;
          157  +  INSERT INTO t1(a,b,c) SELECT a+10, 2, c FROM t1 WHERE b=1;
          158  +  INSERT INTO t1(a,b,c) SELECT a+20, 3, c FROM t1 WHERE b=1;
          159  +  PRAGMA reverse_unordered_selects = ON;
          160  +  DELETE FROM t1 WHERE b=2;
          161  +  SELECT a FROM t1 WHERE b=2;
          162  +} {}
   144    163   
   145    164   finish_test