1bd188afdSdan# 2010 September 22 2bd188afdSdan# 3bd188afdSdan# The author disclaims copyright to this source code. In place of 4bd188afdSdan# a legal notice, here is a blessing: 5bd188afdSdan# 6bd188afdSdan# May you do good and not evil. 7bd188afdSdan# May you find forgiveness for yourself and forgive others. 8bd188afdSdan# May you share freely, never taking more than you give. 9bd188afdSdan# 10bd188afdSdan#*********************************************************************** 11bd188afdSdan# This file contains tests for the r-tree module. Specifically, it tests 12bd188afdSdan# that corrupt or inconsistent databases do not cause crashes in the r-tree 13bd188afdSdan# module. 14bd188afdSdan# 15bd188afdSdan 16bd188afdSdanif {![info exists testdir]} { 17bd188afdSdan set testdir [file join [file dirname [info script]] .. .. test] 18bd188afdSdan} 19bd188afdSdansource $testdir/tester.tcl 20bd188afdSdanifcapable !rtree { finish_test ; return } 21bd188afdSdan 22bd188afdSdanproc create_t1 {} { 23bd188afdSdan db close 24bd188afdSdan forcedelete test.db 25bd188afdSdan sqlite3 db test.db 26bd188afdSdan execsql { 27af7626f5Sdan PRAGMA page_size = 1024; 28bd188afdSdan CREATE VIRTUAL TABLE t1 USING rtree(id, x1, x2, y1, y2); 29bd188afdSdan } 30bd188afdSdan} 31bd188afdSdanproc populate_t1 {} { 32bd188afdSdan execsql BEGIN 33bd188afdSdan for {set i 0} {$i < 500} {incr i} { 34bd188afdSdan set x2 [expr $i+5] 35bd188afdSdan set y2 [expr $i+5] 36bd188afdSdan execsql { INSERT INTO t1 VALUES($i, $i, $x2, $i, $y2) } 37bd188afdSdan } 38bd188afdSdan execsql COMMIT 390f0d3ddfSdrh sqlite3_db_config db DEFENSIVE 0 40bd188afdSdan} 41bd188afdSdan 42bd188afdSdanproc truncate_node {nodeno nTrunc} { 43bd188afdSdan set blob [db one {SELECT data FROM t1_node WHERE nodeno=$nodeno}] 44bd188afdSdan if {$nTrunc<0} {set nTrunc "end-$nTrunc"} 45bd188afdSdan set blob [string range $blob 0 $nTrunc] 46bd188afdSdan db eval { UPDATE t1_node SET data = $blob WHERE nodeno=$nodeno } 47bd188afdSdan} 48bd188afdSdan 49bd188afdSdanproc set_tree_depth {tbl {newvalue ""}} { 50bd188afdSdan set blob [db one "SELECT data FROM ${tbl}_node WHERE nodeno=1"] 51bd188afdSdan 52bd188afdSdan if {$newvalue == ""} { 53bd188afdSdan binary scan $blob Su oldvalue 54bd188afdSdan return $oldvalue 55bd188afdSdan } 56bd188afdSdan 57bd188afdSdan set blob [binary format Sua* $newvalue [string range $blob 2 end]] 58bd188afdSdan db eval "UPDATE ${tbl}_node SET data = \$blob WHERE nodeno=1" 59bd188afdSdan return [set_tree_depth $tbl] 60bd188afdSdan} 61bd188afdSdan 62bd188afdSdanproc set_entry_count {tbl nodeno {newvalue ""}} { 63bd188afdSdan set blob [db one "SELECT data FROM ${tbl}_node WHERE nodeno=$nodeno"] 64bd188afdSdan 65bd188afdSdan if {$newvalue == ""} { 66bd188afdSdan binary scan [string range $blob 2 end] Su oldvalue 67bd188afdSdan return $oldvalue 68bd188afdSdan } 69bd188afdSdan 70bd188afdSdan set blob [binary format a*Sua* \ 71bd188afdSdan [string range $blob 0 1] $newvalue [string range $blob 4 end] 72bd188afdSdan ] 73bd188afdSdan db eval "UPDATE ${tbl}_node SET data = \$blob WHERE nodeno=$nodeno" 74bd188afdSdan return [set_entry_count $tbl $nodeno] 75bd188afdSdan} 76bd188afdSdan 77bd188afdSdan 78bd188afdSdanproc do_corruption_tests {prefix args} { 79bd188afdSdan set testarray [lindex $args end] 80bd188afdSdan set errormsg {database disk image is malformed} 81bd188afdSdan 82bd188afdSdan foreach {z value} [lrange $args 0 end-1] { 83bd188afdSdan set n [string length $z] 84bd188afdSdan if {$n>=2 && [string equal -length $n $z "-error"]} { 85bd188afdSdan set errormsg $value 86bd188afdSdan } 87bd188afdSdan } 88bd188afdSdan 89bd188afdSdan foreach {tn sql} $testarray { 90bd188afdSdan do_catchsql_test $prefix.$tn $sql [list 1 $errormsg] 91bd188afdSdan } 92bd188afdSdan} 93bd188afdSdan 94bd188afdSdan#------------------------------------------------------------------------- 95bd188afdSdan# Test the libraries response if the %_node table is completely empty 96bd188afdSdan# (i.e. the root node is missing), or has been removed from the database 97bd188afdSdan# entirely. 98bd188afdSdan# 99bd188afdSdancreate_t1 100bd188afdSdanpopulate_t1 101bd188afdSdando_execsql_test rtreeA-1.0 { 102bd188afdSdan DELETE FROM t1_node; 103bd188afdSdan} {} 104bd188afdSdan 105bd188afdSdando_corruption_tests rtreeA-1.1 { 106bd188afdSdan 1 "SELECT * FROM t1" 107bd188afdSdan 2 "SELECT * FROM t1 WHERE rowid=5" 108bd188afdSdan 3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)" 109bd188afdSdan 4 "SELECT * FROM t1 WHERE x1<10 AND x2>12" 110bd188afdSdan} 111bd188afdSdan 1121917e92fSdando_execsql_test rtreeA-1.1.1 { 1131917e92fSdan SELECT rtreecheck('main', 't1') 1141917e92fSdan} {{Node 1 missing from database 1151917e92fSdanWrong number of entries in %_rowid table - expected 0, actual 500 1161917e92fSdanWrong number of entries in %_parent table - expected 0, actual 23}} 1171917e92fSdan 118bd188afdSdando_execsql_test rtreeA-1.2.0 { DROP TABLE t1_node } {} 1192033d1c8Sdrhdo_corruption_tests rtreeA-1.2 -error "database disk image is malformed" { 120bd188afdSdan 1 "SELECT * FROM t1" 121bd188afdSdan 2 "SELECT * FROM t1 WHERE rowid=5" 122bd188afdSdan 3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)" 123bd188afdSdan 4 "SELECT * FROM t1 WHERE x1<10 AND x2>12" 124bd188afdSdan} 125bd188afdSdan 126bd188afdSdan#------------------------------------------------------------------------- 127bd188afdSdan# Test the libraries response if some of the entries in the %_node table 128bd188afdSdan# are the wrong size. 129bd188afdSdan# 130bd188afdSdancreate_t1 131bd188afdSdanpopulate_t1 132bd188afdSdando_test rtreeA-2.1.0 { 133bd188afdSdan set nodes [db eval {select nodeno FROM t1_node}] 134bd188afdSdan foreach {a b c} $nodes { truncate_node $c 200 } 135bd188afdSdan} {} 136bd188afdSdando_corruption_tests rtreeA-2.1 { 137bd188afdSdan 1 "SELECT * FROM t1" 138bd188afdSdan 2 "SELECT * FROM t1 WHERE rowid=5" 139bd188afdSdan 3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)" 140bd188afdSdan 4 "SELECT * FROM t1 WHERE x1<10 AND x2>12" 141bd188afdSdan} 142bd188afdSdan 143bd188afdSdancreate_t1 144bd188afdSdanpopulate_t1 145bd188afdSdando_test rtreeA-2.2.0 { truncate_node 1 200 } {} 146bd188afdSdando_corruption_tests rtreeA-2.2 { 147bd188afdSdan 1 "SELECT * FROM t1" 1488038cb99Sdrh 2 "SELECT * FROM t1 WHERE +rowid=5" 149bd188afdSdan 3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)" 150bd188afdSdan 4 "SELECT * FROM t1 WHERE x1<10 AND x2>12" 151bd188afdSdan} 152bd188afdSdan 153bd188afdSdan#------------------------------------------------------------------------- 154bd188afdSdan# Set the "depth" of the tree stored on the root node incorrectly. Test 155bd188afdSdan# that this does not cause any problems. 156bd188afdSdan# 157bd188afdSdancreate_t1 158bd188afdSdanpopulate_t1 159bd188afdSdando_test rtreeA-3.1.0.1 { set_tree_depth t1 } {1} 160bd188afdSdando_test rtreeA-3.1.0.2 { set_tree_depth t1 3 } {3} 161bd188afdSdando_corruption_tests rtreeA-3.1 { 162bd188afdSdan 1 "SELECT * FROM t1" 1638038cb99Sdrh 2 "SELECT * FROM t1 WHERE +rowid=5" 164bd188afdSdan 3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)" 165bd188afdSdan} 166bd188afdSdan 1671917e92fSdando_execsql_test rtreeA-3.1.0.3 { 168*7d44b22dSdrh SELECT rtreecheck('main', 't1')!='ok' 1691917e92fSdan} {1} 1701917e92fSdan 171bd188afdSdando_test rtreeA-3.2.0 { set_tree_depth t1 1000 } {1000} 172bd188afdSdando_corruption_tests rtreeA-3.2 { 173bd188afdSdan 1 "SELECT * FROM t1" 1748038cb99Sdrh 2 "SELECT * FROM t1 WHERE +rowid=5" 175bd188afdSdan 3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)" 176bd188afdSdan} 177bd188afdSdan 178bd188afdSdancreate_t1 179bd188afdSdanpopulate_t1 180bd188afdSdando_test rtreeA-3.3.0 { 181bd188afdSdan execsql { DELETE FROM t1 WHERE rowid = 0 } 182bd188afdSdan set_tree_depth t1 65535 183bd188afdSdan} {65535} 184bd188afdSdando_corruption_tests rtreeA-3.3 { 185bd188afdSdan 1 "SELECT * FROM t1" 1868038cb99Sdrh 2 "SELECT * FROM t1 WHERE +rowid=5" 187bd188afdSdan 3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)" 188bd188afdSdan} 189bd188afdSdan 1901917e92fSdando_execsql_test rtreeA-3.3.3.4 { 1911917e92fSdan SELECT rtreecheck('main', 't1') 1921917e92fSdan} {{Rtree depth out of range (65535) 1931917e92fSdanWrong number of entries in %_rowid table - expected 0, actual 499 1941917e92fSdanWrong number of entries in %_parent table - expected 0, actual 23}} 1951917e92fSdan 196bd188afdSdan#------------------------------------------------------------------------- 197bd188afdSdan# Set the "number of entries" field on some nodes incorrectly. 198bd188afdSdan# 199bd188afdSdancreate_t1 200bd188afdSdanpopulate_t1 201bd188afdSdando_test rtreeA-4.1.0 { 202bd188afdSdan set_entry_count t1 1 4000 203bd188afdSdan} {4000} 204bd188afdSdando_corruption_tests rtreeA-4.1 { 205bd188afdSdan 1 "SELECT * FROM t1" 2068038cb99Sdrh 2 "SELECT * FROM t1 WHERE +rowid=5" 207bd188afdSdan 3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)" 208bd188afdSdan 4 "SELECT * FROM t1 WHERE x1<10 AND x2>12" 209bd188afdSdan} 210bd188afdSdan 211bd188afdSdan#------------------------------------------------------------------------- 212bd188afdSdan# Remove entries from the %_parent table and check that this does not 213bd188afdSdan# cause a crash. 214bd188afdSdan# 215bd188afdSdancreate_t1 216bd188afdSdanpopulate_t1 217bd188afdSdando_execsql_test rtreeA-5.1.0 { DELETE FROM t1_parent } {} 218bd188afdSdando_corruption_tests rtreeA-5.1 { 2198038cb99Sdrh 1 "DELETE FROM t1 WHERE +rowid = 5" 220bd188afdSdan 2 "DELETE FROM t1" 221bd188afdSdan} 222bd188afdSdan 2231917e92fSdando_execsql_test rtreeA-5.2 { 224*7d44b22dSdrh SELECT rtreecheck('main', 't1')!='ok' 2251917e92fSdan} {1} 2261917e92fSdan 227b51d2fa8Sdan#------------------------------------------------------------------------- 228b51d2fa8Sdan# Add some bad entries to the %_parent table. 229b51d2fa8Sdan# 230b51d2fa8Sdancreate_t1 231b51d2fa8Sdanpopulate_t1 232b51d2fa8Sdando_execsql_test rtreeA-6.1.0 { 233b51d2fa8Sdan UPDATE t1_parent set parentnode = parentnode+1 234b51d2fa8Sdan} {} 235b51d2fa8Sdando_corruption_tests rtreeA-6.1 { 236b51d2fa8Sdan 1 "DELETE FROM t1 WHERE rowid = 5" 237af7626f5Sdan 2 "UPDATE t1 SET x1=x1+1, x2=x2+1" 238b51d2fa8Sdan} 239b51d2fa8Sdan 2401917e92fSdando_execsql_test rtreeA-6.2 { 241*7d44b22dSdrh SELECT rtreecheck('main', 't1')!='ok' 2421917e92fSdan} {1} 2431917e92fSdan 244c7b1ee5fSdrh#------------------------------------------------------------------------- 245c7b1ee5fSdrh# Truncated blobs in the _node table. 246c7b1ee5fSdrh# 247c7b1ee5fSdrhcreate_t1 248c7b1ee5fSdrhpopulate_t1 249c7b1ee5fSdrhsqlite3 db test.db 2500f0d3ddfSdrhsqlite3_db_config db DEFENSIVE 0 251c7b1ee5fSdrhdo_execsql_test rtreeA-7.100 { 252c7b1ee5fSdrh UPDATE t1_node SET data=x'' WHERE rowid=1; 253c7b1ee5fSdrh} {} 254c7b1ee5fSdrhdo_catchsql_test rtreeA-7.110 { 255c7b1ee5fSdrh SELECT * FROM t1 WHERE x1>0 AND x1<100 AND x2>0 AND x2<100; 256c7b1ee5fSdrh} {1 {undersize RTree blobs in "t1_node"}} 2577524b613Sdrhdo_test rtreeA-7.120 { 2587524b613Sdrh sqlite3_extended_errcode db 2596362bbe6Sdrh} {SQLITE_CORRUPT_VTAB} 2607524b613Sdrh 261c7b1ee5fSdrh 262bd188afdSdanfinish_test 263