Merge sqlite-release(3.45.1) into prerelease-integration
[sqlcipher.git] / ext / rbu / rbuprogress.test
blob072683742475c448861f7bb599891cf7537ae720
1 # 2016 March 18
3 # The author disclaims copyright to this source code.  In place of
4 # a legal notice, here is a blessing:
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.
10 #***********************************************************************
13 source [file join [file dirname [info script]] rbu_common.tcl]
14 if_no_rbu_support { finish_test ; return }
15 set ::testprefix rbuprogress
18 proc create_db_file {filename sql} {
19   forcedelete $filename
20   sqlite3 tmpdb $filename  
21   tmpdb eval $sql
22   tmpdb close
25 # Create a simple RBU database. That expects to write to a table:
27 #   CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
29 proc create_rbu1 {filename} {
30   create_db_file $filename {
31     CREATE TABLE data_t1(a, b, c, rbu_control);
32     INSERT INTO data_t1 VALUES(1, 2, 3, 0);
33     INSERT INTO data_t1 VALUES(2, 'two', 'three', 0);
34     INSERT INTO data_t1 VALUES(3, NULL, 8.2, 0);
36     CREATE TABLE rbu_count(tbl, cnt);
37     INSERT INTO rbu_count VALUES('data_t1', 3);
38   }
39   return $filename
43 do_execsql_test 1.0 {
44   PRAGMA page_size = 4096;
45   CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
48 do_test 1.1 {
49   create_rbu1 rbu.db
50   sqlite3rbu rbu test.db rbu.db
51   rbu bp_progress
52 } {0 0}
53 do_test 1.2 { rbu step ; rbu bp_progress } {3333 0}
54 do_test 1.3 { rbu step ; rbu bp_progress } {6666 0}
55 do_test 1.4 { rbu step ; rbu bp_progress } {10000 0}
56 do_test 1.5 { rbu step ; rbu bp_progress } {10000 0}
57 do_test 1.6 { rbu step ; rbu bp_progress } {10000 0}
58 do_test 1.7 { rbu step ; rbu bp_progress } {10000 5000}
59 do_test 1.8 { rbu step ; rbu bp_progress } {10000 10000}
60 do_test 1.9 { rbu step ; rbu bp_progress } {10000 10000}
62 do_test 1.10 {
63   rbu close
64 } {SQLITE_DONE}
66 #-------------------------------------------------------------------------
68 proc do_sp_test {tn bReopen target rbu reslist} {
69   uplevel [list do_test $tn [subst -nocommands {
70     if {$bReopen==0} { sqlite3rbu rbu $target $rbu }
71     set res [list]
72     while 1 {
73       if {$bReopen} { sqlite3rbu rbu $target $rbu }
74       set rc [rbu step]
75       if {[set rc] != "SQLITE_OK"} { rbu close ; error "error 1" }
76       lappend res [lindex [rbu bp_progress] 0]
77       if {[lindex [set res] end]==10000} break
78       if {$bReopen} { rbu close }
79     }
80     if {[set res] != [list $reslist]} {
81       rbu close
82       error "1. reslist incorrect (expect=$reslist got=[set res])"
83     }
85     # One step to clean up the temporary tables used to update the only
86     # target table in the rbu database. And one more to move the *-oal 
87     # file to *-wal. After each of these steps, the progress remains
88     # at "10000 0".
89     #
90     if {[lindex [list $reslist] 0]!=-1} {
91       rbu step
92       set res [rbu bp_progress]
93       if {[set res] != [list 10000 0]} {
94         rbu close
95         error "2. reslist incorrect (expect=10000 0 got=[set res])"
96       }
97     }
99     rbu step
100     set res [rbu bp_progress]
101     if {[set res] != [list 10000 0]} {
102       rbu close
103       error "3. reslist incorrect (expect=10000 0 got=[set res])"
104     }
106     # Do the checkpoint.
107     while {[rbu step]=="SQLITE_OK"} { 
108       foreach {a b} [rbu bp_progress] {}
109       if {[set a]!=10000 || [set b]<=0 || [set b]>10000} {
110         rbu close
111         error "4. reslist incorrect (expect=10000 1..10000 got=[set a] [set b])"
112       }
113     }
115     set res [rbu bp_progress]
116     if {[set res] != [list 10000 10000]} {
117       rbu close
118       error "5. reslist is incorrect (expect=10000 10000 got=[set res])"
119     }
121     rbu close
122   }] {SQLITE_DONE}]
125 foreach {bReopen} { 0 1 } {
126   reset_db
127   do_test 2.$bReopen.1.0 {
128     execsql {
129       CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
130     }
131     create_db_file rbu.db {
132       CREATE TABLE data_t1(a, b, c, rbu_control);
133       INSERT INTO data_t1 VALUES(4, 4, 4, 0);
134       INSERT INTO data_t1 VALUES(5, 5, 5, 0);
135   
136       CREATE TABLE rbu_count(tbl, cnt);
137       INSERT INTO rbu_count VALUES('data_t1', 2);
138     }
139   } {}
140   do_sp_test 2.$bReopen.1.1 $bReopen test.db rbu.db {5000 10000}
141   
142   reset_db
143   do_test 2.$bReopen.2.0 {
144     execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c) }
145     create_rbu1 rbu.db
146   } {rbu.db}
147   do_sp_test 2.$bReopen.2.1 $bReopen test.db rbu.db {3333 6666 10000}
148   
149   reset_db
150   do_test 2.$bReopen.3.0 {
151     execsql { 
152       CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
153       CREATE INDEX i1 ON t1(b);
154       INSERT INTO t1 VALUES(1, 1, 1);
155       INSERT INTO t1 VALUES(2, 2, 2);
156       INSERT INTO t1 VALUES(3, 3, 3);
157     }
158     create_db_file rbu.db {
159       CREATE TABLE data_t1(a, b, c, rbu_control);
160       INSERT INTO data_t1 VALUES(4, 4, 4, 0);
161       INSERT INTO data_t1 VALUES(2, NULL, NULL, 1);
162       INSERT INTO data_t1 VALUES(5, NULL, NULL, 1);
163   
164       CREATE TABLE rbu_count(tbl, cnt);
165       INSERT INTO rbu_count VALUES('data_t1', 3);
166     }
167   } {}
168   do_sp_test 2.$bReopen.3.1 $bReopen test.db rbu.db {1666 3333 6000 8000 10000}
169   
170   reset_db
171   do_test 2.$bReopen.4.0 {
172     execsql { 
173       CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
174       CREATE INDEX i1 ON t1(b);
175       INSERT INTO t1 VALUES(1, 1, 1);
176       INSERT INTO t1 VALUES(2, 2, 2);
177       INSERT INTO t1 VALUES(3, 3, 3);
178     }
179     create_db_file rbu.db {
180       CREATE TABLE data_t1(a, b, c, rbu_control);
181       INSERT INTO data_t1 VALUES(2, 4, 4, '.xx');
182   
183       CREATE TABLE rbu_count(tbl, cnt);
184       INSERT INTO rbu_count VALUES('data_t1', 1);
185     }
186   } {}
187   do_sp_test 2.$bReopen.4.1 $bReopen test.db rbu.db {3333 6666 10000}
188   
189   reset_db
190   do_test 2.$bReopen.5.0 {
191     execsql { 
192       CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
193       CREATE INDEX i1 ON t1(b);
194       INSERT INTO t1 VALUES(1, 1, 1);
195       INSERT INTO t1 VALUES(2, 2, 2);
196       INSERT INTO t1 VALUES(3, 3, 3);
197     }
198     create_db_file rbu.db {
199       CREATE TABLE data_t1(a, b, c, rbu_control);
200       INSERT INTO data_t1 VALUES(4, NULL, 4, '.xx');
201   
202       CREATE TABLE rbu_count(tbl, cnt);
203       INSERT INTO rbu_count VALUES('data_t1', 1);
204     }
205   } {}
206   do_sp_test 2.$bReopen.5.1 $bReopen test.db rbu.db {10000}
208   reset_db
209   do_test 2.$bReopen.6.0 {
210     execsql { 
211       CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
212       CREATE INDEX i1 ON t1(b);
213       INSERT INTO t1 VALUES(1, 1, 1);
214       INSERT INTO t1 VALUES(2, 2, 2);
215       INSERT INTO t1 VALUES(3, 3, 3);
216     }
217     create_db_file rbu.db {
218       CREATE TABLE data_t1(a, b, c, rbu_control);
219       INSERT INTO data_t1 VALUES(4, 4, 4, 0);
220       INSERT INTO data_t1 VALUES(2, NULL, NULL, 1);
221       INSERT INTO data_t1 VALUES(5, NULL, NULL, 1);
222     }
223   } {}
224   do_sp_test 2.$bReopen.6.1 $bReopen test.db rbu.db {-1 -1 -1 -1 -1 10000}
227 #-------------------------------------------------------------------------
228 # The following tests verify that the API works when resuming an update
229 # during the incremental checkpoint stage.
231 proc do_phase2_test {tn bReopen target rbu nStep} {
232   uplevel [list do_test $tn [subst -nocommands {
234     # Build the OAL/WAL file:
235     sqlite3rbu rbu $target $rbu
236     while {[lindex [rbu bp_progress] 0]<10000} { 
237       set rc [rbu step]
238       if {"SQLITE_OK" != [set rc]} { rbu close }
239     }
241     # Clean up the temp tables and move the *-oal file to *-wal.
242     rbu step
243     rbu step
245     for {set i 0} {[set i] < $nStep} {incr i} {
246       if {$bReopen} {
247         rbu close
248         sqlite3rbu rbu $target $rbu
249       }
250       rbu step
251       set res [rbu bp_progress]
252       set expect [expr (1 + [set i]) * 10000 / $nStep]
253       if {[lindex [set res] 1] != [set expect]} {
254         error "Have [set res], expected 10000 [set expect]"
255       }
256     }
258     set rc [rbu step]
259     if {[set rc] != "SQLITE_DONE"} {
260       error "Have [set rc], expected SQLITE_DONE" 
261     }
263     rbu close
264   }] {SQLITE_DONE}]
267 foreach bReopen {0 1} {
268   do_test 3.$bReopen.1.0 {
269     reset_db
270     execsql {
271       PRAGMA page_size = 4096;
272       CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
273       CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
274       CREATE TABLE t3(a INTEGER PRIMARY KEY, b);
275       CREATE TABLE t4(a INTEGER PRIMARY KEY, b);
276     }
277     create_db_file rbu.db {
278       CREATE TABLE data_t1(a, b, rbu_control);
279       CREATE TABLE data_t2(a, b, rbu_control);
280       CREATE TABLE data_t3(a, b, rbu_control);
281       CREATE TABLE data_t4(a, b, rbu_control);
282       INSERT INTO data_t1 VALUES(1, 2, 0);
283       INSERT INTO data_t2 VALUES(1, 2, 0);
284       INSERT INTO data_t3 VALUES(1, 2, 0);
285       INSERT INTO data_t4 VALUES(1, 2, 0);
286   
287       CREATE TABLE rbu_count(tbl, cnt);
288       INSERT INTO rbu_count VALUES('data_t1', 1);
289       INSERT INTO rbu_count VALUES('data_t2', 1);
290       INSERT INTO rbu_count VALUES('data_t3', 1);
291       INSERT INTO rbu_count VALUES('data_t4', 1);
292     }
293   } {}
294   do_phase2_test 3.$bReopen.1.1 $bReopen test.db rbu.db 5
298 foreach {bReopen} { 0 1 } {
299   foreach {tn tbl} {
300     ipk { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c) }
301     wr  { CREATE TABLE t1(a INT PRIMARY KEY, b, c) WITHOUT ROWID }
302     pk  { CREATE TABLE t1(a INT PRIMARY KEY, b, c) }
303   } {
305     foreach {tn2 rbusql r1 r3} {
306       1 {
307         CREATE TABLE data0_t1(a, b, c, rbu_control);
308         INSERT INTO data0_t1 VALUES(15, 15, 15, 0);
309         INSERT INTO data0_t1 VALUES(20, 20, 20, 0);
310         CREATE TABLE rbu_count(tbl, cnt);
311         INSERT INTO rbu_count VALUES('data0_t1', 2); 
312       } 
313       {2500 5000 7500 10000}
314       {1666 3333 5000 6666 8333 10000}
316       2 {
317         CREATE TABLE data0_t1(a, b, c, rbu_control);
318         INSERT INTO data0_t1 VALUES(10, 10, 10, 2);
319         CREATE TABLE rbu_count(tbl, cnt);
320         INSERT INTO rbu_count VALUES('data0_t1', 1); 
321       } 
322       {3333 6666 10000}
323       {2000 4000 6000 8000 10000}
325       3 {
326         CREATE TABLE data0_t1(a, b, c, rbu_control);
327         INSERT INTO data0_t1 VALUES(7, 7, 7, 2);
328         INSERT INTO data0_t1 VALUES(10, 10, 10, 2);
329         CREATE TABLE rbu_count(tbl, cnt);
330         INSERT INTO rbu_count VALUES('data0_t1', 2); 
331       } 
332       {2500 4000 6000 8000 10000}
333       {1666 2500 3750 5000 6250 7500 8750 10000}
335     } {
337       reset_db ; execsql $tbl
338       do_test 4.$tn.$bReopen.$tn2.0 {
339         execsql {
340           CREATE INDEX t1c ON t1(c);
341           INSERT INTO t1 VALUES(1, 1, 1);
342           INSERT INTO t1 VALUES(5, 5, 5);
343           INSERT INTO t1 VALUES(10, 10, 10);
344         }
345         create_db_file rbu.db $rbusql
346       } {}
348       set R(ipk) $r1
349       set R(wr) $r1
350       set R(pk) $r3
351       do_sp_test 4.$tn.$bReopen.$tn2.1 $bReopen test.db rbu.db $R($tn)
352     }
353   }
356 foreach {bReopen} { 0 1 } {
357   foreach {tn tbl} {
358     nopk { 
359       CREATE TABLE t1(a, b, c);
360       CREATE INDEX t1c ON t1(c);
361     }
362     vtab { 
363       CREATE VIRTUAL TABLE t1 USING fts5(a, b, c);
364     }
365   } {
367     if {$tn=="vtab"} { ifcapable !fts5 break }
369     foreach {tn2 rbusql r1 r2} {
370       1 {
371         CREATE TABLE data0_t1(a, b, c, rbu_rowid, rbu_control);
372         INSERT INTO data0_t1 VALUES(15, 15, 15, 4, 0);
373         INSERT INTO data0_t1 VALUES(20, 20, 20, 5, 0);
374         CREATE TABLE rbu_count(tbl, cnt);
375         INSERT INTO rbu_count VALUES('data0_t1', 2); 
376       } 
377       {2500 5000 7500 10000}
378       {5000 10000}
380       2 {
381         CREATE TABLE data0_t1(rbu_rowid, a, b, c, rbu_control);
382         INSERT INTO data0_t1 VALUES(0, 7, 7, 7, 2);
383         INSERT INTO data0_t1 VALUES(2, 10, 10, 10, 2);
384         CREATE TABLE rbu_count(tbl, cnt);
385         INSERT INTO rbu_count VALUES('data0_t1', 2); 
386       } 
387       {2500 4000 6000 8000 10000}
388       {5000 10000}
390       3 {
391         CREATE TABLE data0_t1(rbu_rowid, a, b, c, rbu_control);
392         INSERT INTO data0_t1 VALUES(1, NULL, NULL, NULL, 1);
393         INSERT INTO data0_t1 VALUES(2, NULL, NULL, 7, '..x');
394         CREATE TABLE rbu_count(tbl, cnt);
395         INSERT INTO rbu_count VALUES('data0_t1', 2); 
396       } 
397       {2500 4000 6000 8000 10000}
398       {5000 10000}
399     } {
401       reset_db ; execsql $tbl
402       do_test 5.$tn.$bReopen.$tn2.0 {
403         execsql {
404           INSERT INTO t1 VALUES(1, 1, 1);
405           INSERT INTO t1 VALUES(5, 5, 5);
406           INSERT INTO t1 VALUES(10, 10, 10);
407         }
408         create_db_file rbu.db $rbusql
409       } {}
411       set R(nopk) $r1
412       set R(vtab) $r2
413       do_sp_test 5.$tn.$bReopen.$tn2.1 $bReopen test.db rbu.db $R($tn)
414     }
415   }
418 #-------------------------------------------------------------------------
419 # Test that sqlite3_bp_progress() works with an RBU vacuum if there
420 # is an rbu_count table in the db being vacuumed.
422 reset_db
423 do_execsql_test 6.0 {
424   CREATE TABLE t1(a, b, c);
425   CREATE INDEX i1 ON t1(a);
426   CREATE INDEX i2 ON t1(b);
427   WITH s(i) AS (
428     SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100
429   )
430   INSERT INTO t1 SELECT i, i, i FROM s;
431   CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
432   INSERT INTO rbu_count VALUES('t1', (SELECT count(*) FROM t1));
433   INSERT INTO rbu_count VALUES('rbu_count', 2);
436 forcedelete state.db
437 do_test 6.1 {
438   set maxA 0
439   set maxB 0
440   sqlite3rbu_vacuum rbu test.db state.db
441   while {[rbu step]=="SQLITE_OK"} {
442     foreach {a b} [rbu bp_progress] {
443       if {$a > $maxA} { set maxA $a }
444       if {$b > $maxB} { set maxB $b }
445     }
446   }
447   list [rbu close] $maxA $maxB
448 } {SQLITE_DONE 10000 10000}
451 finish_test