fts5connect.test 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. # 2017 August 17
  2. #
  3. # The author disclaims copyright to this source code. In place of
  4. # a legal notice, here is a blessing:
  5. #
  6. # May you do good and not evil.
  7. # May you find forgiveness for yourself and forgive others.
  8. # May you share freely, never taking more than you give.
  9. #
  10. #*************************************************************************
  11. #
  12. source [file join [file dirname [info script]] fts5_common.tcl]
  13. set testprefix fts5connect
  14. ifcapable !fts5 {
  15. finish_test
  16. return
  17. }
  18. #-------------------------------------------------------------------------
  19. # The tests in this file test the outcome of a schema-reset happening
  20. # within the xConnect() method of an FTS5 table. At one point this
  21. # was causing a problem in SQLite. Each test proceeds as follows:
  22. #
  23. # 1. Connection [db] opens the db and reads from some unrelated, non-FTS5
  24. # table causing SQLite to load the db schema into memory.
  25. #
  26. # 2. Connection [db2] opens the db and modifies the db schema.
  27. #
  28. # 3. Connection [db] reads or writes an existing fts5 table. That the
  29. # schema has been modified is detected inside the fts5 xConnect()
  30. # callback that is invoked by sqlite3_prepare().
  31. #
  32. # 4. Verify that the statement in 3 has worked. SQLite should detect
  33. # that the schema has changed and successfully prepare the
  34. # statement against the new schema.
  35. #
  36. # Test plan:
  37. #
  38. # 1.*: Trigger the xConnect()/schema-reset using statements executed
  39. # directly against an FTS5 table.
  40. #
  41. # 2.*: Using various statements executed by various BEFORE triggers.
  42. #
  43. # 3.*: Using various statements executed by various AFTER triggers.
  44. #
  45. # 4.*: Using various statements executed by various INSTEAD OF triggers.
  46. #
  47. do_execsql_test 1.0 {
  48. CREATE VIRTUAL TABLE ft1 USING fts5(a, b);
  49. CREATE TABLE abc(x INTEGER PRIMARY KEY);
  50. CREATE TABLE t1(i INTEGER PRIMARY KEY, a, b);
  51. INSERT INTO ft1 VALUES('one', 'two');
  52. INSERT INTO ft1 VALUES('three', 'four');
  53. }
  54. foreach {tn sql res} {
  55. 1 "SELECT * FROM ft1" {one two three four}
  56. 2 "REPLACE INTO ft1(rowid, a, b) VALUES(1, 'five', 'six')" {}
  57. 3 "SELECT * FROM ft1" {five six three four}
  58. 4 "INSERT INTO ft1 VALUES('seven', 'eight')" {}
  59. 5 "SELECT * FROM ft1" {five six three four seven eight}
  60. 6 "DELETE FROM ft1 WHERE rowid=2" {}
  61. 7 "UPDATE ft1 SET b='nine' WHERE rowid=1" {}
  62. 8 "SELECT * FROM ft1" {five nine seven eight}
  63. } {
  64. catch { db close }
  65. catch { db2 close }
  66. sqlite3 db test.db
  67. sqlite3 db2 test.db
  68. do_test 1.$tn.1 {
  69. db eval { INSERT INTO abc DEFAULT VALUES }
  70. db2 eval { CREATE TABLE newtable(x,y); DROP TABLE newtable }
  71. } {}
  72. do_execsql_test 1.$tn.2 $sql $res
  73. do_execsql_test 1.$tn.3 {
  74. INSERT INTO ft1(ft1) VALUES('integrity-check');
  75. }
  76. }
  77. do_execsql_test 2.0 {
  78. CREATE VIRTUAL TABLE ft2 USING fts5(a, b);
  79. CREATE TABLE t2(a, b);
  80. CREATE TABLE log(txt);
  81. CREATE TRIGGER t2_ai AFTER INSERT ON t2 BEGIN
  82. INSERT INTO ft2(rowid, a, b) VALUES(new.rowid, new.a, new.b);
  83. INSERT INTO log VALUES('insert');
  84. END;
  85. CREATE TRIGGER t2_ad AFTER DELETE ON t2 BEGIN
  86. DELETE FROM ft2 WHERE rowid = old.rowid;
  87. INSERT INTO log VALUES('delete');
  88. END;
  89. CREATE TRIGGER t2_au AFTER UPDATE ON t2 BEGIN
  90. UPDATE ft2 SET a=new.a, b=new.b WHERE rowid=new.rowid;
  91. INSERT INTO log VALUES('update');
  92. END;
  93. INSERT INTO t2 VALUES('one', 'two');
  94. INSERT INTO t2 VALUES('three', 'four');
  95. }
  96. foreach {tn sql res} {
  97. 1 "SELECT * FROM t2" {one two three four}
  98. 2 "REPLACE INTO t2(rowid, a, b) VALUES(1, 'five', 'six')" {}
  99. 3 "SELECT * FROM ft2" {five six three four}
  100. 4 "INSERT INTO t2 VALUES('seven', 'eight')" {}
  101. 5 "SELECT * FROM ft2" {five six three four seven eight}
  102. 6 "DELETE FROM t2 WHERE rowid=2" {}
  103. 7 "UPDATE t2 SET b='nine' WHERE rowid=1" {}
  104. 8 "SELECT * FROM ft2" {five nine seven eight}
  105. } {
  106. catch { db close }
  107. catch { db2 close }
  108. sqlite3 db test.db
  109. sqlite3 db2 test.db
  110. do_test 2.$tn.1 {
  111. db eval { INSERT INTO abc DEFAULT VALUES }
  112. db2 eval { CREATE TABLE newtable(x,y); DROP TABLE newtable }
  113. } {}
  114. do_execsql_test 2.$tn.2 $sql $res
  115. do_execsql_test 2.$tn.3 {
  116. INSERT INTO ft2(ft2) VALUES('integrity-check');
  117. }
  118. }
  119. do_execsql_test 3.0 {
  120. CREATE VIRTUAL TABLE ft3 USING fts5(a, b);
  121. CREATE TABLE t3(a, b);
  122. CREATE TRIGGER t3_ai BEFORE INSERT ON t3 BEGIN
  123. INSERT INTO ft3(rowid, a, b) VALUES(new.rowid, new.a, new.b);
  124. INSERT INTO log VALUES('insert');
  125. END;
  126. CREATE TRIGGER t3_ad BEFORE DELETE ON t3 BEGIN
  127. DELETE FROM ft3 WHERE rowid = old.rowid;
  128. INSERT INTO log VALUES('delete');
  129. END;
  130. CREATE TRIGGER t3_au BEFORE UPDATE ON t3 BEGIN
  131. UPDATE ft3 SET a=new.a, b=new.b WHERE rowid=new.rowid;
  132. INSERT INTO log VALUES('update');
  133. END;
  134. INSERT INTO t3(rowid, a, b) VALUES(1, 'one', 'two');
  135. INSERT INTO t3(rowid, a, b) VALUES(2, 'three', 'four');
  136. }
  137. foreach {tn sql res} {
  138. 1 "SELECT * FROM t3" {one two three four}
  139. 2 "REPLACE INTO t3(rowid, a, b) VALUES(1, 'five', 'six')" {}
  140. 3 "SELECT * FROM ft3" {five six three four}
  141. 4 "INSERT INTO t3(rowid, a, b) VALUES(3, 'seven', 'eight')" {}
  142. 5 "SELECT * FROM ft3" {five six three four seven eight}
  143. 6 "DELETE FROM t3 WHERE rowid=2" {}
  144. 7 "UPDATE t3 SET b='nine' WHERE rowid=1" {}
  145. 8 "SELECT * FROM ft3" {five nine seven eight}
  146. } {
  147. catch { db close }
  148. catch { db2 close }
  149. sqlite3 db test.db
  150. sqlite3 db2 test.db
  151. do_test 3.$tn.1 {
  152. db eval { INSERT INTO abc DEFAULT VALUES }
  153. db2 eval { CREATE TABLE newtable(x,y); DROP TABLE newtable }
  154. } {}
  155. do_execsql_test 3.$tn.2 $sql $res
  156. do_execsql_test 3.$tn.3 {
  157. INSERT INTO ft3(ft3) VALUES('integrity-check');
  158. }
  159. }
  160. do_execsql_test 4.0 {
  161. CREATE VIRTUAL TABLE ft4 USING fts5(a, b);
  162. CREATE VIEW v4 AS SELECT rowid, * FROM ft4;
  163. CREATE TRIGGER t4_ai INSTEAD OF INSERT ON v4 BEGIN
  164. INSERT INTO ft4(rowid, a, b) VALUES(new.rowid, new.a, new.b);
  165. INSERT INTO log VALUES('insert');
  166. END;
  167. CREATE TRIGGER t4_ad INSTEAD OF DELETE ON v4 BEGIN
  168. DELETE FROM ft4 WHERE rowid = old.rowid;
  169. INSERT INTO log VALUES('delete');
  170. END;
  171. CREATE TRIGGER t4_au INSTEAD OF UPDATE ON v4 BEGIN
  172. UPDATE ft4 SET a=new.a, b=new.b WHERE rowid=new.rowid;
  173. INSERT INTO log VALUES('update');
  174. END;
  175. INSERT INTO ft4(rowid, a, b) VALUES(1, 'one', 'two');
  176. INSERT INTO ft4(rowid, a, b) VALUES(2, 'three', 'four');
  177. }
  178. foreach {tn sql res} {
  179. 1 "SELECT * FROM ft4" {one two three four}
  180. 2 "REPLACE INTO v4(rowid, a, b) VALUES(1, 'five', 'six')" {}
  181. 3 "SELECT * FROM ft4" {five six three four}
  182. 4 "INSERT INTO v4(rowid, a, b) VALUES(3, 'seven', 'eight')" {}
  183. 5 "SELECT * FROM ft4" {five six three four seven eight}
  184. 6 "DELETE FROM v4 WHERE rowid=2" {}
  185. 7 "UPDATE v4 SET b='nine' WHERE rowid=1" {}
  186. 8 "SELECT * FROM ft4" {five nine seven eight}
  187. } {
  188. catch { db close }
  189. catch { db2 close }
  190. sqlite3 db test.db
  191. sqlite3 db2 test.db
  192. do_test 4.$tn.1 {
  193. db eval { INSERT INTO abc DEFAULT VALUES }
  194. db2 eval { CREATE TABLE newtable(x,y); DROP TABLE newtable }
  195. } {}
  196. do_execsql_test 4.$tn.2 $sql $res
  197. do_execsql_test 4.$tn.3 {
  198. INSERT INTO ft3(ft3) VALUES('integrity-check');
  199. }
  200. }
  201. finish_test