# 2011 Mar 16 # # 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. # #*********************************************************************** # # The focus of this file is testing the session module. # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source [file join [file dirname [info script]] session_common.tcl] source $testdir/tester.tcl set testprefix session2 proc test_reset {} { catch { db close } catch { db2 close } forcedelete test.db test.db2 sqlite3 db test.db sqlite3 db2 test.db2 } proc do_common_sql {sql} { execsql $sql db execsql $sql db2 } proc xConflict args { return "OMIT" } proc do_then_apply_sql {sql {dbname main}} { sqlite3session S db $dbname db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" { S attach $name } db eval $sql sqlite3changeset_apply db2 [S changeset] xConflict S delete } proc do_iterator_test {tn tbl_list sql res} { sqlite3session S db main foreach t $tbl_list {S attach $t} execsql $sql set r [list] foreach v $res { lappend r $v } set x [list] sqlite3session_foreach c [S changeset] { lappend x $c } uplevel do_test $tn [list [list set {} $x]] [list $r] S delete } # Compare the contents of all tables in [db1] and [db2]. Throw an error if # they are not identical, or return an empty string if they are. # proc compare_db {db1 db2} { set sql {SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name} set lot1 [$db1 eval $sql] set lot2 [$db2 eval $sql] if {$lot1 != $lot2} { error "databases contain different tables" } foreach tbl $lot1 { set col1 [list] set col2 [list] $db1 eval "PRAGMA table_info = $tbl" { lappend col1 $name } $db2 eval "PRAGMA table_info = $tbl" { lappend col2 $name } if {$col1 != $col2} { error "table $tbl schema mismatch" } set sql "SELECT * FROM $tbl ORDER BY [join $col1 ,]" set data1 [$db1 eval $sql] set data2 [$db2 eval $sql] if {$data1 != $data2} { error "table $tbl data mismatch" } } return "" } ########################################################################## # End of proc definitions. Start of tests. ########################################################################## test_reset do_execsql_test 1.0 { CREATE TABLE t1(a PRIMARY KEY, b); INSERT INTO t1 VALUES('i', 'one'); } do_iterator_test 1.1 t1 { DELETE FROM t1 WHERE a = 'i'; INSERT INTO t1 VALUES('ii', 'two'); } { {DELETE t1 {t i t one} {}} {INSERT t1 {} {t ii t two}} } do_iterator_test 1.1 t1 { INSERT INTO t1 VALUES(1.5, 99.9) } { {INSERT t1 {} {f 1.5 f 99.9}} } test_reset do_common_sql { CREATE TABLE t1(a PRIMARY KEY, b); CREATE TABLE t2(a, b INTEGER PRIMARY KEY); CREATE TABLE t3(a, b, c, PRIMARY KEY(a, b)); } # Execute each of the following blocks of SQL on database [db1]. Collect # changes using a session object. Apply the resulting changeset to # database [db2]. Then check that the contents of the two databases are # identical. # foreach {tn sql} { 1 { INSERT INTO t1 VALUES(1, 2) } 2 { INSERT INTO t2 VALUES(1, NULL); INSERT INTO t2 VALUES(2, NULL); INSERT INTO t2 VALUES(3, NULL); DELETE FROM t2 WHERE a = 2; INSERT INTO t2 VALUES(4, NULL); UPDATE t2 SET b=0 WHERE b=1; } 3 { INSERT INTO t3 SELECT *, NULL FROM t2 } 4 { INSERT INTO t3 SELECT a||a, b||b, NULL FROM t3; DELETE FROM t3 WHERE rowid%2; } 5 { UPDATE t3 SET c = a||b } 6 { UPDATE t1 SET a = 32 } 7 { INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; -- 2 INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; -- 4 INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; -- 8 INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; -- 16 INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; -- 32 INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; -- 64 INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; -- 128 INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; -- 256 INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; -- 512 INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; -- 1024 INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; -- 2048 DELETE FROM t1 WHERE (rowid%3)==0; } 8 { BEGIN; INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; ROLLBACK; } 9 { BEGIN; UPDATE t1 SET b = 'xxx'; ROLLBACK; } 10 { BEGIN; DELETE FROM t1 WHERE 1; ROLLBACK; } } { do_then_apply_sql $sql do_test 1.$tn { compare_db db db2 } {} } # The following block of tests is similar to the last, except that the # session object is recording changes made to an attached database. The # main database contains a table of the same name as the table being # modified within the attached db. # test_reset forcedelete test.db3 sqlite3 db3 test.db3 do_test 2.0 { execsql { ATTACH 'test.db3' AS 'aux'; CREATE TABLE t1(a, b PRIMARY KEY); CREATE TABLE t2(x, y, z); CREATE TABLE t3(a); CREATE TABLE aux.t1(a PRIMARY KEY, b); CREATE TABLE aux.t2(a, b INTEGER PRIMARY KEY); CREATE TABLE aux.t3(a, b, c, PRIMARY KEY(a, b)); } execsql { CREATE TABLE t1(a PRIMARY KEY, b); CREATE TABLE t2(a, b INTEGER PRIMARY KEY); CREATE TABLE t3(a, b, c, PRIMARY KEY(a, b)); } db2 } {} proc xTrace {args} { puts $args } foreach {tn sql} { 1 { INSERT INTO aux.t1 VALUES(1, 2) } 2 { INSERT INTO aux.t2 VALUES(1, NULL); INSERT INTO aux.t2 VALUES(2, NULL); INSERT INTO aux.t2 VALUES(3, NULL); DELETE FROM aux.t2 WHERE a = 2; INSERT INTO aux.t2 VALUES(4, NULL); UPDATE aux.t2 SET b=0 WHERE b=1; } 3 { INSERT INTO aux.t3 SELECT *, NULL FROM aux.t2 } 4 { INSERT INTO aux.t3 SELECT a||a, b||b, NULL FROM aux.t3; DELETE FROM aux.t3 WHERE rowid%2; } 5 { UPDATE aux.t3 SET c = a||b } 6 { UPDATE aux.t1 SET a = 32 } 7 { INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; DELETE FROM aux.t1 WHERE (rowid%3)==0; } 8 { BEGIN; INSERT INTO aux.t1 SELECT randomblob(32), randomblob(32) FROM aux.t1; ROLLBACK; } 9 { BEGIN; UPDATE aux.t1 SET b = 'xxx'; ROLLBACK; } 10 { BEGIN; DELETE FROM aux.t1 WHERE 1; ROLLBACK; } 11 { INSERT INTO aux.t1 VALUES(randomblob(21000), randomblob(0)); INSERT INTO aux.t1 VALUES(1.5, 1.5); INSERT INTO aux.t1 VALUES(4.56, -99.999999999999999999999); } } { do_then_apply_sql $sql aux do_test 2.$tn { compare_db db3 db2 } {} } catch {db3 close} finish_test