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 #***********************************************************************
12 # This file contains tests for the RBU module. More specifically, it
13 # contains tests to ensure that the sqlite3rbu_vacuum() API works as
17 source [file join [file dirname [info script]] rbu_common.tcl]
18 if_no_rbu_support { finish_test ; return }
19 set ::testprefix rbuvacuum
23 set ::testprefix rbuvacuum-step=$step
26 # Simplest possible vacuum.
28 PRAGMA page_size = 1024;
29 CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
30 INSERT INTO t1 VALUES(1, 2, 3);
31 INSERT INTO t1 VALUES(4, 5, 6);
32 INSERT INTO t1 VALUES(7, 8, 9);
33 PRAGMA integrity_check;
35 do_rbu_vacuum_test 1.1 $step
37 # A vacuum that actually reclaims space.
38 do_execsql_test 1.2.1 {
39 INSERT INTO t1 VALUES(8, randomblob(900), randomblob(900));
40 INSERT INTO t1 VALUES(9, randomblob(900), randomblob(900));
41 INSERT INTO t1 VALUES(10, randomblob(900), randomblob(900));
42 INSERT INTO t1 VALUES(11, randomblob(900), randomblob(900));
43 INSERT INTO t1 VALUES(12, randomblob(900), randomblob(900));
46 do_execsql_test 1.2.2 {
47 DELETE FROM t1 WHERE rowid BETWEEN 8 AND 11;
50 do_rbu_vacuum_test 1.2.3 $step
51 do_execsql_test 1.2.4 {
55 # Add an index to the table.
56 do_execsql_test 1.3.1 {
57 CREATE INDEX t1b ON t1(b);
58 INSERT INTO t1 VALUES(13, randomblob(900), randomblob(900));
59 INSERT INTO t1 VALUES(14, randomblob(900), randomblob(900));
60 INSERT INTO t1 VALUES(15, randomblob(900), randomblob(900));
61 INSERT INTO t1 VALUES(16, randomblob(900), randomblob(900));
64 do_execsql_test 1.3.2 {
65 DELETE FROM t1 WHERE rowid BETWEEN 12 AND 15;
68 do_rbu_vacuum_test 1.3.3 $step
69 do_execsql_test 1.3.4 {
73 # WITHOUT ROWID table.
74 do_execsql_test 1.4.1 {
75 CREATE TABLE t2(a, b, c, PRIMARY KEY(a, b)) WITHOUT ROWID;
77 INSERT INTO t2 VALUES(randomblob(900), 1, randomblob(900));
78 INSERT INTO t2 VALUES(randomblob(900), 2, randomblob(900));
79 INSERT INTO t2 VALUES(randomblob(900), 3, randomblob(900));
80 INSERT INTO t2 VALUES(randomblob(900), 4, randomblob(900));
81 INSERT INTO t2 VALUES(randomblob(900), 6, randomblob(900));
82 INSERT INTO t2 VALUES(randomblob(900), 7, randomblob(900));
83 INSERT INTO t2 VALUES(randomblob(900), 8, randomblob(900));
85 DELETE FROM t2 WHERE b BETWEEN 2 AND 7;
88 do_rbu_vacuum_test 1.4.2 $step
89 do_execsql_test 1.4.3 {
93 # WITHOUT ROWID table with an index.
94 do_execsql_test 1.4.1 {
95 CREATE INDEX t2c ON t2(c);
97 INSERT INTO t2 VALUES(randomblob(900), 9, randomblob(900));
98 INSERT INTO t2 VALUES(randomblob(900), 10, randomblob(900));
99 INSERT INTO t2 VALUES(randomblob(900), 11, randomblob(900));
100 INSERT INTO t2 VALUES(randomblob(900), 12, randomblob(900));
101 INSERT INTO t2 VALUES(randomblob(900), 13, randomblob(900));
103 DELETE FROM t2 WHERE b BETWEEN 8 AND 12;
106 do_rbu_vacuum_test 1.4.2 $step
107 do_execsql_test 1.4.3 {
110 do_execsql_test 1.4.4 {
115 do_execsql_test 1.5.1 {
116 CREATE TABLE t3(a, b, c);
117 INSERT INTO t3 VALUES('a', 'b', 'c');
118 INSERT INTO t3 VALUES('d', 'e', 'f');
119 INSERT INTO t3 VALUES('g', 'h', 'i');
121 do_rbu_vacuum_test 1.5.2 $step
122 do_execsql_test 1.5.3 {
124 } {a b c d e f g h i}
125 do_execsql_test 1.5.4 {
126 CREATE INDEX t3a ON t3(a);
127 CREATE INDEX t3b ON t3(b);
128 CREATE INDEX t3c ON t3(c);
129 INSERT INTO t3 VALUES('j', 'k', 'l');
130 DELETE FROM t3 WHERE a = 'g';
132 do_rbu_vacuum_test 1.5.5 $step
133 do_execsql_test 1.5.6 {
134 SELECT rowid, * FROM t3 ORDER BY b
135 } {1 a b c 2 d e f 4 j k l}
137 do_execsql_test 1.6.1 {
138 CREATE TABLE t4(a PRIMARY KEY, b, c);
139 INSERT INTO t4 VALUES('a', 'b', 'c');
140 INSERT INTO t4 VALUES('d', 'e', 'f');
141 INSERT INTO t4 VALUES('g', 'h', 'i');
143 do_rbu_vacuum_test 1.6.2 $step
144 do_execsql_test 1.6.3 {
146 } {a b c d e f g h i}
147 do_execsql_test 1.6.4 {
148 CREATE INDEX t4a ON t4(a);
149 CREATE INDEX t4b ON t4(b);
150 CREATE INDEX t4c ON t4(c);
152 INSERT INTO t4 VALUES('j', 'k', 'l');
153 DELETE FROM t4 WHERE a='g';
155 do_rbu_vacuum_test 1.6.5 $step
156 do_execsql_test 1.6.6 {
157 SELECT * FROM t4 ORDER BY b
158 } {a b c d e f j k l}
161 do_execsql_test 1.7.0 {
162 CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b);
163 INSERT INTO t1 VALUES(NULL, 'one');
164 INSERT INTO t1 VALUES(NULL, 'two');
165 DELETE FROM t1 WHERE a=2;
166 INSERT INTO t1 VALUES(NULL, 'three');
167 INSERT INTO t1 VALUES(NULL, 'four');
168 DELETE FROM t1 WHERE a=4;
169 INSERT INTO t1 VALUES(NULL, 'five');
170 INSERT INTO t1 VALUES(NULL, 'six');
171 DELETE FROM t1 WHERE a=6;
173 } {1 one 3 three 5 five}
174 do_rbu_vacuum_test 1.7.1 $step
175 do_execsql_test 1.7.2 {
176 INSERT INTO t1 VALUES(NULL, 'seven');
178 } {1 one 3 three 5 five 7 seven}
181 do_execsql_test 1.8.0 {
182 CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b);
183 CREATE INDEX i1 ON t1(b);
184 INSERT INTO t1 VALUES(NULL, 'one');
185 INSERT INTO t1 VALUES(NULL, 'two');
186 INSERT INTO t1 VALUES(NULL, 'three');
187 INSERT INTO t1 VALUES(NULL, 'four');
188 INSERT INTO t1 VALUES(NULL, 'five');
189 INSERT INTO t1 VALUES(NULL, 'six');
191 SELECT * FROM sqlite_stat1;
193 do_rbu_vacuum_test 1.8.1 $step
194 do_execsql_test 1.7.2 {
195 SELECT * FROM sqlite_stat1;
199 do_execsql_test 1.9.0 {
200 PRAGMA page_size = 8192;
201 PRAGMA auto_vacuum = 2;
202 PRAGMA user_version = 412;
203 PRAGMA application_id = 413;
205 CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b);
206 CREATE INDEX i1 ON t1(b);
207 INSERT INTO t1 VALUES(NULL, 'one');
208 INSERT INTO t1 VALUES(NULL, 'two');
209 INSERT INTO t1 VALUES(NULL, 'three');
210 INSERT INTO t1 VALUES(NULL, 'four');
211 INSERT INTO t1 VALUES(NULL, 'five');
212 INSERT INTO t1 VALUES(NULL, 'six');
214 PRAGMA main.page_size;
215 PRAGMA main.auto_vacuum;
216 PRAGMA main.user_version;
217 PRAGMA main.application_id;
220 do_rbu_vacuum_test 1.9.1 $step
221 do_execsql_test 1.9.2 {
222 PRAGMA main.page_size;
223 PRAGMA main.auto_vacuum;
224 PRAGMA main.user_version;
225 PRAGMA main.application_id;
228 # Vacuum a database with a large sqlite_master table.
232 for {set i 1} {$i < 50} {incr i} {
233 execsql "PRAGMA page_size = 1024"
234 execsql "CREATE TABLE t$i (a, b, c, PRIMARY KEY(a, b));"
236 INSERT INTO t$i VALUES(1, 2, 3);
237 INSERT INTO t$i VALUES(4, 5, 6);
241 do_rbu_vacuum_test 1.10.2 $step
243 # Database with empty tables.
246 do_execsql_test 1.11.1 {
247 CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
248 CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
249 CREATE TABLE t3(a INTEGER PRIMARY KEY, b);
250 CREATE TABLE t4(a INTEGER PRIMARY KEY, b);
251 INSERT INTO t4 VALUES(1, 2);
253 do_rbu_vacuum_test 1.11.2 $step
254 do_execsql_test 1.11.3 {
261 do_execsql_test 1.12.1 {
262 CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
263 CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
264 CREATE TABLE t3(a INTEGER PRIMARY KEY, b);
265 CREATE TABLE t4(a INTEGER PRIMARY KEY, b);
266 INSERT INTO t1 VALUES(1, 2);
268 do_rbu_vacuum_test 1.12.2 $step
269 do_execsql_test 1.12.3 {
276 set ::testprefix rbuvacuum
278 #-------------------------------------------------------------------------
279 # Test some error cases:
281 # 2.1.* the db being vacuumed being in wal mode already.
282 # 2.2.* database modified mid vacuum.
285 do_execsql_test 2.1.0 {
286 CREATE TABLE t1(a, b);
287 INSERT INTO t1 VALUES(1, 2);
288 INSERT INTO t1 VALUES(3, 4);
289 INSERT INTO t1 VALUES(5, 6);
290 INSERT INTO t1 VALUES(7, 8);
291 PRAGMA journal_mode = wal;
292 INSERT INTO t1 VALUES(9, 10);
295 sqlite3rbu_vacuum rbu test.db state.db
299 list [catch { rbu close } msg] $msg
300 } {1 {SQLITE_ERROR - cannot vacuum wal mode database}}
303 sqlite3rbu_vacuum rbu test.db state.db
307 list [catch { rbu close_no_error } msg] $msg
311 do_execsql_test 2.2.0 {
312 CREATE TABLE tx(a PRIMARY KEY, b BLOB);
313 INSERT INTO tx VALUES(1, randomblob(900));
314 INSERT INTO tx SELECT a+1, randomblob(900) FROM tx;
315 INSERT INTO tx SELECT a+2, randomblob(900) FROM tx;
316 INSERT INTO tx SELECT a+4, randomblob(900) FROM tx;
317 INSERT INTO tx SELECT a+8, randomblob(900) FROM tx;
320 for {set i 1} 1 {incr i} {
321 db_restore_and_reopen
323 sqlite3rbu_vacuum rbu test.db state.db
324 for {set step 0} {$step<$i} {incr step} { rbu step }
326 if {[file exists test.db-wal]} break
328 execsql { INSERT INTO tx VALUES(20, 20) }
331 sqlite3rbu_vacuum rbu test.db state.db
335 list [catch { rbu close } msg] $msg
336 } {1 {SQLITE_BUSY - database modified during rbu vacuum}}
339 #-------------------------------------------------------------------------
340 # Test that a database that uses custom collation sequences can be RBU
346 proc length_cmp {x y} {
347 set n1 [string length $x]
348 set n2 [string length $y]
349 return [expr $n1 - $n2]
351 sqlite3_create_collation_v2 db length length_cmp noop
353 do_execsql_test 3.0 {
354 CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
355 INSERT INTO t1 VALUES(1, 'i');
356 INSERT INTO t1 VALUES(2, 'iiii');
357 INSERT INTO t1 VALUES(3, 'ii');
358 INSERT INTO t1 VALUES(4, 'iii');
359 SELECT a FROM t1 ORDER BY b COLLATE length;
361 do_execsql_test 3.1 {
362 CREATE INDEX i1 ON t1(b COLLATE length);
366 sqlite3rbu_vacuum rbu test.db state.db
367 while {[rbu step]=="SQLITE_OK"} {}
368 list [catch { rbu close } msg] $msg
369 } {1 {SQLITE_ERROR - no such collation sequence: length}}
372 sqlite3rbu_vacuum rbu test.db state.db
374 sqlite3_create_collation_v2 $db1 length length_cmp noop
375 while {[rbu step]=="SQLITE_OK"} {}
376 list [catch { rbu close } msg] $msg
377 } {1 {SQLITE_ERROR - no such collation sequence: length}}
380 sqlite3rbu_vacuum rbu test.db state.db
382 sqlite3_create_collation_v2 $db1 length length_cmp noop
383 while {[rbu step]=="SQLITE_OK"} {}
384 list [catch { rbu close } msg] $msg
385 } {1 {SQLITE_ERROR - no such collation sequence: length}}
388 sqlite3rbu_vacuum rbu test.db state.db
392 sqlite3_create_collation_v2 $db1 length length_cmp noop
393 sqlite3_create_collation_v2 $db2 length length_cmp noop
395 while {[rbu step]=="SQLITE_OK"} {}
396 list [catch { rbu close } msg] $msg