xref: /sqlite-3.40.0/test/multiplex.test (revision c27fa4b0)
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 [ expr ($::SQLITE_MAX_PAGE_SIZE*16384) ]
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 [ expr (($chunk_size+($::SQLITE_MAX_PAGE_SIZE-1)) & ~($::SQLITE_MAX_PAGE_SIZE-1)) ]
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
77
78do_test multiplex-1.9.1  { sqlite3_multiplex_initialize "" 1 }     {SQLITE_OK}
79do_test multiplex-1.9.2  { sqlite3 db test.db }                    {}
80do_test multiplex-1.9.3  { multiplex_set db main 32768 16 }        {SQLITE_OK}
81do_test multiplex-1.9.4  { multiplex_set db main 32768 -1 }        {SQLITE_MISUSE}
82do_test multiplex-1.9.5  { multiplex_set db main -1 16 }           {SQLITE_MISUSE}
83do_test multiplex-1.9.6  { multiplex_set db main 31 16 }           {SQLITE_OK}
84do_test multiplex-1.9.7  { multiplex_set db main 32768 100 }       {SQLITE_MISUSE}
85do_test multiplex-1.9.8  { multiplex_set db main 1073741824 1 }    {SQLITE_OK}
86do_test multiplex-1.9.9  { db close }                              {}
87do_test multiplex-1.9.10 { sqlite3_multiplex_shutdown }            {SQLITE_OK}
88
89do_test multiplex-1.10.1  { sqlite3_multiplex_initialize "" 1 }                     {SQLITE_OK}
90do_test multiplex-1.10.2  { sqlite3 db test.db }                                    {}
91do_test multiplex-1.10.3  { execsql { SELECT multiplex_control(2, 32768); } }       {SQLITE_OK}
92do_test multiplex-1.10.4  { execsql { SELECT multiplex_control(3, -1); } }          {SQLITE_MISUSE}
93do_test multiplex-1.10.5  { execsql { SELECT multiplex_control(2, -1); } }          {SQLITE_MISUSE}
94do_test multiplex-1.10.6  { execsql { SELECT multiplex_control(2, 31); } }          {SQLITE_OK}
95do_test multiplex-1.10.7  { execsql { SELECT multiplex_control(3, 100); } }         {SQLITE_MISUSE}
96do_test multiplex-1.10.8  { execsql { SELECT multiplex_control(2, 1073741824); } }  {SQLITE_OK}
97do_test multiplex-1.10.9  { db close }                                              {}
98do_test multiplex-1.10.10 { sqlite3_multiplex_shutdown }                            {SQLITE_OK}
99
100do_test multiplex-1.11.1  { sqlite3_multiplex_initialize "" 1 }                 {SQLITE_OK}
101do_test multiplex-1.11.2  { sqlite3 db test.db }                                {}
102do_test multiplex-1.11.3  { sqlite3_multiplex_control db main enable 0  }       {SQLITE_OK}
103do_test multiplex-1.11.4  { sqlite3_multiplex_control db main enable 1  }       {SQLITE_OK}
104do_test multiplex-1.11.5  { sqlite3_multiplex_control db main enable -1 }       {SQLITE_OK}
105do_test multiplex-1.11.6  { db close }                                          {}
106do_test multiplex-1.11.7  { sqlite3_multiplex_shutdown }                        {SQLITE_OK}
107
108do_test multiplex-1.12.1  { sqlite3_multiplex_initialize "" 1 }                 {SQLITE_OK}
109do_test multiplex-1.12.2  { sqlite3 db test.db }                                {}
110do_test multiplex-1.12.3  { execsql { SELECT multiplex_control(1, 0); } }       {SQLITE_OK}
111do_test multiplex-1.12.4  { execsql { SELECT multiplex_control(1, 1); } }       {SQLITE_OK}
112do_test multiplex-1.12.5  { execsql { SELECT multiplex_control(1, -1); } }      {SQLITE_OK}
113do_test multiplex-1.12.6  { db close }                                          {}
114do_test multiplex-1.12.7  { sqlite3_multiplex_shutdown }                        {SQLITE_OK}
115
116#-------------------------------------------------------------------------
117# Some simple warm-body tests with a single database file in rollback
118# mode:
119#
120#   multiplex-2.1.*: Test simple writing to a multiplex file.
121#
122#   multiplex-2.2.*: More writing.
123#
124#   multiplex-2.3.*: Open and close a second db.
125#
126#   multiplex-2.4.*: Try to shutdown the multiplex system before closing the db
127#                file. Check that this fails and the multiplex system still works
128#                afterwards. Then close the database and successfully shut
129#                down the multiplex system.
130#
131#   multiplex-2.5.*: More reading/writing.
132#
133#   multiplex-2.6.*: More reading/writing with varying small chunk sizes, as
134#                well as varying journal mode.
135#
136#   multiplex-2.7.*: Disable/enable tests.
137#
138
139sqlite3_multiplex_initialize "" 1
140multiplex_set db main 32768 16
141
142do_test multiplex-2.1.2 {
143  sqlite3 db test.db
144  execsql {
145    PRAGMA page_size=1024;
146    PRAGMA auto_vacuum=OFF;
147    PRAGMA journal_mode=DELETE;
148  }
149  execsql {
150    CREATE TABLE t1(a, b);
151    INSERT INTO t1 VALUES(1, randomblob(1100));
152    INSERT INTO t1 VALUES(2, randomblob(1100));
153  }
154} {}
155do_test multiplex-2.1.3 { file size [multiplex_name test.db 0] } {4096}
156do_test multiplex-2.1.4 {
157  execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
158} {}
159
160do_test multiplex-2.2.1 {
161  execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
162} {}
163do_test multiplex-2.2.3 { file size [multiplex_name test.db 0] } {6144}
164
165do_test multiplex-2.3.1 {
166  sqlite3 db2 test2.db
167  db2 close
168} {}
169
170
171do_test multiplex-2.4.1 {
172  sqlite3_multiplex_shutdown
173} {SQLITE_MISUSE}
174do_test multiplex-2.4.2 {
175  execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
176} {}
177do_test multiplex-2.4.4 { file size [multiplex_name test.db 0] } {7168}
178do_test multiplex-2.4.99 {
179  db close
180  sqlite3_multiplex_shutdown
181} {SQLITE_OK}
182
183
184do_test multiplex-2.5.1 {
185  multiplex_delete test.db
186  sqlite3_multiplex_initialize "" 1
187  sqlite3 db test.db
188  multiplex_set db main 4096 16
189} {SQLITE_OK}
190
191do_test multiplex-2.5.2 {
192  execsql {
193    PRAGMA page_size = 1024;
194    PRAGMA journal_mode = delete;
195    PRAGMA auto_vacuum = off;
196    CREATE TABLE t1(a PRIMARY KEY, b);
197  }
198} {delete}
199
200do_test multiplex-2.5.3 {
201  execsql {
202    INSERT INTO t1 VALUES(1, 'one');
203    INSERT INTO t1 VALUES(2, randomblob(4000));
204    INSERT INTO t1 VALUES(3, 'three');
205    INSERT INTO t1 VALUES(4, randomblob(4000));
206    INSERT INTO t1 VALUES(5, 'five');
207    INSERT INTO t1 VALUES(6, randomblob($g_chunk_size));
208    INSERT INTO t1 VALUES(7, randomblob($g_chunk_size));
209  }
210} {}
211
212do_test multiplex-2.5.4 {
213  db eval {SELECT * FROM t1 WHERE a=1}
214} {1 one}
215
216do_test multiplex-2.5.5 {
217  db eval {SELECT * FROM t1 WHERE a=3}
218} {3 three}
219
220do_test multiplex-2.5.6 {
221  db eval {SELECT * FROM t1 WHERE a=5}
222} {5 five}
223
224do_test multiplex-2.5.7 {
225  db eval {SELECT a,length(b) FROM t1 WHERE a=2}
226} {2 4000}
227
228do_test multiplex-2.5.8 {
229  db eval {SELECT a,length(b) FROM t1 WHERE a=4}
230} {4 4000}
231
232do_test multiplex-2.5.9 { file size [multiplex_name test.db 0] } [list $g_chunk_size]
233do_test multiplex-2.5.10 { file size [multiplex_name test.db 1] } [list $g_chunk_size]
234
235do_test multiplex-2.5.99 {
236  db close
237  sqlite3_multiplex_shutdown
238} {SQLITE_OK}
239
240
241set all_journal_modes {delete persist truncate memory off}
242foreach jmode $all_journal_modes {
243  for {set sz 151} {$sz<8000} {set sz [expr $sz+419]} {
244
245    do_test multiplex-2.6.1.$sz.$jmode {
246      multiplex_delete test.db
247      sqlite3_multiplex_initialize "" 1
248      sqlite3 db test.db
249      multiplex_set db main $sz 32
250    } {SQLITE_OK}
251
252    do_test multiplex-2.6.2.$sz.$jmode {
253      db eval {
254        PRAGMA page_size = 1024;
255        PRAGMA auto_vacuum = off;
256      }
257      db eval "PRAGMA journal_mode = $jmode;"
258    } $jmode
259
260    do_test multiplex-2.6.3.$sz.$jmode {
261      execsql {
262        CREATE TABLE t1(a PRIMARY KEY, b);
263        INSERT INTO t1 VALUES(1, 'one');
264        INSERT INTO t1 VALUES(2, randomblob($g_chunk_size));
265      }
266    } {}
267
268    do_test multiplex-2.6.4.$sz.$jmode {
269      db eval {SELECT b FROM t1 WHERE a=1}
270    } {one}
271
272    do_test multiplex-2.6.5.$sz.$jmode {
273      db eval {SELECT length(b) FROM t1 WHERE a=2}
274    } [list $g_chunk_size]
275
276    do_test multiplex-2.6.6.$sz.$jmode { file size [multiplex_name test.db 0] } [list $g_chunk_size]
277
278    do_test multiplex-2.6.99.$sz.$jmode {
279      db close
280      sqlite3_multiplex_shutdown
281    } {SQLITE_OK}
282
283  }
284}
285
286do_test multiplex-2.7.1  { multiplex_delete test.db }                          {}
287do_test multiplex-2.7.2  { sqlite3_multiplex_initialize "" 1 }                 {SQLITE_OK}
288do_test multiplex-2.7.3  { sqlite3 db test.db }                                {}
289do_test multiplex-2.7.4  { execsql { SELECT multiplex_control(2, 65536); } }   {SQLITE_OK}
290do_test multiplex-2.7.5  { execsql { SELECT multiplex_control(1, 0); } }       {SQLITE_OK}
291do_test multiplex-2.7.6 {
292  execsql {
293    CREATE TABLE t1(a PRIMARY KEY, b);
294    INSERT INTO t1 VALUES(1, randomblob(1000));
295  }
296} {}
297# verify only one file, and file size is less than chunks size
298do_test multiplex-2.7.7  { expr ([file size [multiplex_name test.db 0]] < 65536) } {1}
299do_test multiplex-2.7.8  { file exists [multiplex_name test.db 1] }                {0}
300do_test multiplex-2.7.9 {
301  execsql {
302    INSERT INTO t1 VALUES(1, randomblob(65536));
303  }
304} {}
305# verify only one file, and file size exceeds chunks size
306do_test multiplex-2.7.10 { expr ([file size [multiplex_name test.db 0]] > 65536) } {1}
307do_test multiplex-2.7.11 { file exists [multiplex_name test.db 1] }                {0}
308do_test multiplex-2.7.12 { db close }                                              {}
309do_test multiplex-2.7.13 { sqlite3_multiplex_shutdown }                            {SQLITE_OK}
310
311
312#-------------------------------------------------------------------------
313# Try some tests with more than one connection to a database file. Still
314# in rollback mode.
315#
316#   multiplex-3.1.*: Two connections to a single database file.
317#
318#   multiplex-3.2.*: Two connections to each of several database files (that
319#                are in the same multiplex group).
320#
321do_test multiplex-3.1.1 {
322  multiplex_delete test.db
323  sqlite3_multiplex_initialize "" 1
324  sqlite3 db test.db
325  multiplex_set db main 32768 16
326} {SQLITE_OK}
327do_test multiplex-3.1.2 {
328  execsql {
329    PRAGMA page_size = 1024;
330    PRAGMA journal_mode = delete;
331    PRAGMA auto_vacuum = off;
332    CREATE TABLE t1(a PRIMARY KEY, b);
333    INSERT INTO t1 VALUES(1, 'one');
334  }
335  file size [multiplex_name test.db 0]
336} {3072}
337do_test multiplex-3.1.3 {
338  sqlite3 db2 test.db
339  execsql { CREATE TABLE t2(a, b) } db2
340} {}
341do_test multiplex-3.1.4 {
342  execsql { CREATE TABLE t3(a, b) }
343} {}
344do_test multiplex-3.1.5 {
345  catchsql { CREATE TABLE t3(a, b) }
346} {1 {table t3 already exists}}
347do_test multiplex-3.1.6 {
348  db close
349  db2 close
350} {}
351
352do_test multiplex-3.2.1a {
353
354  multiplex_delete test.db
355  multiplex_delete test2.db
356
357  sqlite3 db1a test.db
358  sqlite3 db2a test2.db
359
360  foreach db {db1a db2a} {
361    execsql {
362      PRAGMA page_size = 1024;
363      PRAGMA journal_mode = delete;
364      PRAGMA auto_vacuum = off;
365      CREATE TABLE t1(a, b);
366    } $db
367  }
368
369  list [file size [multiplex_name test.db 0]] [file size [multiplex_name test2.db 0]]
370} {2048 2048}
371
372do_test multiplex-3.2.1b {
373  sqlite3 db1b test.db
374  sqlite3 db2b test2.db
375} {}
376
377do_test multiplex-3.2.2 { execsql { INSERT INTO t1 VALUES('x', 'y') } db1a } {}
378do_test multiplex-3.2.3 { execsql { INSERT INTO t1 VALUES('v', 'w') } db1b } {}
379do_test multiplex-3.2.4 { execsql { INSERT INTO t1 VALUES('t', 'u') } db2a } {}
380do_test multiplex-3.2.5 { execsql { INSERT INTO t1 VALUES('r', 's') } db2b } {}
381
382do_test multiplex-3.2.6 {
383  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1a
384} {}
385do_test multiplex-3.2.7 {
386  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1b
387} {}
388do_test multiplex-3.2.8 {
389  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2a
390} {}
391do_test multiplex-3.2.9 {
392  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2b
393} {}
394
395do_test multiplex-3.3.1 {
396  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1a
397  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1b
398  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2a
399  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2b
400} {}
401
402do_test multiplex-3.2.X {
403  foreach db {db1a db2a db2b db1b} { catch { $db close } }
404} {}
405
406#-------------------------------------------------------------------------
407#
408
409sqlite3_multiplex_initialize "" 1
410multiplex_set db main 32768 16
411
412# Return a list of all currently defined multiplexs.
413proc multiplex_list {} {
414  set allq {}
415  foreach q [sqlite3_multiplex_dump] {
416    lappend allq [lindex $q 0]
417  }
418  return [lsort $allq]
419}
420
421do_test multiplex-4.1.6 {
422  multiplex_delete test2.db
423  sqlite3 db test2.db
424  db eval {CREATE TABLE t2(x); INSERT INTO t2 VALUES('tab-t2');}
425  set res [multiplex_list]
426  list [regexp {test2.db} $res]
427} {1}
428do_test multiplex-4.1.6a {
429  sqlite3 db2 test2.db
430  db2 eval {SELECT * FROM t2}
431} {tab-t2}
432do_test multiplex-4.1.7 {
433  execsql {INSERT INTO t2 VALUES(zeroblob(200000))}
434} {}
435do_test multiplex-4.1.8 {
436  sqlite3 db2 test2.db
437  db2 eval {SELECT count(*) FROM t2}
438} {2}
439do_test multiplex-4.1.8a {
440   db2 eval { DELETE FROM t2 WHERE x = 'tab-t2' }
441} {}
442do_test multiplex-4.1.8b {
443  sqlite3 db2 test2.db
444  db2 eval {SELECT count(*) FROM t2}
445} {1}
446
447
448do_test multiplex-4.1.9 {
449  execsql {INSERT INTO t2 VALUES(zeroblob(200000))}
450} {}
451do_test multiplex-4.1.10 {
452  set res [multiplex_list]
453  list [regexp {test2.db} $res]
454} {1}
455do_test multiplex-4.1.11 {
456  db2 close
457  set res [multiplex_list]
458  list [regexp {test2.db} $res]
459} {1}
460do_test multiplex-4.1.12 {
461  db close
462  multiplex_list
463} {}
464
465
466#-------------------------------------------------------------------------
467# The following tests test that the multiplex VFS handles malloc and IO
468# errors.
469#
470
471sqlite3_multiplex_initialize "" 1
472multiplex_set db main 32768 16
473
474do_faultsim_test multiplex-5.1 -prep {
475  catch {db close}
476} -body {
477  sqlite3 db test2.db
478}
479do_faultsim_test multiplex-5.2 -prep {
480  catch {db close}
481} -body {
482  sqlite3 db test.db
483}
484
485catch { db close }
486multiplex_delete test.db
487multiplex_delete test2.db
488
489do_test multiplex-5.3.prep {
490  sqlite3 db test.db
491  execsql {
492    PRAGMA auto_vacuum = 1;
493    PRAGMA page_size = 1024;
494    CREATE TABLE t1(a, b);
495    INSERT INTO t1 VALUES(10, zeroblob(1200));
496  }
497  faultsim_save_and_close
498} {}
499do_faultsim_test multiplex-5.3 -prep {
500  faultsim_restore_and_reopen
501} -body {
502  execsql { DELETE FROM t1 }
503}
504
505do_test multiplex-5.4.1 {
506  catch { db close }
507  multiplex_delete test.db
508  file mkdir test.db
509  list [catch { sqlite3 db test.db } msg] $msg
510} {1 {unable to open database file}}
511catch { file delete test.db }
512
513do_faultsim_test multiplex-5.5 -prep {
514  catch { sqlite3_multiplex_shutdown }
515} -body {
516  sqlite3_multiplex_initialize "" 1
517  multiplex_set db main 32768 16
518}
519
520# test that mismatch filesize is detected
521#
522# Do not run this test if $::G(perm:presql) is set. If it is set, then the
523# expected IO error will occur within the Tcl [sqlite3] wrapper, not within
524# the first SQL statement executed below. This breaks the test case.
525#
526if {0==[info exists ::G(perm:presql)] || $::G(perm:presql) == ""} {
527  set all_journal_modes {delete persist truncate memory off}
528  foreach jmode $all_journal_modes {
529    do_test multiplex-5.6.1.$jmode {
530      sqlite3_multiplex_shutdown
531      multiplex_delete test.db
532      sqlite3 db test.db
533      db eval {
534        PRAGMA page_size = 1024;
535        PRAGMA auto_vacuum = off;
536      }
537      db eval "PRAGMA journal_mode = $jmode;"
538    } $jmode
539    do_test multiplex-5.6.2.$jmode {
540      execsql {
541        CREATE TABLE t1(a, b);
542        INSERT INTO t1 VALUES(1, randomblob(15000));
543        INSERT INTO t1 VALUES(2, randomblob(15000));
544        INSERT INTO t1 VALUES(3, randomblob(15000));
545        INSERT INTO t1 VALUES(4, randomblob(15000));
546        INSERT INTO t1 VALUES(5, randomblob(15000));
547      }
548      db close
549      sqlite3_multiplex_initialize "" 1
550      sqlite3 db test.db
551      multiplex_set db main 4096 16
552    } {SQLITE_OK}
553    do_test multiplex-5.6.3.$jmode {
554      catchsql {
555        INSERT INTO t1 VALUES(6, randomblob(15000));
556      }
557    } {1 {disk I/O error}}
558    do_test multiplex-5.6.4.$jmode {
559      db close
560    } {}
561  }
562}
563
564catch { sqlite3_multiplex_shutdown }
565finish_test
566