blob: 9793df3f4ea0f682d87177fd589d11825aacaae9 [file] [log] [blame]
drh63da0892010-03-10 21:42:07 +00001# 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
dan2f56da32012-02-13 10:00:35 +000018ifcapable !compound {
19 finish_test
20 return
21}
22
drh887f8d32010-09-09 17:43:06 +000023# Memory statistics must be enabled for this test.
24db close
25sqlite3_shutdown
26sqlite3_config_memstatus 1
27sqlite3_initialize
28sqlite3 db test.db
29
drh63da0892010-03-10 21:42:07 +000030
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}]
drh60a31172010-07-28 18:51:26 +000048 expr {$::PAGESZ>1024 && $::PAGESZ<1300}
drh63da0892010-03-10 21:42:07 +000049} {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
dand46def72010-07-24 11:28:28 +000057
58proc lookaside {db} {
59 expr { $::lookaside_buffer_size *
60 [lindex [sqlite3_db_status $db SQLITE_DBSTATUS_LOOKASIDE_USED 0] 1]
61 }
62}
63
drh4e50c5e2011-08-13 19:35:19 +000064ifcapable stat3 {
65 set STAT3 1
66} else {
67 set STAT3 0
68}
69
drh6a8ab6d2011-11-09 01:53:25 +000070ifcapable malloc_usable_size {
71 finish_test
72 return
73}
74
dand46def72010-07-24 11:28:28 +000075#---------------------------------------------------------------------------
drh643f35e2010-07-26 11:59:40 +000076# Run the dbstatus-2 and dbstatus-3 tests with several of different
dand46def72010-07-24 11:28:28 +000077# lookaside buffer sizes.
78#
79foreach ::lookaside_buffer_size {0 64 120} {
80
dan4f7b8d62010-08-06 14:37:13 +000081 # 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
dand46def72010-07-24 11:28:28 +000087 #-------------------------------------------------------------------------
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 }
drh4e50c5e2011-08-13 19:35:19 +0000137 6y {
dand46def72010-07-24 11:28:28 +0000138 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 }
danccd4ad32010-07-26 14:47:14 +0000165 8x {
166 CREATE TABLE t1(a, b, UNIQUE(a, b));
167 CREATE VIRTUAL TABLE t2 USING echo(t1);
168 }
dand46def72010-07-24 11:28:28 +0000169 } {
170 set tn "$::lookaside_buffer_size-$tn"
171
172 # Step 1.
173 db close
mistachkinfda06be2011-08-02 00:57:34 +0000174 forcedelete test.db
dand46def72010-07-24 11:28:28 +0000175 sqlite3 db test.db
176 sqlite3_db_config_lookaside db 0 $::lookaside_buffer_size 500
177 db cache size 0
danccd4ad32010-07-26 14:47:14 +0000178
179 catch { register_echo_module db }
180 ifcapable !vtab { if {[string match *x $tn]} continue }
dand46def72010-07-24 11:28:28 +0000181
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]
dand46def72010-07-24 11:28:28 +0000205 set nFree [expr {$nAlloc1-$nAlloc2}]
danccd4ad32010-07-26 14:47:14 +0000206
207 # Tests for which the test name ends in an "x" report slightly less
dand47f0d72010-08-11 11:35:50 +0000208 # 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".
danccd4ad32010-07-26 14:47:14 +0000211 #
dand47f0d72010-08-11 11:35:50 +0000212 # 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 #
drh4e50c5e2011-08-13 19:35:19 +0000217 # Some of the memory used for sqlite_stat3 is unaccounted for by
218 # dbstatus.
219 #
dan4373bb82011-12-30 16:09:50 +0000220 # Finally, on osx the estimate of memory used by the schema may be
221 # slightly low.
222 #
drh4e50c5e2011-08-13 19:35:19 +0000223 if {[string match *x $tn] || $AUTOVACUUM
dan4373bb82011-12-30 16:09:50 +0000224 || ([string match *y $tn] && $STAT3)
225 || ($::tcl_platform(os) == "Darwin")
226 } {
danccd4ad32010-07-26 14:47:14 +0000227 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
dand46def72010-07-24 11:28:28 +0000232 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 }
danccd4ad32010-07-26 14:47:14 +0000302 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 }
dand46def72010-07-24 11:28:28 +0000310 } {
311 set tn "$::lookaside_buffer_size-$tn"
312
313 # Step 1.
314 db close
mistachkinfda06be2011-08-02 00:57:34 +0000315 forcedelete test.db
dand46def72010-07-24 11:28:28 +0000316 sqlite3 db test.db
317 sqlite3_db_config_lookaside db 0 $::lookaside_buffer_size 500
318 db cache size 1000
danccd4ad32010-07-26 14:47:14 +0000319
320 catch { register_echo_module db }
321 ifcapable !vtab { if {[string match *x $tn]} continue }
dand46def72010-07-24 11:28:28 +0000322
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]
dan111becf2010-07-26 15:57:01 +0000336 incr nAlloc2 [lookaside db]
dand46def72010-07-24 11:28:28 +0000337 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}]
danccd4ad32010-07-26 14:47:14 +0000353
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 #
dand47f0d72010-08-11 11:35:50 +0000362#puts "$nStmt1 $nFree"
danccd4ad32010-07-26 14:47:14 +0000363 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
dand46def72010-07-24 11:28:28 +0000369 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
drh63da0892010-03-10 21:42:07 +0000374finish_test