xref: /sqlite-3.40.0/ext/session/session2.test (revision 27453fae)
1# 2011 Mar 16
2#
3# The author disclaims copyright to this source code.  In place of
4# a legal notice, here is a blessing:
5#
6#    May you do good and not evil.
7#    May you find forgiveness for yourself and forgive others.
8#    May you share freely, never taking more than you give.
9#
10#***********************************************************************
11#
12# The focus of this file is testing the session module.
13#
14
15if {![info exists testdir]} {
16  set testdir [file join [file dirname [info script]] .. .. test]
17}
18source [file join [file dirname [info script]] session_common.tcl]
19source $testdir/tester.tcl
20
21set testprefix session2
22
23proc test_reset {} {
24  catch { db close }
25  catch { db2 close }
26  forcedelete test.db test.db2
27  sqlite3 db test.db
28  sqlite3 db2 test.db2
29}
30
31proc do_common_sql {sql} {
32  execsql $sql db
33  execsql $sql db2
34}
35proc xConflict args { return "OMIT" }
36
37proc do_then_apply_sql {sql {dbname main}} {
38
39  sqlite3session S db $dbname
40  db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" {
41    S attach $name
42  }
43
44  db eval $sql
45  sqlite3changeset_apply db2 [S changeset] xConflict
46  S delete
47}
48
49proc do_iterator_test {tn tbl_list sql res} {
50  sqlite3session S db main
51  foreach t $tbl_list {S attach $t}
52  execsql $sql
53
54  set r [list]
55  foreach v $res { lappend r $v }
56
57  set x [list]
58  sqlite3session_foreach c [S changeset] { lappend x $c }
59  uplevel do_test $tn [list [list set {} $x]] [list $r]
60
61  S delete
62}
63
64# Compare the contents of all tables in [db1] and [db2]. Throw an error if
65# they are not identical, or return an empty string if they are.
66#
67proc compare_db {db1 db2} {
68
69  set sql {SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name}
70  set lot1 [$db1 eval $sql]
71  set lot2 [$db2 eval $sql]
72
73  if {$lot1 != $lot2} { error "databases contain different tables" }
74
75  foreach tbl $lot1 {
76    set col1 [list]
77    set col2 [list]
78
79    $db1 eval "PRAGMA table_info = $tbl" { lappend col1 $name }
80    $db2 eval "PRAGMA table_info = $tbl" { lappend col2 $name }
81    if {$col1 != $col2} { error "table $tbl schema mismatch" }
82
83    set sql "SELECT * FROM $tbl ORDER BY [join $col1 ,]"
84    set data1 [$db1 eval $sql]
85    set data2 [$db2 eval $sql]
86    if {$data1 != $data2} { error "table $tbl data mismatch" }
87  }
88
89  return ""
90}
91
92##########################################################################
93# End of proc definitions. Start of tests.
94##########################################################################
95
96test_reset
97do_execsql_test 1.0 {
98  CREATE TABLE t1(a PRIMARY KEY, b);
99  INSERT INTO t1 VALUES('i', 'one');
100}
101do_iterator_test 1.1 t1 {
102  DELETE FROM t1 WHERE a = 'i';
103  INSERT INTO t1 VALUES('ii', 'two');
104} {
105  {DELETE t1 {t i t one} {}}
106  {INSERT t1 {} {t ii t two}}
107}
108do_iterator_test 1.1 t1 {
109  INSERT INTO t1 VALUES(1.5, 99.9)
110} {
111  {INSERT t1 {} {f 1.5 f 99.9}}
112}
113
114# Execute each of the following blocks of SQL on database [db1]. Collect
115# changes using a session object. Apply the resulting changeset to
116# database [db2]. Then check that the contents of the two databases are
117# identical.
118#
119
120set set_of_tests {
121  1 { INSERT INTO %T1% VALUES(1, 2) }
122
123  2 {
124    INSERT INTO %T2% VALUES(1, NULL);
125    INSERT INTO %T2% VALUES(2, NULL);
126    INSERT INTO %T2% VALUES(3, NULL);
127    DELETE FROM %T2% WHERE a = 2;
128    INSERT INTO %T2% VALUES(4, NULL);
129    UPDATE %T2% SET b=0 WHERE b=1;
130  }
131
132  3 { INSERT INTO %T3% SELECT *, NULL FROM %T2% }
133
134  4 {
135    INSERT INTO %T3% SELECT a||a, b||b, NULL FROM %T3%;
136    DELETE FROM %T3% WHERE rowid%2;
137  }
138
139  5 { UPDATE %T3% SET c = a||b }
140
141  6 { UPDATE %T1% SET a = 32 }
142
143  7 {
144    INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
145    INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
146    INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
147    INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
148    INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
149    INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
150    INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
151    INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
152    INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
153    INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
154    INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
155    DELETE FROM %T1% WHERE (rowid%3)==0;
156  }
157
158  8 {
159    BEGIN;
160      INSERT INTO %T1% SELECT randomblob(32), randomblob(32) FROM %T1%;
161    ROLLBACK;
162  }
163  9 {
164    BEGIN;
165      UPDATE %T1% SET b = 'xxx';
166    ROLLBACK;
167  }
168  10 {
169    BEGIN;
170      DELETE FROM %T1% WHERE 1;
171    ROLLBACK;
172  }
173  11 {
174    INSERT INTO %T1% VALUES(randomblob(21000), randomblob(0));
175    INSERT INTO %T1% VALUES(1.5, 1.5);
176    INSERT INTO %T1% VALUES(4.56, -99.999999999999999999999);
177  }
178  12 {
179    INSERT INTO %T2% VALUES(NULL, NULL);
180  }
181}
182
183test_reset
184do_common_sql {
185  CREATE TABLE t1(a PRIMARY KEY, b);
186  CREATE TABLE t2(a, b INTEGER PRIMARY KEY);
187  CREATE TABLE t3(a, b, c, PRIMARY KEY(a, b));
188}
189
190foreach {tn sql} [string map {%T1% t1 %T2% t2 %T3% t3} $set_of_tests] {
191  do_then_apply_sql $sql
192  do_test 1.$tn { compare_db db db2 } {}
193}
194
195# The following block of tests is similar to the last, except that the
196# session object is recording changes made to an attached database. The
197# main database contains a table of the same name as the table being
198# modified within the attached db.
199#
200test_reset
201forcedelete test.db3
202sqlite3 db3 test.db3
203do_test 2.0 {
204  execsql {
205    ATTACH 'test.db3' AS 'aux';
206    CREATE TABLE t1(a, b PRIMARY KEY);
207    CREATE TABLE t2(x, y, z);
208    CREATE TABLE t3(a);
209
210    CREATE TABLE aux.t1(a PRIMARY KEY, b);
211    CREATE TABLE aux.t2(a, b INTEGER PRIMARY KEY);
212    CREATE TABLE aux.t3(a, b, c, PRIMARY KEY(a, b));
213  }
214  execsql {
215    CREATE TABLE t1(a PRIMARY KEY, b);
216    CREATE TABLE t2(a, b INTEGER PRIMARY KEY);
217    CREATE TABLE t3(a, b, c, PRIMARY KEY(a, b));
218  } db2
219} {}
220
221proc xTrace {args} { puts $args }
222
223foreach {tn sql} [
224  string map {%T1% aux.t1 %T2% aux.t2 %T3% aux.t3} $set_of_tests
225] {
226  do_then_apply_sql $sql aux
227  do_test 2.$tn { compare_db db3 db2 } {}
228}
229catch {db3 close}
230
231
232#-------------------------------------------------------------------------
233# The following tests verify that NULL values in primary key columns are
234# handled correctly by the session module.
235#
236test_reset
237do_execsql_test 3.0 {
238  CREATE TABLE t1(a PRIMARY KEY);
239  CREATE TABLE t2(a, b, c, PRIMARY KEY(c, b));
240  CREATE TABLE t3(a, b INTEGER PRIMARY KEY);
241}
242
243foreach {tn sql changeset} {
244  1 {
245    INSERT INTO t1 VALUES(123);
246    INSERT INTO t1 VALUES(NULL);
247    INSERT INTO t1 VALUES(456);
248  } {
249    {INSERT t1 {} {i 456}}
250    {INSERT t1 {} {i 123}}
251  }
252
253  2 {
254    UPDATE t1 SET a = NULL;
255  } {
256    {DELETE t1 {i 456} {}}
257    {DELETE t1 {i 123} {}}
258  }
259
260  3 { DELETE FROM t1 } { }
261
262  4 {
263    INSERT INTO t3 VALUES(NULL, NULL)
264  } {
265    {INSERT t3 {} {n {} i 1}}
266  }
267
268  5 { INSERT INTO t2 VALUES(1, 2, NULL) }    { }
269  6 { INSERT INTO t2 VALUES(1, NULL, 3) }    { }
270  7 { INSERT INTO t2 VALUES(1, NULL, NULL) } { }
271  8 { INSERT INTO t2 VALUES(1, 2, 3) }       { {INSERT t2 {} {i 1 i 2 i 3}} }
272  9 { DELETE FROM t2 WHERE 1 }               { {DELETE t2 {i 1 i 2 i 3} {}} }
273
274} {
275  do_iterator_test 3.$tn {t1 t2 t3} $sql $changeset
276}
277
278
279finish_test
280
281