# 2017 August 17 # # 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. # #************************************************************************* # source [file join [file dirname [info script]] fts5_common.tcl] set testprefix fts5connect ifcapable !fts5 { finish_test return } #------------------------------------------------------------------------- # The tests in this file test the outcome of a schema-reset happening # within the xConnect() method of an FTS5 table. At one point this # was causing a problem in SQLite. Each test proceeds as follows: # # 1. Connection [db] opens the db and reads from some unrelated, non-FTS5 # table causing SQLite to load the db schema into memory. # # 2. Connection [db2] opens the db and modifies the db schema. # # 3. Connection [db] reads or writes an existing fts5 table. That the # schema has been modified is detected inside the fts5 xConnect() # callback that is invoked by sqlite3_prepare(). # # 4. Verify that the statement in 3 has worked. SQLite should detect # that the schema has changed and successfully prepare the # statement against the new schema. # # Test plan: # # 1.*: Trigger the xConnect()/schema-reset using statements executed # directly against an FTS5 table. # # 2.*: Using various statements executed by various BEFORE triggers. # # 3.*: Using various statements executed by various AFTER triggers. # # 4.*: Using various statements executed by various INSTEAD OF triggers. # do_execsql_test 1.0 { CREATE VIRTUAL TABLE ft1 USING fts5(a, b); CREATE TABLE abc(x INTEGER PRIMARY KEY); CREATE TABLE t1(i INTEGER PRIMARY KEY, a, b); INSERT INTO ft1 VALUES('one', 'two'); INSERT INTO ft1 VALUES('three', 'four'); } foreach {tn sql res} { 1 "SELECT * FROM ft1" {one two three four} 2 "REPLACE INTO ft1(rowid, a, b) VALUES(1, 'five', 'six')" {} 3 "SELECT * FROM ft1" {five six three four} 4 "INSERT INTO ft1 VALUES('seven', 'eight')" {} 5 "SELECT * FROM ft1" {five six three four seven eight} 6 "DELETE FROM ft1 WHERE rowid=2" {} 7 "UPDATE ft1 SET b='nine' WHERE rowid=1" {} 8 "SELECT * FROM ft1" {five nine seven eight} } { catch { db close } catch { db2 close } sqlite3 db test.db sqlite3 db2 test.db do_test 1.$tn.1 { db eval { INSERT INTO abc DEFAULT VALUES } db2 eval { CREATE TABLE newtable(x,y); DROP TABLE newtable } } {} do_execsql_test 1.$tn.2 $sql $res do_execsql_test 1.$tn.3 { INSERT INTO ft1(ft1) VALUES('integrity-check'); } } do_execsql_test 2.0 { CREATE VIRTUAL TABLE ft2 USING fts5(a, b); CREATE TABLE t2(a, b); CREATE TABLE log(txt); CREATE TRIGGER t2_ai AFTER INSERT ON t2 BEGIN INSERT INTO ft2(rowid, a, b) VALUES(new.rowid, new.a, new.b); INSERT INTO log VALUES('insert'); END; CREATE TRIGGER t2_ad AFTER DELETE ON t2 BEGIN DELETE FROM ft2 WHERE rowid = old.rowid; INSERT INTO log VALUES('delete'); END; CREATE TRIGGER t2_au AFTER UPDATE ON t2 BEGIN UPDATE ft2 SET a=new.a, b=new.b WHERE rowid=new.rowid; INSERT INTO log VALUES('update'); END; INSERT INTO t2 VALUES('one', 'two'); INSERT INTO t2 VALUES('three', 'four'); } foreach {tn sql res} { 1 "SELECT * FROM t2" {one two three four} 2 "REPLACE INTO t2(rowid, a, b) VALUES(1, 'five', 'six')" {} 3 "SELECT * FROM ft2" {five six three four} 4 "INSERT INTO t2 VALUES('seven', 'eight')" {} 5 "SELECT * FROM ft2" {five six three four seven eight} 6 "DELETE FROM t2 WHERE rowid=2" {} 7 "UPDATE t2 SET b='nine' WHERE rowid=1" {} 8 "SELECT * FROM ft2" {five nine seven eight} } { catch { db close } catch { db2 close } sqlite3 db test.db sqlite3 db2 test.db do_test 2.$tn.1 { db eval { INSERT INTO abc DEFAULT VALUES } db2 eval { CREATE TABLE newtable(x,y); DROP TABLE newtable } } {} do_execsql_test 2.$tn.2 $sql $res do_execsql_test 2.$tn.3 { INSERT INTO ft2(ft2) VALUES('integrity-check'); } } do_execsql_test 3.0 { CREATE VIRTUAL TABLE ft3 USING fts5(a, b); CREATE TABLE t3(a, b); CREATE TRIGGER t3_ai BEFORE INSERT ON t3 BEGIN INSERT INTO ft3(rowid, a, b) VALUES(new.rowid, new.a, new.b); INSERT INTO log VALUES('insert'); END; CREATE TRIGGER t3_ad BEFORE DELETE ON t3 BEGIN DELETE FROM ft3 WHERE rowid = old.rowid; INSERT INTO log VALUES('delete'); END; CREATE TRIGGER t3_au BEFORE UPDATE ON t3 BEGIN UPDATE ft3 SET a=new.a, b=new.b WHERE rowid=new.rowid; INSERT INTO log VALUES('update'); END; INSERT INTO t3(rowid, a, b) VALUES(1, 'one', 'two'); INSERT INTO t3(rowid, a, b) VALUES(2, 'three', 'four'); } foreach {tn sql res} { 1 "SELECT * FROM t3" {one two three four} 2 "REPLACE INTO t3(rowid, a, b) VALUES(1, 'five', 'six')" {} 3 "SELECT * FROM ft3" {five six three four} 4 "INSERT INTO t3(rowid, a, b) VALUES(3, 'seven', 'eight')" {} 5 "SELECT * FROM ft3" {five six three four seven eight} 6 "DELETE FROM t3 WHERE rowid=2" {} 7 "UPDATE t3 SET b='nine' WHERE rowid=1" {} 8 "SELECT * FROM ft3" {five nine seven eight} } { catch { db close } catch { db2 close } sqlite3 db test.db sqlite3 db2 test.db do_test 3.$tn.1 { db eval { INSERT INTO abc DEFAULT VALUES } db2 eval { CREATE TABLE newtable(x,y); DROP TABLE newtable } } {} do_execsql_test 3.$tn.2 $sql $res do_execsql_test 3.$tn.3 { INSERT INTO ft3(ft3) VALUES('integrity-check'); } } do_execsql_test 4.0 { CREATE VIRTUAL TABLE ft4 USING fts5(a, b); CREATE VIEW v4 AS SELECT rowid, * FROM ft4; CREATE TRIGGER t4_ai INSTEAD OF INSERT ON v4 BEGIN INSERT INTO ft4(rowid, a, b) VALUES(new.rowid, new.a, new.b); INSERT INTO log VALUES('insert'); END; CREATE TRIGGER t4_ad INSTEAD OF DELETE ON v4 BEGIN DELETE FROM ft4 WHERE rowid = old.rowid; INSERT INTO log VALUES('delete'); END; CREATE TRIGGER t4_au INSTEAD OF UPDATE ON v4 BEGIN UPDATE ft4 SET a=new.a, b=new.b WHERE rowid=new.rowid; INSERT INTO log VALUES('update'); END; INSERT INTO ft4(rowid, a, b) VALUES(1, 'one', 'two'); INSERT INTO ft4(rowid, a, b) VALUES(2, 'three', 'four'); } foreach {tn sql res} { 1 "SELECT * FROM ft4" {one two three four} 2 "REPLACE INTO v4(rowid, a, b) VALUES(1, 'five', 'six')" {} 3 "SELECT * FROM ft4" {five six three four} 4 "INSERT INTO v4(rowid, a, b) VALUES(3, 'seven', 'eight')" {} 5 "SELECT * FROM ft4" {five six three four seven eight} 6 "DELETE FROM v4 WHERE rowid=2" {} 7 "UPDATE v4 SET b='nine' WHERE rowid=1" {} 8 "SELECT * FROM ft4" {five nine seven eight} } { catch { db close } catch { db2 close } sqlite3 db test.db sqlite3 db2 test.db do_test 4.$tn.1 { db eval { INSERT INTO abc DEFAULT VALUES } db2 eval { CREATE TABLE newtable(x,y); DROP TABLE newtable } } {} do_execsql_test 4.$tn.2 $sql $res do_execsql_test 4.$tn.3 { INSERT INTO ft3(ft3) VALUES('integrity-check'); } } finish_test