sharedA.test 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. # 2013 May 14
  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. # Test some specific circumstances to do with shared cache mode.
  13. #
  14. set testdir [file dirname $argv0]
  15. source $testdir/tester.tcl
  16. if {[run_thread_tests]==0} { finish_test ; return }
  17. db close
  18. set ::testprefix sharedA
  19. set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
  20. #-------------------------------------------------------------------------
  21. #
  22. do_test 0.1 {
  23. sqlite3 db1 test.db
  24. sqlite3 db2 test.db
  25. db1 eval {
  26. CREATE TABLE t1(x);
  27. INSERT INTO t1 VALUES(randomblob(100));
  28. INSERT INTO t1 SELECT randomblob(100) FROM t1;
  29. INSERT INTO t1 SELECT randomblob(100) FROM t1;
  30. INSERT INTO t1 SELECT randomblob(100) FROM t1;
  31. INSERT INTO t1 SELECT randomblob(100) FROM t1;
  32. INSERT INTO t1 SELECT randomblob(100) FROM t1;
  33. INSERT INTO t1 SELECT randomblob(100) FROM t1;
  34. CREATE INDEX i1 ON t1(x);
  35. }
  36. db1 eval {
  37. BEGIN;
  38. DROP INDEX i1;
  39. }
  40. db2 close
  41. db1 eval {
  42. INSERT INTO t1 SELECT randomblob(100) FROM t1;
  43. ROLLBACK;
  44. PRAGMA integrity_check;
  45. }
  46. } {ok}
  47. db1 close
  48. forcedelete test.db
  49. #-------------------------------------------------------------------------
  50. #
  51. do_test 1.1 {
  52. sqlite3 db1 test.db
  53. sqlite3 db2 test.db
  54. db2 eval {
  55. CREATE TABLE t1(x);
  56. INSERT INTO t1 VALUES(123);
  57. }
  58. db1 eval {
  59. SELECT * FROM t1;
  60. CREATE INDEX i1 ON t1(x);
  61. }
  62. } {123}
  63. do_test 1.2 {
  64. db2 eval { SELECT * FROM t1 ORDER BY x; }
  65. db1 eval {
  66. BEGIN; DROP INDEX i1;
  67. }
  68. db1 close
  69. db2 eval { SELECT * FROM t1 ORDER BY x; }
  70. } {123}
  71. do_test 1.3 {
  72. db2 close
  73. } {}
  74. #-------------------------------------------------------------------------
  75. #
  76. # sqlite3RollbackAll() loops through all attached b-trees and rolls
  77. # back each one separately. Then if the SQLITE_InternChanges flag is
  78. # set, it resets the schema. Both of the above steps must be done
  79. # while holding a mutex, otherwise another thread might slip in and
  80. # try to use the new schema with the old data.
  81. #
  82. # The following sequence of tests attempt to verify that the actions
  83. # taken by sqlite3RollbackAll() are thread-atomic (that they cannot be
  84. # interrupted by a separate thread.)
  85. #
  86. # Note that a TCL interpreter can only be used within the thread in which
  87. # it was originally created (because it uses thread-local-storage).
  88. # The tvfs callbacks must therefore only run on the main thread.
  89. # There is some trickery in the read_callback procedure to ensure that
  90. # this is the case.
  91. #
  92. testvfs tvfs
  93. # Set up two databases and two database connections.
  94. #
  95. # db1: main(test.db), two(test2.db)
  96. # db2: main(test.db)
  97. #
  98. # The cache for test.db is shared between db1 and db2.
  99. #
  100. do_test 2.1 {
  101. forcedelete test.db test.db2
  102. sqlite3 db1 test.db -vfs tvfs
  103. db1 eval { ATTACH 'test.db2' AS two }
  104. db1 eval {
  105. CREATE TABLE t1(x);
  106. INSERT INTO t1 VALUES(1);
  107. INSERT INTO t1 VALUES(2);
  108. INSERT INTO t1 VALUES(3);
  109. CREATE TABLE two.t2(x);
  110. INSERT INTO t2 SELECT * FROM t1;
  111. }
  112. sqlite3 db2 test.db -vfs tvfs
  113. db2 eval { SELECT * FROM t1 }
  114. } {1 2 3}
  115. # Create a prepared statement on db2 that will attempt a schema change
  116. # in test.db. Meanwhile, start a transaction on db1 that changes
  117. # the schema of test.db and that creates a rollback journal on test2.db
  118. #
  119. do_test 2.2 {
  120. set ::STMT [sqlite3_prepare db2 "CREATE INDEX i1 ON t1(x)" -1 tail]
  121. db1 eval {
  122. BEGIN;
  123. CREATE INDEX i1 ON t1(x);
  124. INSERT INTO t2 VALUES('value!');
  125. }
  126. } {}
  127. # Set up a callback that will cause db2 to try to execute its
  128. # schema change when db1 accesses the journal file of test2.db.
  129. #
  130. # This callback will be invoked after the content of test.db has
  131. # be rolled back but before the schema has been reset. If the
  132. # sqlite3RollbackAll() operation is not thread-atomic, then the
  133. # db2 statement in the callback will see old content with the newer
  134. # schema, which is wrong.
  135. #
  136. tvfs filter xRead
  137. tvfs script read_callback
  138. unset -nocomplain ::some_time_laster
  139. unset -nocomplain ::thread_result
  140. proc read_callback {call file args} {
  141. if {[string match *test.db2-journal $file]} {
  142. tvfs filter {} ;# Ensure that tvfs callbacks to do run on the
  143. # child thread
  144. sqlthread spawn ::thread_result [subst -nocommands {
  145. sqlite3_step $::STMT
  146. set rc [sqlite3_finalize $::STMT]
  147. }]
  148. after 1000 { set ::some_time_later 1 }
  149. vwait ::some_time_later
  150. }
  151. }
  152. do_test 2.3 { db1 eval ROLLBACK } {}
  153. # Verify that the db2 statement invoked by the callback detected the
  154. # schema change.
  155. #
  156. if {[info exists ::thread_result]==0} { vwait ::thread_result }
  157. do_test 2.4 {
  158. list $::thread_result [sqlite3_errmsg db2]
  159. } {SQLITE_SCHEMA {database schema has changed}}
  160. db1 close
  161. db2 close
  162. tvfs delete
  163. sqlite3_enable_shared_cache $::enable_shared_cache
  164. finish_test