| # 2019 April 23 |
| # |
| # The author disclaims copyright to this source code. In place of |
| # a legal notice, here is a blessing: |
| # |
| # May you do good and not evil. |
| # May you find forgiveness for yourself and forgive others. |
| # May you share freely, never taking more than you give. |
| # |
| #*********************************************************************** |
| # |
| # |
| |
| source [file join [file dirname [info script]] recover_common.tcl] |
| set testprefix recoverold |
| |
| proc compare_result {db1 db2 sql} { |
| set r1 [$db1 eval $sql] |
| set r2 [$db2 eval $sql] |
| if {$r1 != $r2} { |
| puts "sql: $sql" |
| puts "r1: $r1" |
| puts "r2: $r2" |
| error "mismatch for $sql" |
| } |
| return "" |
| } |
| |
| proc compare_dbs {db1 db2} { |
| compare_result $db1 $db2 "SELECT sql FROM sqlite_master ORDER BY 1" |
| foreach tbl [$db1 eval {SELECT name FROM sqlite_master WHERE type='table'}] { |
| compare_result $db1 $db2 "SELECT * FROM $tbl" |
| } |
| } |
| |
| proc do_recover_test {tn {tsql {}} {res {}}} { |
| forcedelete test.db2 |
| forcedelete rstate.db |
| |
| set R [sqlite3_recover_init db main test.db2] |
| $R config lostandfound lost_and_found |
| $R run |
| $R finish |
| |
| sqlite3 db2 test.db2 |
| |
| if {$tsql==""} { |
| uplevel [list do_test $tn.1 [list compare_dbs db db2] {}] |
| } else { |
| uplevel [list do_execsql_test -db db2 $tn.1 $tsql $res] |
| } |
| db2 close |
| |
| forcedelete test.db2 |
| forcedelete rstate.db |
| |
| set ::sqlhook [list] |
| set R [sqlite3_recover_init_sql db main my_sql_hook] |
| $R config lostandfound lost_and_found |
| $R run |
| $R finish |
| |
| sqlite3 db2 test.db2 |
| db2 eval [join $::sqlhook ";"] |
| |
| |
| db cache flush |
| if {$tsql==""} { |
| compare_dbs db db2 |
| uplevel [list do_test $tn.sql [list compare_dbs db db2] {}] |
| } else { |
| uplevel [list do_execsql_test -db db2 $tn.sql $tsql $res] |
| } |
| db2 close |
| } |
| |
| proc my_sql_hook {sql} { |
| lappend ::sqlhook $sql |
| return 0 |
| } |
| |
| |
| set doc { |
| hello |
| world |
| } |
| do_execsql_test 1.1.1 { |
| CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); |
| INSERT INTO t1 VALUES(1, 4, X'1234567800'); |
| INSERT INTO t1 VALUES(2, 'test', 8.1); |
| INSERT INTO t1 VALUES(3, $doc, 8.4); |
| } |
| do_recover_test 1.1.2 |
| |
| do_execsql_test 1.2.1 " |
| DELETE FROM t1; |
| INSERT INTO t1 VALUES(13, 'hello\r\nworld', 13); |
| " |
| do_recover_test 1.2.2 |
| |
| do_execsql_test 1.3.1 " |
| CREATE TABLE t2(i INTEGER PRIMARY KEY AUTOINCREMENT, b, c); |
| INSERT INTO t2 VALUES(NULL, 1, 2); |
| INSERT INTO t2 VALUES(NULL, 3, 4); |
| INSERT INTO t2 VALUES(NULL, 5, 6); |
| CREATE TABLE t3(i INTEGER PRIMARY KEY AUTOINCREMENT, b, c); |
| INSERT INTO t3 VALUES(NULL, 1, 2); |
| INSERT INTO t3 VALUES(NULL, 3, 4); |
| INSERT INTO t3 VALUES(NULL, 5, 6); |
| DELETE FROM t2; |
| " |
| do_recover_test 1.3.2 |
| |
| #------------------------------------------------------------------------- |
| reset_db |
| do_execsql_test 2.1.0 { |
| PRAGMA auto_vacuum = 0; |
| CREATE TABLE t1(a, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID; |
| INSERT INTO t1 VALUES(1, 2, 3); |
| INSERT INTO t1 VALUES(4, 5, 6); |
| INSERT INTO t1 VALUES(7, 8, 9); |
| } |
| |
| do_recover_test 2.1.1 |
| |
| do_execsql_test 2.2.0 { |
| PRAGMA writable_schema = 1; |
| DELETE FROM sqlite_master WHERE name='t1'; |
| } |
| do_recover_test 2.2.1 { |
| SELECT name FROM sqlite_master |
| } {lost_and_found} |
| |
| do_execsql_test 2.3.0 { |
| CREATE TABLE lost_and_found(a, b, c); |
| } |
| do_recover_test 2.3.1 { |
| SELECT name FROM sqlite_master |
| } {lost_and_found lost_and_found_0} |
| |
| do_execsql_test 2.4.0 { |
| CREATE TABLE lost_and_found_0(a, b, c); |
| } |
| do_recover_test 2.4.1 { |
| SELECT name FROM sqlite_master; |
| SELECT * FROM lost_and_found_1; |
| } {lost_and_found lost_and_found_0 lost_and_found_1 |
| 2 2 3 {} 2 3 1 |
| 2 2 3 {} 5 6 4 |
| 2 2 3 {} 8 9 7 |
| } |
| |
| do_execsql_test 2.5 { |
| CREATE TABLE x1(a, b, c); |
| WITH s(i) AS ( |
| SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 |
| ) |
| INSERT INTO x1 SELECT i, i, hex(randomblob(500)) FROM s; |
| DROP TABLE x1; |
| } |
| do_recover_test 2.5.1 { |
| SELECT name FROM sqlite_master; |
| SELECT * FROM lost_and_found_1; |
| } {lost_and_found lost_and_found_0 lost_and_found_1 |
| 2 2 3 {} 2 3 1 |
| 2 2 3 {} 5 6 4 |
| 2 2 3 {} 8 9 7 |
| } |
| |
| ifcapable !secure_delete { |
| do_test 2.6 { |
| forcedelete test.db2 |
| set R [sqlite3_recover_init db main test.db2] |
| $R config lostandfound lost_and_found |
| $R config freelistcorrupt 1 |
| $R run |
| $R finish |
| sqlite3 db2 test.db2 |
| execsql { SELECT count(*) FROM lost_and_found_1; } db2 |
| } {103} |
| db2 close |
| } |
| |
| #------------------------------------------------------------------------- |
| breakpoint |
| reset_db |
| do_recover_test 3.0 |
| |
| finish_test |