1# 2010 September 1 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 13set testdir [file dirname $argv0] 14source $testdir/tester.tcl 15 16# If SQLITE_CURDIR is not defined, omit this file. 17ifcapable !curdir { 18 finish_test 19 return 20} 21 22source $testdir/malloc_common.tcl 23 24unset -nocomplain defaultVfs 25set defaultVfs [file_control_vfsname db] 26db close 27 28do_test quota-1.1 { sqlite3_quota_initialize nosuchvfs 1 } {SQLITE_ERROR} 29do_test quota-1.2 { sqlite3_quota_initialize "" 1 } {SQLITE_OK} 30do_test quota-1.3 { sqlite3_quota_initialize "" 1 } {SQLITE_MISUSE} 31do_test quota-1.4 { sqlite3_quota_shutdown } {SQLITE_OK} 32 33do_test quota-1.5 { sqlite3_quota_initialize "" 0 } {SQLITE_OK} 34do_test quota-1.6 { sqlite3_quota_shutdown } {SQLITE_OK} 35do_test quota-1.7 { sqlite3_quota_initialize "" 1 } {SQLITE_OK} 36do_test quota-1.8 { sqlite3_quota_shutdown } {SQLITE_OK} 37 38 39#------------------------------------------------------------------------- 40# Some simple warm-body tests with a single database file in rollback 41# mode: 42# 43# quota-2.1.*: Test that SQLITE_FULL is returned if the database would 44# exceed the configured quota. 45# 46# quota-2.2.*: Test that SQLITE_FULL is not returned and the database 47# grows if the callback extends the quota when the database 48# attempts to grow beyond the configured quota. 49# 50# quota-2.3.*: Open and close a db that is not part of any quota group. At 51# one point this was causing mutex refs to be leaked. 52# 53# quota-2.4.*: Try to shutdown the quota system before closing the db 54# file. Check that this fails and the quota system still works 55# afterwards. Then close the database and successfully shut 56# down the quota system. 57# 58sqlite3_quota_initialize "" 1 59 60unset -nocomplain quota_request_ok 61proc quota_check {filename limitvar size} { 62 upvar $limitvar limit 63 64 lappend ::quota [set limit] $size 65 if {[info exists ::quota_request_ok]} { set limit $size } 66} 67 68do_test quota-2.1.1 { 69 sqlite3_quota_set *test.db 4096 quota_check 70} {SQLITE_OK} 71do_test quota-2.1.2 { 72 sqlite3 db test.db 73 execsql { 74 PRAGMA page_size=1024; 75 PRAGMA auto_vacuum=OFF; 76 PRAGMA journal_mode=DELETE; 77 } 78 set ::quota [list] 79 execsql { 80 CREATE TABLE t1(a, b); 81 INSERT INTO t1 VALUES(1, randomblob(1100)); 82 INSERT INTO t1 VALUES(2, randomblob(1100)); 83 } 84 set ::quota 85} {} 86do_test quota-2.1.2.1 { 87 file_control_vfsname db 88} quota/$defaultVfs 89do_test quota-2.1.3 { file size test.db } {4096} 90do_test quota-2.1.4 { 91 catchsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } 92} {1 {database or disk is full}} 93do_test quota-2.1.5 { set ::quota } {4096 5120} 94 95set ::quota_request_ok 1 96set ::quota [list] 97do_test quota-2.2.1 { 98 execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } 99} {} 100do_test quota-2.2.2 { set ::quota } {4096 5120} 101do_test quota-2.2.3 { file size test.db } {5120} 102unset ::quota_request_ok 103 104do_test quota-2.3.1 { 105 sqlite3 db2 bak.db 106 db2 close 107} {} 108 109do_test quota-2.4.1 { 110 sqlite3_quota_shutdown 111} {SQLITE_MISUSE} 112set ::quota [list] 113do_test quota-2.4.2 { 114 catchsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } 115} {1 {database or disk is full}} 116do_test quota-2.4.3 { set ::quota } {5120 6144} 117do_test quota-2.4.4 { file size test.db } {5120} 118do_test quota-2.4.99 { 119 db close 120 sqlite3_quota_shutdown 121} {SQLITE_OK} 122 123#------------------------------------------------------------------------- 124# Try some tests with more than one connection to a database file. Still 125# in rollback mode. 126# 127# quota-3.1.*: Two connections to a single database file. 128# 129# quota-3.2.*: Two connections to each of several database files (that 130# are in the same quota group). 131# 132proc quota_check {filename limitvar size} { 133 upvar $limitvar limit 134 lappend ::quota [set limit] $size 135 if {[info exists ::quota_request_ok]} { set limit $size } 136} 137 138do_test quota-3.1.1 { 139 forcedelete test.db 140 sqlite3_quota_initialize "" 1 141 sqlite3_quota_set *test.db 4096 quota_check 142} {SQLITE_OK} 143do_test quota-3.1.2 { 144 sqlite3 db test.db 145 execsql { 146 PRAGMA page_size = 1024; 147 PRAGMA journal_mode = delete; 148 PRAGMA auto_vacuum = off; 149 CREATE TABLE t1(a PRIMARY KEY, b); 150 INSERT INTO t1 VALUES(1, 'one'); 151 } 152 file size test.db 153} {3072} 154do_test quota-3.1.3 { 155 sqlite3 db2 test.db 156 set ::quota [list] 157 execsql { CREATE TABLE t2(a, b) } db2 158 set ::quota 159} {} 160do_test quota-3.1.4 { 161 catchsql { CREATE TABLE t3(a, b) } 162} {1 {database or disk is full}} 163do_test quota-3.1.5 { 164 set ::quota_request_ok 1 165 execsql { CREATE TABLE t3(a, b) } 166} {} 167do_test quota-3.1.6 { 168 db close 169 db2 close 170 sqlite3_quota_set *test.db 0 {} 171} {SQLITE_OK} 172 173do_test quota-3.2.1 { 174 delete_file force test.db test2.db 175 176 sqlite3_quota_set * 4096 {} 177 sqlite3 db1a test.db 178 sqlite3 db2a test2.db 179 180 foreach db {db1a db2a} { 181 execsql { 182 PRAGMA page_size = 1024; 183 PRAGMA journal_mode = delete; 184 PRAGMA auto_vacuum = off; 185 CREATE TABLE t1(a, b); 186 } $db 187 } 188 189 sqlite3 db1b test.db 190 sqlite3 db2b test2.db 191 192 list [file size test.db] [file size test2.db] 193} {2048 2048} 194 195catch { unset ::quota_request_ok } 196 197do_test quota-3.2.2 { execsql { INSERT INTO t1 VALUES('x', 'y') } db1a } {} 198do_test quota-3.2.3 { execsql { INSERT INTO t1 VALUES('v', 'w') } db1b } {} 199do_test quota-3.2.4 { execsql { INSERT INTO t1 VALUES('t', 'u') } db2a } {} 200do_test quota-3.2.5 { execsql { INSERT INTO t1 VALUES('r', 's') } db2b } {} 201 202do_test quota-3.2.6 { 203 catchsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1a 204} {1 {database or disk is full}} 205do_test quota-3.2.7 { 206 catchsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1b 207} {1 {database or disk is full}} 208do_test quota-3.2.8 { 209 catchsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2a 210} {1 {database or disk is full}} 211do_test quota-3.2.9 { 212 catchsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2b 213} {1 {database or disk is full}} 214 215set ::quota [list] 216proc quota_callback {file limitvar size} { 217 upvar $limitvar limit 218 if {$::tcl_platform(platform)=="windows"} { 219 set file [ lindex [string map {\\ \/} $file] 0 ] 220 } 221 lappend ::quota $file $size 222 set limit 0 223} 224sqlite3_quota_set * 4096 quota_callback 225do_test quota-3.3.1 { 226 execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1a 227 execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1b 228 execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2a 229 execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2b 230 set ::quota 231} [list [file join [get_pwd] test.db] 5120] 232 233do_test quota-3.2.X { 234 foreach db {db1a db2a db2b db1b} { catch { $db close } } 235 sqlite3_quota_set * 0 {} 236} {SQLITE_OK} 237 238#------------------------------------------------------------------------- 239# Quotas are deleted when unused and when their limit is set to zero 240# 241 242# Return a list of all currently defined quotas. Each quota is identified 243# by its pattern. 244proc quota_list {} { 245 set allq {} 246 foreach q [sqlite3_quota_dump] { 247 lappend allq [lindex $q 0] 248 } 249 return [lsort $allq] 250} 251proc quota_size {name} { 252 set allq {} 253 foreach q [sqlite3_quota_dump] { 254 if {[lindex $q 0]==$name} {return [lindex $q 2]} 255 } 256 return 0 257} 258 259do_test quota-4.1.1 { 260 sqlite3_quota_set *test.db 0 {} 261 quota_list 262} {} 263do_test quota-4.1.2 { 264 sqlite3_quota_set *test.db 4096 {} 265 quota_list 266} {*test.db} 267do_test quota-4.1.3 { 268 sqlite3_quota_set *test2.db 0 {} 269 quota_list 270} {*test.db} 271do_test quota-4.1.4 { 272 sqlite3_quota_set *test2.db 100000 {} 273 quota_list 274} {*test.db *test2.db} 275do_test quota-4.1.5 { 276 sqlite3_quota_set *test.db 0 {} 277 quota_list 278} {*test2.db} 279do_test quota-4.1.6 { 280 forcedelete test2.db test2.db-journal test2.db-wal 281 sqlite3 db test2.db 282 db eval {CREATE TABLE t2(x); INSERT INTO t2 VALUES('tab-t2');} 283 quota_list 284} {*test2.db} 285do_test quota-4.1.7 { 286 catchsql {INSERT INTO t2 VALUES(zeroblob(200000))} 287} {1 {database or disk is full}} 288do_test quota-4.1.8 { 289 sqlite3 db2 test2.db 290 db2 eval {SELECT * FROM t2} 291} {tab-t2} 292do_test quota-4.1.9 { 293 sqlite3_quota_set *test2.db 0 {} 294 catchsql {INSERT INTO t2 VALUES(zeroblob(200000))} 295} {0 {}} 296do_test quota-4.1.10 { 297 quota_list 298} {*test2.db} 299do_test quota-4.1.11 { 300 db2 close 301 quota_list 302} {*test2.db} 303do_test quota-4.1.12 { 304 db close 305 quota_list 306} {} 307 308do_test quota-4.2.1 { 309 sqlite3_quota_set A 1000 {} 310 sqlite3_quota_set B 1000 {} 311 sqlite3_quota_set C 1000 {} 312 sqlite3_quota_set D 1000 {} 313 quota_list 314} {A B C D} 315do_test quota-4.2.2 { 316 sqlite3_quota_set C 0 {} 317 sqlite3_quota_set B 0 {} 318 quota_list 319} {A D} 320do_test quota-4.2.3 { 321 sqlite3_quota_set A 0 {} 322 sqlite3_quota_set D 0 {} 323 quota_list 324} {} 325do_test quota-4.2.4 { 326 sqlite3_quota_set A 1000 {} 327 sqlite3_quota_set B 1000 {} 328 sqlite3_quota_set C 1000 {} 329 sqlite3_quota_set A 0 {} 330 sqlite3_quota_set B 0 {} 331 sqlite3_quota_set C 0 {} 332 quota_list 333} {} 334do_test quota-4.2.5 { 335 sqlite3_quota_set A 1000 {} 336 sqlite3_quota_set B 1000 {} 337 sqlite3_quota_set C 1000 {} 338 sqlite3_quota_set C 0 {} 339 sqlite3_quota_set B 0 {} 340 sqlite3_quota_set A 0 {} 341 quota_list 342} {} 343 344do_test quota-4.3.1 { 345 sqlite3_quota_set A 1000 quota_callback 346 sqlite3 db A 347 sqlite3_quota_set A 0 quota_callback 348 db close 349 quota_list 350} {} 351 352unset -nocomplain quotagroup 353if {$tcl_platform(platform)=="windows"} { 354 set quotagroup *\\quota-test-A?.db 355} else { 356 set quotagroup */quota-test-A?.db 357} 358foreach file [glob -nocomplain quota-test-A*] { 359 forcedelete $file 360} 361do_test quota-4.4.1 { 362 set ::quota {} 363 sqlite3_quota_set $::quotagroup 10000 quota_callback 364 forcedelete ./quota-test-A1.db ./quota-test-A2.db 365 sqlite3 db ./quota-test-A1.db 366 db eval { 367 CREATE TABLE t1(x); 368 INSERT INTO t1 VALUES(randomblob(5000)); 369 } 370 quota_list 371} [list $quotagroup] 372do_test quota-4.4.2 { 373 expr {$::quota==""} 374} {1} 375do_test quota-4.4.3 { 376 db close 377 sqlite3 db ./quota-test-A2.db 378 db eval { 379 CREATE TABLE t1(x); 380 INSERT INTO t1 VALUES(randomblob(5000)); 381 } 382 quota_list 383} [list $quotagroup] 384do_test quota-4.4.4 { 385 expr {$::quota!=""} 386} {1} 387do_test quota-4.4.5 { 388 db close 389 sqlite3_quota_set $::quotagroup 0 {} 390 sqlite3_quota_dump 391} {} 392do_test quota-4.4.6 { 393 sqlite3_quota_set $quotagroup 10000 quota_callback 394 sqlite3 db quota-test-A1.db 395 db eval {SELECT count(*) FROM sqlite_master} 396 quota_size $quotagroup 397} [file size quota-test-A1.db] 398do_test quota-4.4.7 { 399 sqlite3_quota_file quota-test-A2.db 400 quota_size $::quotagroup 401} [expr {[file size quota-test-A1.db]+[file size quota-test-A2.db]}] 402 403unset -nocomplain quotagroup 404if {$tcl_platform(platform)=="windows"} { 405 set quotagroup *\\quota-test-B* 406} else { 407 set quotagroup */quota-test-B* 408} 409foreach file [glob -nocomplain quota-test-B*] { 410 forcedelete $file 411} 412do_test quota-4.5.1 { 413 sqlite3_quota_set $::quotagroup 100000 quota_callback 414 quota_size $::quotagroup 415} {0} 416do_test quota-4.5.2 { 417 sqlite3_quota_file quota-test-B1.txt 418 quota_size $::quotagroup 419} {0} 420proc add_to_file {name n} { 421 set out [open $name a] 422 fconfigure $out -translation binary 423 puts -nonewline $out [string repeat x $n] 424 close $out 425} 426do_test quota-4.5.3 { 427 add_to_file quota-test-B1.txt 123 428 sqlite3_quota_file quota-test-B1.txt 429 quota_size $::quotagroup 430} {123} 431do_test quota-4.5.4 { 432 add_to_file quota-test-B2.txt 234 433 sqlite3_quota_file quota-test-B2.txt 434 quota_size $::quotagroup 435} {357} 436do_test quota-4.5.5 { 437 add_to_file quota-test-B1.txt 2000 438 sqlite3_quota_file quota-test-B1.txt 439 quota_size $::quotagroup 440} {2357} 441do_test quota-4.5.6 { 442 forcedelete quota-test-B1.txt 443 sqlite3_quota_file quota-test-B1.txt 444 quota_size $::quotagroup 445} {234} 446do_test quota-4.5.7 { 447 forcedelete quota-test-B2.txt 448 sqlite3_quota_file quota-test-B2.txt 449 quota_size $::quotagroup 450} {0} 451do_test quota-4.5.8 { 452 add_to_file quota-test-B3.txt 1234 453 sqlite3_quota_file quota-test-B3.txt 454 quota_size $::quotagroup 455} {1234} 456do_test quota-4.5.9 { 457 sqlite3_quota_set $quotagroup 0 {} 458 quota_size $::quotagroup 459} {0} 460 461do_test quota-4.9.1 { 462 db close 463 sqlite3_quota_set A 1000 quota_callback 464 sqlite3_quota_shutdown 465} {SQLITE_OK} 466do_test quota-4.9.2 { 467 quota_list 468} {} 469 470#------------------------------------------------------------------------- 471# The following tests test that the quota VFS handles malloc and IO 472# errors. 473# 474 475sqlite3_quota_initialize "" 1 476sqlite3_quota_set *test.db 4096 {} 477 478do_faultsim_test quota-5.1 -prep { 479 catch {db close} 480} -body { 481 sqlite3 db test2.db 482} 483do_faultsim_test quota-5.2 -prep { 484 catch {db close} 485} -body { 486 sqlite3 db test.db 487} 488 489catch { db close } 490forcedelete test.db 491 492do_test quota-5.3.prep { 493 sqlite3 db test.db 494 execsql { 495 PRAGMA auto_vacuum = 1; 496 PRAGMA page_size = 1024; 497 CREATE TABLE t1(a, b); 498 INSERT INTO t1 VALUES(10, zeroblob(1200)); 499 } 500 faultsim_save_and_close 501} {} 502do_faultsim_test quota-5.3 -prep { 503 faultsim_restore_and_reopen 504} -body { 505 execsql { DELETE FROM t1 } 506} 507 508do_test quota-5.4.1 { 509 catch { db close } 510 forcedelete test.db 511 file mkdir test.db 512 list [catch { sqlite3 db test.db } msg] $msg 513} {1 {unable to open database file}} 514 515do_faultsim_test quota-5.5 -prep { 516 catch { sqlite3_quota_shutdown } 517} -body { 518 sqlite3_quota_initialize "" 1 519} 520 521do_faultsim_test quota-5.6 -prep { 522 catch { sqlite3_quota_shutdown } 523 sqlite3_quota_initialize "" 1 524} -body { 525 sqlite3_quota_set * 4096 {} 526} 527 528catch { sqlite3_quota_shutdown } 529finish_test 530