version bump to 4.6.1
[sqlcipher.git] / test / dbstatus.test
blob8d5d8349cf7aa6d486f09e25ad766987b11bdbbf
1 # 2010 March 10
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 # Tests for the sqlite3_db_status() function
15 set testdir [file dirname $argv0]
16 source $testdir/tester.tcl
17 set testprefix dbstatus
19 ifcapable !compound {
20   finish_test
21   return
24 # Memory statistics must be enabled for this test.
25 db close
26 sqlite3_shutdown
27 sqlite3_config_memstatus 1
28 sqlite3_config_uri 1
29 sqlite3_initialize
30 sqlite3 db test.db
33 # Make sure sqlite3_db_config() and sqlite3_db_status are working.
35 unset -nocomplain PAGESZ
36 unset -nocomplain BASESZ
37 do_test dbstatus-1.1 {
38   db close
39   sqlite3 db :memory:
40   db eval {
41     CREATE TABLE t1(x);
42   }
43   set sz1 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_CACHE_USED 0] 1]
44   db eval {
45     CREATE TABLE t2(y);
46   }
47   set sz2 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_CACHE_USED 0] 1]
48   set ::PAGESZ [expr {$sz2-$sz1}]
49   set ::BASESZ [expr {$sz1-$::PAGESZ}]
50   expr {$::PAGESZ>1024 && $::PAGESZ<1300}
51 } {1}
52 do_test dbstatus-1.2 {
53   db eval {
54     INSERT INTO t1 VALUES(zeroblob(9000));
55   }
56   lindex [sqlite3_db_status db SQLITE_DBSTATUS_CACHE_USED 0] 1
57 } [expr {$BASESZ + 10*$PAGESZ}]
60 proc lookaside {db} {
61   expr { $::lookaside_buffer_size *
62     [lindex [sqlite3_db_status $db SQLITE_DBSTATUS_LOOKASIDE_USED 0] 1]
63   }
66 ifcapable stat4 {
67   set STAT3 1
68 } else {
69   set STAT3 0
72 #---------------------------------------------------------------------------
73 # Run the dbstatus-2 and dbstatus-3 tests with several of different
74 # lookaside buffer sizes.
76 foreach ::lookaside_buffer_size {0 64 120} {
77   ifcapable malloc_usable_size break
79   # Do not run any of these tests if there is SQL configured to run
80   # as part of the [sqlite3] command. This prevents the script from
81   # configuring the size of the lookaside buffer after [sqlite3] has
82   # returned.
83   if {[presql] != ""} break
85   #-------------------------------------------------------------------------
86   # Tests for SQLITE_DBSTATUS_SCHEMA_USED.
87   #
88   # Each test in the following block works as follows. Each test uses a
89   # different database schema.
90   #
91   #   1. Open a connection to an empty database. Disable statement caching.
92   #
93   #   2. Execute the SQL to create the database schema. Measure the total 
94   #      heap and lookaside memory allocated by SQLite, and the memory 
95   #      allocated for the database schema according to sqlite3_db_status().
96   #
97   #   3. Drop all tables in the database schema. Measure the total memory 
98   #      and the schema memory again.
99   #
100   #   4. Repeat step 2.
101   #
102   #   5. Repeat step 3.
103   #
104   # Then test that:
105   #
106   #   a) The difference in schema memory quantities in steps 2 and 3 is the
107   #      same as the difference in total memory in steps 2 and 3.
108   #
109   #   b) Step 4 reports the same amount of schema and total memory used as
110   #      in step 2.
111   #
112   #   c) Step 5 reports the same amount of schema and total memory used as
113   #      in step 3.
114   #
115   foreach {tn schema} { 
116     1 { CREATE TABLE t1(a, b) }
117     2 { CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1, c UNIQUE) }
118     3 {
119       CREATE TABLE t1(a, b);
120       CREATE INDEX i1 ON t1(a, b);
121     }
122     4 {
123       CREATE TABLE t1(a, b);
124       CREATE TABLE t2(c, d);
125       CREATE TRIGGER AFTER INSERT ON t1 BEGIN
126         INSERT INTO t2 VALUES(new.a, new.b);
127         SELECT * FROM t1, t2 WHERE a=c AND b=d GROUP BY b HAVING a>5 ORDER BY a;
128       END;
129     }
130     5 {
131       CREATE TABLE t1(a, b);
132       CREATE TABLE t2(c, d);
133       CREATE VIEW v1 AS SELECT * FROM t1 UNION SELECT * FROM t2;
134     }
135     6k {
136       CREATE TABLE t1(a, b);
137       CREATE INDEX i1 ON t1(a);
138       CREATE INDEX i2 ON t1(a,b);
139       CREATE INDEX i3 ON t1(b,b);
140       INSERT INTO t1 VALUES(randomblob(20), randomblob(25));
141       INSERT INTO t1 SELECT randomblob(20), randomblob(25) FROM t1;
142       INSERT INTO t1 SELECT randomblob(20), randomblob(25) FROM t1;
143       INSERT INTO t1 SELECT randomblob(20), randomblob(25) FROM t1;
144       ANALYZE;
145     }
146     7 {
147       CREATE TABLE t1(a, b);
148       CREATE TABLE t2(c, d);
149       CREATE VIEW v1 AS 
150         SELECT * FROM t1 
151         UNION 
152         SELECT * FROM t2
153         UNION ALL
154         SELECT c||b, d||a FROM t2 LEFT OUTER JOIN t1 GROUP BY c, d
155         ORDER BY 1, 2
156       ;
157       CREATE TRIGGER tr1 INSTEAD OF INSERT ON v1 BEGIN
158         SELECT * FROM v1;
159         UPDATE t1 SET a=5, b=(SELECT c FROM t2);
160       END;
161       SELECT * FROM v1;
162     }
163     8x {
164       CREATE TABLE t1(a, b, UNIQUE(a, b));
165       CREATE VIRTUAL TABLE t2 USING echo(t1);
166     }
167   } {
168     set tn "$::lookaside_buffer_size-$tn"
169   
170     # Step 1.
171     db close
172     forcedelete test.db
173     sqlite3 db test.db
174     sqlite3_db_config_lookaside db 0 $::lookaside_buffer_size 500
175     db cache size 0
177     catch { register_echo_module db }
178     ifcapable !vtab { if {[string match *x $tn]} continue }
179   
180     # Step 2.
181     execsql $schema
182     set nAlloc1  [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
183     incr nAlloc1 [lookaside db]
184     set nSchema1 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_SCHEMA_USED 0] 1]
185   
186     # Step 3.
187     drop_all_tables
188     set nAlloc2  [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
189     incr nAlloc2 [lookaside db]
190     set nSchema2 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_SCHEMA_USED 0] 1]
191   
192     # Step 4.
193     execsql $schema
194     set nAlloc3  [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
195     incr nAlloc3 [lookaside db]
196     set nSchema3 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_SCHEMA_USED 0] 1]
197     
198     # Step 5.
199     drop_all_tables
200     set nAlloc4  [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
201     incr nAlloc4 [lookaside db]
202     set nSchema4 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_SCHEMA_USED 0] 1]
203     set nFree [expr {$nAlloc1-$nAlloc2}]
204     
205     # Tests for which the test name ends in an "k" report slightly less
206     # memory than is actually freed when all schema items are finalized.
207     # This is because memory allocated by KeyInfo objects is no longer
208     # counted as "schema memory".
209     #
210     # Tests for which the test name ends in an "x" report slightly less
211     # memory than is actually freed when all schema items are finalized.
212     # This is because memory allocated by virtual table implementations
213     # for any reason is not counted as "schema memory".
214     #
215     # Additionally, in auto-vacuum mode, dropping tables and indexes causes
216     # the page-cache to shrink. So the amount of memory freed is always
217     # much greater than just that reported by DBSTATUS_SCHEMA_USED in this
218     # case.
219     #
220     # Some of the memory used for sqlite_stat4 is unaccounted for by
221     # dbstatus.
222     #
223     # Finally, on osx the estimate of memory used by the schema may be
224     # slightly low. 
225     #
226     if {[string match *k $tn]
227          || [string match *x $tn] || $AUTOVACUUM
228          || ([string match *y $tn] && $STAT3)
229          || ($::tcl_platform(os) == "Darwin")
230     } {
231       do_test dbstatus-2.$tn.ax { expr {($nSchema1-$nSchema2)<=$nFree} } 1
232     } else {
233       do_test dbstatus-2.$tn.a { expr {$nSchema1-$nSchema2} } $nFree
234     }
235   
236     do_test dbstatus-2.$tn.b { list $nAlloc1 $nSchema1 } "$nAlloc3 $nSchema3"
237     do_test dbstatus-2.$tn.c { list $nAlloc2 $nSchema2 } "$nAlloc4 $nSchema4"
238   }
239   
240   #-------------------------------------------------------------------------
241   # Tests for SQLITE_DBSTATUS_STMT_USED.
242   #
243   # Each test in the following block works as follows. Each test uses a
244   # different database schema.
245   #
246   #   1. Open a connection to an empty database. Initialized the database
247   #      schema.
248   #
249   #   2. Prepare a bunch of SQL statements. Measure the total heap and 
250   #      lookaside memory allocated by SQLite, and the memory allocated 
251   #      for the prepared statements according to sqlite3_db_status().
252   #
253   #   3. Finalize all prepared statements. Measure the total memory 
254   #      and the prepared statement memory again.
255   #
256   #   4. Repeat step 2.
257   #
258   #   5. Repeat step 3.
259   #
260   # Then test that:
261   #
262   #   a) The difference in schema memory quantities in steps 2 and 3 is the
263   #      same as the difference in total memory in steps 2 and 3.
264   #
265   #   b) Step 4 reports the same amount of schema and total memory used as
266   #      in step 2.
267   #
268   #   c) Step 5 reports the same amount of schema and total memory used as
269   #      in step 3.
270   #
271   foreach {tn schema statements} { 
272     1 { CREATE TABLE t1(a, b) } {
273       SELECT * FROM t1;
274       INSERT INTO t1 VALUES(1, 2);
275       INSERT INTO t1 SELECT * FROM t1;
276       UPDATE t1 SET a=5;
277       DELETE FROM t1;
278     }
279     2 {
280       PRAGMA recursive_triggers = 1;
281       CREATE TABLE t1(a, b);
282       CREATE TRIGGER tr1 AFTER INSERT ON t1 WHEN (new.a>0) BEGIN
283         INSERT INTO t1 VALUES(new.a-1, new.b);
284       END;
285     } {
286       INSERT INTO t1 VALUES(5, 'x');
287     } 
288     3 {
289       PRAGMA recursive_triggers = 1;
290       CREATE TABLE t1(a, b);
291       CREATE TABLE t2(a, b);
292       CREATE TRIGGER tr1 AFTER INSERT ON t1 WHEN (new.a>0) BEGIN
293         INSERT INTO t2 VALUES(new.a-1, new.b);
294       END;
295       CREATE TRIGGER tr2 AFTER INSERT ON t1 WHEN (new.a>0) BEGIN
296         INSERT INTO t1 VALUES(new.a-1, new.b);
297       END;
298     } {
299       INSERT INTO t1 VALUES(10, 'x');
300     } 
301     4 {
302       CREATE TABLE t1(a, b);
303     } {
304       SELECT count(*) FROM t1 WHERE upper(a)='ABC';
305     }
306     5x {
307       CREATE TABLE t1(a, b UNIQUE);
308       CREATE VIRTUAL TABLE t2 USING echo(t1);
309     } {
310       SELECT count(*) FROM t2;
311       SELECT * FROM t2 WHERE b>5;
312       SELECT * FROM t2 WHERE b='abcdefg';
313     }
314   } {
315     set tn "$::lookaside_buffer_size-$tn"
317     # Step 1.
318     db close
319     forcedelete test.db
320     sqlite3 db test.db
321     sqlite3_db_config_lookaside db 0 $::lookaside_buffer_size 500
322     db cache size 1000
324     catch { register_echo_module db }
325     ifcapable !vtab { if {[string match *x $tn]} continue }
326   
327     execsql $schema
328     db cache flush
329   
330     # Step 2.
331     execsql $statements
332     set nAlloc1  [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
333     incr nAlloc1 [lookaside db]
334     set nStmt1   [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1]
335     execsql $statements
336   
337     # Step 3.
338     db cache flush
339     set nAlloc2  [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
340     incr nAlloc2 [lookaside db]
341     set nStmt2   [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1]
342     
343     # Step 3.
344     execsql $statements
345     set nAlloc3  [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
346     incr nAlloc3 [lookaside db]
347     set nStmt3   [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1]
348     execsql $statements
349   
350     # Step 4.
351     db cache flush
352     set nAlloc4  [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
353     incr nAlloc4 [lookaside db]
354     set nStmt4 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1]
355   
356     set nFree [expr {$nAlloc1-$nAlloc2}]
358     do_test dbstatus-3.$tn.a { expr $nStmt2 } {0}
360     # Tests for which the test name ends in an "x" report slightly less
361     # memory than is actually freed when all statements are finalized.
362     # This is because a small amount of memory allocated by a virtual table
363     # implementation using sqlite3_mprintf() is technically considered
364     # external and so is not counted as "statement memory".
365     #
366 #puts "$nStmt1 $nFree"
367     if {[string match *x $tn]} {
368       do_test dbstatus-3.$tn.bx { expr $nStmt1<=$nFree }  {1}
369     } else {
370       do_test dbstatus-3.$tn.b { expr $nStmt1==$nFree } {1}
371     }
373     do_test dbstatus-3.$tn.c { list $nAlloc1 $nStmt1 } [list $nAlloc3 $nStmt3]
374     do_test dbstatus-3.$tn.d { list $nAlloc2 $nStmt2 } [list $nAlloc4 $nStmt4]
375   }
378 #-------------------------------------------------------------------------
379 # The following tests focus on DBSTATUS_CACHE_USED_SHARED
381 ifcapable shared_cache {
382   if {([permutation]=="memsys3"
383       || [permutation]=="memsys5"
384       || $::tcl_platform(os)=="Linux") && ![sqlite3 -has-codec]} {
385     proc do_cacheused_test {tn db res} {
386       set cu [sqlite3_db_status $db SQLITE_DBSTATUS_CACHE_USED 0]
387       set pcu [sqlite3_db_status $db SQLITE_DBSTATUS_CACHE_USED_SHARED 0]
388       set cu [lindex $cu 1]
389       set pcu [lindex $pcu 1]
390       uplevel [list do_test $tn [list list $cu $pcu] "#/$res/"]
391     }
392     reset_db
393     sqlite3 db file:test.db?cache=shared
394   
395     do_execsql_test 4.0 {
396       PRAGMA auto_vacuum=NONE;
397       CREATE TABLE t1(a, b, c);
398       INSERT INTO t1 VALUES(1, 2, 3);
399     }
400     do_cacheused_test 4.0.1 db { 4568 4568 }
401     do_execsql_test 4.1 {
402       CREATE TEMP TABLE tt(a, b, c);
403       INSERT INTO tt VALUES(1, 2, 3);
404     }
405     do_cacheused_test 4.1.1 db { 9000 9000 }
406   
407     sqlite3 db2 file:test.db?cache=shared
408     do_cacheused_test 4.2.1 db2 { 4568 2284 }
409     do_cacheused_test 4.2.2 db { 9000 6716 }
410     db close
411     do_cacheused_test 4.2.3 db2 { 4568 4568 }
412     sqlite3 db file:test.db?cache=shared
413     do_cacheused_test 4.2.4 db2 { 4568 2284 }
414     db2 close
415   }
418 #-------------------------------------------------------------------------
419 # Test that passing an out-of-range value to sqlite3_stmt_status does
420 # not cause a crash.
421 reset_db
422 do_execsql_test 5.0 {
423   CREATE TABLE t1(x, y);
424   INSERT INTO t1 VALUES(1, 2);
425   INSERT INTO t1 VALUES(3, 4);
428 do_test 5.1 {
429   set ::stmt [sqlite3_prepare db "SELECT * FROM t1" -1 dummy]
430   sqlite3_step $::stmt
431   sqlite3_step $::stmt
432   sqlite3_step $::stmt
433   sqlite3_reset $::stmt
434 } {SQLITE_OK}
436 ifcapable api_armor {
437   do_test 5.2 { sqlite3_stmt_status $::stmt -1 0 } 0
439 do_test 5.3 { sqlite3_stmt_status $::stmt  0 0 } 0
440 do_test 5.4 { 
441   expr [sqlite3_stmt_status $::stmt 99 0]>0 
442 } 1
443 foreach {tn id res} {
444   1 SQLITE_STMTSTATUS_MEMUSED 1
445   2 SQLITE_STMTSTATUS_FULLSCAN_STEP 1
446   3 SQLITE_STMTSTATUS_SORT 0
447   4 SQLITE_STMTSTATUS_AUTOINDEX 0
448   5 SQLITE_STMTSTATUS_VM_STEP 1
449   6 SQLITE_STMTSTATUS_REPREPARE 0
450   7 SQLITE_STMTSTATUS_RUN 1
451 } {
452 if {$tn==2} breakpoint
453   do_test 5.5.$tn { expr [sqlite3_stmt_status $::stmt $id 0]>0 } $res
456 sqlite3_finalize $::stmt
457 finish_test