mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Add the SQLITE_CHANGESETAPPLY_IGNORENOOP flag, which may be passed to sqlite3changeset_apply_v2() to have it ignore changes that would be no-ops if applied to the database (e.g. deleting a row that has already been deleted), instead of considering them conflicts.
FossilOrigin-Name: cb023fe28560ce0f8c2fd48042553fcdb9db81eba9552be75165de0d46a2645c
This commit is contained in:
@ -191,7 +191,7 @@ do_common_sql {
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach {tn sql} [string map {%T1% t1 %T2% t2 %T3% t3 %T4% t4} $set_of_tests] {
|
foreach {tn sql} [string map {%T1% t1 %T2% t2 %T3% t3 %T4% t4} $set_of_tests] {
|
||||||
do_then_apply_sql $sql
|
do_then_apply_sql -ignorenoop $sql
|
||||||
do_test 2.$tn { compare_db db db2 } {}
|
do_test 2.$tn { compare_db db db2 } {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -598,7 +598,7 @@ do_common_sql {
|
|||||||
INSERT INTO t1 SELECT NULL, 0, 0, 0, 0, 0 FROM s
|
INSERT INTO t1 SELECT NULL, 0, 0, 0, 0, 0 FROM s
|
||||||
}
|
}
|
||||||
|
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
UPDATE t1 SET f=f+1 WHERE a=1;
|
UPDATE t1 SET f=f+1 WHERE a=1;
|
||||||
UPDATE t1 SET e=e+1 WHERE a=2;
|
UPDATE t1 SET e=e+1 WHERE a=2;
|
||||||
UPDATE t1 SET e=e+1, f=f+1 WHERE a=3;
|
UPDATE t1 SET e=e+1, f=f+1 WHERE a=3;
|
||||||
|
@ -34,7 +34,7 @@ do_test 1.0 {
|
|||||||
INSERT INTO t1 VALUES(2, 'two');
|
INSERT INTO t1 VALUES(2, 'two');
|
||||||
INSERT INTO t1 VALUES(3, 'three');
|
INSERT INTO t1 VALUES(3, 'three');
|
||||||
}
|
}
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
DELETE FROM t1 WHERE a=1;
|
DELETE FROM t1 WHERE a=1;
|
||||||
INSERT INTO t1 VALUES(4, 'one');
|
INSERT INTO t1 VALUES(4, 'one');
|
||||||
}
|
}
|
||||||
@ -42,7 +42,7 @@ do_test 1.0 {
|
|||||||
} {}
|
} {}
|
||||||
|
|
||||||
do_test 1.1 {
|
do_test 1.1 {
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
DELETE FROM t1 WHERE a=4;
|
DELETE FROM t1 WHERE a=4;
|
||||||
INSERT INTO t1 VALUES(1, 'one');
|
INSERT INTO t1 VALUES(1, 'one');
|
||||||
}
|
}
|
||||||
@ -51,7 +51,7 @@ do_test 1.1 {
|
|||||||
|
|
||||||
do_test 1.2 {
|
do_test 1.2 {
|
||||||
execsql { INSERT INTO t1 VALUES(5, 'five') } db2
|
execsql { INSERT INTO t1 VALUES(5, 'five') } db2
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
INSERT INTO t1 VALUES(11, 'eleven');
|
INSERT INTO t1 VALUES(11, 'eleven');
|
||||||
INSERT INTO t1 VALUES(12, 'five');
|
INSERT INTO t1 VALUES(12, 'five');
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ do_test 2.2.1 {
|
|||||||
# It is not possible to apply the changeset generated by the following
|
# It is not possible to apply the changeset generated by the following
|
||||||
# SQL, as none of the three updated rows may be updated as part of the
|
# SQL, as none of the three updated rows may be updated as part of the
|
||||||
# first pass.
|
# first pass.
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
UPDATE t1 SET b=0 WHERE a=1;
|
UPDATE t1 SET b=0 WHERE a=1;
|
||||||
UPDATE t1 SET b=1 WHERE a=2;
|
UPDATE t1 SET b=1 WHERE a=2;
|
||||||
UPDATE t1 SET b=2 WHERE a=3;
|
UPDATE t1 SET b=2 WHERE a=3;
|
||||||
@ -109,7 +109,7 @@ do_test 3.1 {
|
|||||||
} {}
|
} {}
|
||||||
|
|
||||||
do_test 3.3 {
|
do_test 3.3 {
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
UPDATE t1 SET b=4 WHERE a=3;
|
UPDATE t1 SET b=4 WHERE a=3;
|
||||||
UPDATE t1 SET b=3 WHERE a=2;
|
UPDATE t1 SET b=3 WHERE a=2;
|
||||||
UPDATE t1 SET b=2 WHERE a=1;
|
UPDATE t1 SET b=2 WHERE a=1;
|
||||||
@ -118,7 +118,7 @@ do_test 3.3 {
|
|||||||
} {}
|
} {}
|
||||||
|
|
||||||
do_test 3.4 {
|
do_test 3.4 {
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
UPDATE t1 SET b=1 WHERE a=1;
|
UPDATE t1 SET b=1 WHERE a=1;
|
||||||
UPDATE t1 SET b=2 WHERE a=2;
|
UPDATE t1 SET b=2 WHERE a=2;
|
||||||
UPDATE t1 SET b=3 WHERE a=3;
|
UPDATE t1 SET b=3 WHERE a=3;
|
||||||
@ -148,7 +148,7 @@ do_test 4.1 {
|
|||||||
} {}
|
} {}
|
||||||
|
|
||||||
do_test 4.2 {
|
do_test 4.2 {
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
UPDATE t1 SET b=4 WHERE a=3;
|
UPDATE t1 SET b=4 WHERE a=3;
|
||||||
UPDATE t1 SET b=3 WHERE a=2;
|
UPDATE t1 SET b=3 WHERE a=2;
|
||||||
UPDATE t1 SET b=2 WHERE a=1;
|
UPDATE t1 SET b=2 WHERE a=1;
|
||||||
@ -161,7 +161,7 @@ do_test 4.2 {
|
|||||||
} {}
|
} {}
|
||||||
|
|
||||||
do_test 4.3 {
|
do_test 4.3 {
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
UPDATE t1 SET b=1 WHERE a=1;
|
UPDATE t1 SET b=1 WHERE a=1;
|
||||||
UPDATE t1 SET b=2 WHERE a=2;
|
UPDATE t1 SET b=2 WHERE a=2;
|
||||||
UPDATE t1 SET b=3 WHERE a=3;
|
UPDATE t1 SET b=3 WHERE a=3;
|
||||||
@ -191,7 +191,7 @@ do_execsql_test -db db2 5.0.2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_test 5.1 {
|
do_test 5.1 {
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
INSERT INTO t1 VALUES(1, 2, 3);
|
INSERT INTO t1 VALUES(1, 2, 3);
|
||||||
INSERT INTO t2 VALUES(4, 5, 6);
|
INSERT INTO t2 VALUES(4, 5, 6);
|
||||||
INSERT INTO t3 VALUES(7, 8, 9);
|
INSERT INTO t3 VALUES(7, 8, 9);
|
||||||
|
@ -25,7 +25,7 @@ do_test 1.0 {
|
|||||||
do_common_sql {
|
do_common_sql {
|
||||||
CREATE TABLE t1(a, b, c, PRIMARY KEY(a, b));
|
CREATE TABLE t1(a, b, c, PRIMARY KEY(a, b));
|
||||||
}
|
}
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
WITH s(i) AS (
|
WITH s(i) AS (
|
||||||
VALUES(1) UNION ALL SELECT i+1 FROM s WHERe i<10000
|
VALUES(1) UNION ALL SELECT i+1 FROM s WHERe i<10000
|
||||||
)
|
)
|
||||||
|
@ -112,20 +112,52 @@ proc patchset_from_sql {sql {dbname main}} {
|
|||||||
return $patchset
|
return $patchset
|
||||||
}
|
}
|
||||||
|
|
||||||
proc do_then_apply_sql {sql {dbname main}} {
|
# Usage: do_then_apply_sql ?-ignorenoop? SQL ?DBNAME?
|
||||||
proc xConflict args { return "OMIT" }
|
#
|
||||||
|
proc do_then_apply_sql {args} {
|
||||||
|
|
||||||
|
set bIgnoreNoop 0
|
||||||
|
set a1 [lindex $args 0]
|
||||||
|
if {[string length $a1]>1 && [string first $a1 -ignorenoop]==0} {
|
||||||
|
set bIgnoreNoop 1
|
||||||
|
set args [lrange $args 1 end]
|
||||||
|
}
|
||||||
|
|
||||||
|
if {[llength $args]!=1 && [llength $args]!=2} {
|
||||||
|
error "usage: do_then_apply_sql ?-ignorenoop? SQL ?DBNAME?"
|
||||||
|
}
|
||||||
|
|
||||||
|
set sql [lindex $args 0]
|
||||||
|
if {[llength $args]==1} {
|
||||||
|
set dbname main
|
||||||
|
} else {
|
||||||
|
set dbname [lindex $args 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
set ::n_conflict 0
|
||||||
|
proc xConflict args { incr ::n_conflict ; return "OMIT" }
|
||||||
set rc [catch {
|
set rc [catch {
|
||||||
sqlite3session S db $dbname
|
sqlite3session S db $dbname
|
||||||
db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" {
|
db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" {
|
||||||
S attach $name
|
S attach $name
|
||||||
}
|
}
|
||||||
db eval $sql
|
db eval $sql
|
||||||
sqlite3changeset_apply db2 [S changeset] xConflict
|
set ::changeset [S changeset]
|
||||||
|
sqlite3changeset_apply db2 $::changeset xConflict
|
||||||
} msg]
|
} msg]
|
||||||
|
|
||||||
catch { S delete }
|
catch { S delete }
|
||||||
|
|
||||||
if {$rc} {error $msg}
|
if {$rc} {error $msg}
|
||||||
|
|
||||||
|
if {$bIgnoreNoop} {
|
||||||
|
set nSave $::n_conflict
|
||||||
|
set ::n_conflict 0
|
||||||
|
proc xConflict args { incr ::n_conflict ; return "OMIT" }
|
||||||
|
sqlite3changeset_apply_v2 -ignorenoop db2 $::changeset xConflict
|
||||||
|
if {$::n_conflict!=$nSave} {
|
||||||
|
error "-ignorenoop problem ($::n_conflict $nSave)..."
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
proc do_iterator_test {tn tbl_list sql res} {
|
proc do_iterator_test {tn tbl_list sql res} {
|
||||||
|
@ -110,7 +110,7 @@ eval [string map [list %WR% $trailing] {
|
|||||||
CREATE TABLE t3(a, b, c DEFAULT 'D', PRIMARY KEY(b)) %WR%;
|
CREATE TABLE t3(a, b, c DEFAULT 'D', PRIMARY KEY(b)) %WR%;
|
||||||
}
|
}
|
||||||
do_test $tn.3.2 {
|
do_test $tn.3.2 {
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
INSERT INTO t3 VALUES(1, 2);
|
INSERT INTO t3 VALUES(1, 2);
|
||||||
INSERT INTO t3 VALUES(3, 4);
|
INSERT INTO t3 VALUES(3, 4);
|
||||||
INSERT INTO t3 VALUES(5, 6);
|
INSERT INTO t3 VALUES(5, 6);
|
||||||
@ -118,7 +118,7 @@ eval [string map [list %WR% $trailing] {
|
|||||||
db2 eval {SELECT * FROM t3}
|
db2 eval {SELECT * FROM t3}
|
||||||
} {1 2 D 3 4 D 5 6 D}
|
} {1 2 D 3 4 D 5 6 D}
|
||||||
do_test $tn.3.3 {
|
do_test $tn.3.3 {
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
UPDATE t3 SET a=45 WHERE b=4;
|
UPDATE t3 SET a=45 WHERE b=4;
|
||||||
DELETE FROM t3 WHERE a=5;
|
DELETE FROM t3 WHERE a=5;
|
||||||
};
|
};
|
||||||
@ -253,7 +253,7 @@ eval [string map [list %WR% $trailing] {
|
|||||||
CREATE TABLE t8(a PRIMARY KEY, b, c, d DEFAULT 'D', e DEFAULT 'E');
|
CREATE TABLE t8(a PRIMARY KEY, b, c, d DEFAULT 'D', e DEFAULT 'E');
|
||||||
}
|
}
|
||||||
|
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
INSERT INTO t8 VALUES(1, 2, 3);
|
INSERT INTO t8 VALUES(1, 2, 3);
|
||||||
INSERT INTO t8 VALUES(4, 5, 6);
|
INSERT INTO t8 VALUES(4, 5, 6);
|
||||||
}
|
}
|
||||||
@ -264,7 +264,7 @@ eval [string map [list %WR% $trailing] {
|
|||||||
SELECT * FROM t8
|
SELECT * FROM t8
|
||||||
} {1 2 3 D E 4 5 6 D E}
|
} {1 2 3 D E 4 5 6 D E}
|
||||||
|
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
UPDATE t8 SET c=45 WHERE a=4;
|
UPDATE t8 SET c=45 WHERE a=4;
|
||||||
}
|
}
|
||||||
do_execsql_test $tn.7.3.1 {
|
do_execsql_test $tn.7.3.1 {
|
||||||
@ -282,7 +282,7 @@ eval [string map [list %WR% $trailing] {
|
|||||||
do_execsql_test -db db2 $tn.8.1 {
|
do_execsql_test -db db2 $tn.8.1 {
|
||||||
CREATE TABLE t9(a PRIMARY KEY, b, c, d, e, f, g, h, i, j, k, l);
|
CREATE TABLE t9(a PRIMARY KEY, b, c, d, e, f, g, h, i, j, k, l);
|
||||||
}
|
}
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
INSERT INTO t9 VALUES(1, 2, 3, 4, 5, 6, 7, 8);
|
INSERT INTO t9 VALUES(1, 2, 3, 4, 5, 6, 7, 8);
|
||||||
}
|
}
|
||||||
do_then_apply_sql {
|
do_then_apply_sql {
|
||||||
@ -291,7 +291,7 @@ eval [string map [list %WR% $trailing] {
|
|||||||
do_execsql_test -db db2 $tn.8.2 {
|
do_execsql_test -db db2 $tn.8.2 {
|
||||||
SELECT * FROM t9
|
SELECT * FROM t9
|
||||||
} {1 2 3 4 5 6 7 450 {} {} {} {}}
|
} {1 2 3 4 5 6 7 450 {} {} {} {}}
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
UPDATE t9 SET h=NULL
|
UPDATE t9 SET h=NULL
|
||||||
}
|
}
|
||||||
do_execsql_test -db db2 $tn.8.2 {
|
do_execsql_test -db db2 $tn.8.2 {
|
||||||
|
@ -43,7 +43,7 @@ do_execsql_test -db db2 1.1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_test 1.2 {
|
do_test 1.2 {
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) );
|
INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) );
|
||||||
INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) );
|
INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) );
|
||||||
INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) );
|
INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) );
|
||||||
@ -71,7 +71,7 @@ do_test 1.3 {
|
|||||||
|
|
||||||
do_test 1.4 {
|
do_test 1.4 {
|
||||||
set rc [catch {
|
set rc [catch {
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) );
|
INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) );
|
||||||
INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) );
|
INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) );
|
||||||
INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) );
|
INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) );
|
||||||
|
@ -44,7 +44,7 @@ do_faultsim_test 1.1 -faults oom-* -prep {
|
|||||||
faultsim_restore_and_reopen
|
faultsim_restore_and_reopen
|
||||||
sqlite3 db2 test.db2
|
sqlite3 db2 test.db2
|
||||||
} -body {
|
} -body {
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
INSERT INTO t1 VALUES('a string value', 8, 9);
|
INSERT INTO t1 VALUES('a string value', 8, 9);
|
||||||
UPDATE t1 SET c = 10 WHERE a = 1;
|
UPDATE t1 SET c = 10 WHERE a = 1;
|
||||||
DELETE FROM t1 WHERE a = 4;
|
DELETE FROM t1 WHERE a = 4;
|
||||||
|
@ -132,7 +132,7 @@ do_faultsim_test 1.1 -faults oom-* -prep {
|
|||||||
faultsim_restore_and_reopen
|
faultsim_restore_and_reopen
|
||||||
sqlite3 db2 test.db2
|
sqlite3 db2 test.db2
|
||||||
} -body {
|
} -body {
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
INSERT INTO sqlite_stat1 VALUES('x', 'y', 45);
|
INSERT INTO sqlite_stat1 VALUES('x', 'y', 45);
|
||||||
UPDATE sqlite_stat1 SET stat = 123 WHERE tbl='t1' AND idx='i1';
|
UPDATE sqlite_stat1 SET stat = 123 WHERE tbl='t1' AND idx='i1';
|
||||||
UPDATE sqlite_stat1 SET stat = 456 WHERE tbl='t2';
|
UPDATE sqlite_stat1 SET stat = 456 WHERE tbl='t2';
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# 2021 Februar 20
|
# 2011 March 07
|
||||||
#
|
#
|
||||||
# The author disclaims copyright to this source code. In place of
|
# The author disclaims copyright to this source code. In place of
|
||||||
# a legal notice, here is a blessing:
|
# a legal notice, here is a blessing:
|
||||||
@ -20,166 +20,159 @@ ifcapable !session {finish_test; return}
|
|||||||
|
|
||||||
set testprefix sessionnoop
|
set testprefix sessionnoop
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
foreach {tn wo} {
|
||||||
# Test plan:
|
1 ""
|
||||||
#
|
2 " WITHOUT ROWID "
|
||||||
# 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
|
||||||
reset_db
|
sqlite3 db2 test.db2
|
||||||
do_execsql_test 2.0 {
|
|
||||||
CREATE TABLE t1(a PRIMARY KEY, b, c);
|
do_execsql_test -db db2 $tn.1.1 {
|
||||||
INSERT INTO t1 VALUES(1, 1, 1);
|
CREATE TABLE t1(a PRIMARY KEY, b, c) %WO%;
|
||||||
INSERT INTO t1 VALUES(2, 2, 2);
|
INSERT INTO t1 VALUES('a', 'A', 'AAA');
|
||||||
INSERT INTO t1 VALUES(3, 3, 3);
|
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');
|
||||||
}
|
}
|
||||||
|
|
||||||
proc do_rebase_test {tn sql_local sql_remote conflict_res expected} {
|
set C [changeset_from_sql {
|
||||||
proc xConflict {args} [list return $conflict_res]
|
UPDATE t1 SET c='123' WHERE a='b';
|
||||||
|
DELETE FROM t1 WHERE a='d';
|
||||||
|
INSERT INTO t1 VALUES('f', 'F', 'FFF');
|
||||||
|
}]
|
||||||
|
|
||||||
uplevel [list \
|
|
||||||
do_test $tn [subst -nocommands {
|
|
||||||
execsql BEGIN
|
|
||||||
set c_remote [changeset_from_sql {$sql_remote}]
|
|
||||||
execsql ROLLBACK
|
|
||||||
|
|
||||||
execsql BEGIN
|
set ::conflict_list [list]
|
||||||
set c_local [changeset_from_sql {$sql_local}]
|
proc xConflict {args} {
|
||||||
set base [sqlite3changeset_apply_v2 db [set c_remote] xConflict]
|
lappend ::conflict_list $args
|
||||||
execsql ROLLBACK
|
return "OMIT"
|
||||||
|
|
||||||
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_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_rebase_test 2.1 {
|
do_test $tn.1.4 {
|
||||||
UPDATE t1 SET c=2 WHERE a=1; -- local
|
set ::conflict_list [list]
|
||||||
} {
|
sqlite3changeset_apply_v2 -ignorenoop db2 $C xConflict
|
||||||
UPDATE t1 SET c=3 WHERE a=1; -- remote
|
set ::conflict_list
|
||||||
} 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 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
# 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
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
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_execsql_test 3.2 {
|
|
||||||
SELECT * FROM t1
|
do_execsql_test -db db2 1.5 {
|
||||||
} {
|
UPDATE t1 SET b='G' WHERE a='f';
|
||||||
1 1 500
|
UPDATE t1 SET c='456' WHERE a='b';
|
||||||
2 2 2
|
|
||||||
3 600 3
|
|
||||||
4 4 4
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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}}}
|
||||||
|
}]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ do_test 2.0 {
|
|||||||
} {}
|
} {}
|
||||||
|
|
||||||
do_test 2.1 {
|
do_test 2.1 {
|
||||||
do_then_apply_sql {
|
do_then_apply_sql -ignorenoop {
|
||||||
WITH s(i) AS (
|
WITH s(i) AS (
|
||||||
SELECT 0 UNION ALL SELECT i+1 FROM s WHERE (i+1)<32
|
SELECT 0 UNION ALL SELECT i+1 FROM s WHERE (i+1)<32
|
||||||
)
|
)
|
||||||
@ -100,7 +100,7 @@ do_execsql_test -db db2 2.2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_test 2.3 {
|
do_test 2.3 {
|
||||||
do_then_apply_sql { DROP INDEX t1c }
|
do_then_apply_sql -ignorenoop { DROP INDEX t1c }
|
||||||
} {}
|
} {}
|
||||||
|
|
||||||
do_execsql_test -db db2 2.4 {
|
do_execsql_test -db db2 2.4 {
|
||||||
@ -111,7 +111,7 @@ do_execsql_test -db db2 2.4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_test 2.3 {
|
do_test 2.3 {
|
||||||
do_then_apply_sql { DROP TABLE t1 }
|
do_then_apply_sql -ignorenoop { DROP TABLE t1 }
|
||||||
} {}
|
} {}
|
||||||
|
|
||||||
do_execsql_test -db db2 2.4 {
|
do_execsql_test -db db2 2.4 {
|
||||||
@ -153,16 +153,16 @@ do_execsql_test 3.2 {
|
|||||||
} {t1 null 4}
|
} {t1 null 4}
|
||||||
do_test 3.3 {
|
do_test 3.3 {
|
||||||
execsql { DELETE FROM sqlite_stat1 }
|
execsql { DELETE FROM sqlite_stat1 }
|
||||||
do_then_apply_sql { ANALYZE }
|
do_then_apply_sql -ignorenoop { ANALYZE }
|
||||||
execsql { SELECT * FROM sqlite_stat1 } db2
|
execsql { SELECT * FROM sqlite_stat1 } db2
|
||||||
} {t1 null 4}
|
} {t1 null 4}
|
||||||
do_test 3.4 {
|
do_test 3.4 {
|
||||||
execsql { INSERT INTO t1 VALUES(5,5,5) }
|
execsql { INSERT INTO t1 VALUES(5,5,5) }
|
||||||
do_then_apply_sql { ANALYZE }
|
do_then_apply_sql -ignorenoop { ANALYZE }
|
||||||
execsql { SELECT * FROM sqlite_stat1 } db2
|
execsql { SELECT * FROM sqlite_stat1 } db2
|
||||||
} {t1 null 5}
|
} {t1 null 5}
|
||||||
do_test 3.5 {
|
do_test 3.5 {
|
||||||
do_then_apply_sql { DROP TABLE t1 }
|
do_then_apply_sql -ignorenoop { DROP TABLE t1 }
|
||||||
execsql { SELECT * FROM sqlite_stat1 } db2
|
execsql { SELECT * FROM sqlite_stat1 } db2
|
||||||
} {}
|
} {}
|
||||||
|
|
||||||
|
@ -2113,9 +2113,10 @@ static void sessionAppendStr(
|
|||||||
int *pRc
|
int *pRc
|
||||||
){
|
){
|
||||||
int nStr = sqlite3Strlen30(zStr);
|
int nStr = sqlite3Strlen30(zStr);
|
||||||
if( 0==sessionBufferGrow(p, nStr, pRc) ){
|
if( 0==sessionBufferGrow(p, nStr+1, pRc) ){
|
||||||
memcpy(&p->aBuf[p->nBuf], zStr, nStr);
|
memcpy(&p->aBuf[p->nBuf], zStr, nStr);
|
||||||
p->nBuf += nStr;
|
p->nBuf += nStr;
|
||||||
|
p->aBuf[p->nBuf] = 0x00;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2137,6 +2138,27 @@ static void sessionAppendInteger(
|
|||||||
sessionAppendStr(p, aBuf, pRc);
|
sessionAppendStr(p, aBuf, pRc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sessionAppendPrintf(
|
||||||
|
SessionBuffer *p, /* Buffer to append to */
|
||||||
|
int *pRc,
|
||||||
|
const char *zFmt,
|
||||||
|
...
|
||||||
|
){
|
||||||
|
if( *pRc==SQLITE_OK ){
|
||||||
|
char *zApp = 0;
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, zFmt);
|
||||||
|
zApp = sqlite3_vmprintf(zFmt, ap);
|
||||||
|
if( zApp==0 ){
|
||||||
|
*pRc = SQLITE_NOMEM;
|
||||||
|
}else{
|
||||||
|
sessionAppendStr(p, zApp, pRc);
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
sqlite3_free(zApp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This function is a no-op if *pRc is other than SQLITE_OK when it is
|
** This function is a no-op if *pRc is other than SQLITE_OK when it is
|
||||||
** called. Otherwise, append the string zStr enclosed in quotes (") and
|
** called. Otherwise, append the string zStr enclosed in quotes (") and
|
||||||
@ -2151,7 +2173,7 @@ static void sessionAppendIdent(
|
|||||||
const char *zStr, /* String to quote, escape and append */
|
const char *zStr, /* String to quote, escape and append */
|
||||||
int *pRc /* IN/OUT: Error code */
|
int *pRc /* IN/OUT: Error code */
|
||||||
){
|
){
|
||||||
int nStr = sqlite3Strlen30(zStr)*2 + 2 + 1;
|
int nStr = sqlite3Strlen30(zStr)*2 + 2 + 2;
|
||||||
if( 0==sessionBufferGrow(p, nStr, pRc) ){
|
if( 0==sessionBufferGrow(p, nStr, pRc) ){
|
||||||
char *zOut = (char *)&p->aBuf[p->nBuf];
|
char *zOut = (char *)&p->aBuf[p->nBuf];
|
||||||
const char *zIn = zStr;
|
const char *zIn = zStr;
|
||||||
@ -2162,6 +2184,7 @@ static void sessionAppendIdent(
|
|||||||
}
|
}
|
||||||
*zOut++ = '"';
|
*zOut++ = '"';
|
||||||
p->nBuf = (int)((u8 *)zOut - p->aBuf);
|
p->nBuf = (int)((u8 *)zOut - p->aBuf);
|
||||||
|
p->aBuf[p->nBuf] = 0x00;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2386,10 +2409,17 @@ static int sessionAppendDelete(
|
|||||||
** Formulate and prepare a SELECT statement to retrieve a row from table
|
** Formulate and prepare a SELECT statement to retrieve a row from table
|
||||||
** zTab in database zDb based on its primary key. i.e.
|
** zTab in database zDb based on its primary key. i.e.
|
||||||
**
|
**
|
||||||
** SELECT * FROM zDb.zTab WHERE pk1 = ? AND pk2 = ? AND ...
|
** SELECT *, <noop-test> FROM zDb.zTab WHERE (pk1, pk2,...) IS (?1, ?2,...)
|
||||||
|
**
|
||||||
|
** where <noop-test> is:
|
||||||
|
**
|
||||||
|
** 1 AND (?A OR ?1 IS <column>) AND ...
|
||||||
|
**
|
||||||
|
** for each non-pk <column>.
|
||||||
*/
|
*/
|
||||||
static int sessionSelectStmt(
|
static int sessionSelectStmt(
|
||||||
sqlite3 *db, /* Database handle */
|
sqlite3 *db, /* Database handle */
|
||||||
|
int bIgnoreNoop,
|
||||||
const char *zDb, /* Database name */
|
const char *zDb, /* Database name */
|
||||||
const char *zTab, /* Table name */
|
const char *zTab, /* Table name */
|
||||||
int nCol, /* Number of columns in table */
|
int nCol, /* Number of columns in table */
|
||||||
@ -2399,8 +2429,51 @@ static int sessionSelectStmt(
|
|||||||
){
|
){
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
char *zSql = 0;
|
char *zSql = 0;
|
||||||
|
const char *zSep = "";
|
||||||
|
const char *zCols = "*";
|
||||||
int nSql = -1;
|
int nSql = -1;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
SessionBuffer nooptest = {0, 0, 0};
|
||||||
|
SessionBuffer pkfield = {0, 0, 0};
|
||||||
|
SessionBuffer pkvar = {0, 0, 0};
|
||||||
|
|
||||||
|
sessionAppendStr(&nooptest, ", 1", &rc);
|
||||||
|
|
||||||
|
if( 0==sqlite3_stricmp("sqlite_stat1", zTab) ){
|
||||||
|
sessionAppendStr(&nooptest, " AND (?6 OR ?3 IS stat)", &rc);
|
||||||
|
sessionAppendStr(&pkfield, "tbl, idx", &rc);
|
||||||
|
sessionAppendStr(&pkvar,
|
||||||
|
"?1, (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", &rc
|
||||||
|
);
|
||||||
|
zCols = "tbl, ?2, stat";
|
||||||
|
}else{
|
||||||
|
for(i=0; i<nCol; i++){
|
||||||
|
|
||||||
|
if( abPK[i] ){
|
||||||
|
sessionAppendStr(&pkfield, zSep, &rc);
|
||||||
|
sessionAppendStr(&pkvar, zSep, &rc);
|
||||||
|
zSep = ", ";
|
||||||
|
sessionAppendIdent(&pkfield, azCol[i], &rc);
|
||||||
|
sessionAppendPrintf(&pkvar, &rc, "?%d", i+1);
|
||||||
|
}else{
|
||||||
|
sessionAppendPrintf(&nooptest, &rc,
|
||||||
|
" AND (?%d OR ?%d IS %w.%w)", i+1+nCol, i+1, zTab, azCol[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
zSql = sqlite3_mprintf(
|
||||||
|
"SELECT %s%s FROM %Q.%Q WHERE (%s) IS (%s)",
|
||||||
|
zCols, (bIgnoreNoop ? (char*)nooptest.aBuf : ""),
|
||||||
|
zDb, zTab, (char*)pkfield.aBuf, (char*)pkvar.aBuf
|
||||||
|
);
|
||||||
|
if( zSql==0 ) rc = SQLITE_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
if( 0==sqlite3_stricmp("sqlite_stat1", zTab) ){
|
if( 0==sqlite3_stricmp("sqlite_stat1", zTab) ){
|
||||||
zSql = sqlite3_mprintf(
|
zSql = sqlite3_mprintf(
|
||||||
"SELECT tbl, ?2, stat FROM %Q.sqlite_stat1 WHERE tbl IS ?1 AND "
|
"SELECT tbl, ?2, stat FROM %Q.sqlite_stat1 WHERE tbl IS ?1 AND "
|
||||||
@ -2408,7 +2481,6 @@ static int sessionSelectStmt(
|
|||||||
);
|
);
|
||||||
if( zSql==0 ) rc = SQLITE_NOMEM;
|
if( zSql==0 ) rc = SQLITE_NOMEM;
|
||||||
}else{
|
}else{
|
||||||
int i;
|
|
||||||
const char *zSep = "";
|
const char *zSep = "";
|
||||||
SessionBuffer buf = {0, 0, 0};
|
SessionBuffer buf = {0, 0, 0};
|
||||||
|
|
||||||
@ -2429,11 +2501,15 @@ static int sessionSelectStmt(
|
|||||||
zSql = (char*)buf.aBuf;
|
zSql = (char*)buf.aBuf;
|
||||||
nSql = buf.nBuf;
|
nSql = buf.nBuf;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = sqlite3_prepare_v2(db, zSql, nSql, ppStmt, 0);
|
rc = sqlite3_prepare_v2(db, zSql, nSql, ppStmt, 0);
|
||||||
}
|
}
|
||||||
sqlite3_free(zSql);
|
sqlite3_free(zSql);
|
||||||
|
sqlite3_free(nooptest.aBuf);
|
||||||
|
sqlite3_free(pkfield.aBuf);
|
||||||
|
sqlite3_free(pkvar.aBuf);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2593,7 +2669,8 @@ static int sessionGenerateChangeset(
|
|||||||
/* Build and compile a statement to execute: */
|
/* Build and compile a statement to execute: */
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = sessionSelectStmt(
|
rc = sessionSelectStmt(
|
||||||
db, pSession->zDb, zName, nCol, azCol, abPK, &pSel);
|
db, 0, pSession->zDb, zName, nCol, azCol, abPK, &pSel
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
nNoop = buf.nBuf;
|
nNoop = buf.nBuf;
|
||||||
@ -3782,6 +3859,7 @@ struct SessionApplyCtx {
|
|||||||
SessionBuffer rebase; /* Rebase information (if any) here */
|
SessionBuffer rebase; /* Rebase information (if any) here */
|
||||||
u8 bRebaseStarted; /* If table header is already in rebase */
|
u8 bRebaseStarted; /* If table header is already in rebase */
|
||||||
u8 bRebase; /* True to collect rebase information */
|
u8 bRebase; /* True to collect rebase information */
|
||||||
|
u8 bIgnoreNoop; /* True to ignore no-op conflicts */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Number of prepared UPDATE statements to cache. */
|
/* Number of prepared UPDATE statements to cache. */
|
||||||
@ -4032,8 +4110,9 @@ static int sessionSelectRow(
|
|||||||
const char *zTab, /* Table name */
|
const char *zTab, /* Table name */
|
||||||
SessionApplyCtx *p /* Session changeset-apply context */
|
SessionApplyCtx *p /* Session changeset-apply context */
|
||||||
){
|
){
|
||||||
return sessionSelectStmt(
|
return sessionSelectStmt(db, p->bIgnoreNoop,
|
||||||
db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect);
|
"main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4192,20 +4271,33 @@ static int sessionBindRow(
|
|||||||
*/
|
*/
|
||||||
static int sessionSeekToRow(
|
static int sessionSeekToRow(
|
||||||
sqlite3_changeset_iter *pIter, /* Changeset iterator */
|
sqlite3_changeset_iter *pIter, /* Changeset iterator */
|
||||||
u8 *abPK, /* Primary key flags array */
|
SessionApplyCtx *p
|
||||||
sqlite3_stmt *pSelect /* SELECT statement from sessionSelectRow() */
|
|
||||||
){
|
){
|
||||||
|
sqlite3_stmt *pSelect = p->pSelect;
|
||||||
int rc; /* Return code */
|
int rc; /* Return code */
|
||||||
int nCol; /* Number of columns in table */
|
int nCol; /* Number of columns in table */
|
||||||
int op; /* Changset operation (SQLITE_UPDATE etc.) */
|
int op; /* Changset operation (SQLITE_UPDATE etc.) */
|
||||||
const char *zDummy; /* Unused */
|
const char *zDummy; /* Unused */
|
||||||
|
|
||||||
|
sqlite3_clear_bindings(pSelect);
|
||||||
sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
|
sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
|
||||||
rc = sessionBindRow(pIter,
|
rc = sessionBindRow(pIter,
|
||||||
op==SQLITE_INSERT ? sqlite3changeset_new : sqlite3changeset_old,
|
op==SQLITE_INSERT ? sqlite3changeset_new : sqlite3changeset_old,
|
||||||
nCol, abPK, pSelect
|
nCol, p->abPK, pSelect
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if( op!=SQLITE_DELETE && p->bIgnoreNoop ){
|
||||||
|
int ii;
|
||||||
|
for(ii=0; rc==SQLITE_OK && ii<nCol; ii++){
|
||||||
|
if( p->abPK[ii]==0 ){
|
||||||
|
sqlite3_value *pVal = 0;
|
||||||
|
sqlite3changeset_new(pIter, ii, &pVal);
|
||||||
|
sqlite3_bind_int(pSelect, ii+1+nCol, (pVal==0));
|
||||||
|
if( pVal ) rc = sessionBindValue(pSelect, ii+1, pVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = sqlite3_step(pSelect);
|
rc = sqlite3_step(pSelect);
|
||||||
if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect);
|
if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect);
|
||||||
@ -4320,16 +4412,22 @@ static int sessionConflictHandler(
|
|||||||
|
|
||||||
/* Bind the new.* PRIMARY KEY values to the SELECT statement. */
|
/* Bind the new.* PRIMARY KEY values to the SELECT statement. */
|
||||||
if( pbReplace ){
|
if( pbReplace ){
|
||||||
rc = sessionSeekToRow(pIter, p->abPK, p->pSelect);
|
rc = sessionSeekToRow(pIter, p);
|
||||||
}else{
|
}else{
|
||||||
rc = SQLITE_OK;
|
rc = SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( rc==SQLITE_ROW ){
|
if( rc==SQLITE_ROW ){
|
||||||
/* There exists another row with the new.* primary key. */
|
/* There exists another row with the new.* primary key. */
|
||||||
pIter->pConflict = p->pSelect;
|
if( p->bIgnoreNoop
|
||||||
res = xConflict(pCtx, eType, pIter);
|
&& sqlite3_column_int(p->pSelect, sqlite3_column_count(p->pSelect)-1)
|
||||||
pIter->pConflict = 0;
|
){
|
||||||
|
res = SQLITE_CHANGESET_OMIT;
|
||||||
|
}else{
|
||||||
|
pIter->pConflict = p->pSelect;
|
||||||
|
res = xConflict(pCtx, eType, pIter);
|
||||||
|
pIter->pConflict = 0;
|
||||||
|
}
|
||||||
rc = sqlite3_reset(p->pSelect);
|
rc = sqlite3_reset(p->pSelect);
|
||||||
}else if( rc==SQLITE_OK ){
|
}else if( rc==SQLITE_OK ){
|
||||||
if( p->bDeferConstraints && eType==SQLITE_CHANGESET_CONFLICT ){
|
if( p->bDeferConstraints && eType==SQLITE_CHANGESET_CONFLICT ){
|
||||||
@ -4437,7 +4535,7 @@ static int sessionApplyOneOp(
|
|||||||
|
|
||||||
sqlite3_step(p->pDelete);
|
sqlite3_step(p->pDelete);
|
||||||
rc = sqlite3_reset(p->pDelete);
|
rc = sqlite3_reset(p->pDelete);
|
||||||
if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
|
if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 && p->bIgnoreNoop==0 ){
|
||||||
rc = sessionConflictHandler(
|
rc = sessionConflictHandler(
|
||||||
SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
|
SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
|
||||||
);
|
);
|
||||||
@ -4494,7 +4592,7 @@ static int sessionApplyOneOp(
|
|||||||
/* Check if there is a conflicting row. For sqlite_stat1, this needs
|
/* Check if there is a conflicting row. For sqlite_stat1, this needs
|
||||||
** to be done using a SELECT, as there is no PRIMARY KEY in the
|
** to be done using a SELECT, as there is no PRIMARY KEY in the
|
||||||
** database schema to throw an exception if a duplicate is inserted. */
|
** database schema to throw an exception if a duplicate is inserted. */
|
||||||
rc = sessionSeekToRow(pIter, p->abPK, p->pSelect);
|
rc = sessionSeekToRow(pIter, p);
|
||||||
if( rc==SQLITE_ROW ){
|
if( rc==SQLITE_ROW ){
|
||||||
rc = SQLITE_CONSTRAINT;
|
rc = SQLITE_CONSTRAINT;
|
||||||
sqlite3_reset(p->pSelect);
|
sqlite3_reset(p->pSelect);
|
||||||
@ -4671,6 +4769,7 @@ static int sessionChangesetApply(
|
|||||||
memset(&sApply, 0, sizeof(sApply));
|
memset(&sApply, 0, sizeof(sApply));
|
||||||
sApply.bRebase = (ppRebase && pnRebase);
|
sApply.bRebase = (ppRebase && pnRebase);
|
||||||
sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
|
sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
|
||||||
|
sApply.bIgnoreNoop = !!(flags & SQLITE_CHANGESETAPPLY_IGNORENOOP);
|
||||||
sqlite3_mutex_enter(sqlite3_db_mutex(db));
|
sqlite3_mutex_enter(sqlite3_db_mutex(db));
|
||||||
if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
|
if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
|
||||||
rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
|
rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
|
||||||
|
@ -1243,9 +1243,23 @@ int sqlite3changeset_apply_v2(
|
|||||||
** Invert the changeset before applying it. This is equivalent to inverting
|
** Invert the changeset before applying it. This is equivalent to inverting
|
||||||
** a changeset using sqlite3changeset_invert() before applying it. It is
|
** a changeset using sqlite3changeset_invert() before applying it. It is
|
||||||
** an error to specify this flag with a patchset.
|
** an error to specify this flag with a patchset.
|
||||||
|
**
|
||||||
|
** <dt>SQLITE_CHANGESETAPPLY_IGNORENOOP <dd>
|
||||||
|
** Do not invoke the conflict handler callback for any changes that
|
||||||
|
** would not actually modify the database even if they were applied.
|
||||||
|
** Specifically, this means that the conflict handler is not invoked
|
||||||
|
** for:
|
||||||
|
** <ul>
|
||||||
|
** <li>a delete change if the row being deleted cannot be found,
|
||||||
|
** <li>an update change if the modified fields are already set to
|
||||||
|
** their new values in the conflicting row, or
|
||||||
|
** <li>an insert change if all fields of the conflicting row match
|
||||||
|
** the row being inserted.
|
||||||
|
** </ul>
|
||||||
*/
|
*/
|
||||||
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
|
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
|
||||||
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
|
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
|
||||||
|
#define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Constants Passed To The Conflict Handler
|
** CAPI3REF: Constants Passed To The Conflict Handler
|
||||||
|
@ -793,32 +793,31 @@ static int SQLITE_TCLAPI testSqlite3changesetApply(
|
|||||||
memset(&sStr, 0, sizeof(sStr));
|
memset(&sStr, 0, sizeof(sStr));
|
||||||
sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
|
sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
|
||||||
|
|
||||||
/* Check for the -nosavepoint flag */
|
/* Check for the -nosavepoint, -invert or -ignorenoop switches */
|
||||||
if( bV2 ){
|
if( bV2 ){
|
||||||
if( objc>1 ){
|
while( objc>1 ){
|
||||||
const char *z1 = Tcl_GetString(objv[1]);
|
const char *z1 = Tcl_GetString(objv[1]);
|
||||||
int n = strlen(z1);
|
int n = strlen(z1);
|
||||||
if( n>1 && n<=12 && 0==sqlite3_strnicmp("-nosavepoint", z1, n) ){
|
if( n>1 && n<=12 && 0==sqlite3_strnicmp("-nosavepoint", z1, n) ){
|
||||||
flags |= SQLITE_CHANGESETAPPLY_NOSAVEPOINT;
|
flags |= SQLITE_CHANGESETAPPLY_NOSAVEPOINT;
|
||||||
objc--;
|
|
||||||
objv++;
|
|
||||||
}
|
}
|
||||||
}
|
else if( n>2 && n<=7 && 0==sqlite3_strnicmp("-invert", z1, n) ){
|
||||||
if( objc>1 ){
|
|
||||||
const char *z1 = Tcl_GetString(objv[1]);
|
|
||||||
int n = strlen(z1);
|
|
||||||
if( n>1 && n<=7 && 0==sqlite3_strnicmp("-invert", z1, n) ){
|
|
||||||
flags |= SQLITE_CHANGESETAPPLY_INVERT;
|
flags |= SQLITE_CHANGESETAPPLY_INVERT;
|
||||||
objc--;
|
|
||||||
objv++;
|
|
||||||
}
|
}
|
||||||
|
else if( n>2 && n<=11 && 0==sqlite3_strnicmp("-ignorenoop", z1, n) ){
|
||||||
|
flags |= SQLITE_CHANGESETAPPLY_IGNORENOOP;
|
||||||
|
}else{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
objc--;
|
||||||
|
objv++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( objc!=4 && objc!=5 ){
|
if( objc!=4 && objc!=5 ){
|
||||||
const char *zMsg;
|
const char *zMsg;
|
||||||
if( bV2 ){
|
if( bV2 ){
|
||||||
zMsg = "?-nosavepoint? ?-inverse? "
|
zMsg = "?-nosavepoint? ?-inverse? ?-ignorenoop? "
|
||||||
"DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?";
|
"DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?";
|
||||||
}else{
|
}else{
|
||||||
zMsg = "DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?";
|
zMsg = "DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?";
|
||||||
|
38
manifest
38
manifest
@ -1,5 +1,5 @@
|
|||||||
C Small\sperformance\simprovement\sin\sthe\sOP_MakeRecord\sopcode.
|
C Add\sthe\sSQLITE_CHANGESETAPPLY_IGNORENOOP\sflag,\swhich\smay\sbe\spassed\sto\ssqlite3changeset_apply_v2()\sto\shave\sit\signore\schanges\sthat\swould\sbe\sno-ops\sif\sapplied\sto\sthe\sdatabase\s(e.g.\sdeleting\sa\srow\sthat\shas\salready\sbeen\sdeleted),\sinstead\sof\sconsidering\sthem\sconflicts.
|
||||||
D 2023-03-08T17:09:32.272
|
D 2023-03-08T18:03:04.122
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||||
@ -432,7 +432,7 @@ F ext/session/changeset.c 7a1e6a14c7e92d36ca177e92e88b5281acd709f3b726298dc34ec0
|
|||||||
F ext/session/changesetfuzz.c 227076ab0ae4447d742c01ee88a564da6478bbf26b65108bf8fac9cd8b0b24aa
|
F ext/session/changesetfuzz.c 227076ab0ae4447d742c01ee88a564da6478bbf26b65108bf8fac9cd8b0b24aa
|
||||||
F ext/session/changesetfuzz1.test 2e1b90d888fbf0eea5e1bd2f1e527a48cc85f8e0ff75df1ec4e320b21f580b3a
|
F ext/session/changesetfuzz1.test 2e1b90d888fbf0eea5e1bd2f1e527a48cc85f8e0ff75df1ec4e320b21f580b3a
|
||||||
F ext/session/session1.test e94f764fbfb672147c0ef7026b195988133b371dc8cf9e52423eba6cad69717e
|
F ext/session/session1.test e94f764fbfb672147c0ef7026b195988133b371dc8cf9e52423eba6cad69717e
|
||||||
F ext/session/session2.test 7f53d755d921e0baf815c4258348e0ed460dfd8a772351bca5ad3ccbb1dc786e
|
F ext/session/session2.test ee83bb973b9ce17ccce4db931cdcdae65eb40bbb22089b2fe6aa4f6be3b9303f
|
||||||
F ext/session/session3.test ce9ce3dfa489473987f899e9f6a0f2db9bde3479
|
F ext/session/session3.test ce9ce3dfa489473987f899e9f6a0f2db9bde3479
|
||||||
F ext/session/session4.test 6778997065b44d99c51ff9cece047ff9244a32856b328735ae27ddef68979c40
|
F ext/session/session4.test 6778997065b44d99c51ff9cece047ff9244a32856b328735ae27ddef68979c40
|
||||||
F ext/session/session5.test 716bc6fafd625ce60dfa62ae128971628c1a1169
|
F ext/session/session5.test 716bc6fafd625ce60dfa62ae128971628c1a1169
|
||||||
@ -445,25 +445,25 @@ F ext/session/sessionC.test f8a5508bc059ae646e5ec9bdbca66ad24bc92fe99fda5790ac57
|
|||||||
F ext/session/sessionD.test 4f91d0ca8afc4c3969c72c9f0b5ea9527e21de29039937d0d973f821e8470724
|
F ext/session/sessionD.test 4f91d0ca8afc4c3969c72c9f0b5ea9527e21de29039937d0d973f821e8470724
|
||||||
F ext/session/sessionE.test b2010949c9d7415306f64e3c2072ddabc4b8250c98478d3c0c4d064bce83111d
|
F ext/session/sessionE.test b2010949c9d7415306f64e3c2072ddabc4b8250c98478d3c0c4d064bce83111d
|
||||||
F ext/session/sessionF.test d37ed800881e742c208df443537bf29aa49fd56eac520d0f0c6df3e6320f3401
|
F ext/session/sessionF.test d37ed800881e742c208df443537bf29aa49fd56eac520d0f0c6df3e6320f3401
|
||||||
F ext/session/sessionG.test 3828b944cd1285f4379340fd36f8b64c464fc84df6ff3ccbc95578fd87140b9c
|
F ext/session/sessionG.test 3efe388282d641b65485b5462e67851002cd91a282dc95b685d085eb8efdad0a
|
||||||
F ext/session/sessionH.test b17afdbd3b8f17e9bab91e235acf167cf35485db2ab2df0ea8893fbb914741a4
|
F ext/session/sessionH.test 71bbff6b1abb2c4ac62b84dee53273c37e0b21e5fde3aed80929403e091ef859
|
||||||
F ext/session/session_common.tcl f613174665456b2d916ae8df3e5735092a1c1712f36f46840172e9a01e8cc53e
|
F ext/session/session_common.tcl db0dda567c75950604072251744e9a6ad5795a3009963c44eb8510f23a8cda64
|
||||||
F ext/session/session_speed_test.c dcf0ef58d76b70c8fbd9eab3be77cf9deb8bc1638fed8be518b62d6cbdef88b3
|
F ext/session/session_speed_test.c dcf0ef58d76b70c8fbd9eab3be77cf9deb8bc1638fed8be518b62d6cbdef88b3
|
||||||
F ext/session/sessionat.test 46fd847f6ed194ebb7ebef9fe68b2e2ec88d9c2383a6846cddc5604b35f1d4ae
|
F ext/session/sessionat.test 00c8badb35e43a2f12a716d2734a44d614ff62361979b6b85419035bc04b45ee
|
||||||
F ext/session/sessionbig.test 890ade19e3f80f3d3a3e83821ff79c5e2af906a67ecb5450879f0015cadf101e
|
F ext/session/sessionbig.test 47c381e7acfabeef17d98519a3080d69151723354d220afa2053852182ca7adf
|
||||||
F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec
|
F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec
|
||||||
F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7
|
F ext/session/sessionfault.test 573bf027fb870d57bd4e7cf50822a3e4b17b2b923407438747aaa918dec57a09
|
||||||
F ext/session/sessionfault2.test dd593f80b6b4786f7adfe83c5939620bc505559770cc181332da26f29cddd7bb
|
F ext/session/sessionfault2.test b0d6a7c1d7398a7e800d84657404909c7d385965ea8576dc79ed344c46fbf41c
|
||||||
F ext/session/sessioninvert.test 04075517a9497a80d39c495ba6b44f3982c7371129b89e2c52219819bc105a25
|
F ext/session/sessioninvert.test 04075517a9497a80d39c495ba6b44f3982c7371129b89e2c52219819bc105a25
|
||||||
F ext/session/sessionmem.test f2a735db84a3e9e19f571033b725b0b2daf847f3f28b1da55a0c1a4e74f1de09
|
F ext/session/sessionmem.test f2a735db84a3e9e19f571033b725b0b2daf847f3f28b1da55a0c1a4e74f1de09
|
||||||
F ext/session/sessionnoop.test a9366a36a95ef85f8a3687856ebef46983df399541174cb1ede2ee53b8011bc7
|
F ext/session/sessionnoop.test 5c9a882219e54711c98dccd2fd81392f189a59325e4fb5d8ed25e33a0c2f0ba2
|
||||||
F ext/session/sessionrebase.test ccfa716b23bd1d3b03217ee58cfd90c78d4b99f53e6a9a2f05e82363b9142810
|
F ext/session/sessionrebase.test ccfa716b23bd1d3b03217ee58cfd90c78d4b99f53e6a9a2f05e82363b9142810
|
||||||
F ext/session/sessionsize.test 6f644aff31c7f1e4871e9ff3542766e18da68fc7e587b83a347ea9820a002dd8
|
F ext/session/sessionsize.test 6f644aff31c7f1e4871e9ff3542766e18da68fc7e587b83a347ea9820a002dd8
|
||||||
F ext/session/sessionstat1.test 218d351cf9fcd6648f125a26b607b140310160184723c2666091b54450a68fb5
|
F ext/session/sessionstat1.test b039e38e2ba83767b464baf39b297cc0b1cc6f3292255cb467ea7e12d0d0280c
|
||||||
F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc
|
F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc
|
||||||
F ext/session/sqlite3session.c 13bdc093416cd284d4075328dd8599eb59bcedc23a21d561a15d78805c5866bf
|
F ext/session/sqlite3session.c 1795263b72c1a17e48e95a131a69543af3fa31aa8e81271c7c5cb0911f063604
|
||||||
F ext/session/sqlite3session.h 0907de79bc13a2e3af30a6dc29acc60792a3eaf7d33d44cf52500d0f3c2b2171
|
F ext/session/sqlite3session.h c367c3043dbb57f69cca35258ebbeadb24e8738980b1a1ae1e281c1b0fac3989
|
||||||
F ext/session/test_session.c 2de472b4d7e62e85ca1992094612725e2450a77dbf7523db64de94197812462e
|
F ext/session/test_session.c b55a669a2150eb7c491b8b42c69a3eed9bc895cf5fea371a2c813b9618f72163
|
||||||
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
|
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
|
||||||
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
|
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
|
||||||
F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
|
F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
|
||||||
@ -2049,8 +2049,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 6d5b5896261c62a7e130b47416ee8c25793859a2afcb1646c257600537a5b71b
|
P ca89daef0fcf6cb04aa6fa90dd333d6f2474bf3f458c833d9cd5bd8e59f2a04a
|
||||||
R 1b5d34199b6078f6cf9502fa50e8d5f3
|
R b858992430ed0de53c8f23b82b0d78e8
|
||||||
U drh
|
U dan
|
||||||
Z 1c424b0c5c8b9aa32605259b67546e86
|
Z efdd331472cbc1f3fc97c7776e84ccdd
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
@ -1 +1 @@
|
|||||||
ca89daef0fcf6cb04aa6fa90dd333d6f2474bf3f458c833d9cd5bd8e59f2a04a
|
cb023fe28560ce0f8c2fd48042553fcdb9db81eba9552be75165de0d46a2645c
|
Reference in New Issue
Block a user