xref: /sqlite-3.40.0/ext/session/sessionB.test (revision 69e224f8)
173b3c055Sdan# 2014 August 16
273b3c055Sdan#
373b3c055Sdan# The author disclaims copyright to this source code.  In place of
473b3c055Sdan# a legal notice, here is a blessing:
573b3c055Sdan#
673b3c055Sdan#    May you do good and not evil.
773b3c055Sdan#    May you find forgiveness for yourself and forgive others.
873b3c055Sdan#    May you share freely, never taking more than you give.
973b3c055Sdan#
1073b3c055Sdan#***********************************************************************
1173b3c055Sdan#
1273b3c055Sdan# This file implements regression tests for sessions SQLite extension.
1373b3c055Sdan# Specifically, this file contains tests for "patchset" changes.
1473b3c055Sdan#
1573b3c055Sdan
1673b3c055Sdanif {![info exists testdir]} {
1773b3c055Sdan  set testdir [file join [file dirname [info script]] .. .. test]
1873b3c055Sdan}
1973b3c055Sdansource [file join [file dirname [info script]] session_common.tcl]
2073b3c055Sdansource $testdir/tester.tcl
2173b3c055Sdanifcapable !session {finish_test; return}
2273b3c055Sdan
2373b3c055Sdanset testprefix sessionB
2473b3c055Sdan
2573b3c055Sdan#
2673b3c055Sdan# 1.*: Test that the blobs returned by the session_patchset() API are
2773b3c055Sdan#      as expected. Also the sqlite3_changeset_iter functions.
2873b3c055Sdan#
2973b3c055Sdan# 2.*: Test that patchset blobs are handled by sqlite3changeset_apply().
3073b3c055Sdan#
3173b3c055Sdan# 3.*: Test that sqlite3changeset_invert() works with patchset blobs.
3273b3c055Sdan#      Correct behaviour is to return SQLITE_CORRUPT.
3373b3c055Sdan
3473b3c055Sdanproc do_sql2patchset_test {tn sql res} {
3573b3c055Sdan  sqlite3session S db main
3673b3c055Sdan  S attach *
3773b3c055Sdan  execsql $sql
3873b3c055Sdan  uplevel [list do_patchset_test $tn S $res]
3973b3c055Sdan  S delete
4073b3c055Sdan}
4173b3c055Sdan
4273b3c055Sdan#-------------------------------------------------------------------------
4373b3c055Sdan# Run simple tests of the _patchset() API.
4473b3c055Sdan#
4573b3c055Sdando_execsql_test 1.0 {
4673b3c055Sdan  CREATE TABLE t1(a, b, c, d, PRIMARY KEY(d, a));
4773b3c055Sdan  INSERT INTO t1 VALUES(1, 2, 3, 4);
4873b3c055Sdan  INSERT INTO t1 VALUES(5, 6, 7, 8);
4973b3c055Sdan  INSERT INTO t1 VALUES(9, 10, 11, 12);
5073b3c055Sdan}
5173b3c055Sdan
5273b3c055Sdando_test 1.1 {
5373b3c055Sdan  sqlite3session S db main
5473b3c055Sdan  S attach t1
5573b3c055Sdan  execsql {
5673b3c055Sdan    INSERT INTO t1 VALUES('w', 'x', 'y', 'z');
5773b3c055Sdan    DELETE FROM t1 WHERE d=4;
5873b3c055Sdan    UPDATE t1 SET c = 14 WHERE a=5;
5973b3c055Sdan  }
6073b3c055Sdan} {}
6173b3c055Sdan
6273b3c055Sdando_patchset_test 1.2 S {
6373b3c055Sdan  {UPDATE t1 0 X..X {i 5 {} {} {} {} i 8} {{} {} {} {} i 14 {} {}}}
6473b3c055Sdan  {INSERT t1 0 X..X {} {t w t x t y t z}}
6573b3c055Sdan  {DELETE t1 0 X..X {i 1 {} {} {} {} i 4} {}}
6673b3c055Sdan}
6773b3c055Sdan
6873b3c055Sdando_test 1.3 {
6973b3c055Sdan  S delete
7073b3c055Sdan} {}
7173b3c055Sdan
7273b3c055Sdando_sql2patchset_test 1.4 {
7373b3c055Sdan  DELETE FROM t1;
7473b3c055Sdan} {
7573b3c055Sdan  {DELETE t1 0 X..X {i 5 {} {} {} {} i 8} {}}
7673b3c055Sdan  {DELETE t1 0 X..X {t w {} {} {} {} t z} {}}
7773b3c055Sdan  {DELETE t1 0 X..X {i 9 {} {} {} {} i 12} {}}
7873b3c055Sdan}
7973b3c055Sdan
8073b3c055Sdando_sql2patchset_test 1.5 {
8173b3c055Sdan  INSERT INTO t1 VALUES(X'61626364', NULL, NULL, 4.2);
8273b3c055Sdan  INSERT INTO t1 VALUES(4.2, NULL, NULL, X'61626364');
8373b3c055Sdan} {
8473b3c055Sdan  {INSERT t1 0 X..X {} {f 4.2 n {} n {} b abcd}}
8573b3c055Sdan  {INSERT t1 0 X..X {} {b abcd n {} n {} f 4.2}}
8673b3c055Sdan}
8773b3c055Sdan
8873b3c055Sdando_sql2patchset_test 1.6 {
8973b3c055Sdan  UPDATE t1 SET b=45 WHERE typeof(a)=='blob';
9073b3c055Sdan  UPDATE t1 SET c='zzzz' WHERE typeof(a)!='blob';
9173b3c055Sdan} {
9273b3c055Sdan  {UPDATE t1 0 X..X {f 4.2 {} {} {} {} b abcd} {{} {} {} {} t zzzz {} {}}}
9373b3c055Sdan  {UPDATE t1 0 X..X {b abcd {} {} {} {} f 4.2} {{} {} i 45 {} {} {} {}}}
9473b3c055Sdan}
9573b3c055Sdan
9673b3c055Sdando_sql2patchset_test 1.7 {
9773b3c055Sdan  UPDATE t1 SET b='xyz' WHERE typeof(a)=='blob';
9873b3c055Sdan  UPDATE t1 SET c='xyz' WHERE typeof(a)!='blob';
9973b3c055Sdan  UPDATE t1 SET b=45 WHERE typeof(a)=='blob';
10073b3c055Sdan  UPDATE t1 SET c='zzzz' WHERE typeof(a)!='blob';
10173b3c055Sdan} {
10273b3c055Sdan}
10373b3c055Sdan
10473b3c055Sdando_sql2patchset_test 1.8 {
10573b3c055Sdan  DELETE FROM t1;
10673b3c055Sdan} {
10773b3c055Sdan  {DELETE t1 0 X..X {f 4.2 {} {} {} {} b abcd} {}}
10873b3c055Sdan  {DELETE t1 0 X..X {b abcd {} {} {} {} f 4.2} {}}
10973b3c055Sdan}
11073b3c055Sdan
11173b3c055Sdan#-------------------------------------------------------------------------
11273b3c055Sdan# Run simple tests of _apply() with patchset objects.
11373b3c055Sdan#
11473b3c055Sdanreset_db
11573b3c055Sdan
11673b3c055Sdanproc noop {args} { error $args }
11773b3c055Sdanproc exec_rollback_replay {sql} {
11873b3c055Sdan  sqlite3session S db main
11973b3c055Sdan  S attach *
12073b3c055Sdan  execsql BEGIN
12173b3c055Sdan  execsql $sql
12273b3c055Sdan  set patchset [S patchset]
12373b3c055Sdan  S delete
12473b3c055Sdan  execsql ROLLBACK
12573b3c055Sdan  sqlite3changeset_apply db $patchset noop
12673b3c055Sdan}
12773b3c055Sdan
12873b3c055Sdando_execsql_test 2.0 {
12973b3c055Sdan  CREATE TABLE t2(a, b, c, d, PRIMARY KEY(b,c));
13073b3c055Sdan  CREATE TABLE t3(w, x, y, z, PRIMARY KEY(w));
13173b3c055Sdan}
13273b3c055Sdan
13373b3c055Sdando_test 2.1 {
13473b3c055Sdan  exec_rollback_replay {
13573b3c055Sdan    INSERT INTO t2 VALUES(1, 2, 3, 4);
13673b3c055Sdan    INSERT INTO t2 VALUES('w', 'x', 'y', 'z');
13773b3c055Sdan  }
13873b3c055Sdan  execsql { SELECT * FROM t2 }
13973b3c055Sdan} {1 2 3 4 w x y z}
14073b3c055Sdan
14173b3c055Sdando_test 2.2 {
14273b3c055Sdan  exec_rollback_replay {
14373b3c055Sdan    DELETE FROM t2 WHERE a=1;
14473b3c055Sdan    UPDATE t2 SET d = 'a';
14573b3c055Sdan  }
14673b3c055Sdan  execsql { SELECT * FROM t2 }
14773b3c055Sdan} {w x y a}
14873b3c055Sdan
14973b3c055Sdan#-------------------------------------------------------------------------
15073b3c055Sdan# sqlite3changeset_invert()
15173b3c055Sdan#
15273b3c055Sdanreset_db
15373b3c055Sdan
15473b3c055Sdando_execsql_test 3.1 { CREATE TABLE t1(x PRIMARY KEY, y) }
15573b3c055Sdando_test 3.2 {
15673b3c055Sdan  sqlite3session S db main
15773b3c055Sdan  S attach *
15873b3c055Sdan  execsql { INSERT INTO t1 VALUES(1, 2) }
15973b3c055Sdan  set patchset [S patchset]
16073b3c055Sdan  S delete
16173b3c055Sdan  list [catch { sqlite3changeset_invert $patchset } msg] [set msg]
16273b3c055Sdan} {1 SQLITE_CORRUPT}
16373b3c055Sdan
16473b3c055Sdan
16573b3c055Sdan#-------------------------------------------------------------------------
16673b3c055Sdan# sqlite3changeset_concat()
16773b3c055Sdan#
16873b3c055Sdanreset_db
16973b3c055Sdan
17073b3c055Sdanproc do_patchconcat_test {tn args} {
17164277f4aSdan  set bRevert 0
17264277f4aSdan  if {[lindex $args 0] == "-revert"} {
17364277f4aSdan    set bRevert 1
17464277f4aSdan    set args [lrange $args 1 end]
17564277f4aSdan  }
17673b3c055Sdan  set nSql [expr [llength $args]-1]
17773b3c055Sdan  set res [lindex $args $nSql]
17873b3c055Sdan  set patchlist [list]
17973b3c055Sdan
18073b3c055Sdan  execsql BEGIN
18164277f4aSdan  if {$bRevert} { execsql { SAVEPOINT x } }
18273b3c055Sdan  foreach sql [lrange $args 0 end-1] {
18373b3c055Sdan    sqlite3session S db main
18473b3c055Sdan    S attach *
18573b3c055Sdan    execsql $sql
18673b3c055Sdan    lappend patchlist [S patchset]
18773b3c055Sdan    S delete
18864277f4aSdan    if {$bRevert} { execsql { ROLLBACK TO x } }
18973b3c055Sdan  }
19073b3c055Sdan  execsql ROLLBACK
19173b3c055Sdan
19273b3c055Sdan  set patch [lindex $patchlist 0]
19373b3c055Sdan  foreach p [lrange $patchlist 1 end] {
19473b3c055Sdan    set patch [sqlite3changeset_concat $patch $p]
19573b3c055Sdan  }
19673b3c055Sdan
19773b3c055Sdan  set x [list]
19873b3c055Sdan  sqlite3session_foreach c $patch { lappend x $c }
19973b3c055Sdan
20073b3c055Sdan  uplevel [list do_test $tn [list set {} $x] [list {*}$res]]
20173b3c055Sdan}
20273b3c055Sdan
20373b3c055Sdando_execsql_test 4.1.1 {
20473b3c055Sdan  CREATE TABLE t1(x PRIMARY KEY, y, z);
20573b3c055Sdan}
20673b3c055Sdando_patchconcat_test 4.1.2 {
20773b3c055Sdan  INSERT INTO t1 VALUES(1, 2, 3);
20873b3c055Sdan} {
20973b3c055Sdan  INSERT INTO t1 VALUES(4, 5, 6);
21073b3c055Sdan} {
21173b3c055Sdan  {INSERT t1 0 X.. {} {i 1 i 2 i 3}}
21273b3c055Sdan  {INSERT t1 0 X.. {} {i 4 i 5 i 6}}
21373b3c055Sdan}
21473b3c055Sdan
21573b3c055Sdando_execsql_test 4.2.1 {
21673b3c055Sdan  INSERT INTO t1 VALUES(1, 2, 3);
21773b3c055Sdan  INSERT INTO t1 VALUES(4, 5, 6);
21873b3c055Sdan}
21964277f4aSdan
22073b3c055Sdando_patchconcat_test 4.2.2 {
22173b3c055Sdan  UPDATE t1 SET z = 'abc' WHERE x=1
22273b3c055Sdan} {
22373b3c055Sdan  UPDATE t1 SET z = 'def' WHERE x=4
22473b3c055Sdan} {
22564277f4aSdan  {UPDATE t1 0 X.. {i 1 {} {} {} {}} {{} {} {} {} t abc}}
22664277f4aSdan  {UPDATE t1 0 X.. {i 4 {} {} {} {}} {{} {} {} {} t def}}
22773b3c055Sdan}
22864277f4aSdan
22964277f4aSdando_patchconcat_test 4.2.3 {
23064277f4aSdan  DELETE FROM t1 WHERE x=1;
23164277f4aSdan} {
23264277f4aSdan  DELETE FROM t1 WHERE x=4;
23364277f4aSdan} {
23464277f4aSdan  {DELETE t1 0 X.. {i 1 {} {} {} {}} {}}
23564277f4aSdan  {DELETE t1 0 X.. {i 4 {} {} {} {}} {}}
23664277f4aSdan}
23764277f4aSdan
23864277f4aSdan
23964277f4aSdando_execsql_test 4.3.1 {
24064277f4aSdan  CREATE TABLE t2(a, b, c, d, PRIMARY KEY(c, b));
24164277f4aSdan  INSERT INTO t2 VALUES('.', 1, 1, '.');
24264277f4aSdan  INSERT INTO t2 VALUES('.', 1, 2, '.');
24364277f4aSdan  INSERT INTO t2 VALUES('.', 2, 1, '.');
24464277f4aSdan  INSERT INTO t2 VALUES('.', 2, 2, '.');
24564277f4aSdan}
24664277f4aSdan
24764277f4aSdan# INSERT + INSERT
24864277f4aSdando_patchconcat_test 4.3.2 -revert {
24964277f4aSdan  INSERT INTO t2 VALUES('a', 'a', 'a', 'a');
25064277f4aSdan} {
25164277f4aSdan  INSERT INTO t2 VALUES('b', 'a', 'a', 'b');
25264277f4aSdan} {
25364277f4aSdan  {INSERT t2 0 .XX. {} {t a t a t a t a}}
25464277f4aSdan}
25564277f4aSdan
25664277f4aSdan# INSERT + DELETE
25764277f4aSdando_patchconcat_test 4.3.3 {
25864277f4aSdan  INSERT INTO t2 VALUES('a', 'a', 'a', 'a');
25964277f4aSdan} {
26064277f4aSdan  DELETE FROM t2 WHERE c = 'a';
261*69e224f8Sdan} {}
26264277f4aSdan
26364277f4aSdan# INSERT + UPDATE
26464277f4aSdando_patchconcat_test 4.3.4 {
26564277f4aSdan  INSERT INTO t2 VALUES('a', 'a', 'a', 'a');
26664277f4aSdan} {
26764277f4aSdan  UPDATE t2 SET d = 'b' WHERE c='a';
26864277f4aSdan} {
26964277f4aSdan  {INSERT t2 0 .XX. {} {t a t a t a t b}}
27064277f4aSdan}
27164277f4aSdan
27264277f4aSdan# UPDATE + UPDATE
27364277f4aSdando_patchconcat_test 4.3.5 {
27464277f4aSdan  UPDATE t2 SET a = 'a' WHERE c=1 AND b=2;
27564277f4aSdan} {
27664277f4aSdan  UPDATE t2 SET d = 'd' WHERE c=1 AND b=2;
27764277f4aSdan} {
27864277f4aSdan  {UPDATE t2 0 .XX. {{} {} i 2 i 1 {} {}} {t a {} {} {} {} t d}}
27964277f4aSdan}
28064277f4aSdan
28164277f4aSdan# UPDATE + DELETE
28264277f4aSdando_patchconcat_test 4.3.6 {
28364277f4aSdan  UPDATE t2 SET a = 'a' WHERE c=1 AND b=2;
28464277f4aSdan} {
28564277f4aSdan  DELETE FROM t2 WHERE c=1 AND b=2;
28664277f4aSdan} {
28764277f4aSdan  {DELETE t2 0 .XX. {{} {} i 2 i 1 {} {}} {}}
28864277f4aSdan}
28964277f4aSdan
29064277f4aSdan# DELETE + INSERT
29164277f4aSdando_patchconcat_test 4.3.7 {
29264277f4aSdan  DELETE FROM t2 WHERE b=1;
29364277f4aSdan} {
29464277f4aSdan  INSERT INTO t2 VALUES('x', 1, 2, '.');
29564277f4aSdan} {
29664277f4aSdan  {DELETE t2 0 .XX. {{} {} i 1 i 1 {} {}} {}}
29764277f4aSdan  {UPDATE t2 0 .XX. {{} {} i 1 i 2 {} {}} {t x {} {} {} {} t .}}
29864277f4aSdan}
29964277f4aSdan
30064277f4aSdan# DELETE + UPDATE
30164277f4aSdando_patchconcat_test 4.3.8 -revert {
30264277f4aSdan  DELETE FROM t2 WHERE b=1 AND c=2;
30364277f4aSdan} {
30464277f4aSdan  UPDATE t2 SET a=5 WHERE b=1 AND c=2;
30564277f4aSdan} {
30664277f4aSdan  {DELETE t2 0 .XX. {{} {} i 1 i 2 {} {}} {}}
30764277f4aSdan}
30864277f4aSdan
30964277f4aSdan# DELETE + UPDATE
31064277f4aSdando_patchconcat_test 4.3.9 -revert {
31164277f4aSdan  DELETE FROM t2 WHERE b=1 AND c=2;
31264277f4aSdan} {
31364277f4aSdan  DELETE FROM t2 WHERE b=1;
31464277f4aSdan} {
31564277f4aSdan  {DELETE t2 0 .XX. {{} {} i 1 i 1 {} {}} {}}
31664277f4aSdan  {DELETE t2 0 .XX. {{} {} i 1 i 2 {} {}} {}}
31773b3c055Sdan}
31873b3c055Sdan
3192e934cd4Sdan#-------------------------------------------------------------------------
3202e934cd4Sdan# More rigorous testing of the _patchset(), _apply and _concat() APIs.
3212e934cd4Sdan#
3222e934cd4Sdan# The inputs to each test are a populate database and a list of DML
3232e934cd4Sdan# statements. This test determines that the final database is the same
3242e934cd4Sdan# if:
3252e934cd4Sdan#
3262e934cd4Sdan#   1) the statements are executed directly on the database.
3272e934cd4Sdan#
3282e934cd4Sdan#   2) a single patchset is collected while executing the statements and
3292e934cd4Sdan#      then applied to a copy of the original database file.
3302e934cd4Sdan#
3312e934cd4Sdan#   3) individual patchsets are collected for statement while executing
3322e934cd4Sdan#      them and concatenated together before being applied to a copy of
3332e934cd4Sdan#      the original database. The concatenation is done in a couple of
3342e934cd4Sdan#      different ways - linear, pairwise etc.
3352e934cd4Sdan#
3362e934cd4Sdan# All tests, as it happens, are run with both changesets and patchsets.
3372e934cd4Sdan# But the focus is on patchset capabilities.
3382e934cd4Sdan#
33973b3c055Sdan
3402e934cd4Sdan# Return a checksum of the contents of the database file. Implicit IPK
3412e934cd4Sdan# columns are not included in the checksum - just modifying rowids does
3422e934cd4Sdan# not change the database checksum.
3432e934cd4Sdan#
3442e934cd4Sdanproc databasecksum {db} {
3452e934cd4Sdan  set alltab [$db eval {SELECT name FROM sqlite_master WHERE type='table'}]
3462e934cd4Sdan  foreach tab $alltab {
3472e934cd4Sdan    $db eval "SELECT * FROM $tab LIMIT 1" res { }
3482e934cd4Sdan    set slist [list]
3492e934cd4Sdan    foreach col [lsort $res(*)] {
3502e934cd4Sdan      lappend slist "quote($col)"
3512e934cd4Sdan    }
3522e934cd4Sdan    set sql "SELECT [join $slist ,] FROM $tab"
3532e934cd4Sdan    append txt "[lsort [$db eval $sql]]\n"
3542e934cd4Sdan  }
3552e934cd4Sdan  return [md5 $txt]
3562e934cd4Sdan}
3572e934cd4Sdan
3582e934cd4Sdanproc do_patchset_test {tn tstcmd lSql} {
3592e934cd4Sdan  if {$tstcmd != "patchset" && $tstcmd != "changeset"} {
3602e934cd4Sdan    error "have $tstcmd: must be patchset or changeset"
3612e934cd4Sdan  }
3622e934cd4Sdan
3632e934cd4Sdan  foreach fname {test.db2 test.db3 test.db4 test.db5} {
3642e934cd4Sdan    forcedelete $fname
3652e934cd4Sdan    forcecopy test.db $fname
3662e934cd4Sdan  }
3672e934cd4Sdan
3682e934cd4Sdan  # Execute the SQL statements on [db]. Collect a patchset for each
3692e934cd4Sdan  # individual statement, as well as a single patchset for the entire
3702e934cd4Sdan  # operation.
3712e934cd4Sdan  sqlite3session S db main
3722e934cd4Sdan  S attach *
3732e934cd4Sdan  foreach sql $lSql {
3742e934cd4Sdan    sqlite3session T db main
3752e934cd4Sdan    T attach *
3762e934cd4Sdan    db eval $sql
377cbf6d2d2Sdan    lappend lPatch [T $tstcmd]
3782e934cd4Sdan    T delete
3792e934cd4Sdan  }
380cbf6d2d2Sdan  set patchset [S $tstcmd]
3812e934cd4Sdan  S delete
3822e934cd4Sdan
3832e934cd4Sdan  # Calculate a checksum for the final database.
3842e934cd4Sdan  set cksum [databasecksum db]
3852e934cd4Sdan
3862e934cd4Sdan  # 1. Apply the single large patchset to test.db2
3872e934cd4Sdan  sqlite3 db2 test.db2
3882e934cd4Sdan  sqlite3changeset_apply db2 $patchset noop
3892e934cd4Sdan  uplevel [list do_test $tn.1 { databasecksum db2 } $cksum ]
3902e934cd4Sdan  db2 close
3912e934cd4Sdan
3922e934cd4Sdan  # 2. Apply each of the single-statement patchsets to test.db3
3932e934cd4Sdan  sqlite3 db2 test.db3
3942e934cd4Sdan  foreach p $lPatch {
3952e934cd4Sdan    sqlite3changeset_apply db2 $p noop
3962e934cd4Sdan  }
3972e934cd4Sdan  uplevel [list do_test $tn.2 { databasecksum db2 } $cksum ]
3982e934cd4Sdan  db2 close
3992e934cd4Sdan
4002e934cd4Sdan  # 3. Concatenate all single-statement patchsets into a single large
4012e934cd4Sdan  #    patchset, then apply it to test.db4.
4022e934cd4Sdan  #
4032e934cd4Sdan  sqlite3 db2 test.db4
4042e934cd4Sdan  set big ""
4052e934cd4Sdan  foreach p $lPatch {
4062e934cd4Sdan    set big [sqlite3changeset_concat $big $p]
4072e934cd4Sdan  }
4082e934cd4Sdan  sqlite3changeset_apply db2 $big noop
4092e934cd4Sdan  uplevel [list do_test $tn.3 { databasecksum db2 } $cksum ]
4102e934cd4Sdan  db2 close
4112e934cd4Sdan
4122e934cd4Sdan  # 4. Concatenate all single-statement patchsets pairwise into a single
4132e934cd4Sdan  #    large patchset, then apply it to test.db5. Pairwise concatenation:
4142e934cd4Sdan  #
4152e934cd4Sdan  #         a b c d e f g h i j k
4162e934cd4Sdan  #      -> {a b} {c d} {e f} {g h} {i j} k
4172e934cd4Sdan  #      -> {a b c d} {e f g h} {i j k}
4182e934cd4Sdan  #      -> {a b c d e f g h} {i j k}
4192e934cd4Sdan  #      -> {a b c d e f g h i j k}
4202e934cd4Sdan  #      -> APPLY!
4212e934cd4Sdan  #
4222e934cd4Sdan  sqlite3 db2 test.db5
4232e934cd4Sdan  set L $lPatch
4242e934cd4Sdan  while {[llength $L] > 1} {
4252e934cd4Sdan    set O [list]
4262e934cd4Sdan    for {set i 0} {$i < [llength $L]} {incr i 2} {
4272e934cd4Sdan      if {$i==[llength $L]-1} {
4282e934cd4Sdan        lappend O [lindex $L $i]
4292e934cd4Sdan      } else {
4302e934cd4Sdan        set i1 [expr $i+1]
4312e934cd4Sdan        lappend O [sqlite3changeset_concat [lindex $L $i] [lindex $L $i1]]
4322e934cd4Sdan      }
4332e934cd4Sdan    }
4342e934cd4Sdan    set L $O
4352e934cd4Sdan  }
4362e934cd4Sdan  sqlite3changeset_apply db2 [lindex $L 0] noop
4372e934cd4Sdan  uplevel [list do_test $tn.4 { databasecksum db2 } $cksum ]
4382e934cd4Sdan  db2 close
4392e934cd4Sdan}
4402e934cd4Sdan
4412e934cd4Sdanproc do_patchset_changeset_test {tn initsql args} {
4422e934cd4Sdan  foreach tstcmd {patchset changeset} {
4432e934cd4Sdan    reset_db
4442e934cd4Sdan    execsql $initsql
445082c96dfSdan    set x 0
4462e934cd4Sdan    foreach sql $args {
447082c96dfSdan      incr x
4482e934cd4Sdan      set lSql [split $sql ";"]
449082c96dfSdan      uplevel [list do_patchset_test $tn.$tstcmd.$x $tstcmd $lSql]
4502e934cd4Sdan    }
4512e934cd4Sdan  }
4522e934cd4Sdan}
4532e934cd4Sdan
4542e934cd4Sdando_patchset_changeset_test 5.1 {
4552e934cd4Sdan  CREATE TABLE t1(a PRIMARY KEY, b, c);
4562e934cd4Sdan  INSERT INTO t1 VALUES(1, 2, 3);
4572e934cd4Sdan} {
4582e934cd4Sdan  INSERT INTO t1 VALUES(4, 5, 6);
4592e934cd4Sdan  DELETE FROM t1 WHERE a=1;
4602e934cd4Sdan} {
4612e934cd4Sdan  INSERT INTO t1 VALUES(7, 8, 9);
4622e934cd4Sdan  UPDATE t1 SET c = 5;
4632e934cd4Sdan  INSERT INTO t1 VALUES(10, 11, 12);
4642e934cd4Sdan  UPDATE t1 SET c = 6;
4652e934cd4Sdan  INSERT INTO t1 VALUES(13, 14, 15);
4662e934cd4Sdan} {
4672e934cd4Sdan  UPDATE t1 SET c=c+1;
4682e934cd4Sdan  DELETE FROM t1 WHERE (a%2);
4692e934cd4Sdan}
4702e934cd4Sdan
4712e934cd4Sdando_patchset_changeset_test 5.2 {
4722e934cd4Sdan  CREATE TABLE t1(a PRIMARY KEY, b, c);
4732e934cd4Sdan  CREATE TABLE t2(a, b, c, d, PRIMARY KEY(c, b));
4742e934cd4Sdan} {
4752e934cd4Sdan  INSERT INTO t1 VALUES(x'00', 0, 'zero');
4762e934cd4Sdan  INSERT INTO t1 VALUES(x'01', 1, 'one');
4772e934cd4Sdan  INSERT INTO t1 VALUES(x'02', 4, 'four');
4782e934cd4Sdan  INSERT INTO t1 VALUES(x'03', 9, 'nine');
4792e934cd4Sdan  INSERT INTO t1 VALUES(x'04', 16, 'sixteen');
4802e934cd4Sdan  INSERT INTO t1 VALUES(x'05', 25, 'twenty-five');
4812e934cd4Sdan} {
4822e934cd4Sdan  UPDATE t1 SET a = b WHERE b<=4;
4832e934cd4Sdan  INSERT INTO t2 SELECT NULL, * FROM t1;
4842e934cd4Sdan  DELETE FROM t1 WHERE b=25;
4852e934cd4Sdan} {
4862e934cd4Sdan  DELETE FROM t2;
4872e934cd4Sdan  INSERT INTO t2 SELECT NULL, * FROM t1;
4882e934cd4Sdan  DELETE FROM t1;
4892e934cd4Sdan  INSERT INTO t1 SELECT b, c, d FROM t2;
4902e934cd4Sdan  UPDATE t1 SET b = b+1;
4912e934cd4Sdan  UPDATE t1 SET b = b+1;
4922e934cd4Sdan  UPDATE t1 SET b = b+1;
4932e934cd4Sdan}
4942e934cd4Sdan
495082c96dfSdanset initsql { CREATE TABLE t1(a, b, c, PRIMARY KEY(c, b)); }
496082c96dfSdanfor {set i 0} {$i < 1000} {incr i} {
497082c96dfSdan  append insert "INSERT INTO t1 VALUES($i, $i, $i);"
498082c96dfSdan  append delete "DELETE FROM t1 WHERE b=$i;"
499082c96dfSdan}
500082c96dfSdando_patchset_changeset_test 5.3 \
501082c96dfSdan  $initsql $insert $delete     \
502082c96dfSdan  $insert $delete              \
503082c96dfSdan  "$insert $delete"            \
504082c96dfSdan  $delete
505082c96dfSdan
5062e934cd4Sdan
5072e934cd4Sdanfinish_test
508