xref: /sqlite-3.40.0/test/dbstatus.test (revision f52bb8d3)
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
17
18ifcapable !compound {
19  finish_test
20  return
21}
22
23# Memory statistics must be enabled for this test.
24db close
25sqlite3_shutdown
26sqlite3_config_memstatus 1
27sqlite3_initialize
28sqlite3 db test.db
29
30
31# Make sure sqlite3_db_config() and sqlite3_db_status are working.
32#
33unset -nocomplain PAGESZ
34unset -nocomplain BASESZ
35do_test dbstatus-1.1 {
36  db close
37  sqlite3 db :memory:
38  db eval {
39    CREATE TABLE t1(x);
40  }
41  set sz1 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_CACHE_USED 0] 1]
42  db eval {
43    CREATE TABLE t2(y);
44  }
45  set sz2 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_CACHE_USED 0] 1]
46  set ::PAGESZ [expr {$sz2-$sz1}]
47  set ::BASESZ [expr {$sz1-$::PAGESZ}]
48  expr {$::PAGESZ>1024 && $::PAGESZ<1300}
49} {1}
50do_test dbstatus-1.2 {
51  db eval {
52    INSERT INTO t1 VALUES(zeroblob(9000));
53  }
54  lindex [sqlite3_db_status db SQLITE_DBSTATUS_CACHE_USED 0] 1
55} [expr {$BASESZ + 10*$PAGESZ}]
56
57
58proc lookaside {db} {
59  expr { $::lookaside_buffer_size *
60    [lindex [sqlite3_db_status $db SQLITE_DBSTATUS_LOOKASIDE_USED 0] 1]
61  }
62}
63
64ifcapable stat4 {
65  set STAT3 1
66} else {
67  set STAT3 0
68}
69
70ifcapable malloc_usable_size {
71  finish_test
72  return
73}
74
75#---------------------------------------------------------------------------
76# Run the dbstatus-2 and dbstatus-3 tests with several of different
77# lookaside buffer sizes.
78#
79foreach ::lookaside_buffer_size {0 64 120} {
80
81  # Do not run any of these tests if there is SQL configured to run
82  # as part of the [sqlite3] command. This prevents the script from
83  # configuring the size of the lookaside buffer after [sqlite3] has
84  # returned.
85  if {[presql] != ""} break
86
87  #-------------------------------------------------------------------------
88  # Tests for SQLITE_DBSTATUS_SCHEMA_USED.
89  #
90  # Each test in the following block works as follows. Each test uses a
91  # different database schema.
92  #
93  #   1. Open a connection to an empty database. Disable statement caching.
94  #
95  #   2. Execute the SQL to create the database schema. Measure the total
96  #      heap and lookaside memory allocated by SQLite, and the memory
97  #      allocated for the database schema according to sqlite3_db_status().
98  #
99  #   3. Drop all tables in the database schema. Measure the total memory
100  #      and the schema memory again.
101  #
102  #   4. Repeat step 2.
103  #
104  #   5. Repeat step 3.
105  #
106  # Then test that:
107  #
108  #   a) The difference in schema memory quantities in steps 2 and 3 is the
109  #      same as the difference in total memory in steps 2 and 3.
110  #
111  #   b) Step 4 reports the same amount of schema and total memory used as
112  #      in step 2.
113  #
114  #   c) Step 5 reports the same amount of schema and total memory used as
115  #      in step 3.
116  #
117  foreach {tn schema} {
118    1 { CREATE TABLE t1(a, b) }
119    2 { CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1, c UNIQUE) }
120    3 {
121      CREATE TABLE t1(a, b);
122      CREATE INDEX i1 ON t1(a, b);
123    }
124    4 {
125      CREATE TABLE t1(a, b);
126      CREATE TABLE t2(c, d);
127      CREATE TRIGGER AFTER INSERT ON t1 BEGIN
128        INSERT INTO t2 VALUES(new.a, new.b);
129        SELECT * FROM t1, t2 WHERE a=c AND b=d GROUP BY b HAVING a>5 ORDER BY a;
130      END;
131    }
132    5 {
133      CREATE TABLE t1(a, b);
134      CREATE TABLE t2(c, d);
135      CREATE VIEW v1 AS SELECT * FROM t1 UNION SELECT * FROM t2;
136    }
137    6y {
138      CREATE TABLE t1(a, b);
139      CREATE INDEX i1 ON t1(a);
140      CREATE INDEX i2 ON t1(a,b);
141      CREATE INDEX i3 ON t1(b,b);
142      INSERT INTO t1 VALUES(randomblob(20), randomblob(25));
143      INSERT INTO t1 SELECT randomblob(20), randomblob(25) FROM t1;
144      INSERT INTO t1 SELECT randomblob(20), randomblob(25) FROM t1;
145      INSERT INTO t1 SELECT randomblob(20), randomblob(25) FROM t1;
146      ANALYZE;
147    }
148    7 {
149      CREATE TABLE t1(a, b);
150      CREATE TABLE t2(c, d);
151      CREATE VIEW v1 AS
152        SELECT * FROM t1
153        UNION
154        SELECT * FROM t2
155        UNION ALL
156        SELECT c||b, d||a FROM t2 LEFT OUTER JOIN t1 GROUP BY c, d
157        ORDER BY 1, 2
158      ;
159      CREATE TRIGGER tr1 INSTEAD OF INSERT ON v1 BEGIN
160        SELECT * FROM v1;
161        UPDATE t1 SET a=5, b=(SELECT c FROM t2);
162      END;
163      SELECT * FROM v1;
164    }
165    8x {
166      CREATE TABLE t1(a, b, UNIQUE(a, b));
167      CREATE VIRTUAL TABLE t2 USING echo(t1);
168    }
169  } {
170    set tn "$::lookaside_buffer_size-$tn"
171
172    # Step 1.
173    db close
174    forcedelete test.db
175    sqlite3 db test.db
176    sqlite3_db_config_lookaside db 0 $::lookaside_buffer_size 500
177    db cache size 0
178
179    catch { register_echo_module db }
180    ifcapable !vtab { if {[string match *x $tn]} continue }
181
182    # Step 2.
183    execsql $schema
184    set nAlloc1  [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
185    incr nAlloc1 [lookaside db]
186    set nSchema1 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_SCHEMA_USED 0] 1]
187
188    # Step 3.
189    drop_all_tables
190    set nAlloc2  [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
191    incr nAlloc2 [lookaside db]
192    set nSchema2 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_SCHEMA_USED 0] 1]
193
194    # Step 4.
195    execsql $schema
196    set nAlloc3  [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
197    incr nAlloc3 [lookaside db]
198    set nSchema3 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_SCHEMA_USED 0] 1]
199
200    # Step 5.
201    drop_all_tables
202    set nAlloc4  [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
203    incr nAlloc4 [lookaside db]
204    set nSchema4 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_SCHEMA_USED 0] 1]
205    set nFree [expr {$nAlloc1-$nAlloc2}]
206
207    # Tests for which the test name ends in an "x" report slightly less
208    # memory than is actually freed when all schema items are finalized.
209    # This is because memory allocated by virtual table implementations
210    # for any reason is not counted as "schema memory".
211    #
212    # Additionally, in auto-vacuum mode, dropping tables and indexes causes
213    # the page-cache to shrink. So the amount of memory freed is always
214    # much greater than just that reported by DBSTATUS_SCHEMA_USED in this
215    # case.
216    #
217    # Some of the memory used for sqlite_stat4 is unaccounted for by
218    # dbstatus.
219    #
220    # Finally, on osx the estimate of memory used by the schema may be
221    # slightly low.
222    #
223    if {[string match *x $tn] || $AUTOVACUUM
224         || ([string match *y $tn] && $STAT3)
225         || ($::tcl_platform(os) == "Darwin")
226    } {
227      do_test dbstatus-2.$tn.ax { expr {($nSchema1-$nSchema2)<=$nFree} } 1
228    } else {
229      do_test dbstatus-2.$tn.a { expr {$nSchema1-$nSchema2} } $nFree
230    }
231
232    do_test dbstatus-2.$tn.b { list $nAlloc1 $nSchema1 } "$nAlloc3 $nSchema3"
233    do_test dbstatus-2.$tn.c { list $nAlloc2 $nSchema2 } "$nAlloc4 $nSchema4"
234  }
235
236  #-------------------------------------------------------------------------
237  # Tests for SQLITE_DBSTATUS_STMT_USED.
238  #
239  # Each test in the following block works as follows. Each test uses a
240  # different database schema.
241  #
242  #   1. Open a connection to an empty database. Initialized the database
243  #      schema.
244  #
245  #   2. Prepare a bunch of SQL statements. Measure the total heap and
246  #      lookaside memory allocated by SQLite, and the memory allocated
247  #      for the prepared statements according to sqlite3_db_status().
248  #
249  #   3. Finalize all prepared statements Measure the total memory
250  #      and the prepared statement memory again.
251  #
252  #   4. Repeat step 2.
253  #
254  #   5. Repeat step 3.
255  #
256  # Then test that:
257  #
258  #   a) The difference in schema memory quantities in steps 2 and 3 is the
259  #      same as the difference in total memory in steps 2 and 3.
260  #
261  #   b) Step 4 reports the same amount of schema and total memory used as
262  #      in step 2.
263  #
264  #   c) Step 5 reports the same amount of schema and total memory used as
265  #      in step 3.
266  #
267  foreach {tn schema statements} {
268    1 { CREATE TABLE t1(a, b) } {
269      SELECT * FROM t1;
270      INSERT INTO t1 VALUES(1, 2);
271      INSERT INTO t1 SELECT * FROM t1;
272      UPDATE t1 SET a=5;
273      DELETE FROM t1;
274    }
275    2 {
276      PRAGMA recursive_triggers = 1;
277      CREATE TABLE t1(a, b);
278      CREATE TRIGGER tr1 AFTER INSERT ON t1 WHEN (new.a>0) BEGIN
279        INSERT INTO t1 VALUES(new.a-1, new.b);
280      END;
281    } {
282      INSERT INTO t1 VALUES(5, 'x');
283    }
284    3 {
285      PRAGMA recursive_triggers = 1;
286      CREATE TABLE t1(a, b);
287      CREATE TABLE t2(a, b);
288      CREATE TRIGGER tr1 AFTER INSERT ON t1 WHEN (new.a>0) BEGIN
289        INSERT INTO t2 VALUES(new.a-1, new.b);
290      END;
291      CREATE TRIGGER tr2 AFTER INSERT ON t1 WHEN (new.a>0) BEGIN
292        INSERT INTO t1 VALUES(new.a-1, new.b);
293      END;
294    } {
295      INSERT INTO t1 VALUES(10, 'x');
296    }
297    4 {
298      CREATE TABLE t1(a, b);
299    } {
300      SELECT count(*) FROM t1 WHERE upper(a)='ABC';
301    }
302    5x {
303      CREATE TABLE t1(a, b UNIQUE);
304      CREATE VIRTUAL TABLE t2 USING echo(t1);
305    } {
306      SELECT count(*) FROM t2;
307      SELECT * FROM t2 WHERE b>5;
308      SELECT * FROM t2 WHERE b='abcdefg';
309    }
310  } {
311    set tn "$::lookaside_buffer_size-$tn"
312
313    # Step 1.
314    db close
315    forcedelete test.db
316    sqlite3 db test.db
317    sqlite3_db_config_lookaside db 0 $::lookaside_buffer_size 500
318    db cache size 1000
319
320    catch { register_echo_module db }
321    ifcapable !vtab { if {[string match *x $tn]} continue }
322
323    execsql $schema
324    db cache flush
325
326    # Step 2.
327    execsql $statements
328    set nAlloc1  [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
329    incr nAlloc1 [lookaside db]
330    set nStmt1   [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1]
331    execsql $statements
332
333    # Step 3.
334    db cache flush
335    set nAlloc2  [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
336    incr nAlloc2 [lookaside db]
337    set nStmt2   [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1]
338
339    # Step 3.
340    execsql $statements
341    set nAlloc3  [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
342    incr nAlloc3 [lookaside db]
343    set nStmt3   [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1]
344    execsql $statements
345
346    # Step 4.
347    db cache flush
348    set nAlloc4  [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
349    incr nAlloc4 [lookaside db]
350    set nStmt4 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1]
351
352    set nFree [expr {$nAlloc1-$nAlloc2}]
353
354    do_test dbstatus-3.$tn.a { expr $nStmt2 } {0}
355
356    # Tests for which the test name ends in an "x" report slightly less
357    # memory than is actually freed when all statements are finalized.
358    # This is because a small amount of memory allocated by a virtual table
359    # implementation using sqlite3_mprintf() is technically considered
360    # external and so is not counted as "statement memory".
361    #
362#puts "$nStmt1 $nFree"
363    if {[string match *x $tn]} {
364      do_test dbstatus-3.$tn.bx { expr $nStmt1<=$nFree }  {1}
365    } else {
366      do_test dbstatus-3.$tn.b { expr $nStmt1==$nFree } {1}
367    }
368
369    do_test dbstatus-3.$tn.c { list $nAlloc1 $nStmt1 } [list $nAlloc3 $nStmt3]
370    do_test dbstatus-3.$tn.d { list $nAlloc2 $nStmt2 } [list $nAlloc4 $nStmt4]
371  }
372}
373
374finish_test
375