xref: /sqlite-3.40.0/ext/rtree/rtreeA.test (revision 7d44b22d)
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
16if {![info exists testdir]} {
17  set testdir [file join [file dirname [info script]] .. .. test]
18}
19source $testdir/tester.tcl
20ifcapable !rtree { finish_test ; return }
21
22proc 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}
31proc 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  sqlite3_db_config db DEFENSIVE 0
40}
41
42proc truncate_node {nodeno nTrunc} {
43  set blob [db one {SELECT data FROM t1_node WHERE nodeno=$nodeno}]
44  if {$nTrunc<0} {set nTrunc "end-$nTrunc"}
45  set blob [string range $blob 0 $nTrunc]
46  db eval { UPDATE t1_node SET data = $blob WHERE nodeno=$nodeno }
47}
48
49proc set_tree_depth {tbl {newvalue ""}} {
50  set blob [db one "SELECT data FROM ${tbl}_node WHERE nodeno=1"]
51
52  if {$newvalue == ""} {
53    binary scan $blob Su oldvalue
54    return $oldvalue
55  }
56
57  set blob [binary format Sua* $newvalue [string range $blob 2 end]]
58  db eval "UPDATE ${tbl}_node SET data = \$blob WHERE nodeno=1"
59  return [set_tree_depth $tbl]
60}
61
62proc set_entry_count {tbl nodeno {newvalue ""}} {
63  set blob [db one "SELECT data FROM ${tbl}_node WHERE nodeno=$nodeno"]
64
65  if {$newvalue == ""} {
66    binary scan [string range $blob 2 end] Su oldvalue
67    return $oldvalue
68  }
69
70  set blob [binary format a*Sua* \
71    [string range $blob 0 1] $newvalue [string range $blob 4 end]
72  ]
73  db eval "UPDATE ${tbl}_node SET data = \$blob WHERE nodeno=$nodeno"
74  return [set_entry_count $tbl $nodeno]
75}
76
77
78proc do_corruption_tests {prefix args} {
79  set testarray [lindex $args end]
80  set errormsg {database disk image is malformed}
81
82  foreach {z value} [lrange $args 0 end-1] {
83    set n [string length $z]
84    if {$n>=2 && [string equal -length $n $z "-error"]} {
85      set errormsg $value
86    }
87  }
88
89  foreach {tn sql} $testarray {
90    do_catchsql_test $prefix.$tn $sql [list 1 $errormsg]
91  }
92}
93
94#-------------------------------------------------------------------------
95# Test the libraries response if the %_node table is completely empty
96# (i.e. the root node is missing), or has been removed from the database
97# entirely.
98#
99create_t1
100populate_t1
101do_execsql_test rtreeA-1.0 {
102  DELETE FROM t1_node;
103} {}
104
105do_corruption_tests rtreeA-1.1 {
106  1   "SELECT * FROM t1"
107  2   "SELECT * FROM t1 WHERE rowid=5"
108  3   "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
109  4   "SELECT * FROM t1 WHERE x1<10 AND x2>12"
110}
111
112do_execsql_test rtreeA-1.1.1 {
113  SELECT rtreecheck('main', 't1')
114} {{Node 1 missing from database
115Wrong number of entries in %_rowid table - expected 0, actual 500
116Wrong number of entries in %_parent table - expected 0, actual 23}}
117
118do_execsql_test  rtreeA-1.2.0 { DROP TABLE t1_node } {}
119do_corruption_tests rtreeA-1.2 -error "database disk image is malformed" {
120  1   "SELECT * FROM t1"
121  2   "SELECT * FROM t1 WHERE rowid=5"
122  3   "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
123  4   "SELECT * FROM t1 WHERE x1<10 AND x2>12"
124}
125
126#-------------------------------------------------------------------------
127# Test the libraries response if some of the entries in the %_node table
128# are the wrong size.
129#
130create_t1
131populate_t1
132do_test rtreeA-2.1.0 {
133  set nodes [db eval {select nodeno FROM t1_node}]
134  foreach {a b c} $nodes { truncate_node $c 200 }
135} {}
136do_corruption_tests rtreeA-2.1 {
137  1   "SELECT * FROM t1"
138  2   "SELECT * FROM t1 WHERE rowid=5"
139  3   "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
140  4   "SELECT * FROM t1 WHERE x1<10 AND x2>12"
141}
142
143create_t1
144populate_t1
145do_test rtreeA-2.2.0 { truncate_node 1 200 } {}
146do_corruption_tests rtreeA-2.2 {
147  1   "SELECT * FROM t1"
148  2   "SELECT * FROM t1 WHERE +rowid=5"
149  3   "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
150  4   "SELECT * FROM t1 WHERE x1<10 AND x2>12"
151}
152
153#-------------------------------------------------------------------------
154# Set the "depth" of the tree stored on the root node incorrectly. Test
155# that this does not cause any problems.
156#
157create_t1
158populate_t1
159do_test rtreeA-3.1.0.1 { set_tree_depth t1 } {1}
160do_test rtreeA-3.1.0.2 { set_tree_depth t1 3 } {3}
161do_corruption_tests rtreeA-3.1 {
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
167do_execsql_test rtreeA-3.1.0.3 {
168  SELECT rtreecheck('main', 't1')!='ok'
169} {1}
170
171do_test rtreeA-3.2.0 { set_tree_depth t1 1000 } {1000}
172do_corruption_tests rtreeA-3.2 {
173  1   "SELECT * FROM t1"
174  2   "SELECT * FROM t1 WHERE +rowid=5"
175  3   "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
176}
177
178create_t1
179populate_t1
180do_test rtreeA-3.3.0 {
181  execsql { DELETE FROM t1 WHERE rowid = 0 }
182  set_tree_depth t1 65535
183} {65535}
184do_corruption_tests rtreeA-3.3 {
185  1   "SELECT * FROM t1"
186  2   "SELECT * FROM t1 WHERE +rowid=5"
187  3   "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
188}
189
190do_execsql_test rtreeA-3.3.3.4 {
191  SELECT rtreecheck('main', 't1')
192} {{Rtree depth out of range (65535)
193Wrong number of entries in %_rowid table - expected 0, actual 499
194Wrong number of entries in %_parent table - expected 0, actual 23}}
195
196#-------------------------------------------------------------------------
197# Set the "number of entries" field on some nodes incorrectly.
198#
199create_t1
200populate_t1
201do_test rtreeA-4.1.0 {
202  set_entry_count t1 1 4000
203} {4000}
204do_corruption_tests rtreeA-4.1 {
205  1   "SELECT * FROM t1"
206  2   "SELECT * FROM t1 WHERE +rowid=5"
207  3   "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
208  4   "SELECT * FROM t1 WHERE x1<10 AND x2>12"
209}
210
211#-------------------------------------------------------------------------
212# Remove entries from the %_parent table and check that this does not
213# cause a crash.
214#
215create_t1
216populate_t1
217do_execsql_test rtreeA-5.1.0 { DELETE FROM t1_parent } {}
218do_corruption_tests rtreeA-5.1 {
219  1   "DELETE FROM t1 WHERE +rowid = 5"
220  2   "DELETE FROM t1"
221}
222
223do_execsql_test rtreeA-5.2 {
224  SELECT rtreecheck('main', 't1')!='ok'
225} {1}
226
227#-------------------------------------------------------------------------
228# Add some bad entries to the %_parent table.
229#
230create_t1
231populate_t1
232do_execsql_test rtreeA-6.1.0 {
233  UPDATE t1_parent set parentnode = parentnode+1
234} {}
235do_corruption_tests rtreeA-6.1 {
236  1   "DELETE FROM t1 WHERE rowid = 5"
237  2   "UPDATE t1 SET x1=x1+1, x2=x2+1"
238}
239
240do_execsql_test rtreeA-6.2 {
241  SELECT rtreecheck('main', 't1')!='ok'
242} {1}
243
244#-------------------------------------------------------------------------
245# Truncated blobs in the _node table.
246#
247create_t1
248populate_t1
249sqlite3 db test.db
250sqlite3_db_config db DEFENSIVE 0
251do_execsql_test rtreeA-7.100 {
252  UPDATE t1_node SET data=x'' WHERE rowid=1;
253} {}
254do_catchsql_test rtreeA-7.110 {
255  SELECT * FROM t1 WHERE x1>0 AND x1<100 AND x2>0 AND x2<100;
256} {1 {undersize RTree blobs in "t1_node"}}
257do_test rtreeA-7.120 {
258  sqlite3_extended_errcode db
259} {SQLITE_CORRUPT_VTAB}
260
261
262finish_test
263