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