xref: /sqlite-3.40.0/test/dbstatus.test (revision 175b8f06)
1# 2010 March 10
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# Tests for the sqlite3_db_status() function
13#
14
15set testdir [file dirname $argv0]
16source $testdir/tester.tcl
17set testprefix dbstatus
18
19ifcapable !compound {
20  finish_test
21  return
22}
23
24# Memory statistics must be enabled for this test.
25db close
26sqlite3_shutdown
27sqlite3_config_memstatus 1
28sqlite3_config_uri 1
29sqlite3_initialize
30sqlite3 db test.db
31
32
33# Make sure sqlite3_db_config() and sqlite3_db_status are working.
34#
35unset -nocomplain PAGESZ
36unset -nocomplain BASESZ
37do_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}
52do_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}]
58
59
60proc lookaside {db} {
61  expr { $::lookaside_buffer_size *
62    [lindex [sqlite3_db_status $db SQLITE_DBSTATUS_LOOKASIDE_USED 0] 1]
63  }
64}
65
66ifcapable stat4 {
67  set STAT3 1
68} else {
69  set STAT3 0
70}
71
72#---------------------------------------------------------------------------
73# Run the dbstatus-2 and dbstatus-3 tests with several of different
74# lookaside buffer sizes.
75#
76foreach ::lookaside_buffer_size {0 64 120} {
77  ifcapable malloc_usable_size break
78
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
84
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
176
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"
316
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
323
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}]
357
358    do_test dbstatus-3.$tn.a { expr $nStmt2 } {0}
359
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    }
372
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  }
376}
377
378#-------------------------------------------------------------------------
379# The following tests focus on DBSTATUS_CACHE_USED_SHARED
380#
381ifcapable 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  }
416}
417
418#-------------------------------------------------------------------------
419# Test that passing an out-of-range value to sqlite3_stmt_status does
420# not cause a crash.
421reset_db
422do_execsql_test 5.0 {
423  CREATE TABLE t1(x, y);
424  INSERT INTO t1 VALUES(1, 2);
425  INSERT INTO t1 VALUES(3, 4);
426}
427
428do_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}
435
436ifcapable api_armor {
437  do_test 5.2 { sqlite3_stmt_status $::stmt -1 0 } 0
438}
439do_test 5.3 { sqlite3_stmt_status $::stmt  0 0 } 0
440do_test 5.4 {
441  expr [sqlite3_stmt_status $::stmt 99 0]>0
442} 1
443foreach {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} {
452if {$tn==2} breakpoint
453  do_test 5.5.$tn { expr [sqlite3_stmt_status $::stmt $id 0]>0 } $res
454}
455
456sqlite3_finalize $::stmt
457finish_test
458