1eecc3983Sdan# 2013 March 20 2eecc3983Sdan# 3eecc3983Sdan# The author disclaims copyright to this source code. In place of 4eecc3983Sdan# a legal notice, here is a blessing: 5eecc3983Sdan# 6eecc3983Sdan# May you do good and not evil. 7eecc3983Sdan# May you find forgiveness for yourself and forgive others. 8eecc3983Sdan# May you share freely, never taking more than you give. 9eecc3983Sdan# 10eecc3983Sdan#*********************************************************************** 11eecc3983Sdan# 12eecc3983Sdan 13eecc3983Sdanset testdir [file dirname $argv0] 14eecc3983Sdansource $testdir/tester.tcl 15*a32536b4Sdanifcapable !mmap||!incrblob { 16188d4884Sdrh finish_test 17188d4884Sdrh return 18188d4884Sdrh} 19eecc3983Sdansource $testdir/lock_common.tcl 20eecc3983Sdanset testprefix mmap1 21eecc3983Sdan 22eecc3983Sdanproc nRead {db} { 23eecc3983Sdan set bt [btree_from_db $db] 24eecc3983Sdan db_enter $db 25eecc3983Sdan array set stats [btree_pager_stats $bt] 26eecc3983Sdan db_leave $db 27c3d53189Sdrh # puts [array get stats] 28eecc3983Sdan return $stats(read) 29eecc3983Sdan} 30eecc3983Sdan 31be7721d1Sdan# Return a Tcl script that registers a user-defined scalar function 32be7721d1Sdan# named rblob() with database handle $dbname. The function returns a 33be7721d1Sdan# sequence of pseudo-random blobs based on seed value $seed. 34be7721d1Sdan# 35ced9813bSdanproc register_rblob_code {dbname seed} { 36ced9813bSdan return [subst -nocommands { 37ced9813bSdan set ::rcnt $seed 38ced9813bSdan proc rblob {n} { 39ced9813bSdan set ::rcnt [expr (([set ::rcnt] << 3) + [set ::rcnt] + 456) & 0xFFFFFFFF] 40ced9813bSdan set str [format %.8x [expr [set ::rcnt] ^ 0xbdf20da3]] 41ced9813bSdan string range [string repeat [set str] [expr [set n]/4]] 1 [set n] 42ced9813bSdan } 43ced9813bSdan $dbname func rblob rblob 44ced9813bSdan }] 45ced9813bSdan} 46ced9813bSdan 47be7721d1Sdan 48f054396bSdan# For cases 1.1 and 1.4, the number of pages read using xRead() is 4 on 49f054396bSdan# unix and 9 on windows. The difference is that windows only ever maps 50f054396bSdan# an integer number of OS pages (i.e. creates mappings that are a multiple 51f054396bSdan# of 4KB in size). Whereas on unix any sized mapping may be created. 52f054396bSdan# 539b4c59faSdrhforeach {t mmap_size nRead c2init} { 54f054396bSdan 1.1 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 0} 559b4c59faSdrh 1.2 { PRAGMA mmap_size = 53248 } 150 {PRAGMA mmap_size = 0} 569b4c59faSdrh 1.3 { PRAGMA mmap_size = 0 } 344 {PRAGMA mmap_size = 0} 57f054396bSdan 1.4 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 67108864 } 589b4c59faSdrh 1.5 { PRAGMA mmap_size = 53248 } 150 {PRAGMA mmap_size = 67108864 } 599b4c59faSdrh 1.6 { PRAGMA mmap_size = 0 } 344 {PRAGMA mmap_size = 67108864 } 60eecc3983Sdan} { 61f054396bSdan 62eecc3983Sdan do_multiclient_test tn { 635b04dc51Sdan sql1 {PRAGMA cache_size=2000} 645b04dc51Sdan sql2 {PRAGMA cache_size=2000} 655b04dc51Sdan 66c3d53189Sdrh sql1 {PRAGMA page_size=1024} 679b4c59faSdrh sql1 $mmap_size 689d56c6dfSdan sql2 $c2init 69eecc3983Sdan 70ced9813bSdan code2 [register_rblob_code db2 0] 71eecc3983Sdan 72eecc3983Sdan sql2 { 73c3d53189Sdrh PRAGMA page_size=1024; 74eecc3983Sdan PRAGMA auto_vacuum = 1; 75eecc3983Sdan CREATE TABLE t1(a, b, UNIQUE(a, b)); 76eecc3983Sdan INSERT INTO t1 VALUES(rblob(500), rblob(500)); 77eecc3983Sdan INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 78eecc3983Sdan INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 79eecc3983Sdan INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 80eecc3983Sdan INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 81eecc3983Sdan INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32 82eecc3983Sdan } 83eecc3983Sdan do_test $t.$tn.1 { 84eecc3983Sdan sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count" 85eecc3983Sdan } {32 ok 77} 86eecc3983Sdan 87eecc3983Sdan # Have connection 2 shrink the file. Check connection 1 can still read it. 88eecc3983Sdan sql2 { DELETE FROM t1 WHERE rowid%2; } 89eecc3983Sdan do_test $t.$tn.2 { 90eecc3983Sdan sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count" 917da56b4fSdrh } "16 ok [expr {42+[nonzero_reserved_bytes]}]" 92eecc3983Sdan 93eecc3983Sdan # Have connection 2 grow the file. Check connection 1 can still read it. 94eecc3983Sdan sql2 { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1 } 95eecc3983Sdan do_test $t.$tn.3 { 96eecc3983Sdan sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count" 97eecc3983Sdan } {32 ok 79} 98eecc3983Sdan 99eecc3983Sdan # Have connection 2 grow the file again. Check connection 1 is still ok. 100eecc3983Sdan sql2 { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1 } 101eecc3983Sdan do_test $t.$tn.4 { 102eecc3983Sdan sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count" 103eecc3983Sdan } {64 ok 149} 104eecc3983Sdan 105eecc3983Sdan # Check that the number of pages read by connection 1 indicates that the 1069b4c59faSdrh # "PRAGMA mmap_size" command worked. 1077da56b4fSdrh if {[nonzero_reserved_bytes]==0} { 108eecc3983Sdan do_test $t.$tn.5 { nRead db } $nRead 109eecc3983Sdan } 110eecc3983Sdan } 1117da56b4fSdrh} 112eecc3983Sdan 1139d56c6dfSdanset ::rcnt 0 1149d56c6dfSdanproc rblob {n} { 1159d56c6dfSdan set ::rcnt [expr (($::rcnt << 3) + $::rcnt + 456) & 0xFFFFFFFF] 1169d56c6dfSdan set str [format %.8x [expr $::rcnt ^ 0xbdf20da3]] 1179d56c6dfSdan string range [string repeat $str [expr $n/4]] 1 $n 1189d56c6dfSdan} 1199d56c6dfSdan 1209d56c6dfSdanreset_db 1219d56c6dfSdandb func rblob rblob 1229d56c6dfSdan 123fdece7baSmistachkinifcapable wal { 1249d56c6dfSdan do_execsql_test 2.1 { 1259d56c6dfSdan PRAGMA auto_vacuum = 1; 1269b4c59faSdrh PRAGMA mmap_size = 67108864; 1279d56c6dfSdan PRAGMA journal_mode = wal; 1289d56c6dfSdan CREATE TABLE t1(a, b, UNIQUE(a, b)); 1299d56c6dfSdan INSERT INTO t1 VALUES(rblob(500), rblob(500)); 1309d56c6dfSdan INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 1319d56c6dfSdan INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 1329d56c6dfSdan INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 1339d56c6dfSdan INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 1349d56c6dfSdan INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32 1359d56c6dfSdan PRAGMA wal_checkpoint; 13634f74903Sdrh } {67108864 wal 0 103 103} 1379d56c6dfSdan 1389d56c6dfSdan do_execsql_test 2.2 { 1399d56c6dfSdan PRAGMA auto_vacuum; 1409d56c6dfSdan SELECT count(*) FROM t1; 1419d56c6dfSdan } {1 32} 1429d56c6dfSdan 1435b04dc51Sdan if {[permutation] != "inmemory_journal"} { 1449d56c6dfSdan do_test 2.3 { 1459d56c6dfSdan sqlite3 db2 test.db 1469d56c6dfSdan db2 func rblob rblob 1479d56c6dfSdan db2 eval { 1489d56c6dfSdan DELETE FROM t1 WHERE (rowid%4); 1499d56c6dfSdan PRAGMA wal_checkpoint; 1509d56c6dfSdan } 1519d56c6dfSdan db2 eval { 1529d56c6dfSdan INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 1539d56c6dfSdan SELECT count(*) FROM t1; 1549d56c6dfSdan } 1559d56c6dfSdan } {16} 1569d56c6dfSdan 1579d56c6dfSdan do_execsql_test 2.4 { 1589d56c6dfSdan PRAGMA wal_checkpoint; 1599d56c6dfSdan } {0 24 24} 160c3d53189Sdrh db2 close 1615b04dc51Sdan } 162fdece7baSmistachkin} 1635b04dc51Sdan 164db082408Sdanreset_db 165cf8489feSdanexecsql { PRAGMA mmap_size = 67108864; } 166db082408Sdandb func rblob rblob 167db082408Sdando_execsql_test 3.1 { 168db082408Sdan PRAGMA auto_vacuum = 1; 169db082408Sdan 170db082408Sdan CREATE TABLE t1(a, b, UNIQUE(a, b)); 171db082408Sdan INSERT INTO t1 VALUES(rblob(500), rblob(500)); 172db082408Sdan INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 173db082408Sdan INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 174db082408Sdan INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 175db082408Sdan 176db082408Sdan CREATE TABLE t2(a, b, UNIQUE(a, b)); 177db082408Sdan INSERT INTO t2 SELECT * FROM t1; 178db082408Sdan} {} 179db082408Sdan 180db082408Sdando_test 3.2 { 181db082408Sdan set nRow 0 182db082408Sdan db eval {SELECT * FROM t2 ORDER BY a, b} { 183db082408Sdan if {$nRow==4} { db eval { DELETE FROM t1 } } 184db082408Sdan incr nRow 185db082408Sdan } 186db082408Sdan set nRow 187db082408Sdan} {8} 188db082408Sdan 189227a1c48Sdan#------------------------------------------------------------------------- 190227a1c48Sdan# Ensure that existing cursors using xFetch() pages see changes made 191227a1c48Sdan# to rows using the incrblob API. 192227a1c48Sdan# 193227a1c48Sdanreset_db 194cf8489feSdanexecsql { PRAGMA mmap_size = 67108864; } 195227a1c48Sdanset aaa [string repeat a 400] 196227a1c48Sdanset bbb [string repeat b 400] 197227a1c48Sdanset ccc [string repeat c 400] 198227a1c48Sdanset ddd [string repeat d 400] 199227a1c48Sdanset eee [string repeat e 400] 200227a1c48Sdan 201227a1c48Sdando_execsql_test 4.1 { 202227a1c48Sdan PRAGMA page_size = 1024; 203227a1c48Sdan CREATE TABLE t1(x); 204227a1c48Sdan INSERT INTO t1 VALUES($aaa); 205227a1c48Sdan INSERT INTO t1 VALUES($bbb); 206227a1c48Sdan INSERT INTO t1 VALUES($ccc); 207227a1c48Sdan INSERT INTO t1 VALUES($ddd); 208227a1c48Sdan SELECT * FROM t1; 209227a1c48Sdan BEGIN; 210227a1c48Sdan} [list $aaa $bbb $ccc $ddd] 211227a1c48Sdan 212227a1c48Sdando_test 4.2 { 213227a1c48Sdan set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy] 214227a1c48Sdan sqlite3_step $::STMT 215227a1c48Sdan sqlite3_column_text $::STMT 0 216227a1c48Sdan} $aaa 217227a1c48Sdan 218227a1c48Sdando_test 4.3 { 219227a1c48Sdan foreach r {2 3 4} { 220227a1c48Sdan set fd [db incrblob t1 x $r] 221227a1c48Sdan puts -nonewline $fd $eee 222227a1c48Sdan close $fd 223227a1c48Sdan } 224227a1c48Sdan 225227a1c48Sdan set res [list] 226227a1c48Sdan while {"SQLITE_ROW" == [sqlite3_step $::STMT]} { 227227a1c48Sdan lappend res [sqlite3_column_text $::STMT 0] 228227a1c48Sdan } 229227a1c48Sdan set res 230227a1c48Sdan} [list $eee $eee $eee] 231227a1c48Sdan 232227a1c48Sdando_test 4.4 { 233227a1c48Sdan sqlite3_finalize $::STMT 234227a1c48Sdan} SQLITE_OK 235227a1c48Sdan 236227a1c48Sdando_execsql_test 4.5 { COMMIT } 237227a1c48Sdan 238f7679ad1Sdan#------------------------------------------------------------------------- 239f7679ad1Sdan# Ensure that existing cursors holding xFetch() references are not 240f7679ad1Sdan# confused if those pages are moved to make way for the root page of a 241f7679ad1Sdan# new table or index. 242f7679ad1Sdan# 243f7679ad1Sdanreset_db 244cf8489feSdanexecsql { PRAGMA mmap_size = 67108864; } 245f7679ad1Sdando_execsql_test 5.1 { 246f7679ad1Sdan PRAGMA auto_vacuum = 2; 247f7679ad1Sdan PRAGMA page_size = 1024; 248f7679ad1Sdan CREATE TABLE t1(x); 249f7679ad1Sdan INSERT INTO t1 VALUES($aaa); 250f7679ad1Sdan INSERT INTO t1 VALUES($bbb); 251f7679ad1Sdan INSERT INTO t1 VALUES($ccc); 252f7679ad1Sdan INSERT INTO t1 VALUES($ddd); 253227a1c48Sdan 254f7679ad1Sdan PRAGMA auto_vacuum; 255f7679ad1Sdan SELECT * FROM t1; 256f7679ad1Sdan} [list 2 $aaa $bbb $ccc $ddd] 257f7679ad1Sdan 258f7679ad1Sdando_test 5.2 { 259f7679ad1Sdan set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy] 260f7679ad1Sdan sqlite3_step $::STMT 261f7679ad1Sdan sqlite3_column_text $::STMT 0 262f7679ad1Sdan} $aaa 263f7679ad1Sdan 264f7679ad1Sdando_execsql_test 5.3 { 265f7679ad1Sdan CREATE TABLE t2(x); 266f7679ad1Sdan INSERT INTO t2 VALUES('tricked you!'); 267f7679ad1Sdan INSERT INTO t2 VALUES('tricked you!'); 268f7679ad1Sdan} 269f7679ad1Sdan 270f7679ad1Sdando_test 5.4 { 271f7679ad1Sdan sqlite3_step $::STMT 272f7679ad1Sdan sqlite3_column_text $::STMT 0 273f7679ad1Sdan} $bbb 274f7679ad1Sdan 275f7679ad1Sdando_test 5.5 { 276f7679ad1Sdan sqlite3_finalize $::STMT 277f7679ad1Sdan} SQLITE_OK 278f7679ad1Sdan 2791e8487dbSmistachkin# 2801e8487dbSmistachkin# The "6.*" tests are designed to test the interaction of mmap with file 2811e8487dbSmistachkin# truncation (e.g. on Win32) via the VACUUM command. 2821e8487dbSmistachkin# 2831e8487dbSmistachkinforcedelete test2.db 2841e8487dbSmistachkinsqlite3 db2 test2.db 2851e8487dbSmistachkindo_test 6.0 { 2861e8487dbSmistachkin db2 eval { 287202a0274Sdan PRAGMA auto_vacuum = 0; 2881e8487dbSmistachkin PRAGMA page_size = 4096; 2891e8487dbSmistachkin } 2901e8487dbSmistachkin} {} 2911e8487dbSmistachkindo_test 6.1 { 2921e8487dbSmistachkin db2 eval { 2931e8487dbSmistachkin CREATE TABLE t1(x); 2941e8487dbSmistachkin INSERT INTO t1(x) VALUES(randomblob(1000000)); 2951e8487dbSmistachkin } 2961e8487dbSmistachkin} {} 2971e8487dbSmistachkindo_test 6.2 { 2981e8487dbSmistachkin db2 eval { 2991e8487dbSmistachkin PRAGMA mmap_size = 1048576; 3001e8487dbSmistachkin } 3011e8487dbSmistachkin} {1048576} 3021e8487dbSmistachkindo_test 6.3 { 3031e8487dbSmistachkin expr {[file size test2.db] > 1000000} 3041e8487dbSmistachkin} {1} 3051e8487dbSmistachkindo_test 6.4 { 3061e8487dbSmistachkin db2 eval { 3071e8487dbSmistachkin DELETE FROM t1; 3081e8487dbSmistachkin } 3091e8487dbSmistachkin} {} 3101e8487dbSmistachkindo_test 6.5 { 3111e8487dbSmistachkin expr {[file size test2.db] > 1000000} 3121e8487dbSmistachkin} {1} 3131e8487dbSmistachkindo_test 6.6 { 3141e8487dbSmistachkin db2 eval { 3151e8487dbSmistachkin VACUUM; 3161e8487dbSmistachkin } 3171e8487dbSmistachkin} {} 3181e8487dbSmistachkindo_test 6.7 { 3191e8487dbSmistachkin expr {[file size test2.db] < 1000000} 3201e8487dbSmistachkin} {1} 3211e8487dbSmistachkindb2 close 322ced9813bSdan 323f7679ad1Sdanfinish_test 324