xref: /sqlite-3.40.0/ext/session/session1.test (revision dfe4e6bb)
1# 2011 March 07
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# This file implements regression tests for SQLite library.
12#
13
14if {![info exists testdir]} {
15  set testdir [file join [file dirname [info script]] .. .. test]
16}
17source [file join [file dirname [info script]] session_common.tcl]
18source $testdir/tester.tcl
19ifcapable !session {finish_test; return}
20
21set testprefix session1
22
23do_execsql_test 1.0 {
24  CREATE TABLE t1(x PRIMARY KEY, y);
25  INSERT INTO t1 VALUES('abc', 'def');
26}
27
28#-------------------------------------------------------------------------
29# Test creating, attaching tables to and deleting session objects.
30#
31do_test 1.1 { sqlite3session S db main } {S}
32do_test 1.2 { S delete } {}
33do_test 1.3 { sqlite3session S db main } {S}
34do_test 1.4 { S attach t1 } {}
35do_test 1.5 { S delete } {}
36do_test 1.6 { sqlite3session S db main } {S}
37do_test 1.7 { S attach t1 ; S attach t2 ; S attach t3 } {}
38do_test 1.8 { S attach t1 ; S attach t2 ; S attach t3 } {}
39do_test 1.9 { S delete } {}
40do_test 1.10 {
41  sqlite3session S db main
42  S attach t1
43  execsql { INSERT INTO t1 VALUES('ghi', 'jkl') }
44} {}
45do_test 1.11 { S delete } {}
46do_test 1.12 {
47  sqlite3session S db main
48  S attach t1
49  execsql { INSERT INTO t1 VALUES('mno', 'pqr') }
50  execsql { UPDATE t1 SET x = 111 WHERE rowid = 1 }
51  execsql { DELETE FROM t1 WHERE rowid = 2 }
52} {}
53do_test 1.13 {
54  S changeset
55  S delete
56} {}
57
58#-------------------------------------------------------------------------
59# Simple changeset tests. Also test the sqlite3changeset_invert()
60# function.
61#
62do_test 2.1.1 {
63  execsql { DELETE FROM t1 }
64  sqlite3session S db main
65  S attach t1
66  execsql { INSERT INTO t1 VALUES(1, 'Sukhothai') }
67  execsql { INSERT INTO t1 VALUES(2, 'Ayutthaya') }
68  execsql { INSERT INTO t1 VALUES(3, 'Thonburi') }
69} {}
70do_changeset_test 2.1.2 S {
71  {INSERT t1 0 X. {} {i 1 t Sukhothai}}
72  {INSERT t1 0 X. {} {i 2 t Ayutthaya}}
73  {INSERT t1 0 X. {} {i 3 t Thonburi}}
74}
75do_changeset_invert_test 2.1.3 S {
76  {DELETE t1 0 X. {i 1 t Sukhothai} {}}
77  {DELETE t1 0 X. {i 2 t Ayutthaya} {}}
78  {DELETE t1 0 X. {i 3 t Thonburi} {}}
79}
80do_test 2.1.4 { S delete } {}
81
82do_test 2.2.1 {
83  sqlite3session S db main
84  S attach t1
85  execsql { DELETE FROM t1 WHERE 1 }
86} {}
87do_changeset_test 2.2.2 S {
88  {DELETE t1 0 X. {i 1 t Sukhothai} {}}
89  {DELETE t1 0 X. {i 2 t Ayutthaya} {}}
90  {DELETE t1 0 X. {i 3 t Thonburi} {}}
91}
92do_changeset_invert_test 2.2.3 S {
93  {INSERT t1 0 X. {} {i 1 t Sukhothai}}
94  {INSERT t1 0 X. {} {i 2 t Ayutthaya}}
95  {INSERT t1 0 X. {} {i 3 t Thonburi}}
96}
97do_test 2.2.4 { S delete } {}
98
99do_test 2.3.1 {
100  execsql { DELETE FROM t1 }
101  sqlite3session S db main
102  execsql { INSERT INTO t1 VALUES(1, 'Sukhothai') }
103  execsql { INSERT INTO t1 VALUES(2, 'Ayutthaya') }
104  execsql { INSERT INTO t1 VALUES(3, 'Thonburi') }
105  S attach t1
106  execsql {
107    UPDATE t1 SET x = 10 WHERE x = 1;
108    UPDATE t1 SET y = 'Surin' WHERE x = 2;
109    UPDATE t1 SET x = 20, y = 'Thapae' WHERE x = 3;
110  }
111} {}
112
113do_changeset_test 2.3.2 S {
114  {INSERT t1 0 X. {} {i 10 t Sukhothai}}
115  {DELETE t1 0 X. {i 1 t Sukhothai} {}}
116  {UPDATE t1 0 X. {i 2 t Ayutthaya} {{} {} t Surin}}
117  {DELETE t1 0 X. {i 3 t Thonburi} {}}
118  {INSERT t1 0 X. {} {i 20 t Thapae}}
119}
120
121do_changeset_invert_test 2.3.3 S {
122  {DELETE t1 0 X. {i 10 t Sukhothai} {}}
123  {INSERT t1 0 X. {} {i 1 t Sukhothai}}
124  {UPDATE t1 0 X. {i 2 t Surin} {{} {} t Ayutthaya}}
125  {INSERT t1 0 X. {} {i 3 t Thonburi}}
126  {DELETE t1 0 X. {i 20 t Thapae} {}}
127}
128do_test 2.3.4 { S delete } {}
129
130do_test 2.4.1 {
131  sqlite3session S db main
132  S attach t1
133  execsql { INSERT INTO t1 VALUES(100, 'Bangkok') }
134  execsql { DELETE FROM t1 WHERE x = 100 }
135} {}
136do_changeset_test 2.4.2 S {}
137do_changeset_invert_test 2.4.3 S {}
138do_test 2.4.4 { S delete } {}
139
140#-------------------------------------------------------------------------
141# Test the application of simple changesets. These tests also test that
142# the conflict callback is invoked correctly. For these tests, the
143# conflict callback always returns OMIT.
144#
145db close
146forcedelete test.db test.db2
147sqlite3 db test.db
148sqlite3 db2 test.db2
149
150proc xConflict {args} {
151  lappend ::xConflict $args
152  return ""
153}
154
155proc bgerror {args} { set ::background_error $args }
156
157proc do_conflict_test {tn args} {
158  set O(-tables)    [list]
159  set O(-sql)       [list]
160  set O(-conflicts) [list]
161
162  array set V $args
163  foreach key [array names V] {
164    if {![info exists O($key)]} {error "no such option: $key"}
165  }
166  array set O $args
167
168  sqlite3session S db main
169  foreach t $O(-tables) { S attach $t }
170  execsql $O(-sql)
171  set ::xConflict [list]
172  sqlite3changeset_apply db2 [S changeset] xConflict
173
174  set conflicts [list]
175  foreach c $O(-conflicts) {
176    lappend conflicts $c
177  }
178
179  after 1 {set go 1}
180  vwait go
181
182  uplevel do_test $tn [list { set ::xConflict }] [list $conflicts]
183  S delete
184}
185
186proc do_db2_test {testname sql {result {}}} {
187  uplevel do_test $testname [list "execsql {$sql} db2"] [list [list {*}$result]]
188}
189
190# Test INSERT changesets.
191#
192do_test 3.1.0 {
193  execsql { CREATE TABLE t1(a PRIMARY KEY, b NOT NULL) } db2
194  execsql {
195    CREATE TABLE t1(a PRIMARY KEY, b);
196    INSERT INTO t1 VALUES(1, 'one');
197    INSERT INTO t1 VALUES(2, 'two');
198  } db
199} {}
200do_db2_test 3.1.1 "INSERT INTO t1 VALUES(6, 'VI')"
201do_conflict_test 3.1.2 -tables t1 -sql {
202  INSERT INTO t1 VALUES(3, 'three');
203  INSERT INTO t1 VALUES(4, 'four');
204  INSERT INTO t1 VALUES(5, 'five');
205  INSERT INTO t1 VALUES(6, 'six');
206  INSERT INTO t1 VALUES(7, 'seven');
207  INSERT INTO t1 VALUES(8, NULL);
208} -conflicts {
209  {INSERT t1 CONFLICT {i 6 t six} {i 6 t VI}}
210  {INSERT t1 CONSTRAINT {i 8 n {}}}
211}
212
213do_db2_test 3.1.3 "SELECT * FROM t1" {
214  6 VI 3 three 4 four 5 five 7 seven
215}
216do_execsql_test 3.1.4 "SELECT * FROM t1" {
217  1 one 2 two 3 three 4 four 5 five 6 six 7 seven 8 {}
218}
219
220# Test DELETE changesets.
221#
222do_execsql_test 3.2.1 {
223  PRAGMA foreign_keys = on;
224  CREATE TABLE t2(a PRIMARY KEY, b);
225  CREATE TABLE t3(c, d REFERENCES t2);
226  INSERT INTO t2 VALUES(1, 'one');
227  INSERT INTO t2 VALUES(2, 'two');
228  INSERT INTO t2 VALUES(3, 'three');
229  INSERT INTO t2 VALUES(4, 'four');
230}
231do_db2_test 3.2.2 {
232  PRAGMA foreign_keys = on;
233  CREATE TABLE t2(a PRIMARY KEY, b);
234  CREATE TABLE t3(c, d REFERENCES t2);
235  INSERT INTO t2 VALUES(1, 'one');
236  INSERT INTO t2 VALUES(2, 'two');
237  INSERT INTO t2 VALUES(4, 'five');
238  INSERT INTO t3 VALUES('i', 1);
239}
240do_conflict_test 3.2.3 -tables t2 -sql {
241  DELETE FROM t2 WHERE a = 1;
242  DELETE FROM t2 WHERE a = 2;
243  DELETE FROM t2 WHERE a = 3;
244  DELETE FROM t2 WHERE a = 4;
245} -conflicts {
246  {DELETE t2 NOTFOUND {i 3 t three}}
247  {DELETE t2 DATA {i 4 t four} {i 4 t five}}
248  {FOREIGN_KEY 1}
249}
250do_execsql_test 3.2.4 "SELECT * FROM t2" {}
251do_db2_test     3.2.5 "SELECT * FROM t2" {4 five}
252
253# Test UPDATE changesets.
254#
255do_execsql_test 3.3.1 {
256  CREATE TABLE t4(a, b, c, PRIMARY KEY(b, c));
257  INSERT INTO t4 VALUES(1, 2, 3);
258  INSERT INTO t4 VALUES(4, 5, 6);
259  INSERT INTO t4 VALUES(7, 8, 9);
260  INSERT INTO t4 VALUES(10, 11, 12);
261}
262do_db2_test 3.3.2 {
263  CREATE TABLE t4(a NOT NULL, b, c, PRIMARY KEY(b, c));
264  INSERT INTO t4 VALUES(0, 2, 3);
265  INSERT INTO t4 VALUES(4, 5, 7);
266  INSERT INTO t4 VALUES(7, 8, 9);
267  INSERT INTO t4 VALUES(10, 11, 12);
268}
269do_conflict_test 3.3.3 -tables t4 -sql {
270  UPDATE t4 SET a = -1 WHERE b = 2;
271  UPDATE t4 SET a = -1 WHERE b = 5;
272  UPDATE t4 SET a = NULL WHERE c = 9;
273  UPDATE t4 SET a = 'x' WHERE b = 11;
274} -conflicts {
275  {UPDATE t4 DATA {i 1 i 2 i 3} {i -1 {} {} {} {}} {i 0 i 2 i 3}}
276  {UPDATE t4 NOTFOUND {i 4 i 5 i 6} {i -1 {} {} {} {}}}
277  {UPDATE t4 CONSTRAINT {i 7 i 8 i 9} {n {} {} {} {} {}}}
278}
279do_db2_test     3.3.4 { SELECT * FROM t4 } {0 2 3 4 5 7 7 8 9 x 11 12}
280do_execsql_test 3.3.5 { SELECT * FROM t4 } {-1 2 3 -1 5 6 {} 8 9 x 11 12}
281
282#-------------------------------------------------------------------------
283# This next block of tests verifies that values returned by the conflict
284# handler are intepreted correctly.
285#
286
287proc test_reset {} {
288  db close
289  db2 close
290  forcedelete test.db test.db2
291  sqlite3 db test.db
292  sqlite3 db2 test.db2
293}
294
295proc xConflict {args} {
296  lappend ::xConflict $args
297  return $::conflict_return
298}
299
300foreach {tn conflict_return after} {
301  1 OMIT      {1 2 value1   4 5 7       10 x x}
302  2 REPLACE   {1 2 value1   4 5 value2  10 8 9}
303} {
304  test_reset
305
306  do_test 4.$tn.1 {
307    foreach db {db db2} {
308      execsql {
309        CREATE TABLE t1(a, b, c, PRIMARY KEY(a));
310        INSERT INTO t1 VALUES(1, 2, 3);
311        INSERT INTO t1 VALUES(4, 5, 6);
312        INSERT INTO t1 VALUES(7, 8, 9);
313      } $db
314    }
315    execsql {
316      REPLACE INTO t1 VALUES(4, 5, 7);
317      REPLACE INTO t1 VALUES(10, 'x', 'x');
318    } db2
319  } {}
320
321  do_conflict_test 4.$tn.2 -tables t1 -sql {
322    UPDATE t1 SET c = 'value1' WHERE a = 1;       -- no conflict
323    UPDATE t1 SET c = 'value2' WHERE a = 4;       -- DATA conflict
324    UPDATE t1 SET a = 10 WHERE a = 7;             -- CONFLICT conflict
325  } -conflicts {
326    {INSERT t1 CONFLICT {i 10 i 8 i 9} {i 10 t x t x}}
327    {UPDATE t1 DATA {i 4 {} {} i 6} {{} {} {} {} t value2} {i 4 i 5 i 7}}
328  }
329
330  do_db2_test 4.$tn.3 "SELECT * FROM t1 ORDER BY a" $after
331}
332
333foreach {tn conflict_return} {
334  1 OMIT
335  2 REPLACE
336} {
337  test_reset
338
339  do_test 5.$tn.1 {
340    # Create an identical schema in both databases.
341    set schema {
342      CREATE TABLE "'foolish name'"(x, y, z, PRIMARY KEY(x, y));
343    }
344    execsql $schema db
345    execsql $schema db2
346
347    # Add some rows to [db2]. These rows will cause conflicts later
348    # on when the changeset from [db] is applied to it.
349    execsql {
350      INSERT INTO "'foolish name'" VALUES('one', 'one', 'ii');
351      INSERT INTO "'foolish name'" VALUES('one', 'two', 'i');
352      INSERT INTO "'foolish name'" VALUES('two', 'two', 'ii');
353    } db2
354
355  } {}
356
357  do_conflict_test 5.$tn.2 -tables {{'foolish name'}} -sql {
358    INSERT INTO "'foolish name'" VALUES('one', 'two', 2);
359  } -conflicts {
360    {INSERT {'foolish name'} CONFLICT {t one t two i 2} {t one t two t i}}
361  }
362
363  set res(REPLACE) {one one ii one two 2 two two ii}
364  set res(OMIT)    {one one ii one two i two two ii}
365  do_db2_test 5.$tn.3 {
366    SELECT * FROM "'foolish name'" ORDER BY x, y
367  } $res($conflict_return)
368
369
370  do_test 5.$tn.1 {
371    set schema {
372      CREATE TABLE d1("z""z" PRIMARY KEY, y);
373      INSERT INTO d1 VALUES(1, 'one');
374      INSERT INTO d1 VALUES(2, 'two');
375    }
376    execsql $schema db
377    execsql $schema db2
378
379    execsql {
380      UPDATE d1 SET y = 'TWO' WHERE "z""z" = 2;
381    } db2
382
383  } {}
384
385  do_conflict_test 5.$tn.2 -tables d1 -sql {
386    DELETE FROM d1 WHERE "z""z" = 2;
387  } -conflicts {
388    {DELETE d1 DATA {i 2 t two} {i 2 t TWO}}
389  }
390
391  set res(REPLACE) {1 one}
392  set res(OMIT)    {1 one 2 TWO}
393  do_db2_test 5.$tn.3 "SELECT * FROM d1" $res($conflict_return)
394}
395
396#-------------------------------------------------------------------------
397# Test that two tables can be monitored by a single session object.
398#
399test_reset
400set schema {
401  CREATE TABLE t1(a COLLATE nocase PRIMARY KEY, b);
402  CREATE TABLE t2(a, b PRIMARY KEY);
403}
404do_test 6.0 {
405  execsql $schema db
406  execsql $schema db2
407  execsql {
408    INSERT INTO t1 VALUES('a', 'b');
409    INSERT INTO t2 VALUES('a', 'b');
410  } db2
411} {}
412
413set conflict_return ""
414do_conflict_test 6.1 -tables {t1 t2} -sql {
415  INSERT INTO t1 VALUES('1', '2');
416  INSERT INTO t1 VALUES('A', 'B');
417  INSERT INTO t2 VALUES('A', 'B');
418} -conflicts {
419  {INSERT t1 CONFLICT {t A t B} {t a t b}}
420}
421
422do_db2_test 6.2 "SELECT * FROM t1" {a b 1 2}
423do_db2_test 6.3 "SELECT * FROM t2" {a b A B}
424
425#-------------------------------------------------------------------------
426# Test that session objects are not confused by changes to table in
427# other databases.
428#
429catch { db2 close }
430drop_all_tables
431forcedelete test.db2
432do_iterator_test 7.1 * {
433  ATTACH 'test.db2' AS aux;
434  CREATE TABLE main.t1(x PRIMARY KEY, y);
435  CREATE TABLE aux.t1(x PRIMARY KEY, y);
436
437  INSERT INTO main.t1 VALUES('one', 1);
438  INSERT INTO main.t1 VALUES('two', 2);
439  INSERT INTO aux.t1 VALUES('three', 3);
440  INSERT INTO aux.t1 VALUES('four', 4);
441} {
442  {INSERT t1 0 X. {} {t two i 2}}
443  {INSERT t1 0 X. {} {t one i 1}}
444}
445
446#-------------------------------------------------------------------------
447# Test the sqlite3session_isempty() function.
448#
449do_test 8.1 {
450  execsql {
451    CREATE TABLE t5(x PRIMARY KEY, y);
452    CREATE TABLE t6(x PRIMARY KEY, y);
453    INSERT INTO t5 VALUES('a', 'b');
454    INSERT INTO t6 VALUES('a', 'b');
455  }
456  sqlite3session S db main
457  S attach *
458
459  S isempty
460} {1}
461do_test 8.2 {
462  execsql { DELETE FROM t5 }
463  S isempty
464} {0}
465do_test 8.3 {
466  S delete
467  sqlite3session S db main
468  S attach t5
469  execsql { DELETE FROM t5 }
470  S isempty
471} {1}
472do_test 8.4 { S delete } {}
473
474do_test 8.5 {
475  sqlite3session S db main
476  S attach t5
477  S attach t6
478  execsql { INSERT INTO t5 VALUES(1, 2) }
479  S isempty
480} {0}
481
482do_test 8.6 {
483  S delete
484  sqlite3session S db main
485  S attach t5
486  S attach t6
487  execsql { INSERT INTO t6 VALUES(1, 2) }
488  S isempty
489} {0}
490do_test 8.7 { S delete } {}
491
492#-------------------------------------------------------------------------
493#
494do_execsql_test 9.1 {
495  CREATE TABLE t7(a, b, c, d, e PRIMARY KEY, f, g);
496  INSERT INTO t7 VALUES(1, 1, 1, 1, 1, 1, 1);
497}
498do_test 9.2 {
499  sqlite3session S db main
500  S attach *
501  execsql { UPDATE t7 SET b=2, d=2 }
502} {}
503do_changeset_test 9.2 S {{UPDATE t7 0 ....X.. {{} {} i 1 {} {} i 1 i 1 {} {} {} {}} {{} {} i 2 {} {} i 2 {} {} {} {} {} {}}}}
504S delete
505catch { db2 close }
506
507#-------------------------------------------------------------------------
508# Test a really long table name.
509#
510reset_db
511set tblname [string repeat tblname123 100]
512do_test 10.1.1 {
513  execsql "
514    CREATE TABLE $tblname (a PRIMARY KEY, b);
515    INSERT INTO $tblname VALUES('xyz', 'def');
516  "
517  sqlite3session S db main
518  S attach $tblname
519  execsql "
520    INSERT INTO $tblname VALUES('uvw', 'abc');
521    DELETE FROM $tblname WHERE a = 'xyz';
522  "
523} {}
524breakpoint
525do_changeset_test 10.1.2 S "
526  {INSERT $tblname 0 X. {} {t uvw t abc}}
527  {DELETE $tblname 0 X. {t xyz t def} {}}
528"
529do_test 10.1.4 { S delete } {}
530
531#---------------------------------------------------------------
532reset_db
533do_execsql_test 11.1 {
534  CREATE TABLE t1(a, b);
535}
536do_test 11.2 {
537  sqlite3session S db main
538  S attach t1
539  execsql {
540    INSERT INTO t1 VALUES(1, 2);
541  }
542  S changeset
543} {}
544
545S delete
546
547
548#-------------------------------------------------------------------------
549# Test a really long table name.
550#
551reset_db
552set tblname [string repeat tblname123 100]
553do_test 10.1.1 {
554  execsql "
555    CREATE TABLE $tblname (a PRIMARY KEY, b);
556    INSERT INTO $tblname VALUES('xyz', 'def');
557  "
558  sqlite3session S db main
559  S attach $tblname
560  execsql "
561    INSERT INTO $tblname VALUES('uvw', 'abc');
562    DELETE FROM $tblname WHERE a = 'xyz';
563  "
564} {}
565breakpoint
566do_changeset_test 10.1.2 S "
567  {INSERT $tblname 0 X. {} {t uvw t abc}}
568  {DELETE $tblname 0 X. {t xyz t def} {}}
569"
570do_test 10.1.4 { S delete } {}
571
572
573finish_test
574