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]

FossilOrigin-Name: ca2ef8a86cf806cbbcc64db03251b1df5b2c5501
This commit is contained in:
drh 2016-04-09 17:04:05 +00:00
parent 53801efcdf
commit bfc7a8bb01
4 changed files with 51 additions and 32 deletions

View File

@ -1,5 +1,5 @@
C Limit\sthe\snumber\sof\sdigits\sshown\sin\sthe\s"prereq"\smask\sfor\s".wheretrace"\ndebugging\soutput.
D 2016-04-09T14:36:07.399
C Fix\sthe\ssqlite3BtreeDelete()\sroutine\sso\sthat\sit\spreserves\sthe\scorrect\nkey\seven\swhen\sthe\srow\sbeing\sdeleted\sis\snot\son\sa\sleaf\spage.\nFix\sfor\sticket\s[a306e56ff68b8fa56]
D 2016-04-09T17:04:05.661
F Makefile.in eba680121821b8a60940a81454316f47a341487a
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 1f123a0757f6f04f0341accb46457e116817159a
@ -319,7 +319,7 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
F src/backup.c f60f0aa55d25d853ffde53d0b0370a7bb7ee41ce
F src/bitvec.c 3ee4c8b2c94ed3a7377256e18199e6ff5cf33f63
F src/btmutex.c bc87dd3b062cc26edfe79918de2200ccb8d41e73
F src/btree.c 556203aab543e91f4e20cc273a507ed712c8da26
F src/btree.c 3ae6aea66cc4e13d30162ff0d0d43c7088e34abf
F src/btree.h a5008b9afe56e8e54ade6c436a910f112defcca9
F src/btreeInt.h c18b7d2a3494695133e4e60ee36061d37f45d9a5
F src/build.c 1944d95f0250ec72dab939f8319a12e237aaad61
@ -615,7 +615,7 @@ F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d
F test/delete.test e1bcdf8926234e27aac24b346ad83d3329ec8b6f
F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
F test/delete3.test 555e84a00a99230b7d049d477a324a631126a6ab
F test/delete4.test 3ac0b8d23689ba764c2e8b78c1b56b8f1b942fa2
F test/delete4.test 738044ee892ee0c84e0848e36ba92c55f907d52b
F test/descidx1.test 6d03b44c8538fe0eb4924e19fba10cdd8f3c9240
F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2
@ -1482,7 +1482,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 1dfa5234d3ee38c6af2d18a6294afa93232821e7
R 8cb0faecb86a13a69a59d8a42b73cabb
P 3686ed7413ae6cdbc8020c0023205e0455e87467
R 4553ce3d8ac9552c77beb258f84ad711
U drh
Z ae55d26bb66b3417bd5295b83c3ebe20
Z 3040395f9dd600c859bc208544af87b9

View File

@ -1 +1 @@
3686ed7413ae6cdbc8020c0023205e0455e87467
ca2ef8a86cf806cbbcc64db03251b1df5b2c5501

View File

@ -8140,6 +8140,28 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
pPage = pCur->apPage[iCellDepth];
pCell = findCell(pPage, iCellIdx);
/* If the bPreserve flag is set to true, then the cursor position must
** be preserved following this delete operation. If the current delete
** will cause a b-tree rebalance, then this is done by saving the cursor
** key and leaving the cursor in CURSOR_REQUIRESEEK state before
** returning.
**
** Or, if the current delete will not cause a rebalance, then the cursor
** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
** before or after the deleted entry. In this case set bSkipnext to true. */
if( bPreserve ){
if( !pPage->leaf
|| (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
){
/* A b-tree rebalance will be required after deleting this entry.
** Save the cursor key. */
rc = saveCursorKey(pCur);
if( rc ) return rc;
}else{
bSkipnext = 1;
}
}
/* If the page containing the entry to delete is not a leaf page, move
** the cursor to the largest entry in the tree that is smaller than
** the entry being deleted. This cell will replace the cell being deleted
@ -8166,28 +8188,6 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
invalidateIncrblobCursors(p, pCur->info.nKey, 0);
}
/* If the bPreserve flag is set to true, then the cursor position must
** be preserved following this delete operation. If the current delete
** will cause a b-tree rebalance, then this is done by saving the cursor
** key and leaving the cursor in CURSOR_REQUIRESEEK state before
** returning.
**
** Or, if the current delete will not cause a rebalance, then the cursor
** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
** before or after the deleted entry. In this case set bSkipnext to true. */
if( bPreserve ){
if( !pPage->leaf
|| (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
){
/* A b-tree rebalance will be required after deleting this entry.
** Save the cursor key. */
rc = saveCursorKey(pCur);
if( rc ) return rc;
}else{
bSkipnext = 1;
}
}
/* Make the page containing the entry to be deleted writable. Then free any
** overflow pages associated with the entry and finally remove the cell
** itself from within the page. */

View File

@ -139,7 +139,26 @@ do_execsql_test 4.12 {
PRAGMA integrity_check;
} {ok}
# 2016-04-09
# Ticket https://sqlite.org/src/info/a306e56ff68b8fa5
# Failure to completely delete when reverse_unordered_selects is
# engaged.
#
db close
forcedelete test.db
sqlite3 db test.db
do_execsql_test 5.0 {
PRAGMA page_size=1024;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
CREATE INDEX x1 ON t1(b, c);
INSERT INTO t1(a,b,c) VALUES(1, 1, zeroblob(80));
INSERT INTO t1(a,b,c) SELECT a+1, 1, c FROM t1;
INSERT INTO t1(a,b,c) SELECT a+2, 1, c FROM t1;
INSERT INTO t1(a,b,c) SELECT a+10, 2, c FROM t1 WHERE b=1;
INSERT INTO t1(a,b,c) SELECT a+20, 3, c FROM t1 WHERE b=1;
PRAGMA reverse_unordered_selects = ON;
DELETE FROM t1 WHERE b=2;
SELECT a FROM t1 WHERE b=2;
} {}
finish_test