18dcd7cabSdrh# 2003 September 6 28dcd7cabSdrh# 38dcd7cabSdrh# The author disclaims copyright to this source code. In place of 48dcd7cabSdrh# a legal notice, here is a blessing: 58dcd7cabSdrh# 68dcd7cabSdrh# May you do good and not evil. 78dcd7cabSdrh# May you find forgiveness for yourself and forgive others. 88dcd7cabSdrh# May you share freely, never taking more than you give. 98dcd7cabSdrh# 108dcd7cabSdrh#*********************************************************************** 118dcd7cabSdrh# This file implements regression tests for SQLite library. The 128dcd7cabSdrh# focus of this script is a test to replicate the bug reported by 138dcd7cabSdrh# ticket #842. 148dcd7cabSdrh# 158dcd7cabSdrh# Ticket #842 was a database corruption problem caused by a DELETE that 168dcd7cabSdrh# removed an index entry by not the main table entry. To recreate the 178dcd7cabSdrh# problem do this: 188dcd7cabSdrh# 198dcd7cabSdrh# (1) Create a table with an index. Insert some data into that table. 208dcd7cabSdrh# (2) Start a query on the table but do not complete the query. 218dcd7cabSdrh# (3) Try to delete a single entry from the table. 228dcd7cabSdrh# 238dcd7cabSdrh# Step 3 will fail because there is still a read cursor on the table. 248dcd7cabSdrh# But the database is corrupted by the DELETE. It turns out that the 258dcd7cabSdrh# index entry was deleted first, before the table entry. And the index 268dcd7cabSdrh# delete worked. Thus an entry was deleted from the index but not from 278dcd7cabSdrh# the table. 288dcd7cabSdrh# 298dcd7cabSdrh# The solution to the problem was to detect that the table is locked 308dcd7cabSdrh# before the index entry is deleted. 318dcd7cabSdrh# 32*9ffe5d72Sdanielk1977# $Id: delete2.test,v 1.8 2008/07/08 15:59:52 danielk1977 Exp $ 338dcd7cabSdrh# 348dcd7cabSdrh 358dcd7cabSdrhset testdir [file dirname $argv0] 368dcd7cabSdrhsource $testdir/tester.tcl 378dcd7cabSdrh 388dcd7cabSdrh# Create a table that has an index. 398dcd7cabSdrh# 408dcd7cabSdrhdo_test delete2-1.1 { 41dddca286Sdrh set DB [sqlite3_connection_pointer db] 428dcd7cabSdrh execsql { 438dcd7cabSdrh CREATE TABLE q(s string, id string, constraint pk_q primary key(id)); 448dcd7cabSdrh BEGIN; 458dcd7cabSdrh INSERT INTO q(s,id) VALUES('hello','id.1'); 468dcd7cabSdrh INSERT INTO q(s,id) VALUES('goodbye','id.2'); 478dcd7cabSdrh INSERT INTO q(s,id) VALUES('again','id.3'); 488dcd7cabSdrh END; 498dcd7cabSdrh SELECT * FROM q; 508dcd7cabSdrh } 518dcd7cabSdrh} {hello id.1 goodbye id.2 again id.3} 528dcd7cabSdrhdo_test delete2-1.2 { 538dcd7cabSdrh execsql { 548dcd7cabSdrh SELECT * FROM q WHERE id='id.1'; 558dcd7cabSdrh } 568dcd7cabSdrh} {hello id.1} 5740e016e4Sdrhintegrity_check delete2-1.3 588dcd7cabSdrh 598dcd7cabSdrh# Start a query on the table. The query should not use the index. 608dcd7cabSdrh# Do not complete the query, thus leaving the table locked. 618dcd7cabSdrh# 628dcd7cabSdrhdo_test delete2-1.4 { 638dcd7cabSdrh set STMT [sqlite3_prepare $DB {SELECT * FROM q} -1 TAIL] 648dcd7cabSdrh sqlite3_step $STMT 658dcd7cabSdrh} SQLITE_ROW 6640e016e4Sdrhintegrity_check delete2-1.5 678dcd7cabSdrh 68980b1a74Sdrh# Try to delete a row from the table while a read is in process. 69980b1a74Sdrh# As of 2006-08-16, this is allowed. (It used to fail with SQLITE_LOCKED.) 708dcd7cabSdrh# 718dcd7cabSdrhdo_test delete2-1.6 { 728dcd7cabSdrh catchsql { 738dcd7cabSdrh DELETE FROM q WHERE rowid=1 748dcd7cabSdrh } 75980b1a74Sdrh} {0 {}} 7640e016e4Sdrhintegrity_check delete2-1.7 778dcd7cabSdrhdo_test delete2-1.8 { 788dcd7cabSdrh execsql { 798dcd7cabSdrh SELECT * FROM q; 808dcd7cabSdrh } 81980b1a74Sdrh} {goodbye id.2 again id.3} 828dcd7cabSdrh 8312b13002Sdanielk1977# Finalize the query, thus clearing the lock on the table. Then 8412b13002Sdanielk1977# retry the delete. The delete should work this time. 8512b13002Sdanielk1977# 868dcd7cabSdrhdo_test delete2-1.9 { 878dcd7cabSdrh sqlite3_finalize $STMT 888dcd7cabSdrh catchsql { 8912b13002Sdanielk1977 DELETE FROM q WHERE rowid=1 908dcd7cabSdrh } 918dcd7cabSdrh} {0 {}} 9240e016e4Sdrhintegrity_check delete2-1.10 938dcd7cabSdrhdo_test delete2-1.11 { 948dcd7cabSdrh execsql { 958dcd7cabSdrh SELECT * FROM q; 968dcd7cabSdrh } 9712b13002Sdanielk1977} {goodbye id.2 again id.3} 988dcd7cabSdrh 99*9ffe5d72Sdanielk1977do_test delete2-2.1 { 100*9ffe5d72Sdanielk1977 execsql { 101*9ffe5d72Sdanielk1977 CREATE TABLE t1(a, b); 102*9ffe5d72Sdanielk1977 CREATE TABLE t2(c, d); 103*9ffe5d72Sdanielk1977 INSERT INTO t1 VALUES(1, 2); 104*9ffe5d72Sdanielk1977 INSERT INTO t2 VALUES(3, 4); 105*9ffe5d72Sdanielk1977 INSERT INTO t2 VALUES(5, 6); 106*9ffe5d72Sdanielk1977 } 107*9ffe5d72Sdanielk1977} {} 108*9ffe5d72Sdanielk1977do_test delete2-2.2 { 109*9ffe5d72Sdanielk1977 set res [list] 110*9ffe5d72Sdanielk1977 db eval { 111*9ffe5d72Sdanielk1977 SELECT CASE WHEN c = 5 THEN b ELSE NULL END AS b, c, d FROM t1, t2 112*9ffe5d72Sdanielk1977 } { 113*9ffe5d72Sdanielk1977 db eval {DELETE FROM t1} 114*9ffe5d72Sdanielk1977 lappend res $b $c $d 115*9ffe5d72Sdanielk1977 } 116*9ffe5d72Sdanielk1977 set res 117*9ffe5d72Sdanielk1977} {{} 3 4 {} 5 6} 118*9ffe5d72Sdanielk1977 1198dcd7cabSdrhfinish_test 120