xref: /sqlite-3.40.0/ext/rbu/rbu12.test (revision 6ab91a7a)
1# 2015 February 16
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
13if {![info exists testdir]} {
14  set testdir [file join [file dirname [info script]] .. .. test]
15}
16source $testdir/tester.tcl
17source $testdir/lock_common.tcl
18set ::testprefix rbu12
19
20set setup_sql {
21  DROP TABLE IF EXISTS xx;
22  DROP TABLE IF EXISTS xy;
23  CREATE TABLE xx(a, b, c PRIMARY KEY);
24  INSERT INTO xx VALUES(1, 2, 3);
25  CREATE TABLE xy(a, b, c PRIMARY KEY);
26
27  ATTACH 'rbu.db' AS rbu;
28    DROP TABLE IF EXISTS data_xx;
29    CREATE TABLE rbu.data_xx(a, b, c, rbu_control);
30    INSERT INTO data_xx VALUES(4, 5, 6, 0);
31    INSERT INTO data_xx VALUES(7, 8, 9, 0);
32    CREATE TABLE rbu.data_xy(a, b, c, rbu_control);
33    INSERT INTO data_xy VALUES(10, 11, 12, 0);
34  DETACH rbu;
35}
36
37do_multiclient_test tn {
38
39  # Initialize a target (test.db) and rbu (rbu.db) database.
40  #
41  forcedelete rbu.db
42  sql1 $setup_sql
43
44  # Using connection 2, open a read transaction on the target database.
45  # RBU will still be able to generate "test.db-oal", but it will not be
46  # able to rename it to "test.db-wal".
47  #
48  do_test 1.$tn.1 {
49    sql2 { BEGIN; SELECT * FROM xx; }
50  } {1 2 3}
51  do_test 1.$tn.2 {
52    sqlite3rbu rbu test.db rbu.db
53    while 1 {
54      set res [rbu step]
55      if {$res!="SQLITE_OK"} break
56    }
57    set res
58  } {SQLITE_BUSY}
59
60  do_test 1.$tn.3 { sql2 { SELECT * FROM xx; } } {1 2 3}
61  do_test 1.$tn.4 { sql2 { SELECT * FROM xy; } } {}
62  do_test 1.$tn.5 {
63    list [file exists test.db-wal] [file exists test.db-oal]
64  } {0 1}
65  do_test 1.$tn.6 { sql2 COMMIT } {}
66
67  # The rbu object that hit the SQLITE_BUSY error above cannot be reused.
68  # It is stuck in a permanent SQLITE_BUSY state at this point.
69  #
70  do_test 1.$tn.7 { rbu step } {SQLITE_BUSY}
71  do_test 1.$tn.8 {
72    list [catch { rbu close } msg] $msg
73  } {1 SQLITE_BUSY}
74
75  do_test 1.$tn.9.1 { sql2 { BEGIN EXCLUSIVE } } {}
76  do_test 1.$tn.9.2 {
77    sqlite3rbu rbu test.db rbu.db
78    rbu step
79  } {SQLITE_BUSY}
80  do_test 1.$tn.9.3 {
81    list [catch { rbu close } msg] $msg
82  } {1 {SQLITE_BUSY - database is locked}}
83  do_test 1.$tn.9.4 { sql2 COMMIT } {}
84
85  sqlite3rbu rbu test.db rbu.db
86  do_test 1.$tn.10.1 { sql2 { BEGIN EXCLUSIVE } } {}
87  do_test 1.$tn.10.2 {
88    rbu step
89  } {SQLITE_BUSY}
90  do_test 1.$tn.10.3 {
91    list [catch { rbu close } msg] $msg
92  } {1 SQLITE_BUSY}
93  do_test 1.$tn.10.4 { sql2 COMMIT } {}
94
95  # A new rbu object can finish the work though.
96  #
97  do_test 1.$tn.11 {
98    sqlite3rbu rbu test.db rbu.db
99    rbu step
100  } {SQLITE_OK}
101  do_test 1.$tn.12 {
102    list [file exists test.db-wal] [file exists test.db-oal]
103  } {1 0}
104  do_test 1.$tn.13 {
105    while 1 {
106      set res [rbu step]
107      if {$res!="SQLITE_OK"} break
108    }
109    set res
110  } {SQLITE_DONE}
111
112  do_test 1.$tn.14 {
113    rbu close
114  } {SQLITE_DONE}
115}
116
117do_multiclient_test tn {
118
119  # Initialize a target (test.db) and rbu (rbu.db) database.
120  #
121  forcedelete rbu.db
122  sql1 $setup_sql
123
124  do_test 2.$tn.1 {
125    sqlite3rbu rbu test.db rbu.db
126    while {[file exists test.db-wal]==0} {
127      if {[rbu step]!="SQLITE_OK"} {error "problem here...."}
128    }
129    rbu close
130  } {SQLITE_OK}
131
132
133  do_test 2.$tn.2 { sql2 { BEGIN IMMEDIATE } } {}
134
135  do_test 2.$tn.3 {
136    sqlite3rbu rbu test.db rbu.db
137    rbu step
138  } {SQLITE_BUSY}
139
140  do_test 2.$tn.4 { list [catch { rbu close } msg] $msg } {1 SQLITE_BUSY}
141
142  do_test 2.$tn.5 {
143    sql2 { SELECT * FROM xx ; COMMIT }
144  } {1 2 3 4 5 6 7 8 9}
145
146  do_test 2.$tn.6 {
147    sqlite3rbu rbu test.db rbu.db
148    rbu step
149    rbu close
150  } {SQLITE_OK}
151
152  do_test 2.$tn.7 { sql2 { BEGIN EXCLUSIVE } } {}
153
154  do_test 2.$tn.8 {
155    sqlite3rbu rbu test.db rbu.db
156    rbu step
157  } {SQLITE_BUSY}
158  do_test 2.$tn.9 { list [catch { rbu close } msg] $msg } {1 SQLITE_BUSY}
159  do_test 2.$tn.10 {
160    sql2 { SELECT * FROM xx ; COMMIT }
161  } {1 2 3 4 5 6 7 8 9}
162
163  do_test 2.$tn.11 {
164    sqlite3rbu rbu test.db rbu.db
165    while {[rbu step]=="SQLITE_OK"} {}
166    rbu close
167  } {SQLITE_DONE}
168
169}
170
171#-------------------------------------------------------------------------
172# Test that "PRAGMA data_version" works when an RBU client writes the
173# database.
174#
175do_multiclient_test tn {
176
177  # Initialize a target (test.db) and rbu (rbu.db) database.
178  #
179  forcedelete rbu.db
180  sql1 $setup_sql
181
182  # Check the initial database contains table "xx" with a single row.
183  # Also save the current values of "PRAGMA data-version" for [db1]
184  # and [db2].
185  #
186  do_test 2.$tn.1 {
187    list [sql1 { SELECT count(*) FROM xx }] [sql2 { SELECT count(*) FROM xx }]
188  } {1 1}
189  set V1 [sql1 {PRAGMA data_version}]
190  set V2 [sql2 {PRAGMA data_version}]
191
192  # Check the values of data-version have not magically changed.
193  #
194  do_test 2.$tn.2 {
195    list [sql1 {PRAGMA data_version}] [sql2 {PRAGMA data_version}]
196  } [list $V1 $V2]
197
198  # Start stepping the RBU. From the point of view of [db1] and [db2], the
199  # data-version values remain unchanged until the database contents are
200  # modified. At which point the values are incremented.
201  #
202  sqlite3rbu rbu test.db rbu.db
203  set x 0
204  while {[db one {SELECT count(*) FROM xx}]==1} {
205    do_test 2.$tn.3.[incr x] {
206      list [sql1 {PRAGMA data_version}] [sql2 {PRAGMA data_version}]
207    } [list $V1 $V2]
208    rbu step
209  }
210  do_test 2.$tn.5.1 { expr {$V1 < [sql1 {PRAGMA data_version}]} } 1
211  do_test 2.$tn.5.2 { expr {$V2 < [sql2 {PRAGMA data_version}]} } 1
212
213  # Check the db contents is as expected.
214  #
215  do_test 2.$tn.4 {
216    list [sql1 {SELECT count(*) FROM xx}] [sql2 {SELECT count(*) FROM xx}]
217  } {3 3}
218
219  set V1 [sql1 {PRAGMA data_version}]
220  set V2 [sql2 {PRAGMA data_version}]
221
222  # Finish applying the RBU (i.e. do the incremental checkpoint). Check that
223  # this does not cause the data-version values to change.
224  #
225  while {[rbu step]=="SQLITE_OK"} { }
226  rbu close
227
228  do_test 2.$tn.6 {
229    list [sql1 {PRAGMA data_version}] [sql2 {PRAGMA data_version}]
230  } [list $V1 $V2]
231
232}
233
234finish_test
235