Home | History | Annotate | Download | only in rtree
      1 # 2010 September 22
      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 # This file contains tests for the r-tree module. Specifically, it tests
     12 # that corrupt or inconsistent databases do not cause crashes in the r-tree
     13 # module.
     14 # 
     15 
     16 if {![info exists testdir]} {
     17   set testdir [file join [file dirname [info script]] .. .. test]
     18 } 
     19 source $testdir/tester.tcl
     20 ifcapable !rtree { finish_test ; return }
     21 
     22 proc create_t1 {} {
     23   db close
     24   forcedelete test.db
     25   sqlite3 db test.db
     26   execsql {
     27     PRAGMA page_size = 1024;
     28     CREATE VIRTUAL TABLE t1 USING rtree(id, x1, x2, y1, y2);
     29   }
     30 }
     31 proc populate_t1 {} {
     32   execsql BEGIN
     33   for {set i 0} {$i < 500} {incr i} {
     34     set x2 [expr $i+5]
     35     set y2 [expr $i+5]
     36     execsql { INSERT INTO t1 VALUES($i, $i, $x2, $i, $y2) }
     37   }
     38   execsql COMMIT
     39 }
     40 
     41 proc truncate_node {nodeno nTrunc} {
     42   set blob [db one {SELECT data FROM t1_node WHERE nodeno=$nodeno}]
     43   if {$nTrunc<0} {set nTrunc "end-$nTrunc"}
     44   set blob [string range $blob 0 $nTrunc]
     45   db eval { UPDATE t1_node SET data = $blob WHERE nodeno=$nodeno }
     46 }
     47 
     48 proc set_tree_depth {tbl {newvalue ""}} {
     49   set blob [db one "SELECT data FROM ${tbl}_node WHERE nodeno=1"]
     50 
     51   if {$newvalue == ""} {
     52     binary scan $blob Su oldvalue
     53     return $oldvalue
     54   }
     55 
     56   set blob [binary format Sua* $newvalue [string range $blob 2 end]]
     57   db eval "UPDATE ${tbl}_node SET data = \$blob WHERE nodeno=1"
     58   return [set_tree_depth $tbl]
     59 }
     60 
     61 proc set_entry_count {tbl nodeno {newvalue ""}} {
     62   set blob [db one "SELECT data FROM ${tbl}_node WHERE nodeno=$nodeno"]
     63 
     64   if {$newvalue == ""} {
     65     binary scan [string range $blob 2 end] Su oldvalue
     66     return $oldvalue
     67   }
     68 
     69   set blob [binary format a*Sua* \
     70     [string range $blob 0 1] $newvalue [string range $blob 4 end]
     71   ]
     72   db eval "UPDATE ${tbl}_node SET data = \$blob WHERE nodeno=$nodeno"
     73   return [set_entry_count $tbl $nodeno]
     74 }
     75 
     76 
     77 proc do_corruption_tests {prefix args} {
     78   set testarray [lindex $args end]
     79   set errormsg {database disk image is malformed}
     80 
     81   foreach {z value} [lrange $args 0 end-1] {
     82     set n [string length $z]
     83     if {$n>=2 && [string equal -length $n $z "-error"]} {
     84       set errormsg $value
     85     }
     86   }
     87 
     88   foreach {tn sql} $testarray {
     89     do_catchsql_test $prefix.$tn $sql [list 1 $errormsg]
     90   }
     91 }
     92 
     93 #-------------------------------------------------------------------------
     94 # Test the libraries response if the %_node table is completely empty
     95 # (i.e. the root node is missing), or has been removed from the database
     96 # entirely.
     97 #
     98 create_t1
     99 populate_t1
    100 do_execsql_test rtreeA-1.0 {
    101   DELETE FROM t1_node;
    102 } {}
    103 
    104 do_corruption_tests rtreeA-1.1 {
    105   1   "SELECT * FROM t1"
    106   2   "SELECT * FROM t1 WHERE rowid=5"
    107   3   "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
    108   4   "SELECT * FROM t1 WHERE x1<10 AND x2>12"
    109 }
    110 
    111 do_execsql_test  rtreeA-1.2.0 { DROP TABLE t1_node } {}
    112 do_corruption_tests rtreeA-1.2 -error "SQL logic error or missing database" {
    113   1   "SELECT * FROM t1"
    114   2   "SELECT * FROM t1 WHERE rowid=5"
    115   3   "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
    116   4   "SELECT * FROM t1 WHERE x1<10 AND x2>12"
    117 }
    118 
    119 #-------------------------------------------------------------------------
    120 # Test the libraries response if some of the entries in the %_node table 
    121 # are the wrong size.
    122 #
    123 create_t1
    124 populate_t1
    125 do_test rtreeA-2.1.0 {
    126   set nodes [db eval {select nodeno FROM t1_node}]
    127   foreach {a b c} $nodes { truncate_node $c 200 }
    128 } {}
    129 do_corruption_tests rtreeA-2.1 {
    130   1   "SELECT * FROM t1"
    131   2   "SELECT * FROM t1 WHERE rowid=5"
    132   3   "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
    133   4   "SELECT * FROM t1 WHERE x1<10 AND x2>12"
    134 }
    135 
    136 create_t1
    137 populate_t1
    138 do_test rtreeA-2.2.0 { truncate_node 1 200 } {}
    139 do_corruption_tests rtreeA-2.2 {
    140   1   "SELECT * FROM t1"
    141   2   "SELECT * FROM t1 WHERE rowid=5"
    142   3   "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
    143   4   "SELECT * FROM t1 WHERE x1<10 AND x2>12"
    144 }
    145 
    146 #-------------------------------------------------------------------------
    147 # Set the "depth" of the tree stored on the root node incorrectly. Test
    148 # that this does not cause any problems.
    149 #
    150 create_t1
    151 populate_t1
    152 do_test rtreeA-3.1.0.1 { set_tree_depth t1 } {1}
    153 do_test rtreeA-3.1.0.2 { set_tree_depth t1 3 } {3}
    154 do_corruption_tests rtreeA-3.1 {
    155   1   "SELECT * FROM t1"
    156   2   "SELECT * FROM t1 WHERE rowid=5"
    157   3   "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
    158 }
    159 
    160 do_test rtreeA-3.2.0 { set_tree_depth t1 1000 } {1000}
    161 do_corruption_tests rtreeA-3.2 {
    162   1   "SELECT * FROM t1"
    163   2   "SELECT * FROM t1 WHERE rowid=5"
    164   3   "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
    165 }
    166 
    167 create_t1
    168 populate_t1
    169 do_test rtreeA-3.3.0 { 
    170   execsql { DELETE FROM t1 WHERE rowid = 0 }
    171   set_tree_depth t1 65535
    172 } {65535}
    173 do_corruption_tests rtreeA-3.3 {
    174   1   "SELECT * FROM t1"
    175   2   "SELECT * FROM t1 WHERE rowid=5"
    176   3   "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
    177 }
    178 
    179 #-------------------------------------------------------------------------
    180 # Set the "number of entries" field on some nodes incorrectly.
    181 #
    182 create_t1
    183 populate_t1
    184 do_test rtreeA-4.1.0 { 
    185   set_entry_count t1 1 4000
    186 } {4000}
    187 do_corruption_tests rtreeA-4.1 {
    188   1   "SELECT * FROM t1"
    189   2   "SELECT * FROM t1 WHERE rowid=5"
    190   3   "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
    191   4   "SELECT * FROM t1 WHERE x1<10 AND x2>12"
    192 }
    193 
    194 #-------------------------------------------------------------------------
    195 # Remove entries from the %_parent table and check that this does not
    196 # cause a crash.
    197 #
    198 create_t1
    199 populate_t1
    200 do_execsql_test rtreeA-5.1.0 { DELETE FROM t1_parent } {}
    201 do_corruption_tests rtreeA-5.1 {
    202   1   "DELETE FROM t1 WHERE rowid = 5"
    203   2   "DELETE FROM t1"
    204 }
    205 
    206 #-------------------------------------------------------------------------
    207 # Add some bad entries to the %_parent table.
    208 #
    209 create_t1
    210 populate_t1
    211 do_execsql_test rtreeA-6.1.0 { 
    212   UPDATE t1_parent set parentnode = parentnode+1
    213 } {}
    214 do_corruption_tests rtreeA-6.1 {
    215   1   "DELETE FROM t1 WHERE rowid = 5"
    216   2   "UPDATE t1 SET x1=x1+1, x2=x2+1"
    217 }
    218 
    219 
    220 finish_test
    221