drh | 63da089 | 2010-03-10 21:42:07 +0000 | [diff] [blame] | 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 | |
dan | 2f56da3 | 2012-02-13 10:00:35 +0000 | [diff] [blame] | 18 | ifcapable !compound { |
| 19 | finish_test |
| 20 | return |
| 21 | } |
| 22 | |
drh | 887f8d3 | 2010-09-09 17:43:06 +0000 | [diff] [blame] | 23 | # Memory statistics must be enabled for this test. |
| 24 | db close |
| 25 | sqlite3_shutdown |
| 26 | sqlite3_config_memstatus 1 |
| 27 | sqlite3_initialize |
| 28 | sqlite3 db test.db |
| 29 | |
drh | 63da089 | 2010-03-10 21:42:07 +0000 | [diff] [blame] | 30 | |
| 31 | # Make sure sqlite3_db_config() and sqlite3_db_status are working. |
| 32 | # |
| 33 | unset -nocomplain PAGESZ |
| 34 | unset -nocomplain BASESZ |
| 35 | do_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}] |
drh | 60a3117 | 2010-07-28 18:51:26 +0000 | [diff] [blame] | 48 | expr {$::PAGESZ>1024 && $::PAGESZ<1300} |
drh | 63da089 | 2010-03-10 21:42:07 +0000 | [diff] [blame] | 49 | } {1} |
| 50 | do_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 | |
dan | d46def7 | 2010-07-24 11:28:28 +0000 | [diff] [blame] | 57 | |
| 58 | proc lookaside {db} { |
| 59 | expr { $::lookaside_buffer_size * |
| 60 | [lindex [sqlite3_db_status $db SQLITE_DBSTATUS_LOOKASIDE_USED 0] 1] |
| 61 | } |
| 62 | } |
| 63 | |
drh | 4e50c5e | 2011-08-13 19:35:19 +0000 | [diff] [blame] | 64 | ifcapable stat3 { |
| 65 | set STAT3 1 |
| 66 | } else { |
| 67 | set STAT3 0 |
| 68 | } |
| 69 | |
drh | 6a8ab6d | 2011-11-09 01:53:25 +0000 | [diff] [blame] | 70 | ifcapable malloc_usable_size { |
| 71 | finish_test |
| 72 | return |
| 73 | } |
| 74 | |
dan | d46def7 | 2010-07-24 11:28:28 +0000 | [diff] [blame] | 75 | #--------------------------------------------------------------------------- |
drh | 643f35e | 2010-07-26 11:59:40 +0000 | [diff] [blame] | 76 | # Run the dbstatus-2 and dbstatus-3 tests with several of different |
dan | d46def7 | 2010-07-24 11:28:28 +0000 | [diff] [blame] | 77 | # lookaside buffer sizes. |
| 78 | # |
| 79 | foreach ::lookaside_buffer_size {0 64 120} { |
| 80 | |
dan | 4f7b8d6 | 2010-08-06 14:37:13 +0000 | [diff] [blame] | 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 | |
dan | d46def7 | 2010-07-24 11:28:28 +0000 | [diff] [blame] | 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 | } |
drh | 4e50c5e | 2011-08-13 19:35:19 +0000 | [diff] [blame] | 137 | 6y { |
dan | d46def7 | 2010-07-24 11:28:28 +0000 | [diff] [blame] | 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 | } |
dan | ccd4ad3 | 2010-07-26 14:47:14 +0000 | [diff] [blame] | 165 | 8x { |
| 166 | CREATE TABLE t1(a, b, UNIQUE(a, b)); |
| 167 | CREATE VIRTUAL TABLE t2 USING echo(t1); |
| 168 | } |
dan | d46def7 | 2010-07-24 11:28:28 +0000 | [diff] [blame] | 169 | } { |
| 170 | set tn "$::lookaside_buffer_size-$tn" |
| 171 | |
| 172 | # Step 1. |
| 173 | db close |
mistachkin | fda06be | 2011-08-02 00:57:34 +0000 | [diff] [blame] | 174 | forcedelete test.db |
dan | d46def7 | 2010-07-24 11:28:28 +0000 | [diff] [blame] | 175 | sqlite3 db test.db |
| 176 | sqlite3_db_config_lookaside db 0 $::lookaside_buffer_size 500 |
| 177 | db cache size 0 |
dan | ccd4ad3 | 2010-07-26 14:47:14 +0000 | [diff] [blame] | 178 | |
| 179 | catch { register_echo_module db } |
| 180 | ifcapable !vtab { if {[string match *x $tn]} continue } |
dan | d46def7 | 2010-07-24 11:28:28 +0000 | [diff] [blame] | 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] |
dan | d46def7 | 2010-07-24 11:28:28 +0000 | [diff] [blame] | 205 | set nFree [expr {$nAlloc1-$nAlloc2}] |
dan | ccd4ad3 | 2010-07-26 14:47:14 +0000 | [diff] [blame] | 206 | |
| 207 | # Tests for which the test name ends in an "x" report slightly less |
dan | d47f0d7 | 2010-08-11 11:35:50 +0000 | [diff] [blame] | 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". |
dan | ccd4ad3 | 2010-07-26 14:47:14 +0000 | [diff] [blame] | 211 | # |
dan | d47f0d7 | 2010-08-11 11:35:50 +0000 | [diff] [blame] | 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 | # |
drh | 4e50c5e | 2011-08-13 19:35:19 +0000 | [diff] [blame] | 217 | # Some of the memory used for sqlite_stat3 is unaccounted for by |
| 218 | # dbstatus. |
| 219 | # |
dan | 4373bb8 | 2011-12-30 16:09:50 +0000 | [diff] [blame] | 220 | # Finally, on osx the estimate of memory used by the schema may be |
| 221 | # slightly low. |
| 222 | # |
drh | 4e50c5e | 2011-08-13 19:35:19 +0000 | [diff] [blame] | 223 | if {[string match *x $tn] || $AUTOVACUUM |
dan | 4373bb8 | 2011-12-30 16:09:50 +0000 | [diff] [blame] | 224 | || ([string match *y $tn] && $STAT3) |
| 225 | || ($::tcl_platform(os) == "Darwin") |
| 226 | } { |
dan | ccd4ad3 | 2010-07-26 14:47:14 +0000 | [diff] [blame] | 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 | |
dan | d46def7 | 2010-07-24 11:28:28 +0000 | [diff] [blame] | 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 | } |
dan | ccd4ad3 | 2010-07-26 14:47:14 +0000 | [diff] [blame] | 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 | } |
dan | d46def7 | 2010-07-24 11:28:28 +0000 | [diff] [blame] | 310 | } { |
| 311 | set tn "$::lookaside_buffer_size-$tn" |
| 312 | |
| 313 | # Step 1. |
| 314 | db close |
mistachkin | fda06be | 2011-08-02 00:57:34 +0000 | [diff] [blame] | 315 | forcedelete test.db |
dan | d46def7 | 2010-07-24 11:28:28 +0000 | [diff] [blame] | 316 | sqlite3 db test.db |
| 317 | sqlite3_db_config_lookaside db 0 $::lookaside_buffer_size 500 |
| 318 | db cache size 1000 |
dan | ccd4ad3 | 2010-07-26 14:47:14 +0000 | [diff] [blame] | 319 | |
| 320 | catch { register_echo_module db } |
| 321 | ifcapable !vtab { if {[string match *x $tn]} continue } |
dan | d46def7 | 2010-07-24 11:28:28 +0000 | [diff] [blame] | 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] |
dan | 111becf | 2010-07-26 15:57:01 +0000 | [diff] [blame] | 336 | incr nAlloc2 [lookaside db] |
dan | d46def7 | 2010-07-24 11:28:28 +0000 | [diff] [blame] | 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}] |
dan | ccd4ad3 | 2010-07-26 14:47:14 +0000 | [diff] [blame] | 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 | # |
dan | d47f0d7 | 2010-08-11 11:35:50 +0000 | [diff] [blame] | 362 | #puts "$nStmt1 $nFree" |
dan | ccd4ad3 | 2010-07-26 14:47:14 +0000 | [diff] [blame] | 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 | |
dan | d46def7 | 2010-07-24 11:28:28 +0000 | [diff] [blame] | 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 | |
drh | 63da089 | 2010-03-10 21:42:07 +0000 | [diff] [blame] | 374 | finish_test |