mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Changes so that the pre-update hook and the sessions module work with WITHOUT
ROWID tables. FossilOrigin-Name: 964bdc27f8f1b1db2e5c0c2a65c8156614cbe087
This commit is contained in:
@@ -20,46 +20,61 @@ ifcapable !session {finish_test; return}
|
||||
|
||||
set testprefix session1
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(x PRIMARY KEY, y);
|
||||
# Run all tests in this file twice. Once with "WITHOUT ROWID", and once
|
||||
# with regular rowid tables.
|
||||
#
|
||||
foreach {tn trailing} {
|
||||
1 ""
|
||||
2 " WITHOUT ROWID "
|
||||
} {
|
||||
eval [string map [list %WR% $trailing] {
|
||||
|
||||
db close
|
||||
forcedelete test.db test.db2
|
||||
reset_db
|
||||
|
||||
do_execsql_test $tn.1.0 {
|
||||
CREATE TABLE t1(x PRIMARY KEY, y) %WR%;
|
||||
INSERT INTO t1 VALUES('abc', 'def');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test creating, attaching tables to and deleting session objects.
|
||||
#
|
||||
do_test 1.1 { sqlite3session S db main } {S}
|
||||
do_test 1.2 { S delete } {}
|
||||
do_test 1.3 { sqlite3session S db main } {S}
|
||||
do_test 1.4 { S attach t1 } {}
|
||||
do_test 1.5 { S delete } {}
|
||||
do_test 1.6 { sqlite3session S db main } {S}
|
||||
do_test 1.7 { S attach t1 ; S attach t2 ; S attach t3 } {}
|
||||
do_test 1.8 { S attach t1 ; S attach t2 ; S attach t3 } {}
|
||||
do_test 1.9 { S delete } {}
|
||||
do_test 1.10 {
|
||||
do_test $tn.1.1 { sqlite3session S db main } {S}
|
||||
do_test $tn.1.2 { S delete } {}
|
||||
do_test $tn.1.3 { sqlite3session S db main } {S}
|
||||
do_test $tn.1.4 { S attach t1 } {}
|
||||
do_test $tn.1.5 { S delete } {}
|
||||
do_test $tn.1.6 { sqlite3session S db main } {S}
|
||||
do_test $tn.1.7 { S attach t1 ; S attach t2 ; S attach t3 } {}
|
||||
do_test $tn.1.8 { S attach t1 ; S attach t2 ; S attach t3 } {}
|
||||
do_test $tn.1.9 { S delete } {}
|
||||
do_test $tn.1.10 {
|
||||
sqlite3session S db main
|
||||
S attach t1
|
||||
execsql { INSERT INTO t1 VALUES('ghi', 'jkl') }
|
||||
} {}
|
||||
do_test 1.11 { S delete } {}
|
||||
do_test 1.12 {
|
||||
sqlite3session S db main
|
||||
S attach t1
|
||||
execsql { INSERT INTO t1 VALUES('mno', 'pqr') }
|
||||
execsql { UPDATE t1 SET x = 111 WHERE rowid = 1 }
|
||||
execsql { DELETE FROM t1 WHERE rowid = 2 }
|
||||
} {}
|
||||
do_test 1.13 {
|
||||
S changeset
|
||||
S delete
|
||||
} {}
|
||||
do_test $tn.1.11 { S delete } {}
|
||||
if {$tn==1} {
|
||||
do_test $tn.1.12 {
|
||||
sqlite3session S db main
|
||||
S attach t1
|
||||
execsql { INSERT INTO t1 VALUES('mno', 'pqr') }
|
||||
execsql { UPDATE t1 SET x = 111 WHERE rowid = 1 }
|
||||
execsql { DELETE FROM t1 WHERE rowid = 2 }
|
||||
} {}
|
||||
do_test $tn.1.13 {
|
||||
S changeset
|
||||
S delete
|
||||
} {}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Simple changeset tests. Also test the sqlite3changeset_invert()
|
||||
# function.
|
||||
#
|
||||
do_test 2.1.1 {
|
||||
do_test $tn.2.1.1 {
|
||||
execsql { DELETE FROM t1 }
|
||||
sqlite3session S db main
|
||||
S attach t1
|
||||
@@ -67,36 +82,36 @@ do_test 2.1.1 {
|
||||
execsql { INSERT INTO t1 VALUES(2, 'Ayutthaya') }
|
||||
execsql { INSERT INTO t1 VALUES(3, 'Thonburi') }
|
||||
} {}
|
||||
do_changeset_test 2.1.2 S {
|
||||
do_changeset_test $tn.2.1.2 S {
|
||||
{INSERT t1 0 X. {} {i 1 t Sukhothai}}
|
||||
{INSERT t1 0 X. {} {i 2 t Ayutthaya}}
|
||||
{INSERT t1 0 X. {} {i 3 t Thonburi}}
|
||||
}
|
||||
do_changeset_invert_test 2.1.3 S {
|
||||
do_changeset_invert_test $tn.2.1.3 S {
|
||||
{DELETE t1 0 X. {i 1 t Sukhothai} {}}
|
||||
{DELETE t1 0 X. {i 2 t Ayutthaya} {}}
|
||||
{DELETE t1 0 X. {i 3 t Thonburi} {}}
|
||||
}
|
||||
do_test 2.1.4 { S delete } {}
|
||||
do_test $tn.2.1.4 { S delete } {}
|
||||
|
||||
do_test 2.2.1 {
|
||||
do_test $tn.2.2.1 {
|
||||
sqlite3session S db main
|
||||
S attach t1
|
||||
execsql { DELETE FROM t1 WHERE 1 }
|
||||
} {}
|
||||
do_changeset_test 2.2.2 S {
|
||||
do_changeset_test $tn.2.2.2 S {
|
||||
{DELETE t1 0 X. {i 1 t Sukhothai} {}}
|
||||
{DELETE t1 0 X. {i 2 t Ayutthaya} {}}
|
||||
{DELETE t1 0 X. {i 3 t Thonburi} {}}
|
||||
}
|
||||
do_changeset_invert_test 2.2.3 S {
|
||||
do_changeset_invert_test $tn.2.2.3 S {
|
||||
{INSERT t1 0 X. {} {i 1 t Sukhothai}}
|
||||
{INSERT t1 0 X. {} {i 2 t Ayutthaya}}
|
||||
{INSERT t1 0 X. {} {i 3 t Thonburi}}
|
||||
}
|
||||
do_test 2.2.4 { S delete } {}
|
||||
do_test $tn.2.2.4 { S delete } {}
|
||||
|
||||
do_test 2.3.1 {
|
||||
do_test $tn.2.3.1 {
|
||||
execsql { DELETE FROM t1 }
|
||||
sqlite3session S db main
|
||||
execsql { INSERT INTO t1 VALUES(1, 'Sukhothai') }
|
||||
@@ -110,7 +125,7 @@ do_test 2.3.1 {
|
||||
}
|
||||
} {}
|
||||
|
||||
do_changeset_test 2.3.2 S {
|
||||
do_changeset_test $tn.2.3.2 S {
|
||||
{INSERT t1 0 X. {} {i 10 t Sukhothai}}
|
||||
{DELETE t1 0 X. {i 1 t Sukhothai} {}}
|
||||
{UPDATE t1 0 X. {i 2 t Ayutthaya} {{} {} t Surin}}
|
||||
@@ -118,24 +133,24 @@ do_changeset_test 2.3.2 S {
|
||||
{INSERT t1 0 X. {} {i 20 t Thapae}}
|
||||
}
|
||||
|
||||
do_changeset_invert_test 2.3.3 S {
|
||||
do_changeset_invert_test $tn.2.3.3 S {
|
||||
{DELETE t1 0 X. {i 10 t Sukhothai} {}}
|
||||
{INSERT t1 0 X. {} {i 1 t Sukhothai}}
|
||||
{UPDATE t1 0 X. {i 2 t Surin} {{} {} t Ayutthaya}}
|
||||
{INSERT t1 0 X. {} {i 3 t Thonburi}}
|
||||
{DELETE t1 0 X. {i 20 t Thapae} {}}
|
||||
}
|
||||
do_test 2.3.4 { S delete } {}
|
||||
do_test $tn.2.3.4 { S delete } {}
|
||||
|
||||
do_test 2.4.1 {
|
||||
do_test $tn.2.4.1 {
|
||||
sqlite3session S db main
|
||||
S attach t1
|
||||
execsql { INSERT INTO t1 VALUES(100, 'Bangkok') }
|
||||
execsql { DELETE FROM t1 WHERE x = 100 }
|
||||
} {}
|
||||
do_changeset_test 2.4.2 S {}
|
||||
do_changeset_invert_test 2.4.3 S {}
|
||||
do_test 2.4.4 { S delete } {}
|
||||
do_changeset_test $tn.2.4.2 S {}
|
||||
do_changeset_invert_test $tn.2.4.3 S {}
|
||||
do_test $tn.2.4.4 { S delete } {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the application of simple changesets. These tests also test that
|
||||
@@ -189,16 +204,16 @@ proc do_db2_test {testname sql {result {}}} {
|
||||
|
||||
# Test INSERT changesets.
|
||||
#
|
||||
do_test 3.1.0 {
|
||||
execsql { CREATE TABLE t1(a PRIMARY KEY, b NOT NULL) } db2
|
||||
do_test $tn.3.1.0 {
|
||||
execsql { CREATE TABLE t1(a PRIMARY KEY, b NOT NULL) %WR% } db2
|
||||
execsql {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||
CREATE TABLE t1(a PRIMARY KEY, b) %WR%;
|
||||
INSERT INTO t1 VALUES(1, 'one');
|
||||
INSERT INTO t1 VALUES(2, 'two');
|
||||
} db
|
||||
} {}
|
||||
do_db2_test 3.1.1 "INSERT INTO t1 VALUES(6, 'VI')"
|
||||
do_conflict_test 3.1.2 -tables t1 -sql {
|
||||
do_db2_test $tn.3.1.1 "INSERT INTO t1 VALUES(6, 'VI')"
|
||||
do_conflict_test $tn.3.1.2 -tables t1 -sql {
|
||||
INSERT INTO t1 VALUES(3, 'three');
|
||||
INSERT INTO t1 VALUES(4, 'four');
|
||||
INSERT INTO t1 VALUES(5, 'five');
|
||||
@@ -210,34 +225,34 @@ do_conflict_test 3.1.2 -tables t1 -sql {
|
||||
{INSERT t1 CONSTRAINT {i 8 n {}}}
|
||||
}
|
||||
|
||||
do_db2_test 3.1.3 "SELECT * FROM t1" {
|
||||
6 VI 3 three 4 four 5 five 7 seven
|
||||
do_db2_test $tn.3.1.3 "SELECT * FROM t1 ORDER BY a" {
|
||||
3 three 4 four 5 five 6 VI 7 seven
|
||||
}
|
||||
do_execsql_test 3.1.4 "SELECT * FROM t1" {
|
||||
do_execsql_test $tn.3.1.4 "SELECT * FROM t1" {
|
||||
1 one 2 two 3 three 4 four 5 five 6 six 7 seven 8 {}
|
||||
}
|
||||
|
||||
# Test DELETE changesets.
|
||||
#
|
||||
do_execsql_test 3.2.1 {
|
||||
do_execsql_test $tn.3.2.1 {
|
||||
PRAGMA foreign_keys = on;
|
||||
CREATE TABLE t2(a PRIMARY KEY, b);
|
||||
CREATE TABLE t2(a PRIMARY KEY, b)%WR%;
|
||||
CREATE TABLE t3(c, d REFERENCES t2);
|
||||
INSERT INTO t2 VALUES(1, 'one');
|
||||
INSERT INTO t2 VALUES(2, 'two');
|
||||
INSERT INTO t2 VALUES(3, 'three');
|
||||
INSERT INTO t2 VALUES(4, 'four');
|
||||
}
|
||||
do_db2_test 3.2.2 {
|
||||
do_db2_test $tn.3.2.2 {
|
||||
PRAGMA foreign_keys = on;
|
||||
CREATE TABLE t2(a PRIMARY KEY, b);
|
||||
CREATE TABLE t2(a PRIMARY KEY, b)%WR%;
|
||||
CREATE TABLE t3(c, d REFERENCES t2);
|
||||
INSERT INTO t2 VALUES(1, 'one');
|
||||
INSERT INTO t2 VALUES(2, 'two');
|
||||
INSERT INTO t2 VALUES(4, 'five');
|
||||
INSERT INTO t3 VALUES('i', 1);
|
||||
}
|
||||
do_conflict_test 3.2.3 -tables t2 -sql {
|
||||
do_conflict_test $tn.3.2.3 -tables t2 -sql {
|
||||
DELETE FROM t2 WHERE a = 1;
|
||||
DELETE FROM t2 WHERE a = 2;
|
||||
DELETE FROM t2 WHERE a = 3;
|
||||
@@ -247,26 +262,26 @@ do_conflict_test 3.2.3 -tables t2 -sql {
|
||||
{DELETE t2 DATA {i 4 t four} {i 4 t five}}
|
||||
{FOREIGN_KEY 1}
|
||||
}
|
||||
do_execsql_test 3.2.4 "SELECT * FROM t2" {}
|
||||
do_db2_test 3.2.5 "SELECT * FROM t2" {4 five}
|
||||
do_execsql_test $tn.3.2.4 "SELECT * FROM t2" {}
|
||||
do_db2_test $tn.3.2.5 "SELECT * FROM t2" {4 five}
|
||||
|
||||
# Test UPDATE changesets.
|
||||
#
|
||||
do_execsql_test 3.3.1 {
|
||||
CREATE TABLE t4(a, b, c, PRIMARY KEY(b, c));
|
||||
do_execsql_test $tn.3.3.1 {
|
||||
CREATE TABLE t4(a, b, c, PRIMARY KEY(b, c))%WR%;
|
||||
INSERT INTO t4 VALUES(1, 2, 3);
|
||||
INSERT INTO t4 VALUES(4, 5, 6);
|
||||
INSERT INTO t4 VALUES(7, 8, 9);
|
||||
INSERT INTO t4 VALUES(10, 11, 12);
|
||||
}
|
||||
do_db2_test 3.3.2 {
|
||||
CREATE TABLE t4(a NOT NULL, b, c, PRIMARY KEY(b, c));
|
||||
do_db2_test $tn.3.3.2 {
|
||||
CREATE TABLE t4(a NOT NULL, b, c, PRIMARY KEY(b, c))%WR%;
|
||||
INSERT INTO t4 VALUES(0, 2, 3);
|
||||
INSERT INTO t4 VALUES(4, 5, 7);
|
||||
INSERT INTO t4 VALUES(7, 8, 9);
|
||||
INSERT INTO t4 VALUES(10, 11, 12);
|
||||
}
|
||||
do_conflict_test 3.3.3 -tables t4 -sql {
|
||||
do_conflict_test $tn.3.3.3 -tables t4 -sql {
|
||||
UPDATE t4 SET a = -1 WHERE b = 2;
|
||||
UPDATE t4 SET a = -1 WHERE b = 5;
|
||||
UPDATE t4 SET a = NULL WHERE c = 9;
|
||||
@@ -276,8 +291,8 @@ do_conflict_test 3.3.3 -tables t4 -sql {
|
||||
{UPDATE t4 NOTFOUND {i 4 i 5 i 6} {i -1 {} {} {} {}}}
|
||||
{UPDATE t4 CONSTRAINT {i 7 i 8 i 9} {n {} {} {} {} {}}}
|
||||
}
|
||||
do_db2_test 3.3.4 { SELECT * FROM t4 } {0 2 3 4 5 7 7 8 9 x 11 12}
|
||||
do_execsql_test 3.3.5 { SELECT * FROM t4 } {-1 2 3 -1 5 6 {} 8 9 x 11 12}
|
||||
do_db2_test $tn.3.3.4 { SELECT * FROM t4 } {0 2 3 4 5 7 7 8 9 x 11 12}
|
||||
do_execsql_test $tn.3.3.5 { SELECT * FROM t4 } {-1 2 3 -1 5 6 {} 8 9 x 11 12}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# This next block of tests verifies that values returned by the conflict
|
||||
@@ -297,16 +312,16 @@ proc xConflict {args} {
|
||||
return $::conflict_return
|
||||
}
|
||||
|
||||
foreach {tn conflict_return after} {
|
||||
foreach {tn2 conflict_return after} {
|
||||
1 OMIT {1 2 value1 4 5 7 10 x x}
|
||||
2 REPLACE {1 2 value1 4 5 value2 10 8 9}
|
||||
} {
|
||||
test_reset
|
||||
|
||||
do_test 4.$tn.1 {
|
||||
do_test $tn.4.$tn2.1 {
|
||||
foreach db {db db2} {
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b, c, PRIMARY KEY(a));
|
||||
CREATE TABLE t1(a, b, c, PRIMARY KEY(a))%WR%;
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
INSERT INTO t1 VALUES(4, 5, 6);
|
||||
INSERT INTO t1 VALUES(7, 8, 9);
|
||||
@@ -318,7 +333,7 @@ foreach {tn conflict_return after} {
|
||||
} db2
|
||||
} {}
|
||||
|
||||
do_conflict_test 4.$tn.2 -tables t1 -sql {
|
||||
do_conflict_test $tn.4.$tn2.2 -tables t1 -sql {
|
||||
UPDATE t1 SET c = 'value1' WHERE a = 1; -- no conflict
|
||||
UPDATE t1 SET c = 'value2' WHERE a = 4; -- DATA conflict
|
||||
UPDATE t1 SET a = 10 WHERE a = 7; -- CONFLICT conflict
|
||||
@@ -327,19 +342,19 @@ foreach {tn conflict_return after} {
|
||||
{UPDATE t1 DATA {i 4 {} {} i 6} {{} {} {} {} t value2} {i 4 i 5 i 7}}
|
||||
}
|
||||
|
||||
do_db2_test 4.$tn.3 "SELECT * FROM t1 ORDER BY a" $after
|
||||
do_db2_test $tn.4.$tn2.3 "SELECT * FROM t1 ORDER BY a" $after
|
||||
}
|
||||
|
||||
foreach {tn conflict_return} {
|
||||
foreach {tn2 conflict_return} {
|
||||
1 OMIT
|
||||
2 REPLACE
|
||||
} {
|
||||
test_reset
|
||||
|
||||
do_test 5.$tn.1 {
|
||||
do_test $tn.5.$tn2.1 {
|
||||
# Create an identical schema in both databases.
|
||||
set schema {
|
||||
CREATE TABLE "'foolish name'"(x, y, z, PRIMARY KEY(x, y));
|
||||
CREATE TABLE "'foolish name'"(x, y, z, PRIMARY KEY(x, y))%WR%;
|
||||
}
|
||||
execsql $schema db
|
||||
execsql $schema db2
|
||||
@@ -354,7 +369,7 @@ foreach {tn conflict_return} {
|
||||
|
||||
} {}
|
||||
|
||||
do_conflict_test 5.$tn.2 -tables {{'foolish name'}} -sql {
|
||||
do_conflict_test $tn.5.$tn2.2 -tables {{'foolish name'}} -sql {
|
||||
INSERT INTO "'foolish name'" VALUES('one', 'two', 2);
|
||||
} -conflicts {
|
||||
{INSERT {'foolish name'} CONFLICT {t one t two i 2} {t one t two t i}}
|
||||
@@ -362,14 +377,14 @@ foreach {tn conflict_return} {
|
||||
|
||||
set res(REPLACE) {one one ii one two 2 two two ii}
|
||||
set res(OMIT) {one one ii one two i two two ii}
|
||||
do_db2_test 5.$tn.3 {
|
||||
do_db2_test $tn.5.$tn2.3 {
|
||||
SELECT * FROM "'foolish name'" ORDER BY x, y
|
||||
} $res($conflict_return)
|
||||
|
||||
|
||||
do_test 5.$tn.1 {
|
||||
do_test $tn.5.$tn2.1 {
|
||||
set schema {
|
||||
CREATE TABLE d1("z""z" PRIMARY KEY, y);
|
||||
CREATE TABLE d1("z""z" PRIMARY KEY, y)%WR%;
|
||||
INSERT INTO d1 VALUES(1, 'one');
|
||||
INSERT INTO d1 VALUES(2, 'two');
|
||||
}
|
||||
@@ -382,7 +397,7 @@ foreach {tn conflict_return} {
|
||||
|
||||
} {}
|
||||
|
||||
do_conflict_test 5.$tn.2 -tables d1 -sql {
|
||||
do_conflict_test $tn.5.$tn2.2 -tables d1 -sql {
|
||||
DELETE FROM d1 WHERE "z""z" = 2;
|
||||
} -conflicts {
|
||||
{DELETE d1 DATA {i 2 t two} {i 2 t TWO}}
|
||||
@@ -390,7 +405,7 @@ foreach {tn conflict_return} {
|
||||
|
||||
set res(REPLACE) {1 one}
|
||||
set res(OMIT) {1 one 2 TWO}
|
||||
do_db2_test 5.$tn.3 "SELECT * FROM d1" $res($conflict_return)
|
||||
do_db2_test $tn.5.$tn2.3 "SELECT * FROM d1" $res($conflict_return)
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
@@ -398,10 +413,10 @@ foreach {tn conflict_return} {
|
||||
#
|
||||
test_reset
|
||||
set schema {
|
||||
CREATE TABLE t1(a COLLATE nocase PRIMARY KEY, b);
|
||||
CREATE TABLE t2(a, b PRIMARY KEY);
|
||||
CREATE TABLE t1(a COLLATE nocase PRIMARY KEY, b)%WR%;
|
||||
CREATE TABLE t2(a, b PRIMARY KEY)%WR%;
|
||||
}
|
||||
do_test 6.0 {
|
||||
do_test $tn.6.0 {
|
||||
execsql $schema db
|
||||
execsql $schema db2
|
||||
execsql {
|
||||
@@ -411,7 +426,7 @@ do_test 6.0 {
|
||||
} {}
|
||||
|
||||
set conflict_return ""
|
||||
do_conflict_test 6.1 -tables {t1 t2} -sql {
|
||||
do_conflict_test $tn.6.1 -tables {t1 t2} -sql {
|
||||
INSERT INTO t1 VALUES('1', '2');
|
||||
INSERT INTO t1 VALUES('A', 'B');
|
||||
INSERT INTO t2 VALUES('A', 'B');
|
||||
@@ -419,8 +434,8 @@ do_conflict_test 6.1 -tables {t1 t2} -sql {
|
||||
{INSERT t1 CONFLICT {t A t B} {t a t b}}
|
||||
}
|
||||
|
||||
do_db2_test 6.2 "SELECT * FROM t1" {a b 1 2}
|
||||
do_db2_test 6.3 "SELECT * FROM t2" {a b A B}
|
||||
do_db2_test $tn.6.2 "SELECT * FROM t1 ORDER BY a" {1 2 a b}
|
||||
do_db2_test $tn.6.3 "SELECT * FROM t2 ORDER BY a" {A B a b}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that session objects are not confused by changes to table in
|
||||
@@ -429,10 +444,10 @@ do_db2_test 6.3 "SELECT * FROM t2" {a b A B}
|
||||
catch { db2 close }
|
||||
drop_all_tables
|
||||
forcedelete test.db2
|
||||
do_iterator_test 7.1 * {
|
||||
do_iterator_test $tn.7.1 * {
|
||||
ATTACH 'test.db2' AS aux;
|
||||
CREATE TABLE main.t1(x PRIMARY KEY, y);
|
||||
CREATE TABLE aux.t1(x PRIMARY KEY, y);
|
||||
CREATE TABLE main.t1(x PRIMARY KEY, y)%WR%;
|
||||
CREATE TABLE aux.t1(x PRIMARY KEY, y)%WR%;
|
||||
|
||||
INSERT INTO main.t1 VALUES('one', 1);
|
||||
INSERT INTO main.t1 VALUES('two', 2);
|
||||
@@ -446,10 +461,10 @@ do_iterator_test 7.1 * {
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the sqlite3session_isempty() function.
|
||||
#
|
||||
do_test 8.1 {
|
||||
do_test $tn.8.1 {
|
||||
execsql {
|
||||
CREATE TABLE t5(x PRIMARY KEY, y);
|
||||
CREATE TABLE t6(x PRIMARY KEY, y);
|
||||
CREATE TABLE t5(x PRIMARY KEY, y)%WR%;
|
||||
CREATE TABLE t6(x PRIMARY KEY, y)%WR%;
|
||||
INSERT INTO t5 VALUES('a', 'b');
|
||||
INSERT INTO t6 VALUES('a', 'b');
|
||||
}
|
||||
@@ -458,20 +473,20 @@ do_test 8.1 {
|
||||
|
||||
S isempty
|
||||
} {1}
|
||||
do_test 8.2 {
|
||||
do_test $tn.8.2 {
|
||||
execsql { DELETE FROM t5 }
|
||||
S isempty
|
||||
} {0}
|
||||
do_test 8.3 {
|
||||
do_test $tn.8.3 {
|
||||
S delete
|
||||
sqlite3session S db main
|
||||
S attach t5
|
||||
execsql { DELETE FROM t5 }
|
||||
S isempty
|
||||
} {1}
|
||||
do_test 8.4 { S delete } {}
|
||||
do_test $tn.8.4 { S delete } {}
|
||||
|
||||
do_test 8.5 {
|
||||
do_test $tn.8.5 {
|
||||
sqlite3session S db main
|
||||
S attach t5
|
||||
S attach t6
|
||||
@@ -479,7 +494,7 @@ do_test 8.5 {
|
||||
S isempty
|
||||
} {0}
|
||||
|
||||
do_test 8.6 {
|
||||
do_test $tn.8.6 {
|
||||
S delete
|
||||
sqlite3session S db main
|
||||
S attach t5
|
||||
@@ -487,20 +502,20 @@ do_test 8.6 {
|
||||
execsql { INSERT INTO t6 VALUES(1, 2) }
|
||||
S isempty
|
||||
} {0}
|
||||
do_test 8.7 { S delete } {}
|
||||
do_test $tn.8.7 { S delete } {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 9.1 {
|
||||
CREATE TABLE t7(a, b, c, d, e PRIMARY KEY, f, g);
|
||||
do_execsql_test $tn.9.1 {
|
||||
CREATE TABLE t7(a, b, c, d, e PRIMARY KEY, f, g)%WR%;
|
||||
INSERT INTO t7 VALUES(1, 1, 1, 1, 1, 1, 1);
|
||||
}
|
||||
do_test 9.2 {
|
||||
do_test $tn.9.2 {
|
||||
sqlite3session S db main
|
||||
S attach *
|
||||
execsql { UPDATE t7 SET b=2, d=2 }
|
||||
} {}
|
||||
do_changeset_test 9.2 S {{UPDATE t7 0 ....X.. {{} {} i 1 {} {} i 1 i 1 {} {} {} {}} {{} {} i 2 {} {} i 2 {} {} {} {} {} {}}}}
|
||||
do_changeset_test $tn.9.2 S {{UPDATE t7 0 ....X.. {{} {} i 1 {} {} i 1 i 1 {} {} {} {}} {{} {} i 2 {} {} i 2 {} {} {} {} {} {}}}}
|
||||
S delete
|
||||
catch { db2 close }
|
||||
|
||||
@@ -509,9 +524,9 @@ catch { db2 close }
|
||||
#
|
||||
reset_db
|
||||
set tblname [string repeat tblname123 100]
|
||||
do_test 10.1.1 {
|
||||
do_test $tn.10.1.1 {
|
||||
execsql "
|
||||
CREATE TABLE $tblname (a PRIMARY KEY, b);
|
||||
CREATE TABLE $tblname (a PRIMARY KEY, b)%WR%;
|
||||
INSERT INTO $tblname VALUES('xyz', 'def');
|
||||
"
|
||||
sqlite3session S db main
|
||||
@@ -522,18 +537,18 @@ do_test 10.1.1 {
|
||||
"
|
||||
} {}
|
||||
breakpoint
|
||||
do_changeset_test 10.1.2 S "
|
||||
do_changeset_test $tn.10.1.2 S "
|
||||
{INSERT $tblname 0 X. {} {t uvw t abc}}
|
||||
{DELETE $tblname 0 X. {t xyz t def} {}}
|
||||
"
|
||||
do_test 10.1.4 { S delete } {}
|
||||
do_test $tn.10.1.4 { S delete } {}
|
||||
|
||||
#---------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 11.1 {
|
||||
do_execsql_test $tn.11.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
}
|
||||
do_test 11.2 {
|
||||
do_test $tn.11.2 {
|
||||
sqlite3session S db main
|
||||
S attach t1
|
||||
execsql {
|
||||
@@ -550,9 +565,9 @@ S delete
|
||||
#
|
||||
reset_db
|
||||
set tblname [string repeat tblname123 100]
|
||||
do_test 10.1.1 {
|
||||
do_test $tn.10.1.1 {
|
||||
execsql "
|
||||
CREATE TABLE $tblname (a PRIMARY KEY, b);
|
||||
CREATE TABLE $tblname (a PRIMARY KEY, b)%WR%;
|
||||
INSERT INTO $tblname VALUES('xyz', 'def');
|
||||
"
|
||||
sqlite3session S db main
|
||||
@@ -563,35 +578,35 @@ do_test 10.1.1 {
|
||||
"
|
||||
} {}
|
||||
breakpoint
|
||||
do_changeset_test 10.1.2 S "
|
||||
do_changeset_test $tn.10.1.2 S "
|
||||
{INSERT $tblname 0 X. {} {t uvw t abc}}
|
||||
{DELETE $tblname 0 X. {t xyz t def} {}}
|
||||
"
|
||||
do_test 10.1.4 { S delete } {}
|
||||
do_test $tn.10.1.4 { S delete } {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the effect of updating a column from 0.0 to 0.0.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 11.1 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b REAL);
|
||||
do_execsql_test $tn.11.1 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b REAL)%WR%;
|
||||
INSERT INTO t1 VALUES(1, 0.0);
|
||||
}
|
||||
do_iterator_test 11.2 * {
|
||||
do_iterator_test $tn.11.2 * {
|
||||
UPDATE t1 SET b = 0.0;
|
||||
} {
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 12.1 {
|
||||
CREATE TABLE t1(r INTEGER PRIMARY KEY, a, b);
|
||||
do_execsql_test $tn.12.1 {
|
||||
CREATE TABLE t1(r INTEGER PRIMARY KEY, a, b)%WR%;
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
INSERT INTO t1 VALUES(1, 1, 1);
|
||||
INSERT INTO t1 VALUES(2, 1, 2);
|
||||
INSERT INTO t1 VALUES(3, 1, 3);
|
||||
}
|
||||
|
||||
do_iterator_test 12.2 * {
|
||||
do_iterator_test $tn.12.2 * {
|
||||
UPDATE t1 SET b='one' WHERE a=1;
|
||||
} {
|
||||
{UPDATE t1 0 X.. {i 1 {} {} i 1} {{} {} {} {} t one}}
|
||||
@@ -599,6 +614,8 @@ do_iterator_test 12.2 * {
|
||||
{UPDATE t1 0 X.. {i 3 {} {} i 3} {{} {} {} {} t one}}
|
||||
}
|
||||
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
360
ext/session/session_speed_test.c
Normal file
360
ext/session/session_speed_test.c
Normal file
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
** 2017 January 31
|
||||
**
|
||||
** 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 contains the source code for a standalone program used to
|
||||
** test the performance of the sessions module. Compile and run:
|
||||
**
|
||||
** ./session_speed_test -help
|
||||
**
|
||||
** for details.
|
||||
*/
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*************************************************************************
|
||||
** Start of generic command line parser.
|
||||
*/
|
||||
#define CMDLINE_BARE 0
|
||||
#define CMDLINE_INTEGER 1
|
||||
#define CMDLINE_STRING 2
|
||||
#define CMDLINE_BOOLEAN 3
|
||||
|
||||
typedef struct CmdLineOption CmdLineOption;
|
||||
struct CmdLineOption {
|
||||
const char *zText; /* Name of command line option */
|
||||
const char *zHelp; /* Help text for option */
|
||||
int eType; /* One of the CMDLINE_* values */
|
||||
int iOff; /* Offset of output variable */
|
||||
};
|
||||
|
||||
#define CMDLINE_INT32(x,y,z) {x, y, CMDLINE_INTEGER, z}
|
||||
#define CMDLINE_BOOL(x,y,z) {x, y, CMDLINE_BOOLEAN, z}
|
||||
#define CMDLINE_TEXT(x,y,z) {x, y, CMDLINE_STRING, z}
|
||||
#define CMDLINE_NONE(x,y,z) {x, y, CMDLINE_BARE, z}
|
||||
|
||||
static void option_requires_argument_error(CmdLineOption *pOpt){
|
||||
fprintf(stderr, "Option requires a%s argument: %s\n",
|
||||
pOpt->eType==CMDLINE_INTEGER ? "n integer" :
|
||||
pOpt->eType==CMDLINE_STRING ? " string" : " boolean",
|
||||
pOpt->zText
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void ambiguous_option_error(const char *zArg){
|
||||
fprintf(stderr, "Option is ambiguous: %s\n", zArg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void unknown_option_error(
|
||||
const char *zArg,
|
||||
CmdLineOption *aOpt,
|
||||
const char *zHelp
|
||||
){
|
||||
int i;
|
||||
fprintf(stderr, "Unknown option: %s\n", zArg);
|
||||
fprintf(stderr, "\nOptions are:\n");
|
||||
fprintf(stderr, " % -30sEcho command line options\n", "-cmdline:verbose");
|
||||
for(i=0; aOpt[i].zText; i++){
|
||||
int eType = aOpt[i].eType;
|
||||
char *zOpt = sqlite3_mprintf("%s %s", aOpt[i].zText,
|
||||
eType==CMDLINE_BARE ? "" :
|
||||
eType==CMDLINE_INTEGER ? "N" :
|
||||
eType==CMDLINE_BOOLEAN ? "BOOLEAN" : "TEXT"
|
||||
);
|
||||
fprintf(stderr, " % -30s%s\n", zOpt, aOpt[i].zHelp);
|
||||
sqlite3_free(zOpt);
|
||||
}
|
||||
if( zHelp ){
|
||||
fprintf(stderr, "\n%s\n", zHelp);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int get_integer_option(CmdLineOption *pOpt, const char *zArg){
|
||||
int i = 0;
|
||||
int iRet = 0;
|
||||
int bSign = 1;
|
||||
if( zArg[0]=='-' ){
|
||||
bSign = -1;
|
||||
i = 1;
|
||||
}
|
||||
while( zArg[i] ){
|
||||
if( zArg[i]<'0' || zArg[i]>'9' ) option_requires_argument_error(pOpt);
|
||||
iRet = iRet*10 + (zArg[i] - '0');
|
||||
i++;
|
||||
}
|
||||
return (iRet*bSign);
|
||||
}
|
||||
|
||||
static int get_boolean_option(CmdLineOption *pOpt, const char *zArg){
|
||||
if( 0==sqlite3_stricmp(zArg, "true") ) return 1;
|
||||
if( 0==sqlite3_stricmp(zArg, "1") ) return 1;
|
||||
if( 0==sqlite3_stricmp(zArg, "0") ) return 0;
|
||||
if( 0==sqlite3_stricmp(zArg, "false") ) return 0;
|
||||
option_requires_argument_error(pOpt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void parse_command_line(
|
||||
int argc,
|
||||
char **argv,
|
||||
int iStart,
|
||||
CmdLineOption *aOpt,
|
||||
void *pStruct,
|
||||
const char *zHelp
|
||||
){
|
||||
char *pOut = (char*)pStruct;
|
||||
int bVerbose = 0;
|
||||
int iArg;
|
||||
|
||||
for(iArg=iStart; iArg<argc; iArg++){
|
||||
const char *zArg = argv[iArg];
|
||||
int nArg = strlen(zArg);
|
||||
int nMatch = 0;
|
||||
int iOpt;
|
||||
|
||||
for(iOpt=0; aOpt[iOpt].zText; iOpt++){
|
||||
CmdLineOption *pOpt = &aOpt[iOpt];
|
||||
if( 0==sqlite3_strnicmp(pOpt->zText, zArg, nArg) ){
|
||||
if( nMatch ){
|
||||
ambiguous_option_error(zArg);
|
||||
}
|
||||
nMatch++;
|
||||
if( pOpt->eType==CMDLINE_BARE ){
|
||||
*(int*)(&pOut[pOpt->iOff]) = 1;
|
||||
}else{
|
||||
iArg++;
|
||||
if( iArg==argc ){
|
||||
option_requires_argument_error(pOpt);
|
||||
}
|
||||
switch( pOpt->eType ){
|
||||
case CMDLINE_INTEGER:
|
||||
*(int*)(&pOut[pOpt->iOff]) = get_integer_option(pOpt, argv[iArg]);
|
||||
break;
|
||||
case CMDLINE_STRING:
|
||||
*(const char**)(&pOut[pOpt->iOff]) = argv[iArg];
|
||||
break;
|
||||
case CMDLINE_BOOLEAN:
|
||||
*(int*)(&pOut[pOpt->iOff]) = get_boolean_option(pOpt, argv[iArg]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( nMatch==0 && 0==sqlite3_strnicmp("-cmdline:verbose", zArg, nArg) ){
|
||||
bVerbose = 1;
|
||||
nMatch = 1;
|
||||
}
|
||||
|
||||
if( nMatch==0 ){
|
||||
unknown_option_error(zArg, aOpt, zHelp);
|
||||
}
|
||||
}
|
||||
|
||||
if( bVerbose ){
|
||||
int iOpt;
|
||||
fprintf(stdout, "Options are: ");
|
||||
for(iOpt=0; aOpt[iOpt].zText; iOpt++){
|
||||
CmdLineOption *pOpt = &aOpt[iOpt];
|
||||
if( pOpt->eType!=CMDLINE_BARE || *(int*)(&pOut[pOpt->iOff]) ){
|
||||
fprintf(stdout, "%s ", pOpt->zText);
|
||||
}
|
||||
switch( pOpt->eType ){
|
||||
case CMDLINE_INTEGER:
|
||||
fprintf(stdout, "%d ", *(int*)(&pOut[pOpt->iOff]));
|
||||
break;
|
||||
case CMDLINE_BOOLEAN:
|
||||
fprintf(stdout, "%d ", *(int*)(&pOut[pOpt->iOff]));
|
||||
break;
|
||||
case CMDLINE_STRING:
|
||||
fprintf(stdout, "%s ", *(const char**)(&pOut[pOpt->iOff]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
}
|
||||
/*
|
||||
** End of generic command line parser.
|
||||
*************************************************************************/
|
||||
|
||||
static void abort_due_to_error(int rc){
|
||||
fprintf(stderr, "Error: %d\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
static void execsql(sqlite3 *db, const char *zSql){
|
||||
int rc = sqlite3_exec(db, zSql, 0, 0, 0);
|
||||
if( rc!=SQLITE_OK ) abort_due_to_error(rc);
|
||||
}
|
||||
|
||||
static int xConflict(void *pCtx, int eConflict, sqlite3_changeset_iter *p){
|
||||
return SQLITE_CHANGESET_ABORT;
|
||||
}
|
||||
|
||||
static void run_test(
|
||||
sqlite3 *db,
|
||||
sqlite3 *db2,
|
||||
int nRow,
|
||||
const char *zSql
|
||||
){
|
||||
sqlite3_session *pSession = 0;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int rc;
|
||||
int i;
|
||||
int nChangeset;
|
||||
void *pChangeset;
|
||||
|
||||
/* Attach a session object to database db */
|
||||
rc = sqlite3session_create(db, "main", &pSession);
|
||||
if( rc!=SQLITE_OK ) abort_due_to_error(rc);
|
||||
|
||||
/* Configure the session to capture changes on all tables */
|
||||
rc = sqlite3session_attach(pSession, 0);
|
||||
if( rc!=SQLITE_OK ) abort_due_to_error(rc);
|
||||
|
||||
/* Prepare the SQL statement */
|
||||
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
|
||||
if( rc!=SQLITE_OK ) abort_due_to_error(rc);
|
||||
|
||||
/* Open a transaction */
|
||||
execsql(db, "BEGIN");
|
||||
|
||||
/* Execute the SQL statement nRow times */
|
||||
for(i=0; i<nRow; i++){
|
||||
sqlite3_bind_int(pStmt, 1, i);
|
||||
sqlite3_step(pStmt);
|
||||
rc = sqlite3_reset(pStmt);
|
||||
if( rc!=SQLITE_OK ) abort_due_to_error(rc);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
|
||||
/* Extract a changeset from the sessions object */
|
||||
rc = sqlite3session_changeset(pSession, &nChangeset, &pChangeset);
|
||||
if( rc!=SQLITE_OK ) abort_due_to_error(rc);
|
||||
execsql(db, "COMMIT");
|
||||
|
||||
/* Apply the changeset to the second db */
|
||||
rc = sqlite3changeset_apply(db2, nChangeset, pChangeset, 0, xConflict, 0);
|
||||
if( rc!=SQLITE_OK ) abort_due_to_error(rc);
|
||||
|
||||
/* Cleanup */
|
||||
sqlite3_free(pChangeset);
|
||||
sqlite3session_delete(pSession);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
struct Options {
|
||||
int nRow;
|
||||
int bWithoutRowid;
|
||||
int bInteger;
|
||||
int bAll;
|
||||
const char *zDb;
|
||||
};
|
||||
struct Options o = { 2500, 0, 0, 0, "session_speed_test.db" };
|
||||
|
||||
CmdLineOption aOpt[] = {
|
||||
CMDLINE_INT32( "-rows", "number of rows in test",
|
||||
offsetof(struct Options, nRow) ),
|
||||
CMDLINE_BOOL("-without-rowid", "use WITHOUT ROWID tables",
|
||||
offsetof(struct Options, bWithoutRowid) ),
|
||||
CMDLINE_BOOL("-integer", "use integer data (instead of text/blobs)",
|
||||
offsetof(struct Options, bInteger) ),
|
||||
CMDLINE_NONE("-all", "Run all 4 combos of -without-rowid and -integer",
|
||||
offsetof(struct Options, bAll) ),
|
||||
CMDLINE_TEXT("-database", "prefix for database files to use",
|
||||
offsetof(struct Options, zDb) ),
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
const char *azCreate[] = {
|
||||
"CREATE TABLE t1(a PRIMARY KEY, b, c, d)",
|
||||
"CREATE TABLE t1(a PRIMARY KEY, b, c, d) WITHOUT ROWID",
|
||||
};
|
||||
|
||||
const char *azInsert[] = {
|
||||
"INSERT INTO t1 VALUES("
|
||||
"printf('%.8d',?), randomblob(50), randomblob(50), randomblob(50))",
|
||||
"INSERT INTO t1 VALUES(?, random(), random(), random())"
|
||||
};
|
||||
|
||||
const char *azUpdate[] = {
|
||||
"UPDATE t1 SET d = randomblob(50) WHERE a = printf('%.8d',?)",
|
||||
"UPDATE t1 SET d = random() WHERE a = ?"
|
||||
};
|
||||
|
||||
const char *azDelete[] = {
|
||||
"DELETE FROM t1 WHERE a = printf('%.8d',?)",
|
||||
"DELETE FROM t1 WHERE a = ?"
|
||||
};
|
||||
|
||||
int rc;
|
||||
sqlite3 *db;
|
||||
sqlite3 *db2;
|
||||
char *zDb2;
|
||||
int bWithoutRowid;
|
||||
int bInteger;
|
||||
|
||||
parse_command_line(argc, argv, 1, aOpt, (void*)&o,
|
||||
"This program creates two new, empty, databases each containing a single\n"
|
||||
"table. It then does the following:\n\n"
|
||||
" 1. Inserts -rows rows into the first database\n"
|
||||
" 2. Updates each row in the first db\n"
|
||||
" 3. Delete each row from the first db\n\n"
|
||||
"The modifications made by each step are captured in a changeset and\n"
|
||||
"applied to the second database.\n"
|
||||
);
|
||||
zDb2 = sqlite3_mprintf("%s2", o.zDb);
|
||||
|
||||
for(bWithoutRowid=0; bWithoutRowid<2; bWithoutRowid++){
|
||||
for(bInteger=0; bInteger<2; bInteger++){
|
||||
if( o.bAll || (o.bWithoutRowid==bWithoutRowid && o.bInteger==bInteger) ){
|
||||
fprintf(stdout, "Testing %s data with %s table\n",
|
||||
bInteger ? "integer" : "blob/text",
|
||||
bWithoutRowid ? "WITHOUT ROWID" : "rowid"
|
||||
);
|
||||
|
||||
/* Open new database handles on two empty databases */
|
||||
unlink(o.zDb);
|
||||
rc = sqlite3_open(o.zDb, &db);
|
||||
if( rc!=SQLITE_OK ) abort_due_to_error(rc);
|
||||
unlink(zDb2);
|
||||
rc = sqlite3_open(zDb2, &db2);
|
||||
if( rc!=SQLITE_OK ) abort_due_to_error(rc);
|
||||
|
||||
/* Create the schema in both databases. */
|
||||
execsql(db, azCreate[o.bWithoutRowid]);
|
||||
execsql(db2, azCreate[o.bWithoutRowid]);
|
||||
|
||||
/* Run the three tests */
|
||||
run_test(db, db2, o.nRow, azInsert[o.bInteger]);
|
||||
run_test(db, db2, o.nRow, azUpdate[o.bInteger]);
|
||||
run_test(db, db2, o.nRow, azDelete[o.bInteger]);
|
||||
|
||||
/* Close the db handles */
|
||||
sqlite3_close(db);
|
||||
sqlite3_close(db2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
57
ext/session/sessionwor.test
Normal file
57
ext/session/sessionwor.test
Normal file
@@ -0,0 +1,57 @@
|
||||
# 2017 Jan 31
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# The focus of this file is testing the session module. Specifically,
|
||||
# testing support for WITHOUT ROWID tables.
|
||||
#
|
||||
|
||||
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 sessionwor
|
||||
|
||||
proc test_reset {} {
|
||||
catch { db close }
|
||||
catch { db2 close }
|
||||
forcedelete test.db test.db2
|
||||
sqlite3 db test.db
|
||||
sqlite3 db2 test.db2
|
||||
}
|
||||
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b) WITHOUT ROWID;
|
||||
}
|
||||
|
||||
do_iterator_test 1.1 t1 {
|
||||
INSERT INTO t1 VALUES('one', 'two');
|
||||
} {
|
||||
{INSERT t1 0 X. {} {t one t two}}
|
||||
}
|
||||
|
||||
do_iterator_test 1.2 t1 {
|
||||
UPDATE t1 SET b='three'
|
||||
} {
|
||||
{UPDATE t1 0 X. {t one t two} {{} {} t three}}
|
||||
}
|
||||
|
||||
do_iterator_test 1.3 t1 {
|
||||
DELETE FROM t1;
|
||||
} {
|
||||
{DELETE t1 0 X. {t one t three} {}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
27
manifest
27
manifest
@@ -1,5 +1,5 @@
|
||||
C More\sRTREE\sperformance\soptimizations\srelated\sto\sdecoding\svalues.
|
||||
D 2017-02-01T02:25:28.535
|
||||
C Changes\sso\sthat\sthe\spre-update\shook\sand\sthe\ssessions\smodule\swork\swith\sWITHOUT\nROWID\stables.
|
||||
D 2017-02-01T14:10:24.369
|
||||
F Makefile.in 5f415e7867296d678fed2e6779aea10c1318b4bc
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc b8ca53350ae545e3562403d5da2a69cec79308da
|
||||
@@ -288,7 +288,7 @@ F ext/rtree/sqlite3rtree.h 9c5777af3d2921c7b4ae4954e8e5697502289d28
|
||||
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F ext/session/changeset.c 4ccbaa4531944c24584bf6a61ba3a39c62b6267a
|
||||
F ext/session/session1.test 482e9b861169d0b7e283e1563a28c0fa32779fa5
|
||||
F ext/session/session1.test c8a50e0e8581dc1a00e832aa59bb61f180404d44
|
||||
F ext/session/session2.test 284de45abae4cc1082bc52012ee81521d5ac58e0
|
||||
F ext/session/session3.test a7a9ce59b8d1e49e2cc23d81421ac485be0eea01
|
||||
F ext/session/session4.test 457b02bdc349eb01151e54de014df77abd3c08c8
|
||||
@@ -304,8 +304,10 @@ F ext/session/sessionE.test e60a238c47f0feb3bb707e7f35e22be09c7e8f26
|
||||
F ext/session/sessionF.test c2f178d4dfd723a5fd94a730ea2ccb44c669e3ce
|
||||
F ext/session/sessionG.test 01ef705096a9d3984eebdcca79807a211dee1b60
|
||||
F ext/session/session_common.tcl 9b696a341cf1d3744823715ed92bb19749b6c3d4
|
||||
F ext/session/session_speed_test.c edc1f96fd5e0e4b16eb03e2a73041013d59e8723
|
||||
F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7
|
||||
F ext/session/sessionfault2.test 04aa0bc9aa70ea43d8de82c4f648db4de1e990b0
|
||||
F ext/session/sessionwor.test 2f3744236dc8b170a695b7d8ddc8c743c7e79fdc
|
||||
F ext/session/sqlite3session.c c61a43396368ec00dc127f7bc647e9bd6a4ee5fb
|
||||
F ext/session/sqlite3session.h 9345166bd8f80562145586cf817f707de5ecada2
|
||||
F ext/session/test_session.c eb0bd6c1ea791c1d66ee4ef94c16500dad936386
|
||||
@@ -353,7 +355,7 @@ F src/hash.c 63d0ee752a3b92d4695b2b1f5259c4621b2cfebd
|
||||
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
|
||||
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 8183e1778ec42d26732bec8c98aeffa8af13038f
|
||||
F src/insert.c 444354c23d4d140a57d6eb46f34e376a7f8f62e8
|
||||
F src/legacy.c 75d3023be8f0d2b99d60f905090341a03358c58e
|
||||
F src/loadext.c a68d8d1d14cf7488bb29dc5311cb1ce9a4404258
|
||||
F src/main.c e207b81542d13b9f13d61e78ca441f9781f055b0
|
||||
@@ -458,11 +460,11 @@ F src/update.c 456d4a4656f8a03c2abc88a51b19172197400e58
|
||||
F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
|
||||
F src/util.c a88b0466fddf445ce752226d4698ca3faada620a
|
||||
F src/vacuum.c 33c174b28886b2faf26e503b5a49a1c01a9b1c16
|
||||
F src/vdbe.c d3765f4d8f667b8d10232b2a1d0498497f3ac09f
|
||||
F src/vdbe.c ec059d331da77cb2e3e8af3fb7e40443ed148fbd
|
||||
F src/vdbe.h 59998ffd71d7caa8886bc78dafaf8caeccd4c13c
|
||||
F src/vdbeInt.h 281cb70332dc8b593b8c7afe776f3a2ba7d4255e
|
||||
F src/vdbeapi.c 7a65f10684982daecfce50f557f2632b7f20b198
|
||||
F src/vdbeaux.c 6847b02aa2db536ed15d90f1fdc2923afef93c5b
|
||||
F src/vdbeInt.h 4e4b15b2e1330e1636e4e01974eab2b0b985092f
|
||||
F src/vdbeapi.c 3e4a8893feeb78620f4aac4ac5b85d92255b97e1
|
||||
F src/vdbeaux.c b9a36e530e6525ca9d9a685bc7b1d01fa77b5cf8
|
||||
F src/vdbeblob.c 359891617358deefc85bef7bcf787fa6b77facb9
|
||||
F src/vdbemem.c 3b5a9a5b375458d3e12a50ae1aaa41eeec2175fd
|
||||
F src/vdbesort.c eda25cb2d1727efca6f7862fea32b8aa33c0face
|
||||
@@ -834,6 +836,7 @@ F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
|
||||
F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
|
||||
F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711
|
||||
F test/hook.test dbc0b87756e1e20e7497b56889c9e9cd2f8cc2b5
|
||||
F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8
|
||||
F test/icu.test 73956798bace8982909c00476b216714a6d0559a
|
||||
F test/ieee754.test 806fc0ce7f305f57e3331eaceeddcfec9339e607
|
||||
F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
|
||||
@@ -1549,7 +1552,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 9663eea2a16bb4eec71476d307a3722a768308c3
|
||||
R 5d2055e5a67aa8455e161eeb4945e6a1
|
||||
U drh
|
||||
Z 3923bc85bfbb1c570a9230cd663fc66b
|
||||
P c5395e7496d0cd593f5e16ee5f6719d020dc0c66 25f1275fe3e940c1d9a7b013cb3744304b2eda1e
|
||||
R f7a2435ee7007416912dcdfda9016a2c
|
||||
U dan
|
||||
Z 84db606ff358cb3acbf24f0cef50dec1
|
||||
|
@@ -1 +1 @@
|
||||
c5395e7496d0cd593f5e16ee5f6719d020dc0c66
|
||||
964bdc27f8f1b1db2e5c0c2a65c8156614cbe087
|
17
src/insert.c
17
src/insert.c
@@ -1730,16 +1730,23 @@ void sqlite3CompleteInsertion(
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i],
|
||||
aRegIdx[i]+1,
|
||||
pIdx->uniqNotNull ? pIdx->nKeyCol: pIdx->nColumn);
|
||||
pik_flags = 0;
|
||||
if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT;
|
||||
pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0);
|
||||
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
|
||||
assert( pParse->nested==0 );
|
||||
pik_flags |= OPFLAG_NCHANGE;
|
||||
pik_flags |= (update_flags & OPFLAG_SAVEPOSITION);
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
if( update_flags==0 ){
|
||||
sqlite3VdbeAddOp4(v, OP_InsertInt,
|
||||
iIdxCur+i, aRegIdx[i], 0, (char*)pTab, P4_TABLE
|
||||
);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i],
|
||||
aRegIdx[i]+1,
|
||||
pIdx->uniqNotNull ? pIdx->nKeyCol: pIdx->nColumn);
|
||||
sqlite3VdbeChangeP5(v, pik_flags);
|
||||
}
|
||||
if( !HasRowid(pTab) ) return;
|
||||
|
13
src/vdbe.c
13
src/vdbe.c
@@ -4383,7 +4383,7 @@ case OP_InsertInt: {
|
||||
assert( pC!=0 );
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
assert( pC->isTable );
|
||||
assert( (pOp->p5 & OPFLAG_ISNOOP) || pC->isTable );
|
||||
assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC );
|
||||
REGISTER_TRACE(pOp->p2, pData);
|
||||
|
||||
@@ -4399,11 +4399,10 @@ case OP_InsertInt: {
|
||||
}
|
||||
|
||||
if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
|
||||
assert( pC->isTable );
|
||||
assert( pC->iDb>=0 );
|
||||
zDb = db->aDb[pC->iDb].zDbSName;
|
||||
pTab = pOp->p4.pTab;
|
||||
assert( HasRowid(pTab) );
|
||||
assert( (pOp->p5 & OPFLAG_ISNOOP) || HasRowid(pTab) );
|
||||
op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
|
||||
}else{
|
||||
pTab = 0; /* Not needed. Silence a compiler warning. */
|
||||
@@ -4418,6 +4417,7 @@ case OP_InsertInt: {
|
||||
){
|
||||
sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, x.nKey, pOp->p2);
|
||||
}
|
||||
if( pOp->p5 & OPFLAG_ISNOOP ) break;
|
||||
#endif
|
||||
|
||||
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
|
||||
@@ -4530,8 +4530,11 @@ case OP_Delete: {
|
||||
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
/* Invoke the pre-update-hook if required. */
|
||||
if( db->xPreUpdateCallback && pOp->p4.pTab && HasRowid(pTab) ){
|
||||
assert( !(opflags & OPFLAG_ISUPDATE) || (aMem[pOp->p3].flags & MEM_Int) );
|
||||
if( db->xPreUpdateCallback && pOp->p4.pTab ){
|
||||
assert( !(opflags & OPFLAG_ISUPDATE)
|
||||
|| HasRowid(pTab)==0
|
||||
|| (aMem[pOp->p3].flags & MEM_Int)
|
||||
);
|
||||
sqlite3VdbePreUpdateHook(p, pC,
|
||||
(opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE,
|
||||
zDb, pTab, pC->movetoTarget,
|
||||
|
@@ -434,6 +434,7 @@ struct PreUpdate {
|
||||
i64 iKey2; /* Second key value passed to hook */
|
||||
Mem *aNew; /* Array of new.* values */
|
||||
Table *pTab; /* Schema object being upated */
|
||||
Index *pPk; /* PK index if pTab is WITHOUT ROWID */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@@ -1669,6 +1669,9 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
|
||||
rc = SQLITE_MISUSE_BKPT;
|
||||
goto preupdate_old_out;
|
||||
}
|
||||
if( p->pPk ){
|
||||
iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx);
|
||||
}
|
||||
if( iIdx>=p->pCsr->nField || iIdx<0 ){
|
||||
rc = SQLITE_RANGE;
|
||||
goto preupdate_old_out;
|
||||
@@ -1754,6 +1757,9 @@ int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
|
||||
rc = SQLITE_MISUSE_BKPT;
|
||||
goto preupdate_new_out;
|
||||
}
|
||||
if( p->pPk && p->op!=SQLITE_UPDATE ){
|
||||
iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx);
|
||||
}
|
||||
if( iIdx>=p->pCsr->nField || iIdx<0 ){
|
||||
rc = SQLITE_RANGE;
|
||||
goto preupdate_new_out;
|
||||
|
@@ -4620,10 +4620,15 @@ void sqlite3VdbePreUpdateHook(
|
||||
|
||||
assert( db->pPreUpdate==0 );
|
||||
memset(&preupdate, 0, sizeof(PreUpdate));
|
||||
if( op==SQLITE_UPDATE ){
|
||||
iKey2 = v->aMem[iReg].u.i;
|
||||
if( HasRowid(pTab)==0 ){
|
||||
iKey1 = iKey2 = 0;
|
||||
preupdate.pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
}else{
|
||||
iKey2 = iKey1;
|
||||
if( op==SQLITE_UPDATE ){
|
||||
iKey2 = v->aMem[iReg].u.i;
|
||||
}else{
|
||||
iKey2 = iKey1;
|
||||
}
|
||||
}
|
||||
|
||||
assert( pCsr->nField==pTab->nCol
|
||||
|
218
test/hook2.test
Normal file
218
test/hook2.test
Normal file
@@ -0,0 +1,218 @@
|
||||
# 2017 Jan 30
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
# The tests in this file focus on the pre-update hook.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix hook2
|
||||
|
||||
ifcapable !preupdate {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
proc do_preupdate_test {tn sql x} {
|
||||
set X [list]
|
||||
foreach elem $x {lappend X $elem}
|
||||
uplevel do_test $tn [list "
|
||||
set ::preupdate \[list\]
|
||||
execsql { $sql }
|
||||
set ::preupdate
|
||||
"] [list $X]
|
||||
}
|
||||
|
||||
proc preupdate_hook {args} {
|
||||
set type [lindex $args 0]
|
||||
eval lappend ::preupdate $args
|
||||
if {$type != "INSERT"} {
|
||||
for {set i 0} {$i < [db preupdate count]} {incr i} {
|
||||
lappend ::preupdate [db preupdate old $i]
|
||||
}
|
||||
}
|
||||
if {$type != "DELETE"} {
|
||||
for {set i 0} {$i < [db preupdate count]} {incr i} {
|
||||
set rc [catch { db preupdate new $i } v]
|
||||
lappend ::preupdate $v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Simple tests - INSERT, UPDATE and DELETE on a WITHOUT ROWID table.
|
||||
#
|
||||
db preupdate hook preupdate_hook
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b) WITHOUT ROWID;
|
||||
}
|
||||
do_preupdate_test 1.1 {
|
||||
INSERT INTO t1 VALUES('one', 1);
|
||||
} {
|
||||
INSERT main t1 0 0 one 1
|
||||
}
|
||||
do_preupdate_test 1.2 {
|
||||
UPDATE t1 SET b=2 WHERE a='one';
|
||||
} {
|
||||
UPDATE main t1 0 0 one 1 one 2
|
||||
}
|
||||
do_preupdate_test 1.3 {
|
||||
DELETE FROM t1 WHERE a='one';
|
||||
} {
|
||||
DELETE main t1 0 0 one 2
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Some more complex tests for the pre-update callback on WITHOUT ROWID
|
||||
# tables.
|
||||
#
|
||||
# 2.1.1 - INSERT statement.
|
||||
# 2.1.2 - INSERT INTO ... SELECT statement.
|
||||
# 2.1.3 - REPLACE INTO ... (PK conflict)
|
||||
# 2.1.4 - REPLACE INTO ... (other index conflicts)
|
||||
# 2.1.5 - REPLACE INTO ... (both PK and other index conflicts)
|
||||
#
|
||||
# 2.2.1 - DELETE statement.
|
||||
# 2.2.2 - DELETE statement that uses the truncate optimization.
|
||||
#
|
||||
# 2.3.1 - UPDATE statement.
|
||||
# 2.3.2 - UPDATE statement that modifies the PK.
|
||||
# 2.3.3 - UPDATE OR REPLACE ... (PK conflict).
|
||||
# 2.3.4 - UPDATE OR REPLACE ... (other index conflicts)
|
||||
# 2.3.4 - UPDATE OR REPLACE ... (both PK and other index conflicts)
|
||||
#
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t2(a DEFAULT 4, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID;
|
||||
CREATE UNIQUE INDEX t2a ON t2(a);
|
||||
}
|
||||
|
||||
do_preupdate_test 2.1.1 {
|
||||
INSERT INTO t2(b, c) VALUES(1, 1);
|
||||
} {
|
||||
INSERT main t2 0 0 4 1 1
|
||||
}
|
||||
|
||||
do_execsql_test 2.1.2.0 {
|
||||
CREATE TABLE d1(a DEFAULT 4, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID;
|
||||
CREATE UNIQUE INDEX d1a ON d1(a);
|
||||
INSERT INTO d1 VALUES(1, 2, 3);
|
||||
INSERT INTO d1 VALUES(11, 12, 13);
|
||||
}
|
||||
do_preupdate_test 2.1.2.1 {
|
||||
INSERT INTO t2 SELECT * FROM d1;
|
||||
} {
|
||||
INSERT main t2 0 0 1 2 3
|
||||
INSERT main t2 0 0 11 12 13
|
||||
}
|
||||
do_preupdate_test 2.1.2.2 {
|
||||
INSERT INTO t2 SELECT a+20, b+20, c+20 FROM d1;
|
||||
} {
|
||||
INSERT main t2 0 0 21 22 23
|
||||
INSERT main t2 0 0 31 32 33
|
||||
}
|
||||
do_execsql_test 2.1.2.3 {
|
||||
SELECT * FROM t2 ORDER BY b, c;
|
||||
} {
|
||||
4 1 1
|
||||
1 2 3
|
||||
11 12 13
|
||||
21 22 23
|
||||
31 32 33
|
||||
}
|
||||
do_preupdate_test 2.1.3 {
|
||||
REPLACE INTO t2 VALUES(45, 22, 23);
|
||||
} {
|
||||
DELETE main t2 0 0 21 22 23
|
||||
INSERT main t2 0 0 45 22 23
|
||||
}
|
||||
do_preupdate_test 2.1.4 {
|
||||
REPLACE INTO t2 VALUES(11, 100, 100);
|
||||
} {
|
||||
DELETE main t2 0 0 11 12 13
|
||||
INSERT main t2 0 0 11 100 100
|
||||
}
|
||||
do_preupdate_test 2.1.5 {
|
||||
REPLACE INTO t2(c, b) VALUES(33, 32)
|
||||
} {
|
||||
DELETE main t2 0 0 4 1 1
|
||||
DELETE main t2 0 0 31 32 33
|
||||
INSERT main t2 0 0 4 32 33
|
||||
}
|
||||
|
||||
do_execsql_test 2.2.0 {
|
||||
SELECT * FROM t2 ORDER BY b,c;
|
||||
} {
|
||||
1 2 3
|
||||
45 22 23
|
||||
4 32 33
|
||||
11 100 100
|
||||
}
|
||||
do_preupdate_test 2.2.1 {
|
||||
DELETE FROM t2 WHERE b=22;
|
||||
} {
|
||||
DELETE main t2 0 0 45 22 23
|
||||
}
|
||||
do_preupdate_test 2.2.2 {
|
||||
DELETE FROM t2;
|
||||
} {
|
||||
DELETE main t2 0 0 1 2 3
|
||||
DELETE main t2 0 0 4 32 33
|
||||
DELETE main t2 0 0 11 100 100
|
||||
}
|
||||
|
||||
do_execsql_test 2.3.0 {
|
||||
CREATE TABLE t3(x, y PRIMARY KEY, z UNIQUE) WITHOUT ROWID;
|
||||
INSERT INTO t3 VALUES('a', 'b', 'c');
|
||||
INSERT INTO t3 VALUES('d', 'e', 'f');
|
||||
|
||||
INSERT INTO t3 VALUES(1, 1, 1);
|
||||
INSERT INTO t3 VALUES(2, 2, 2);
|
||||
INSERT INTO t3 VALUES(3, 3, 3);
|
||||
}
|
||||
|
||||
do_preupdate_test 2.3.1 {
|
||||
UPDATE t3 SET x=4 WHERE y IN ('b', 'e', 'x');
|
||||
} {
|
||||
UPDATE main t3 0 0 a b c 4 b c
|
||||
UPDATE main t3 0 0 d e f 4 e f
|
||||
}
|
||||
|
||||
do_preupdate_test 2.3.2 {
|
||||
UPDATE t3 SET y=y||y WHERE z IN('c', 'f');
|
||||
} {
|
||||
UPDATE main t3 0 0 4 b c 4 bb c
|
||||
UPDATE main t3 0 0 4 e f 4 ee f
|
||||
}
|
||||
|
||||
do_preupdate_test 2.3.3 {
|
||||
UPDATE OR REPLACE t3 SET y='bb' WHERE z='f'
|
||||
} {
|
||||
DELETE main t3 0 0 4 bb c
|
||||
UPDATE main t3 0 0 4 ee f 4 bb f
|
||||
}
|
||||
|
||||
do_preupdate_test 2.3.4 {
|
||||
UPDATE OR REPLACE t3 SET z=2 WHERE y=1;
|
||||
} {
|
||||
DELETE main t3 0 0 2 2 2
|
||||
UPDATE main t3 0 0 1 1 1 1 1 2
|
||||
}
|
||||
|
||||
do_preupdate_test 2.3.5 {
|
||||
UPDATE OR REPLACE t3 SET z=2, y='bb' WHERE y=3;
|
||||
} {
|
||||
DELETE main t3 0 0 1 1 2
|
||||
DELETE main t3 0 0 4 bb f
|
||||
UPDATE main t3 0 0 3 3 3 3 bb 2
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
Reference in New Issue
Block a user