191b48aa1Sdrh# 2004 June 30 291b48aa1Sdrh# 391b48aa1Sdrh# The author disclaims copyright to this source code. In place of 491b48aa1Sdrh# a legal notice, here is a blessing: 591b48aa1Sdrh# 691b48aa1Sdrh# May you do good and not evil. 791b48aa1Sdrh# May you find forgiveness for yourself and forgive others. 891b48aa1Sdrh# May you share freely, never taking more than you give. 991b48aa1Sdrh# 1091b48aa1Sdrh#*********************************************************************** 1191b48aa1Sdrh# This file implements regression tests for SQLite library. The 1291b48aa1Sdrh# focus of this file is verifying that a rollback in one statement 1391b48aa1Sdrh# caused by an ON CONFLICT ROLLBACK clause aborts any other pending 1491b48aa1Sdrh# statements. 1591b48aa1Sdrh# 166f4c73eeSdanielk1977# $Id: rollback.test,v 1.11 2009/06/26 07:12:07 danielk1977 Exp $ 1791b48aa1Sdrh 1891b48aa1Sdrhset testdir [file dirname $argv0] 1991b48aa1Sdrhsource $testdir/tester.tcl 2091b48aa1Sdrh 21dddca286Sdrhset DB [sqlite3_connection_pointer db] 2291b48aa1Sdrh 2391b48aa1Sdrhdo_test rollback-1.1 { 2491b48aa1Sdrh execsql { 2591b48aa1Sdrh CREATE TABLE t1(a); 2691b48aa1Sdrh INSERT INTO t1 VALUES(1); 2791b48aa1Sdrh INSERT INTO t1 VALUES(2); 2891b48aa1Sdrh INSERT INTO t1 VALUES(3); 2991b48aa1Sdrh INSERT INTO t1 VALUES(4); 3091b48aa1Sdrh SELECT * FROM t1; 3191b48aa1Sdrh } 3291b48aa1Sdrh} {1 2 3 4} 3391b48aa1Sdrh 343bdca9c9Sdanielk1977ifcapable conflict { 3591b48aa1Sdrh do_test rollback-1.2 { 3691b48aa1Sdrh execsql { 3791b48aa1Sdrh CREATE TABLE t3(a unique on conflict rollback); 3891b48aa1Sdrh INSERT INTO t3 SELECT a FROM t1; 3991b48aa1Sdrh BEGIN; 4091b48aa1Sdrh INSERT INTO t1 SELECT * FROM t1; 4191b48aa1Sdrh } 4291b48aa1Sdrh } {} 433bdca9c9Sdanielk1977} 4491b48aa1Sdrhdo_test rollback-1.3 { 4591b48aa1Sdrh set STMT [sqlite3_prepare $DB "SELECT a FROM t1" -1 TAIL] 4691b48aa1Sdrh sqlite3_step $STMT 4791b48aa1Sdrh} {SQLITE_ROW} 4891b48aa1Sdrh 493bdca9c9Sdanielk1977ifcapable conflict { 5091b48aa1Sdrh # This causes a ROLLBACK, which deletes the table out from underneath the 5191b48aa1Sdrh # SELECT statement. 5291b48aa1Sdrh # 5391b48aa1Sdrh do_test rollback-1.4 { 5491b48aa1Sdrh catchsql { 5591b48aa1Sdrh INSERT INTO t3 SELECT a FROM t1; 5691b48aa1Sdrh } 57f9c8ce3cSdrh } {1 {UNIQUE constraint failed: t3.a}} 5891b48aa1Sdrh 5991b48aa1Sdrh # Try to continue with the SELECT statement 6091b48aa1Sdrh # 6191b48aa1Sdrh do_test rollback-1.5 { 6291b48aa1Sdrh sqlite3_step $STMT 6347b7fc78Sdrh } {SQLITE_ROW} 6491b48aa1Sdrh 6591b48aa1Sdrh # Restart the SELECT statement 6691b48aa1Sdrh # 6747b7fc78Sdrh do_test rollback-1.6 { sqlite3_reset $STMT } {SQLITE_OK} 684152e677Sdanielk1977} else { 694152e677Sdanielk1977 do_test rollback-1.6 { sqlite3_reset $STMT } {SQLITE_OK} 704152e677Sdanielk1977} 714152e677Sdanielk1977 7291b48aa1Sdrhdo_test rollback-1.7 { 7391b48aa1Sdrh sqlite3_step $STMT 7491b48aa1Sdrh} {SQLITE_ROW} 7591b48aa1Sdrhdo_test rollback-1.8 { 7691b48aa1Sdrh sqlite3_step $STMT 7791b48aa1Sdrh} {SQLITE_ROW} 7891b48aa1Sdrhdo_test rollback-1.9 { 7991b48aa1Sdrh sqlite3_finalize $STMT 8091b48aa1Sdrh} {SQLITE_OK} 8191b48aa1Sdrh 82b3175389Sdanielk1977if {$tcl_platform(platform) == "unix" 83430e74cdSdan && [permutation] ne "onefile" 84430e74cdSdan && [permutation] ne "inmemory_journal" 854da30f88Sdan && [permutation] ne "atomic-batch-write" 86*69aedc8dSdan && [atomic_batch_write test.db]==0 87b3175389Sdanielk1977} { 88c56774e2Sdanielk1977 do_test rollback-2.1 { 89c56774e2Sdanielk1977 execsql { 90c56774e2Sdanielk1977 BEGIN; 91c56774e2Sdanielk1977 INSERT INTO t3 VALUES('hello world'); 92c56774e2Sdanielk1977 } 93fda06befSmistachkin forcecopy test.db testA.db 94fda06befSmistachkin forcecopy test.db-journal testA.db-journal 95c56774e2Sdanielk1977 execsql { 96c56774e2Sdanielk1977 COMMIT; 97c56774e2Sdanielk1977 } 98c56774e2Sdanielk1977 } {} 99c56774e2Sdanielk1977 100c56774e2Sdanielk1977 # At this point files testA.db and testA.db-journal are present in the 101c56774e2Sdanielk1977 # file system. This block adds a master-journal file pointer to the 102c56774e2Sdanielk1977 # end of testA.db-journal. The master-journal file does not exist. 103c56774e2Sdanielk1977 # 104c56774e2Sdanielk1977 set mj [file normalize testA.db-mj-123] 105c56774e2Sdanielk1977 binary scan $mj c* a 106c56774e2Sdanielk1977 set cksum 0 107c56774e2Sdanielk1977 foreach i $a { incr cksum $i } 108c56774e2Sdanielk1977 set mj_pgno [expr $sqlite_pending_byte / 1024] 109c56774e2Sdanielk1977 set zAppend [binary format Ia*IIa8 $mj_pgno $mj [string length $mj] $cksum \ 110c56774e2Sdanielk1977 "\xd9\xd5\x05\xf9\x20\xa1\x63\xd7" 111c56774e2Sdanielk1977 ] 112c56774e2Sdanielk1977 set iOffset [expr (([file size testA.db-journal] + 511)/512)*512] 113c56774e2Sdanielk1977 set fd [open testA.db-journal a+] 114c56774e2Sdanielk1977 fconfigure $fd -encoding binary -translation binary 115c56774e2Sdanielk1977 seek $fd $iOffset 116c56774e2Sdanielk1977 puts -nonewline $fd $zAppend 1176f4c73eeSdanielk1977 1186f4c73eeSdanielk1977 # Also, fix the first journal-header in the journal-file. Because the 1196f4c73eeSdanielk1977 # journal file has not yet been synced, the 8-byte magic string at the 1206f4c73eeSdanielk1977 # start of the first journal-header has not been written by SQLite. 1216f4c73eeSdanielk1977 # So write it now. 1226f4c73eeSdanielk1977 seek $fd 0 1236f4c73eeSdanielk1977 puts -nonewline $fd "\xd9\xd5\x05\xf9\x20\xa1\x63\xd7" 124c56774e2Sdanielk1977 close $fd 125c56774e2Sdanielk1977 126c56774e2Sdanielk1977 # Open a handle on testA.db and use it to query the database. At one 127c56774e2Sdanielk1977 # point the first query would attempt a hot rollback, attempt to open 128c56774e2Sdanielk1977 # the master-journal file and return SQLITE_CANTOPEN when it could not 129c56774e2Sdanielk1977 # be opened. This is incorrect, it should simply delete the journal 130c56774e2Sdanielk1977 # file and proceed with the query. 131c56774e2Sdanielk1977 # 132c56774e2Sdanielk1977 do_test rollback-2.2 { 133c56774e2Sdanielk1977 sqlite3 db2 testA.db 134c56774e2Sdanielk1977 execsql { 135c56774e2Sdanielk1977 SELECT distinct tbl_name FROM sqlite_master; 136c56774e2Sdanielk1977 } db2 137c56774e2Sdanielk1977 } {t1 t3} 138430e74cdSdan if {[lsearch {exclusive persistent_journal no_journal} [permutation]]<0} { 139c56774e2Sdanielk1977 do_test rollback-2.3 { 140c56774e2Sdanielk1977 file exists testA.db-journal 141c56774e2Sdanielk1977 } 0 14215542621Sdrh } 143c56774e2Sdanielk1977 do_test rollback-2.4 { 144c56774e2Sdanielk1977 execsql { 145c56774e2Sdanielk1977 SELECT distinct tbl_name FROM sqlite_master; 146c56774e2Sdanielk1977 } db2 147c56774e2Sdanielk1977 } {t1 t3} 148c56774e2Sdanielk1977 149c56774e2Sdanielk1977 db2 close 150c56774e2Sdanielk1977} 151c56774e2Sdanielk1977 15291b48aa1Sdrhfinish_test 153