diff --git a/ext/session/sessionnoop.test b/ext/session/sessionnoop.test index 5549773440..16c60b7abf 100644 --- a/ext/session/sessionnoop.test +++ b/ext/session/sessionnoop.test @@ -1,4 +1,4 @@ -# 2011 March 07 +# 2021 Februar 20 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: @@ -20,159 +20,166 @@ ifcapable !session {finish_test; return} set testprefix sessionnoop -foreach {tn wo} { - 1 "" - 2 " WITHOUT ROWID " +#------------------------------------------------------------------------- +# Test plan: +# +# 1.*: Test that concatenating changesets cannot produce a noop UPDATE. +# 2.*: Test that rebasing changesets cannot produce a noop UPDATE. +# 3.*: Test that sqlite3changeset_apply() ignores noop UPDATE changes. +# + +do_execsql_test 1.0 { + CREATE TABLE t1(a PRIMARY KEY, b, c, d); + INSERT INTO t1 VALUES(1, 1, 1, 1); + INSERT INTO t1 VALUES(2, 2, 2, 2); + INSERT INTO t1 VALUES(3, 3, 3, 3); +} + +proc do_concat_test {tn sql1 sql2 res} { + uplevel [list do_test $tn [subst -nocommands { + set C1 [changeset_from_sql {$sql1}] + set C2 [changeset_from_sql {$sql2}] + set C3 [sqlite3changeset_concat [set C1] [set C2]] + set got [list] + sqlite3session_foreach elem [set C3] { lappend got [set elem] } + set got + }] [list {*}$res]] +} + +do_concat_test 1.1 { + UPDATE t1 SET c=c+1; +} { + UPDATE t1 SET c=c-1; } { - reset_db - eval [string map [list %WO% $wo] { -do_execsql_test $tn.1.0 { - CREATE TABLE t1(a PRIMARY KEY, b, c) %WO%; - INSERT INTO t1 VALUES('a', 'A', 'AAA'); - INSERT INTO t1 VALUES('b', 'B', 'BBB'); - INSERT INTO t1 VALUES('c', 'C', 'CCC'); - INSERT INTO t1 VALUES('d', 'D', 'DDD'); - INSERT INTO t1 VALUES('e', 'E', 'EEE'); } -forcedelete test.db2 -sqlite3 db2 test.db2 - -do_execsql_test -db db2 $tn.1.1 { - CREATE TABLE t1(a PRIMARY KEY, b, c) %WO%; - INSERT INTO t1 VALUES('a', 'A', 'AAA'); - INSERT INTO t1 VALUES('b', 'B', '123'); - INSERT INTO t1 VALUES('c', 'C', 'CCC'); - INSERT INTO t1 VALUES('e', 'E', 'EEE'); - INSERT INTO t1 VALUES('f', 'F', 'FFF'); -} - -set C [changeset_from_sql { - UPDATE t1 SET c='123' WHERE a='b'; - DELETE FROM t1 WHERE a='d'; - INSERT INTO t1 VALUES('f', 'F', 'FFF'); -}] - - -set ::conflict_list [list] -proc xConflict {args} { - lappend ::conflict_list $args - return "OMIT" -} -do_test $tn.1.2 { - sqlite3changeset_apply_v2 db2 $C xConflict - set ::conflict_list -} [list {*}{ - {UPDATE t1 DATA {t b {} {} t BBB} {{} {} {} {} t 123} {t b t B t 123}} - {INSERT t1 CONFLICT {t f t F t FFF} {t f t F t FFF}} - {DELETE t1 NOTFOUND {t d t D t DDD}} -}] -do_test $tn.1.3 { - set ::conflict_list [list] - sqlite3changeset_apply_v2 db2 $C xConflict - set ::conflict_list -} [list {*}{ - {UPDATE t1 DATA {t b {} {} t BBB} {{} {} {} {} t 123} {t b t B t 123}} - {INSERT t1 CONFLICT {t f t F t FFF} {t f t F t FFF}} - {DELETE t1 NOTFOUND {t d t D t DDD}} -}] - -do_test $tn.1.4 { - set ::conflict_list [list] - sqlite3changeset_apply_v2 -ignorenoop db2 $C xConflict - set ::conflict_list -} {} - -do_execsql_test -db db2 1.5 { - UPDATE t1 SET b='G' WHERE a='f'; - UPDATE t1 SET c='456' WHERE a='b'; -} - -do_test $tn.1.6 { - set ::conflict_list [list] - sqlite3changeset_apply_v2 -ignorenoop db2 $C xConflict - set ::conflict_list -} [list {*}{ - {UPDATE t1 DATA {t b {} {} t BBB} {{} {} {} {} t 123} {t b t B t 456}} - {INSERT t1 CONFLICT {t f t F t FFF} {t f t G t FFF}} -}] - -db2 close - -#-------------------------------------------------------------------------- - -reset_db -forcedelete test.db2 -sqlite3 db2 test.db2 -do_execsql_test $tn.2.0 { - CREATE TABLE t1(a PRIMARY KEY, b) %WO%; -} -do_execsql_test -db db2 $tn.2.1 { - CREATE TABLE t1(a PRIMARY KEY, b, c DEFAULT 'val') %WO%; -} - -do_test $tn.2.2 { - do_then_apply_sql -ignorenoop { - INSERT INTO t1 VALUES(1, 2); - } - do_then_apply_sql -ignorenoop { - UPDATE t1 SET b=2 WHERE a=1 - } -} {} - - -}] -} - -db2 close - #------------------------------------------------------------------------- reset_db -forcedelete test.db2 +do_execsql_test 2.0 { + CREATE TABLE t1(a PRIMARY KEY, b, c); + INSERT INTO t1 VALUES(1, 1, 1); + INSERT INTO t1 VALUES(2, 2, 2); + INSERT INTO t1 VALUES(3, 3, 3); +} + +proc do_rebase_test {tn sql_local sql_remote conflict_res expected} { + proc xConflict {args} [list return $conflict_res] + + uplevel [list \ + do_test $tn [subst -nocommands { + execsql BEGIN + set c_remote [changeset_from_sql {$sql_remote}] + execsql ROLLBACK + + execsql BEGIN + set c_local [changeset_from_sql {$sql_local}] + set base [sqlite3changeset_apply_v2 db [set c_remote] xConflict] + execsql ROLLBACK + + sqlite3rebaser_create R + R config [set base] + set res [list] + sqlite3session_foreach elem [R rebase [set c_local]] { + lappend res [set elem] + } + R delete + set res + }] [list {*}$expected] + ] +} + +do_rebase_test 2.1 { + UPDATE t1 SET c=2 WHERE a=1; -- local +} { + UPDATE t1 SET c=3 WHERE a=1; -- remote +} OMIT { + {UPDATE t1 0 X.. {i 1 {} {} i 3} {{} {} {} {} i 2}} +} + +do_rebase_test 2.2 { + UPDATE t1 SET c=2 WHERE a=1; -- local +} { + UPDATE t1 SET c=3 WHERE a=1; -- remote +} REPLACE { +} + +do_rebase_test 2.3.1 { + UPDATE t1 SET c=4 WHERE a=1; -- local +} { + UPDATE t1 SET c=4 WHERE a=1 -- remote +} OMIT { + {UPDATE t1 0 X.. {i 1 {} {} i 4} {{} {} {} {} i 4}} +} + +do_rebase_test 2.3.2 { + UPDATE t1 SET c=5 WHERE a=1; -- local +} { + UPDATE t1 SET c=5 WHERE a=1 -- remote +} REPLACE { +} + +#------------------------------------------------------------------------- +# +reset_db do_execsql_test 3.0 { - CREATE TABLE xyz(a, b, c, PRIMARY KEY(a, b), UNIQUE(c)); - ANALYZE; - WITH s(i) AS ( - VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100 - ) - INSERT INTO xyz SELECT i, i, i FROM s; - VACUUM INTO 'test.db2'; + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); + INSERT INTO t1 VALUES(1, 1, 1); + INSERT INTO t1 VALUES(2, 2, 2); + INSERT INTO t1 VALUES(3, 3, 3); + INSERT INTO t1 VALUES(4, 4, 4); } -set C [changeset_from_sql { ANALYZE }] -sqlite3 db2 test.db2 +# Arg $pkstr contains one character for each column in the table. An +# "X" for PK column, or a "." for a non-PK. +# +proc mk_tbl_header {name pkstr} { + set ret [binary format H2c 54 [string length $pkstr]] + foreach i [split $pkstr {}] { + if {$i=="X"} { + append ret [binary format H2 01] + } else { + if {$i!="."} {error "bad pkstr: $pkstr ($i)"} + append ret [binary format H2 00] + } + } + append ret $name + append ret [binary format H2 00] + set ret +} -set ::conflict_list [list] -proc xConflict {args} { lappend ::conflict_list $args ; return "OMIT" } +proc mk_update_change {args} { + set ret [binary format H2H2 17 00] + foreach a $args { + if {$a==""} { + append ret [binary format H2 00] + } else { + append ret [binary format H2W 01 $a] + } + } + set ret +} + +proc xConflict {args} { return "ABORT" } do_test 3.1 { - sqlite3changeset_apply_v2 db2 $C xConflict - set ::conflict_list + set C [mk_tbl_header t1 X..] + append C [mk_update_change 1 {} 1 {} {} 500] + append C [mk_update_change 2 {} {} {} {} {}] + append C [mk_update_change 3 3 {} {} 600 {}] + append C [mk_update_change 4 {} {} {} {} {}] + + sqlite3changeset_apply_v2 db $C xConflict } {} - -do_test 3.2 { - sqlite3changeset_apply_v2 -ignorenoop db2 $C xConflict - set ::conflict_list -} {} - -do_test 3.3 { - sqlite3changeset_apply_v2 db2 $C xConflict - set ::conflict_list -} [list {*}{ - {INSERT sqlite_stat1 CONFLICT {t xyz t sqlite_autoindex_xyz_1 t {100 1 1}} {t xyz t sqlite_autoindex_xyz_1 t {100 1 1}}} - {INSERT sqlite_stat1 CONFLICT {t xyz t sqlite_autoindex_xyz_2 t {100 1}} {t xyz t sqlite_autoindex_xyz_2 t {100 1}}} -}] - -do_execsql_test -db db2 3.4 { - UPDATE sqlite_stat1 SET stat='200 1 1' WHERE idx='sqlite_autoindex_xyz_1'; +do_execsql_test 3.2 { + SELECT * FROM t1 +} { + 1 1 500 + 2 2 2 + 3 600 3 + 4 4 4 } -do_test 3.5 { - set ::conflict_list [list] - sqlite3changeset_apply_v2 -ignorenoop db2 $C xConflict - set ::conflict_list -} [list {*}{ - {INSERT sqlite_stat1 CONFLICT {t xyz t sqlite_autoindex_xyz_1 t {100 1 1}} {t xyz t sqlite_autoindex_xyz_1 t {200 1 1}}} -}] + + diff --git a/ext/session/sessionnoop2.test b/ext/session/sessionnoop2.test new file mode 100644 index 0000000000..5549773440 --- /dev/null +++ b/ext/session/sessionnoop2.test @@ -0,0 +1,180 @@ +# 2011 March 07 +# +# 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. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# + +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 +ifcapable !session {finish_test; return} + +set testprefix sessionnoop + +foreach {tn wo} { + 1 "" + 2 " WITHOUT ROWID " +} { + reset_db + eval [string map [list %WO% $wo] { +do_execsql_test $tn.1.0 { + CREATE TABLE t1(a PRIMARY KEY, b, c) %WO%; + INSERT INTO t1 VALUES('a', 'A', 'AAA'); + INSERT INTO t1 VALUES('b', 'B', 'BBB'); + INSERT INTO t1 VALUES('c', 'C', 'CCC'); + INSERT INTO t1 VALUES('d', 'D', 'DDD'); + INSERT INTO t1 VALUES('e', 'E', 'EEE'); +} + +forcedelete test.db2 +sqlite3 db2 test.db2 + +do_execsql_test -db db2 $tn.1.1 { + CREATE TABLE t1(a PRIMARY KEY, b, c) %WO%; + INSERT INTO t1 VALUES('a', 'A', 'AAA'); + INSERT INTO t1 VALUES('b', 'B', '123'); + INSERT INTO t1 VALUES('c', 'C', 'CCC'); + INSERT INTO t1 VALUES('e', 'E', 'EEE'); + INSERT INTO t1 VALUES('f', 'F', 'FFF'); +} + +set C [changeset_from_sql { + UPDATE t1 SET c='123' WHERE a='b'; + DELETE FROM t1 WHERE a='d'; + INSERT INTO t1 VALUES('f', 'F', 'FFF'); +}] + + +set ::conflict_list [list] +proc xConflict {args} { + lappend ::conflict_list $args + return "OMIT" +} +do_test $tn.1.2 { + sqlite3changeset_apply_v2 db2 $C xConflict + set ::conflict_list +} [list {*}{ + {UPDATE t1 DATA {t b {} {} t BBB} {{} {} {} {} t 123} {t b t B t 123}} + {INSERT t1 CONFLICT {t f t F t FFF} {t f t F t FFF}} + {DELETE t1 NOTFOUND {t d t D t DDD}} +}] +do_test $tn.1.3 { + set ::conflict_list [list] + sqlite3changeset_apply_v2 db2 $C xConflict + set ::conflict_list +} [list {*}{ + {UPDATE t1 DATA {t b {} {} t BBB} {{} {} {} {} t 123} {t b t B t 123}} + {INSERT t1 CONFLICT {t f t F t FFF} {t f t F t FFF}} + {DELETE t1 NOTFOUND {t d t D t DDD}} +}] + +do_test $tn.1.4 { + set ::conflict_list [list] + sqlite3changeset_apply_v2 -ignorenoop db2 $C xConflict + set ::conflict_list +} {} + +do_execsql_test -db db2 1.5 { + UPDATE t1 SET b='G' WHERE a='f'; + UPDATE t1 SET c='456' WHERE a='b'; +} + +do_test $tn.1.6 { + set ::conflict_list [list] + sqlite3changeset_apply_v2 -ignorenoop db2 $C xConflict + set ::conflict_list +} [list {*}{ + {UPDATE t1 DATA {t b {} {} t BBB} {{} {} {} {} t 123} {t b t B t 456}} + {INSERT t1 CONFLICT {t f t F t FFF} {t f t G t FFF}} +}] + +db2 close + +#-------------------------------------------------------------------------- + +reset_db +forcedelete test.db2 +sqlite3 db2 test.db2 +do_execsql_test $tn.2.0 { + CREATE TABLE t1(a PRIMARY KEY, b) %WO%; +} +do_execsql_test -db db2 $tn.2.1 { + CREATE TABLE t1(a PRIMARY KEY, b, c DEFAULT 'val') %WO%; +} + +do_test $tn.2.2 { + do_then_apply_sql -ignorenoop { + INSERT INTO t1 VALUES(1, 2); + } + do_then_apply_sql -ignorenoop { + UPDATE t1 SET b=2 WHERE a=1 + } +} {} + + +}] +} + +db2 close + +#------------------------------------------------------------------------- +reset_db +forcedelete test.db2 +do_execsql_test 3.0 { + CREATE TABLE xyz(a, b, c, PRIMARY KEY(a, b), UNIQUE(c)); + ANALYZE; + WITH s(i) AS ( + VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100 + ) + INSERT INTO xyz SELECT i, i, i FROM s; + VACUUM INTO 'test.db2'; +} + +set C [changeset_from_sql { ANALYZE }] +sqlite3 db2 test.db2 + +set ::conflict_list [list] +proc xConflict {args} { lappend ::conflict_list $args ; return "OMIT" } +do_test 3.1 { + sqlite3changeset_apply_v2 db2 $C xConflict + set ::conflict_list +} {} + +do_test 3.2 { + sqlite3changeset_apply_v2 -ignorenoop db2 $C xConflict + set ::conflict_list +} {} + +do_test 3.3 { + sqlite3changeset_apply_v2 db2 $C xConflict + set ::conflict_list +} [list {*}{ + {INSERT sqlite_stat1 CONFLICT {t xyz t sqlite_autoindex_xyz_1 t {100 1 1}} {t xyz t sqlite_autoindex_xyz_1 t {100 1 1}}} + {INSERT sqlite_stat1 CONFLICT {t xyz t sqlite_autoindex_xyz_2 t {100 1}} {t xyz t sqlite_autoindex_xyz_2 t {100 1}}} +}] + +do_execsql_test -db db2 3.4 { + UPDATE sqlite_stat1 SET stat='200 1 1' WHERE idx='sqlite_autoindex_xyz_1'; +} + +do_test 3.5 { + set ::conflict_list [list] + sqlite3changeset_apply_v2 -ignorenoop db2 $C xConflict + set ::conflict_list +} [list {*}{ + {INSERT sqlite_stat1 CONFLICT {t xyz t sqlite_autoindex_xyz_1 t {100 1 1}} {t xyz t sqlite_autoindex_xyz_1 t {200 1 1}}} +}] + + + +finish_test + diff --git a/manifest b/manifest index 7eedebd097..395629ab8d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\scountofview.test\sso\sthat\sit\sworks\swith\sSQLITE_OMIT_PROGRESS_CALLBACK\sbuilds. -D 2023-03-09T15:08:06.155 +C Reinstate\ssome\stest\scases\saccidentally\sremoved\sby\s[cb023fe28560ce0f]. +D 2023-03-09T16:11:43.576 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -456,7 +456,8 @@ F ext/session/sessionfault.test 573bf027fb870d57bd4e7cf50822a3e4b17b2b9234074387 F ext/session/sessionfault2.test b0d6a7c1d7398a7e800d84657404909c7d385965ea8576dc79ed344c46fbf41c F ext/session/sessioninvert.test 04075517a9497a80d39c495ba6b44f3982c7371129b89e2c52219819bc105a25 F ext/session/sessionmem.test f2a735db84a3e9e19f571033b725b0b2daf847f3f28b1da55a0c1a4e74f1de09 -F ext/session/sessionnoop.test 5c9a882219e54711c98dccd2fd81392f189a59325e4fb5d8ed25e33a0c2f0ba2 +F ext/session/sessionnoop.test a9366a36a95ef85f8a3687856ebef46983df399541174cb1ede2ee53b8011bc7 +F ext/session/sessionnoop2.test 5c9a882219e54711c98dccd2fd81392f189a59325e4fb5d8ed25e33a0c2f0ba2 F ext/session/sessionrebase.test ccfa716b23bd1d3b03217ee58cfd90c78d4b99f53e6a9a2f05e82363b9142810 F ext/session/sessionsize.test 6f644aff31c7f1e4871e9ff3542766e18da68fc7e587b83a347ea9820a002dd8 F ext/session/sessionstat1.test b039e38e2ba83767b464baf39b297cc0b1cc6f3292255cb467ea7e12d0d0280c @@ -2049,8 +2050,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P a5db97fa17d15711ab19af70595912d342ffa326a9b7029d4deb2194ae72a9f0 -R 3676734d6a6a7d185c9f818259772398 +P 2fc7c3fcee05c2a251ceb3666f3f6e9014cfe6e2f8570b72c43f251067e6b252 +R 9fdb5fa7fb7a117f6c9f957b7fddcae2 U dan -Z dc232d0f3fec0eb69d0d02fdfd511211 +Z 5974dbe29f84c67ef0a243c359b4746e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 30323296f9..118682aaf8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2fc7c3fcee05c2a251ceb3666f3f6e9014cfe6e2f8570b72c43f251067e6b252 \ No newline at end of file +870de61f8ef8781f2f9969b012f5c1cb95b6bce1a9a4dcaf02945b7846c3aa83 \ No newline at end of file