xref: /sqlite-3.40.0/test/multiplex.test (revision ac039688)
1# 2010 October 29
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
13set testdir [file dirname $argv0]
14source $testdir/tester.tcl
15source $testdir/malloc_common.tcl
16
17set g_chunk_size 2147483648
18set g_max_chunks 32
19
20# This handles appending the chunk number
21# to the end of the filename.  if
22# SQLITE_MULTIPLEX_EXT_OVWR is defined, then
23# it overwrites the last 2 bytes of the
24# file name with the chunk number.
25proc multiplex_name {name chunk} {
26  if {$chunk==0} { return $name }
27  set num [format "%02d" $chunk]
28  ifcapable {multiplex_ext_overwrite} {
29    set name [string range $name 0 [expr [string length $name]-2-1]]
30  }
31  return $name$num
32}
33
34# This saves off the parameters and calls the
35# underlying sqlite3_multiplex_control() API.
36proc multiplex_set {db name chunk_size max_chunks} {
37  global g_chunk_size
38  global g_max_chunks
39  set g_chunk_size $chunk_size
40  set g_max_chunks $max_chunks
41  set rc [catch {sqlite3_multiplex_control $db $name chunk_size $chunk_size} msg]
42  if { $rc==0 } {
43    set rc [catch {sqlite3_multiplex_control $db $name max_chunks $max_chunks} msg]
44  }
45  list $msg
46}
47
48# This attempts to delete the base file and
49# and files with the chunk extension.
50proc multiplex_delete {name} {
51  global g_max_chunks
52  for {set i 0} {$i<$g_max_chunks} {incr i} {
53    forcedelete [multiplex_name $name $i]
54    forcedelete [multiplex_name $name-journal $i]
55    forcedelete [multiplex_name $name-wal $i]
56  }
57}
58
59db close
60
61multiplex_delete test.db
62multiplex_delete test2.db
63
64#-------------------------------------------------------------------------
65#   multiplex-1.1.*: Test initialize and shutdown.
66
67do_test multiplex-1.1 { sqlite3_multiplex_initialize nosuchvfs 1 } {SQLITE_ERROR}
68do_test multiplex-1.2 { sqlite3_multiplex_initialize "" 1 }        {SQLITE_OK}
69do_test multiplex-1.3 { sqlite3_multiplex_initialize "" 1 }        {SQLITE_MISUSE}
70do_test multiplex-1.4 { sqlite3_multiplex_shutdown }               {SQLITE_OK}
71
72do_test multiplex-1.5 { sqlite3_multiplex_initialize "" 0 }        {SQLITE_OK}
73do_test multiplex-1.6 { sqlite3_multiplex_shutdown }               {SQLITE_OK}
74do_test multiplex-1.7 { sqlite3_multiplex_initialize "" 1 }        {SQLITE_OK}
75do_test multiplex-1.8 { sqlite3_multiplex_shutdown }               {SQLITE_OK}
76
77do_test multiplex-1.9  { sqlite3_multiplex_initialize "" 1 }       {SQLITE_OK}
78sqlite3 db test.db
79do_test multiplex-1.10.1 { multiplex_set db main 32768 16 }        {SQLITE_OK}
80do_test multiplex-1.10.2 { multiplex_set db main 32768 -1 }        {SQLITE_MISUSE}
81do_test multiplex-1.10.3 { multiplex_set db main -1 16 }           {SQLITE_MISUSE}
82do_test multiplex-1.10.4 { multiplex_set db main 31 16 }           {SQLITE_MISUSE}
83do_test multiplex-1.10.5 { multiplex_set db main 32768 100 }       {SQLITE_MISUSE}
84db close
85do_test multiplex-1.11 { sqlite3_multiplex_shutdown }              {SQLITE_OK}
86
87#-------------------------------------------------------------------------
88# Some simple warm-body tests with a single database file in rollback
89# mode:
90#
91#   multiplex-2.1.*: Test simple writing to a multiplex file.
92#
93#   multiplex-2.2.*: More writing.
94#
95#   multiplex-2.3.*: Open and close a second db.
96#
97#   multiplex-2.4.*: Try to shutdown the multiplex system befor e closing the db
98#                file. Check that this fails and the multiplex system still works
99#                afterwards. Then close the database and successfully shut
100#                down the multiplex system.
101#
102#   multiplex-2.5.*: More reading/writing.
103#
104#   multiplex-2.6.*: More reading/writing with varying small chunk sizes, as
105#                well as varying journal mode.
106
107sqlite3_multiplex_initialize "" 1
108multiplex_set db main 32768 16
109
110do_test multiplex-2.1.2 {
111  sqlite3 db test.db
112  execsql {
113    PRAGMA page_size=1024;
114    PRAGMA auto_vacuum=OFF;
115    PRAGMA journal_mode=DELETE;
116  }
117  execsql {
118    CREATE TABLE t1(a, b);
119    INSERT INTO t1 VALUES(1, randomblob(1100));
120    INSERT INTO t1 VALUES(2, randomblob(1100));
121  }
122} {}
123do_test multiplex-2.1.3 { file size [multiplex_name test.db 0] } {4096}
124do_test multiplex-2.1.4 {
125  execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
126} {}
127
128do_test multiplex-2.2.1 {
129  execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
130} {}
131do_test multiplex-2.2.3 { file size [multiplex_name test.db 0] } {6144}
132
133do_test multiplex-2.3.1 {
134  sqlite3 db2 test2.db
135  db2 close
136} {}
137
138
139do_test multiplex-2.4.1 {
140  sqlite3_multiplex_shutdown
141} {SQLITE_MISUSE}
142do_test multiplex-2.4.2 {
143  execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
144} {}
145do_test multiplex-2.4.4 { file size [multiplex_name test.db 0] } {7168}
146do_test multiplex-2.4.99 {
147  db close
148  sqlite3_multiplex_shutdown
149} {SQLITE_OK}
150
151
152do_test multiplex-2.5.1 {
153  multiplex_delete test.db
154  sqlite3_multiplex_initialize "" 1
155  sqlite3 db test.db
156  multiplex_set db main 4096 16
157} {SQLITE_OK}
158
159do_test multiplex-2.5.2 {
160  execsql {
161    PRAGMA page_size = 1024;
162    PRAGMA journal_mode = delete;
163    PRAGMA auto_vacuum = off;
164    CREATE TABLE t1(a PRIMARY KEY, b);
165  }
166} {delete}
167
168do_test multiplex-2.5.3 {
169  execsql {
170    INSERT INTO t1 VALUES(1, 'one');
171    INSERT INTO t1 VALUES(2, randomblob(4000));
172    INSERT INTO t1 VALUES(3, 'three');
173    INSERT INTO t1 VALUES(4, randomblob(4000));
174    INSERT INTO t1 VALUES(5, 'five')
175  }
176} {}
177
178do_test multiplex-2.5.4 {
179  db eval {SELECT * FROM t1 WHERE a=1}
180} {1 one}
181
182do_test multiplex-2.5.5 {
183  db eval {SELECT * FROM t1 WHERE a=3}
184} {3 three}
185
186do_test multiplex-2.5.6 {
187  db eval {SELECT * FROM t1 WHERE a=5}
188} {5 five}
189
190do_test multiplex-2.5.7 {
191  db eval {SELECT a,length(b) FROM t1 WHERE a=2}
192} {2 4000}
193
194do_test multiplex-2.5.8 {
195  db eval {SELECT a,length(b) FROM t1 WHERE a=4}
196} {4 4000}
197
198do_test multiplex-2.5.9 { file size [multiplex_name test.db 0] } [list $g_chunk_size]
199do_test multiplex-2.5.10 { file size [multiplex_name test.db 1] } [list $g_chunk_size]
200
201do_test multiplex-2.5.99 {
202  db close
203  sqlite3_multiplex_shutdown
204} {SQLITE_OK}
205
206
207set all_journal_modes {delete persist truncate memory off}
208foreach jmode $all_journal_modes {
209  for {set sz 151} {$sz<8000} {set sz [expr $sz+419]} {
210
211    do_test multiplex-2.6.1.$sz.$jmode {
212      multiplex_delete test.db
213      sqlite3_multiplex_initialize "" 1
214      sqlite3 db test.db
215      multiplex_set db main $sz 32
216    } {SQLITE_OK}
217
218    do_test multiplex-2.6.2.$sz.$jmode {
219      db eval {
220        PRAGMA page_size = 1024;
221        PRAGMA auto_vacuum = off;
222      }
223      db eval "PRAGMA journal_mode = $jmode;"
224    } $jmode
225
226    do_test multiplex-2.6.3.$sz.$jmode {
227      execsql {
228        CREATE TABLE t1(a PRIMARY KEY, b);
229        INSERT INTO t1 VALUES(1, 'one');
230        INSERT INTO t1 VALUES(2, randomblob($g_chunk_size));
231      }
232    } {}
233
234    do_test multiplex-2.6.4.$sz.$jmode {
235      db eval {SELECT b FROM t1 WHERE a=1}
236    } {one}
237
238    do_test multiplex-2.6.5.$sz.$jmode {
239      db eval {SELECT length(b) FROM t1 WHERE a=2}
240    } [list $g_chunk_size]
241
242    do_test multiplex-2.6.6.$sz.$jmode { file size [multiplex_name test.db 0] } [list $g_chunk_size]
243
244    do_test multiplex-2.6.99.$sz.$jmode {
245      db close
246      sqlite3_multiplex_shutdown
247    } {SQLITE_OK}
248
249  }
250}
251
252#-------------------------------------------------------------------------
253# Try some tests with more than one connection to a database file. Still
254# in rollback mode.
255#
256#   multiplex-3.1.*: Two connections to a single database file.
257#
258#   multiplex-3.2.*: Two connections to each of several database files (that
259#                are in the same multiplex group).
260#
261do_test multiplex-3.1.1 {
262  multiplex_delete test.db
263  sqlite3_multiplex_initialize "" 1
264  sqlite3 db test.db
265  multiplex_set db main 32768 16
266} {SQLITE_OK}
267do_test multiplex-3.1.2 {
268  execsql {
269    PRAGMA page_size = 1024;
270    PRAGMA journal_mode = delete;
271    PRAGMA auto_vacuum = off;
272    CREATE TABLE t1(a PRIMARY KEY, b);
273    INSERT INTO t1 VALUES(1, 'one');
274  }
275  file size [multiplex_name test.db 0]
276} {3072}
277do_test multiplex-3.1.3 {
278  sqlite3 db2 test.db
279  execsql { CREATE TABLE t2(a, b) } db2
280} {}
281do_test multiplex-3.1.4 {
282  execsql { CREATE TABLE t3(a, b) }
283} {}
284do_test multiplex-3.1.5 {
285  catchsql { CREATE TABLE t3(a, b) }
286} {1 {table t3 already exists}}
287do_test multiplex-3.1.6 {
288  db close
289  db2 close
290} {}
291
292do_test multiplex-3.2.1a {
293
294  multiplex_delete test.db
295  multiplex_delete test2.db
296
297  sqlite3 db1a test.db
298  sqlite3 db2a test2.db
299
300  foreach db {db1a db2a} {
301    execsql {
302      PRAGMA page_size = 1024;
303      PRAGMA journal_mode = delete;
304      PRAGMA auto_vacuum = off;
305      CREATE TABLE t1(a, b);
306    } $db
307  }
308
309  list [file size [multiplex_name test.db 0]] [file size [multiplex_name test2.db 0]]
310} {2048 2048}
311
312do_test multiplex-3.2.1b {
313  sqlite3 db1b test.db
314  sqlite3 db2b test2.db
315} {}
316
317do_test multiplex-3.2.2 { execsql { INSERT INTO t1 VALUES('x', 'y') } db1a } {}
318do_test multiplex-3.2.3 { execsql { INSERT INTO t1 VALUES('v', 'w') } db1b } {}
319do_test multiplex-3.2.4 { execsql { INSERT INTO t1 VALUES('t', 'u') } db2a } {}
320do_test multiplex-3.2.5 { execsql { INSERT INTO t1 VALUES('r', 's') } db2b } {}
321
322do_test multiplex-3.2.6 {
323  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1a
324} {}
325do_test multiplex-3.2.7 {
326  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1b
327} {}
328do_test multiplex-3.2.8 {
329  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2a
330} {}
331do_test multiplex-3.2.9 {
332  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2b
333} {}
334
335do_test multiplex-3.3.1 {
336  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1a
337  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1b
338  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2a
339  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2b
340} {}
341
342do_test multiplex-3.2.X {
343  foreach db {db1a db2a db2b db1b} { catch { $db close } }
344} {}
345
346#-------------------------------------------------------------------------
347#
348
349sqlite3_multiplex_initialize "" 1
350multiplex_set db main 32768 16
351
352# Return a list of all currently defined multiplexs.
353proc multiplex_list {} {
354  set allq {}
355  foreach q [sqlite3_multiplex_dump] {
356    lappend allq [lindex $q 0]
357  }
358  return [lsort $allq]
359}
360
361do_test multiplex-4.1.6 {
362  multiplex_delete test2.db
363  sqlite3 db test2.db
364  db eval {CREATE TABLE t2(x); INSERT INTO t2 VALUES('tab-t2');}
365  set res [multiplex_list]
366  list [regexp {test2.db} $res]
367} {1}
368do_test multiplex-4.1.6a {
369  sqlite3 db2 test2.db
370  db2 eval {SELECT * FROM t2}
371} {tab-t2}
372do_test multiplex-4.1.7 {
373  execsql {INSERT INTO t2 VALUES(zeroblob(200000))}
374} {}
375do_test multiplex-4.1.8 {
376  sqlite3 db2 test2.db
377  db2 eval {SELECT count(*) FROM t2}
378} {2}
379do_test multiplex-4.1.8a {
380   db2 eval { DELETE FROM t2 WHERE x = 'tab-t2' }
381} {}
382do_test multiplex-4.1.8b {
383  sqlite3 db2 test2.db
384  db2 eval {SELECT count(*) FROM t2}
385} {1}
386
387
388do_test multiplex-4.1.9 {
389  execsql {INSERT INTO t2 VALUES(zeroblob(200000))}
390} {}
391do_test multiplex-4.1.10 {
392  set res [multiplex_list]
393  list [regexp {test2.db} $res]
394} {1}
395do_test multiplex-4.1.11 {
396  db2 close
397  set res [multiplex_list]
398  list [regexp {test2.db} $res]
399} {1}
400do_test multiplex-4.1.12 {
401  db close
402  multiplex_list
403} {}
404
405
406#-------------------------------------------------------------------------
407# The following tests test that the multiplex VFS handles malloc and IO
408# errors.
409#
410
411sqlite3_multiplex_initialize "" 1
412multiplex_set db main 32768 16
413
414do_faultsim_test multiplex-5.1 -prep {
415  catch {db close}
416} -body {
417  sqlite3 db test2.db
418}
419do_faultsim_test multiplex-5.2 -prep {
420  catch {db close}
421} -body {
422  sqlite3 db test.db
423}
424
425catch { db close }
426multiplex_delete test.db
427multiplex_delete test2.db
428
429do_test multiplex-5.3.prep {
430  sqlite3 db test.db
431  execsql {
432    PRAGMA auto_vacuum = 1;
433    PRAGMA page_size = 1024;
434    CREATE TABLE t1(a, b);
435    INSERT INTO t1 VALUES(10, zeroblob(1200));
436  }
437  faultsim_save_and_close
438} {}
439do_faultsim_test multiplex-5.3 -prep {
440  faultsim_restore_and_reopen
441} -body {
442  execsql { DELETE FROM t1 }
443}
444
445do_test multiplex-5.4.1 {
446  catch { db close }
447  multiplex_delete test.db
448  file mkdir test.db
449  list [catch { sqlite3 db test.db } msg] $msg
450} {1 {unable to open database file}}
451catch { file delete test.db }
452
453do_faultsim_test multiplex-5.5 -prep {
454  catch { sqlite3_multiplex_shutdown }
455} -body {
456  sqlite3_multiplex_initialize "" 1
457  multiplex_set db main 32768 16
458}
459
460# test that mismatch filesize is detected
461#
462# Do not run this test if $::G(perm:presql) is set. If it is set, then the
463# expected IO error will occur within the Tcl [sqlite3] wrapper, not within
464# the first SQL statement executed below. This breaks the test case.
465#
466if {0==[info exists ::G(perm:presql)] || $::G(perm:presql) == ""} {
467  set all_journal_modes {delete persist truncate memory off}
468  foreach jmode $all_journal_modes {
469    do_test multiplex-5.6.1.$jmode {
470      sqlite3_multiplex_shutdown
471      multiplex_delete test.db
472      sqlite3 db test.db
473      db eval {
474        PRAGMA page_size = 1024;
475        PRAGMA auto_vacuum = off;
476      }
477      db eval "PRAGMA journal_mode = $jmode;"
478    } $jmode
479    do_test multiplex-5.6.2.$jmode {
480      execsql {
481        CREATE TABLE t1(a, b);
482        INSERT INTO t1 VALUES(1, randomblob(1100));
483        INSERT INTO t1 VALUES(2, randomblob(1100));
484        INSERT INTO t1 VALUES(3, randomblob(1100));
485        INSERT INTO t1 VALUES(4, randomblob(1100));
486        INSERT INTO t1 VALUES(5, randomblob(1100));
487      }
488      db close
489      sqlite3_multiplex_initialize "" 1
490      sqlite3 db test.db
491      multiplex_set db main 4096 16
492    } {SQLITE_OK}
493    do_test multiplex-5.6.3.$jmode {
494      catchsql {
495        INSERT INTO t1 VALUES(6, randomblob(1100));
496      }
497    } {1 {disk I/O error}}
498    do_test multiplex-5.6.4.$jmode {
499      db close
500    } {}
501  }
502}
503
504catch { sqlite3_multiplex_shutdown }
505finish_test
506