27453faef8
FossilOrigin-Name: aed4273054cbd150c86b36ea951d17c981633ba0
281 lines
7.2 KiB
Plaintext
281 lines
7.2 KiB
Plaintext
# 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}}
|
|
}
|
|
|
|
# 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.
|
|
#
|
|
|
|
set set_of_tests {
|
|
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%;
|
|
INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
|
|
INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
|
|
INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
|
|
INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
|
|
INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
|
|
INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
|
|
INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
|
|
INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
|
|
INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
|
|
INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
|
|
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;
|
|
}
|
|
11 {
|
|
INSERT INTO %T1% VALUES(randomblob(21000), randomblob(0));
|
|
INSERT INTO %T1% VALUES(1.5, 1.5);
|
|
INSERT INTO %T1% VALUES(4.56, -99.999999999999999999999);
|
|
}
|
|
12 {
|
|
INSERT INTO %T2% VALUES(NULL, NULL);
|
|
}
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
foreach {tn sql} [string map {%T1% t1 %T2% t2 %T3% t3} $set_of_tests] {
|
|
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} [
|
|
string map {%T1% aux.t1 %T2% aux.t2 %T3% aux.t3} $set_of_tests
|
|
] {
|
|
do_then_apply_sql $sql aux
|
|
do_test 2.$tn { compare_db db3 db2 } {}
|
|
}
|
|
catch {db3 close}
|
|
|
|
|
|
#-------------------------------------------------------------------------
|
|
# The following tests verify that NULL values in primary key columns are
|
|
# handled correctly by the session module.
|
|
#
|
|
test_reset
|
|
do_execsql_test 3.0 {
|
|
CREATE TABLE t1(a PRIMARY KEY);
|
|
CREATE TABLE t2(a, b, c, PRIMARY KEY(c, b));
|
|
CREATE TABLE t3(a, b INTEGER PRIMARY KEY);
|
|
}
|
|
|
|
foreach {tn sql changeset} {
|
|
1 {
|
|
INSERT INTO t1 VALUES(123);
|
|
INSERT INTO t1 VALUES(NULL);
|
|
INSERT INTO t1 VALUES(456);
|
|
} {
|
|
{INSERT t1 {} {i 456}}
|
|
{INSERT t1 {} {i 123}}
|
|
}
|
|
|
|
2 {
|
|
UPDATE t1 SET a = NULL;
|
|
} {
|
|
{DELETE t1 {i 456} {}}
|
|
{DELETE t1 {i 123} {}}
|
|
}
|
|
|
|
3 { DELETE FROM t1 } { }
|
|
|
|
4 {
|
|
INSERT INTO t3 VALUES(NULL, NULL)
|
|
} {
|
|
{INSERT t3 {} {n {} i 1}}
|
|
}
|
|
|
|
5 { INSERT INTO t2 VALUES(1, 2, NULL) } { }
|
|
6 { INSERT INTO t2 VALUES(1, NULL, 3) } { }
|
|
7 { INSERT INTO t2 VALUES(1, NULL, NULL) } { }
|
|
8 { INSERT INTO t2 VALUES(1, 2, 3) } { {INSERT t2 {} {i 1 i 2 i 3}} }
|
|
9 { DELETE FROM t2 WHERE 1 } { {DELETE t2 {i 1 i 2 i 3} {}} }
|
|
|
|
} {
|
|
do_iterator_test 3.$tn {t1 t2 t3} $sql $changeset
|
|
}
|
|
|
|
|
|
finish_test
|
|
|