xref: /sqlite-3.40.0/ext/rtree/rtreeC.test (revision a3bc8425)
1# 2011 March 2
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# Make sure the rtreenode() testing function can handle entries with
12# 64-bit rowids.
13#
14
15if {![info exists testdir]} {
16  set testdir [file join [file dirname [info script]] .. .. test]
17}
18source [file join [file dirname [info script]] rtree_util.tcl]
19source $testdir/tester.tcl
20ifcapable !rtree { finish_test ; return }
21set testprefix rtreeC
22
23do_execsql_test 1.0 {
24  CREATE VIRTUAL TABLE r_tree USING rtree(id, min_x, max_x, min_y, max_y);
25  CREATE TABLE t(x, y);
26}
27
28do_eqp_test 1.1 {
29  SELECT * FROM r_tree, t
30  WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
31} {
32  0 0 1 {SCAN TABLE t}
33  0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
34}
35
36do_eqp_test 1.2 {
37  SELECT * FROM t, r_tree
38  WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
39} {
40  0 0 0 {SCAN TABLE t}
41  0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
42}
43
44do_eqp_test 1.3 {
45  SELECT * FROM t, r_tree
46  WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y
47} {
48  0 0 0 {SCAN TABLE t}
49  0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
50}
51
52do_eqp_test 1.5 {
53  SELECT * FROM t, r_tree
54} {
55  0 0 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:}
56  0 1 0 {SCAN TABLE t}
57}
58
59do_execsql_test 2.0 {
60  INSERT INTO t VALUES(0, 0);
61  INSERT INTO t VALUES(0, 1);
62  INSERT INTO t VALUES(0, 2);
63  INSERT INTO t VALUES(0, 3);
64  INSERT INTO t VALUES(0, 4);
65  INSERT INTO t VALUES(0, 5);
66  INSERT INTO t VALUES(0, 6);
67  INSERT INTO t VALUES(0, 7);
68  INSERT INTO t VALUES(0, 8);
69  INSERT INTO t VALUES(0, 9);
70
71  INSERT INTO t SELECT x+1, y FROM t;
72  INSERT INTO t SELECT x+2, y FROM t;
73  INSERT INTO t SELECT x+4, y FROM t;
74  INSERT INTO r_tree SELECT NULL, x-1, x+1, y-1, y+1 FROM t;
75  ANALYZE;
76}
77
78db close
79sqlite3 db test.db
80
81do_eqp_test 2.1 {
82  SELECT * FROM r_tree, t
83  WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
84} {
85  0 0 1 {SCAN TABLE t}
86  0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
87}
88
89do_eqp_test 2.2 {
90  SELECT * FROM t, r_tree
91  WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
92} {
93  0 0 0 {SCAN TABLE t}
94  0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
95}
96
97do_eqp_test 2.3 {
98  SELECT * FROM t, r_tree
99  WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y
100} {
101  0 0 0 {SCAN TABLE t}
102  0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
103}
104
105do_eqp_test 2.5 {
106  SELECT * FROM t, r_tree
107} {
108  0 0 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:}
109  0 1 0 {SCAN TABLE t}
110}
111
112#-------------------------------------------------------------------------
113# Test that the special CROSS JOIN handling works with rtree tables.
114#
115do_execsql_test 3.1 {
116  CREATE TABLE t1(x);
117  CREATE TABLE t2(y);
118  CREATE VIRTUAL TABLE t3 USING rtree(z, x1,x2, y1,y2);
119}
120
121do_eqp_test 3.2.1 { SELECT * FROM t1 CROSS JOIN t2 } {
122  0 0 0 {SCAN TABLE t1}
123  0 1 1 {SCAN TABLE t2}
124}
125do_eqp_test 3.2.2 { SELECT * FROM t2 CROSS JOIN t1 } {
126  0 0 0 {SCAN TABLE t2} 0 1 1 {SCAN TABLE t1}
127}
128
129do_eqp_test 3.3.1 { SELECT * FROM t1 CROSS JOIN t3 } {
130  0 0 0 {SCAN TABLE t1}
131  0 1 1 {SCAN TABLE t3 VIRTUAL TABLE INDEX 2:}
132}
133do_eqp_test 3.3.2 { SELECT * FROM t3 CROSS JOIN t1 } {
134  0 0 0 {SCAN TABLE t3 VIRTUAL TABLE INDEX 2:}
135  0 1 1 {SCAN TABLE t1}
136}
137
138#--------------------------------------------------------------------
139# Test that LEFT JOINs are not reordered if the right-hand-side is
140# a virtual table.
141#
142reset_db
143do_execsql_test 4.1 {
144  CREATE TABLE t1(a);
145  CREATE VIRTUAL TABLE t2 USING rtree(b, x1,x2);
146
147  INSERT INTO t1 VALUES(1);
148  INSERT INTO t1 VALUES(2);
149
150  INSERT INTO t2 VALUES(1, 0.0, 0.1);
151  INSERT INTO t2 VALUES(3, 0.0, 0.1);
152}
153
154do_execsql_test 4.2 {
155  SELECT a, b FROM t1 LEFT JOIN t2 ON (+a = +b);
156} {1 1 2 {}}
157
158do_execsql_test 4.3 {
159  SELECT b, a FROM t2 LEFT JOIN t1 ON (+a = +b);
160} {1 1 3 {}}
161
162#--------------------------------------------------------------------
163# Test that the sqlite_stat1 data is used correctly.
164#
165reset_db
166do_execsql_test 5.1 {
167  CREATE TABLE t1(x PRIMARY KEY, y);
168  CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2);
169
170  INSERT INTO t1(x) VALUES(1);
171  INSERT INTO t1(x) SELECT x+1 FROM t1;   --   2
172  INSERT INTO t1(x) SELECT x+2 FROM t1;   --   4
173  INSERT INTO t1(x) SELECT x+4 FROM t1;   --   8
174  INSERT INTO t1(x) SELECT x+8 FROM t1;   --  16
175  INSERT INTO t1(x) SELECT x+16 FROM t1;  --  32
176  INSERT INTO t1(x) SELECT x+32 FROM t1;  --  64
177  INSERT INTO t1(x) SELECT x+64 FROM t1;  -- 128
178  INSERT INTO t1(x) SELECT x+128 FROM t1; -- 256
179  INSERT INTO t1(x) SELECT x+256 FROM t1; -- 512
180  INSERT INTO t1(x) SELECT x+512 FROM t1; --1024
181
182  INSERT INTO rt SELECT x, x, x+1 FROM t1 WHERE x<=5;
183}
184do_rtree_integrity_test 5.1.1 rt
185
186# First test a query with no ANALYZE data at all. The outer loop is
187# real table "t1".
188#
189do_eqp_test 5.2 {
190  SELECT * FROM t1, rt WHERE x==id;
191} {
192  0 0 0 {SCAN TABLE t1}
193  0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 1:}
194}
195
196# Now create enough ANALYZE data to tell SQLite that virtual table "rt"
197# contains very few rows. This causes it to move "rt" to the outer loop.
198#
199do_execsql_test 5.3 {
200  ANALYZE;
201  DELETE FROM sqlite_stat1 WHERE tbl='t1';
202}
203db close
204sqlite3 db test.db
205do_eqp_test 5.4 {
206  SELECT * FROM t1, rt WHERE x==id;
207} {
208  0 0 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:}
209  0 1 0 {SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (x=?)}
210}
211
212# Delete the ANALYZE data. "t1" should be the outer loop again.
213#
214do_execsql_test 5.5 { DROP TABLE sqlite_stat1; }
215db close
216sqlite3 db test.db
217do_eqp_test 5.6 {
218  SELECT * FROM t1, rt WHERE x==id;
219} {
220  0 0 0 {SCAN TABLE t1}
221  0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 1:}
222}
223
224# This time create and attach a database that contains ANALYZE data for
225# tables of the same names as those used internally by virtual table
226# "rt". Check that the rtree module is not fooled into using this data.
227# Table "t1" should remain the outer loop.
228#
229do_test 5.7 {
230  db backup test.db2
231  sqlite3 db2 test.db2
232  db2 eval {
233    ANALYZE;
234    DELETE FROM sqlite_stat1 WHERE tbl='t1';
235  }
236  db2 close
237  db close
238  sqlite3 db test.db
239  execsql { ATTACH 'test.db2' AS aux; }
240} {}
241do_eqp_test 5.8 {
242  SELECT * FROM t1, rt WHERE x==id;
243} {
244  0 0 0 {SCAN TABLE t1}
245  0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 1:}
246}
247
248#--------------------------------------------------------------------
249# Test that having a second connection drop the sqlite_stat1 table
250# before it is required by rtreeConnect() does not cause problems.
251#
252ifcapable rtree {
253  reset_db
254  do_execsql_test 6.1 {
255    CREATE TABLE t1(x);
256    CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2);
257    INSERT INTO t1 VALUES(1);
258    INSERT INTO rt VALUES(1,2,3);
259    ANALYZE;
260  }
261  db close
262  sqlite3 db test.db
263  do_execsql_test 6.2 { SELECT * FROM t1 } {1}
264
265  do_test 6.3 {
266    sqlite3 db2 test.db
267    db2 eval { DROP TABLE sqlite_stat1 }
268    db2 close
269    execsql { SELECT * FROM rt }
270  } {1 2.0 3.0}
271  db close
272}
273
274#--------------------------------------------------------------------
275# Test that queries featuring LEFT or CROSS JOINS are handled correctly.
276# Handled correctly in this case means:
277#
278#   * Terms with prereqs that appear to the left of a LEFT JOIN against
279#     the virtual table are always available to xBestIndex.
280#
281#   * Terms with prereqs that appear to the right of a LEFT JOIN against
282#     the virtual table are never available to xBestIndex.
283#
284# And the same behaviour for CROSS joins.
285#
286reset_db
287do_execsql_test 7.0 {
288  CREATE TABLE xdir(x1);
289  CREATE TABLE ydir(y1);
290  CREATE VIRTUAL TABLE rt USING rtree_i32(id, xmin, xmax, ymin, ymax);
291
292  INSERT INTO xdir VALUES(5);
293  INSERT INTO ydir VALUES(10);
294
295  INSERT INTO rt VALUES(1, 2, 7, 12, 14);      -- Not a hit
296  INSERT INTO rt VALUES(2, 2, 7, 8, 12);       -- A hit!
297  INSERT INTO rt VALUES(3, 7, 11, 8, 12);      -- Not a hit!
298  INSERT INTO rt VALUES(4, 5, 5, 10, 10);      -- A hit!
299
300}
301
302proc do_eqp_execsql_test {tn sql res} {
303  set query "EXPLAIN QUERY PLAN $sql ; $sql "
304  uplevel [list do_execsql_test $tn $query $res]
305}
306
307do_eqp_execsql_test 7.1 {
308  SELECT id FROM xdir, rt, ydir
309  ON (y1 BETWEEN ymin AND ymax)
310  WHERE (x1 BETWEEN xmin AND xmax);
311} {
312  0 0 0 {SCAN TABLE xdir}
313  0 1 2 {SCAN TABLE ydir}
314  0 2 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B2D3B0D1}
315  2 4
316}
317
318do_eqp_execsql_test 7.2 {
319  SELECT * FROM xdir, rt LEFT JOIN ydir
320  ON (y1 BETWEEN ymin AND ymax)
321  WHERE (x1 BETWEEN xmin AND xmax);
322} {
323  0 0 0 {SCAN TABLE xdir}
324  0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1}
325  0 2 2 {SCAN TABLE ydir}
326
327  5 1 2 7 12 14 {}
328  5 2 2 7  8 12 10
329  5 4 5 5 10 10 10
330}
331
332do_eqp_execsql_test 7.3 {
333  SELECT id FROM xdir, rt CROSS JOIN ydir
334  ON (y1 BETWEEN ymin AND ymax)
335  WHERE (x1 BETWEEN xmin AND xmax);
336} {
337  0 0 0 {SCAN TABLE xdir}
338  0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1}
339  0 2 2 {SCAN TABLE ydir}
340  2 4
341}
342
343do_eqp_execsql_test 7.4 {
344  SELECT id FROM rt, xdir CROSS JOIN ydir
345  ON (y1 BETWEEN ymin AND ymax)
346  WHERE (x1 BETWEEN xmin AND xmax);
347} {
348  0 0 1 {SCAN TABLE xdir}
349  0 1 0 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1}
350  0 2 2 {SCAN TABLE ydir}
351  2 4
352}
353
354finish_test
355