| OLD | NEW |
| (Empty) |
| 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 ifcapable !compound { | |
| 19 finish_test | |
| 20 return | |
| 21 } | |
| 22 | |
| 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 | |
| 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}] | |
| 48 expr {$::PAGESZ>1024 && $::PAGESZ<1300} | |
| 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 | |
| 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 | |
| 64 ifcapable stat4||stat3 { | |
| 65 set STAT3 1 | |
| 66 } else { | |
| 67 set STAT3 0 | |
| 68 } | |
| 69 | |
| 70 ifcapable 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 # | |
| 79 foreach ::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 6k { | |
| 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 "k" report slightly less | |
| 208 # memory than is actually freed when all schema items are finalized. | |
| 209 # This is because memory allocated by KeyInfo objects is no longer | |
| 210 # counted as "schema memory". | |
| 211 # | |
| 212 # Tests for which the test name ends in an "x" report slightly less | |
| 213 # memory than is actually freed when all schema items are finalized. | |
| 214 # This is because memory allocated by virtual table implementations | |
| 215 # for any reason is not counted as "schema memory". | |
| 216 # | |
| 217 # Additionally, in auto-vacuum mode, dropping tables and indexes causes | |
| 218 # the page-cache to shrink. So the amount of memory freed is always | |
| 219 # much greater than just that reported by DBSTATUS_SCHEMA_USED in this | |
| 220 # case. | |
| 221 # | |
| 222 # Some of the memory used for sqlite_stat4 is unaccounted for by | |
| 223 # dbstatus. | |
| 224 # | |
| 225 # Finally, on osx the estimate of memory used by the schema may be | |
| 226 # slightly low. | |
| 227 # | |
| 228 if {[string match *k $tn] | |
| 229 || [string match *x $tn] || $AUTOVACUUM | |
| 230 || ([string match *y $tn] && $STAT3) | |
| 231 || ($::tcl_platform(os) == "Darwin") | |
| 232 } { | |
| 233 do_test dbstatus-2.$tn.ax { expr {($nSchema1-$nSchema2)<=$nFree} } 1 | |
| 234 } else { | |
| 235 do_test dbstatus-2.$tn.a { expr {$nSchema1-$nSchema2} } $nFree | |
| 236 } | |
| 237 | |
| 238 do_test dbstatus-2.$tn.b { list $nAlloc1 $nSchema1 } "$nAlloc3 $nSchema3" | |
| 239 do_test dbstatus-2.$tn.c { list $nAlloc2 $nSchema2 } "$nAlloc4 $nSchema4" | |
| 240 } | |
| 241 | |
| 242 #------------------------------------------------------------------------- | |
| 243 # Tests for SQLITE_DBSTATUS_STMT_USED. | |
| 244 # | |
| 245 # Each test in the following block works as follows. Each test uses a | |
| 246 # different database schema. | |
| 247 # | |
| 248 # 1. Open a connection to an empty database. Initialized the database | |
| 249 # schema. | |
| 250 # | |
| 251 # 2. Prepare a bunch of SQL statements. Measure the total heap and | |
| 252 # lookaside memory allocated by SQLite, and the memory allocated | |
| 253 # for the prepared statements according to sqlite3_db_status(). | |
| 254 # | |
| 255 # 3. Finalize all prepared statements. Measure the total memory | |
| 256 # and the prepared statement memory again. | |
| 257 # | |
| 258 # 4. Repeat step 2. | |
| 259 # | |
| 260 # 5. Repeat step 3. | |
| 261 # | |
| 262 # Then test that: | |
| 263 # | |
| 264 # a) The difference in schema memory quantities in steps 2 and 3 is the | |
| 265 # same as the difference in total memory in steps 2 and 3. | |
| 266 # | |
| 267 # b) Step 4 reports the same amount of schema and total memory used as | |
| 268 # in step 2. | |
| 269 # | |
| 270 # c) Step 5 reports the same amount of schema and total memory used as | |
| 271 # in step 3. | |
| 272 # | |
| 273 foreach {tn schema statements} { | |
| 274 1 { CREATE TABLE t1(a, b) } { | |
| 275 SELECT * FROM t1; | |
| 276 INSERT INTO t1 VALUES(1, 2); | |
| 277 INSERT INTO t1 SELECT * FROM t1; | |
| 278 UPDATE t1 SET a=5; | |
| 279 DELETE FROM t1; | |
| 280 } | |
| 281 2 { | |
| 282 PRAGMA recursive_triggers = 1; | |
| 283 CREATE TABLE t1(a, b); | |
| 284 CREATE TRIGGER tr1 AFTER INSERT ON t1 WHEN (new.a>0) BEGIN | |
| 285 INSERT INTO t1 VALUES(new.a-1, new.b); | |
| 286 END; | |
| 287 } { | |
| 288 INSERT INTO t1 VALUES(5, 'x'); | |
| 289 } | |
| 290 3 { | |
| 291 PRAGMA recursive_triggers = 1; | |
| 292 CREATE TABLE t1(a, b); | |
| 293 CREATE TABLE t2(a, b); | |
| 294 CREATE TRIGGER tr1 AFTER INSERT ON t1 WHEN (new.a>0) BEGIN | |
| 295 INSERT INTO t2 VALUES(new.a-1, new.b); | |
| 296 END; | |
| 297 CREATE TRIGGER tr2 AFTER INSERT ON t1 WHEN (new.a>0) BEGIN | |
| 298 INSERT INTO t1 VALUES(new.a-1, new.b); | |
| 299 END; | |
| 300 } { | |
| 301 INSERT INTO t1 VALUES(10, 'x'); | |
| 302 } | |
| 303 4 { | |
| 304 CREATE TABLE t1(a, b); | |
| 305 } { | |
| 306 SELECT count(*) FROM t1 WHERE upper(a)='ABC'; | |
| 307 } | |
| 308 5x { | |
| 309 CREATE TABLE t1(a, b UNIQUE); | |
| 310 CREATE VIRTUAL TABLE t2 USING echo(t1); | |
| 311 } { | |
| 312 SELECT count(*) FROM t2; | |
| 313 SELECT * FROM t2 WHERE b>5; | |
| 314 SELECT * FROM t2 WHERE b='abcdefg'; | |
| 315 } | |
| 316 } { | |
| 317 set tn "$::lookaside_buffer_size-$tn" | |
| 318 | |
| 319 # Step 1. | |
| 320 db close | |
| 321 forcedelete test.db | |
| 322 sqlite3 db test.db | |
| 323 sqlite3_db_config_lookaside db 0 $::lookaside_buffer_size 500 | |
| 324 db cache size 1000 | |
| 325 | |
| 326 catch { register_echo_module db } | |
| 327 ifcapable !vtab { if {[string match *x $tn]} continue } | |
| 328 | |
| 329 execsql $schema | |
| 330 db cache flush | |
| 331 | |
| 332 # Step 2. | |
| 333 execsql $statements | |
| 334 set nAlloc1 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1] | |
| 335 incr nAlloc1 [lookaside db] | |
| 336 set nStmt1 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1] | |
| 337 execsql $statements | |
| 338 | |
| 339 # Step 3. | |
| 340 db cache flush | |
| 341 set nAlloc2 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1] | |
| 342 incr nAlloc2 [lookaside db] | |
| 343 set nStmt2 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1] | |
| 344 | |
| 345 # Step 3. | |
| 346 execsql $statements | |
| 347 set nAlloc3 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1] | |
| 348 incr nAlloc3 [lookaside db] | |
| 349 set nStmt3 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1] | |
| 350 execsql $statements | |
| 351 | |
| 352 # Step 4. | |
| 353 db cache flush | |
| 354 set nAlloc4 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1] | |
| 355 incr nAlloc4 [lookaside db] | |
| 356 set nStmt4 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1] | |
| 357 | |
| 358 set nFree [expr {$nAlloc1-$nAlloc2}] | |
| 359 | |
| 360 do_test dbstatus-3.$tn.a { expr $nStmt2 } {0} | |
| 361 | |
| 362 # Tests for which the test name ends in an "x" report slightly less | |
| 363 # memory than is actually freed when all statements are finalized. | |
| 364 # This is because a small amount of memory allocated by a virtual table | |
| 365 # implementation using sqlite3_mprintf() is technically considered | |
| 366 # external and so is not counted as "statement memory". | |
| 367 # | |
| 368 #puts "$nStmt1 $nFree" | |
| 369 if {[string match *x $tn]} { | |
| 370 do_test dbstatus-3.$tn.bx { expr $nStmt1<=$nFree } {1} | |
| 371 } else { | |
| 372 do_test dbstatus-3.$tn.b { expr $nStmt1==$nFree } {1} | |
| 373 } | |
| 374 | |
| 375 do_test dbstatus-3.$tn.c { list $nAlloc1 $nStmt1 } [list $nAlloc3 $nStmt3] | |
| 376 do_test dbstatus-3.$tn.d { list $nAlloc2 $nStmt2 } [list $nAlloc4 $nStmt4] | |
| 377 } | |
| 378 } | |
| 379 | |
| 380 finish_test | |
| OLD | NEW |