xref: /sqlite-3.40.0/ext/rtree/rtreedoc.test (revision dcf10a1a)
1# 2021 September 13
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#
12# The focus of this file is testing the r-tree extension.
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
20set testprefix rtreedoc
21
22ifcapable !rtree {
23  finish_test
24  return
25}
26
27# This command returns the number of columns in table $tbl within the
28# database opened by database handle $db
29proc column_count {db tbl} {
30  set nCol 0
31  $db eval "PRAGMA table_info = $tbl" { incr nCol }
32  return $nCol
33}
34
35proc column_name_list {db tbl} {
36  set lCol [list]
37  $db eval "PRAGMA table_info = $tbl" {
38    lappend lCol $name
39  }
40  return $lCol
41}
42unset -nocomplain res
43
44#-------------------------------------------------------------------------
45#-------------------------------------------------------------------------
46# Section 3 of documentation.
47#-------------------------------------------------------------------------
48#-------------------------------------------------------------------------
49set testprefix rtreedoc-1
50
51# EVIDENCE-OF: R-15060-13876 A 1-dimensional R*Tree thus has 3 columns.
52do_execsql_test 1.1.1 { CREATE VIRTUAL TABLE rt1 USING rtree(id, x1,x2) }
53do_test         1.1.2 { column_count db rt1 } 3
54
55# EVIDENCE-OF: R-19353-19546 A 2-dimensional R*Tree has 5 columns.
56do_execsql_test 1.2.1 { CREATE VIRTUAL TABLE rt2 USING rtree(id,x1,x2, y1,y2) }
57do_test         1.2.2 { column_count db rt2 } 5
58
59# EVIDENCE-OF: R-13615-19528 A 3-dimensional R*Tree has 7 columns.
60do_execsql_test 1.3.1 {
61  CREATE VIRTUAL TABLE rt3 USING rtree(id, x1,x2, y1,y2, z1,z2)
62}
63do_test         1.3.2 { column_count db rt3 } 7
64
65# EVIDENCE-OF: R-53479-41922 A 4-dimensional R*Tree has 9 columns.
66do_execsql_test 1.4.1 {
67  CREATE VIRTUAL TABLE rt4 USING rtree(id, x1,x2, y1,y2, z1,z2, v1,v2)
68}
69do_test         1.4.2 { column_count db rt4 } 9
70
71# EVIDENCE-OF: R-13981-28768 And a 5-dimensional R*Tree has 11 columns.
72do_execsql_test 1.5.1 {
73  CREATE VIRTUAL TABLE rt5 USING rtree(id, x1,x2, y1,y2, z1,z2, v1,v2, w1,w2)
74}
75do_test         1.5.2 { column_count db rt5 } 11
76
77
78# Attempt to create r-tree tables with 6 and 7 dimensions.
79#
80# EVIDENCE-OF: R-61533-25862 The SQLite R*Tree implementation does not
81# support R*Trees wider than 5 dimensions.
82do_catchsql_test 2.1.1 {
83  CREATE VIRTUAL TABLE rt6 USING rtree(
84    id, x1,x2, y1,y2, z1,z2, v1,v2, w1,w2, a1,a2
85  )
86} {1 {Too many columns for an rtree table}}
87do_catchsql_test 2.1.2 {
88  CREATE VIRTUAL TABLE rt6 USING rtree(
89    id, x1,x2, y1,y2, z1,z2, v1,v2, w1,w2, a1,a2, b1, b2
90  )
91} {1 {Too many columns for an rtree table}}
92
93# Attempt to create r-tree tables with no columns, a single column, or
94# an even number of columns. This and the tests above establish that:
95#
96# EVIDENCE-OF: R-16717-50504 Each R*Tree index is a virtual table with
97# an odd number of columns between 3 and 11.
98foreach {tn cols err} {
99  1 ""                        "Too few columns for an rtree table"
100  2 "x"                       "Too few columns for an rtree table"
101  3 "x,y"                     "Too few columns for an rtree table"
102  4 "a,b,c,d"                 "Wrong number of columns for an rtree table"
103  5 "a,b,c,d,e,f"             "Wrong number of columns for an rtree table"
104  6 "a,b,c,d,e,f,g,h"         "Wrong number of columns for an rtree table"
105  7 "a,b,c,d,e,f,g,h,i,j"     "Wrong number of columns for an rtree table"
106  8 "a,b,c,d,e,f,g,h,i,j,k,l" "Too many columns for an rtree table"
107} {
108  do_catchsql_test 3.$tn "
109    CREATE VIRTUAL TABLE xyz USING rtree($cols)
110  " [list 1 $err]
111}
112
113# EVIDENCE-OF: R-17874-21123 The first column of an SQLite R*Tree is
114# similar to an integer primary key column of a normal SQLite table.
115#
116# EVIDENCE-OF: R-46619-65417 The first column is always a 64-bit signed
117# integer primary key.
118#
119# EVIDENCE-OF: R-46866-24036 It may only store a 64-bit signed integer
120# value.
121#
122# EVIDENCE-OF: R-00250-64843 If an attempt is made to insert any other
123# non-integer value into this column, the r-tree module silently
124# converts it to an integer before writing it into the database.
125#
126do_execsql_test 4.0 { CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2) }
127foreach {tn val res} {
128  1 10    10
129  2 10.6  10
130  3 10.99 10
131  4 '123' 123
132  5 X'313233'  123
133  6 -10   -10
134  7  9223372036854775807 9223372036854775807
135  8 -9223372036854775808 -9223372036854775808
136  9  '9223372036854775807' 9223372036854775807
137  10  '-9223372036854775808' -9223372036854775808
138  11  'hello+world' 0
139} {
140  do_execsql_test 4.$tn.1 "
141    DELETE FROM rt;
142    INSERT INTO rt VALUES($val, 10, 20);
143  "
144  do_execsql_test 4.$tn.2 {
145    SELECT typeof(id), id FROM rt
146  } [list integer $res]
147}
148
149# EVIDENCE-OF: R-15544-29079 Inserting a NULL value into this column
150# causes SQLite to automatically generate a new unique primary key
151# value.
152do_execsql_test 5.1 {
153  DELETE FROM rt;
154  INSERT INTO rt VALUES(100, 1, 2);
155  INSERT INTO rt VALUES(NULL, 1, 2);
156}
157do_execsql_test 5.2 { SELECT id FROM rt } {100 101}
158do_execsql_test 5.3 {
159  INSERT INTO rt VALUES(9223372036854775807, 1, 2);
160  INSERT INTO rt VALUES(NULL, 1, 2);
161}
162do_execsql_test 5.4 {
163  SELECT count(*) FROM rt;
164} 4
165do_execsql_test 5.5 {
166  SELECT id IN(100, 101, 9223372036854775807) FROM rt ORDER BY 1;
167} {0 1 1 1}
168
169
170# EVIDENCE-OF: R-64317-38978 The other columns are pairs, one pair per
171# dimension, containing the minimum and maximum values for that
172# dimension, respectively.
173#
174# Show this by observing that attempts to insert rows with max>min fail.
175#
176do_execsql_test 6.1 {
177  CREATE VIRTUAL TABLE rtF USING rtree(id, x1,x2, y1,y2);
178  CREATE VIRTUAL TABLE rtI USING rtree_i32(id, x1,x2, y1,y2, z1,z2);
179}
180foreach {tn x1 x2 y1 y2 ok} {
181  1   10.3 20.1   30.9 40.2   1
182  2   10.3 20.1   40.2 30.9   0
183  3   10.3 30.9   20.1 40.2   1
184  4   20.1 10.3   30.9 40.2   0
185} {
186  do_test 6.2.$tn {
187    catch { db eval { INSERT INTO rtF VALUES(NULL, $x1, $x2, $y1, $y2) } }
188  } [expr $ok==0]
189}
190foreach {tn x1 x2 y1 y2 z1 z2 ok} {
191  1   10 20   30 40  50 60  1
192  2   10 20   30 40  60 50  0
193  3   10 20   30 50  40 60  1
194  4   10 20   40 30  50 60  0
195  5   10 30   20 40  50 60  1
196  6   20 10   30 40  50 60  0
197} {
198  do_test 6.3.$tn {
199    catch { db eval { INSERT INTO rtI VALUES(NULL,$x1,$x2,$y1,$y2,$z1,$z2) } }
200  } [expr $ok==0]
201}
202
203# EVIDENCE-OF: R-08054-15429 The min/max-value pair columns are stored
204# as 32-bit floating point values for "rtree" virtual tables or as
205# 32-bit signed integers in "rtree_i32" virtual tables.
206#
207# Show this by showing that large values are rounded in ways consistent
208# with those two 32-bit types.
209do_execsql_test 7.1 {
210  DELETE FROM rtI;
211  INSERT INTO rtI VALUES(
212    0, -2000000000, 2000000000, -5000000000, 5000000000,
213    -1000000000000, 10000000000000
214  );
215  SELECT * FROM rtI;
216} {
217  0 -2000000000 2000000000 -705032704 705032704 727379968 1316134912
218}
219do_execsql_test 7.2 {
220  DELETE FROM rtF;
221  INSERT INTO rtF VALUES(
222    0, -2000000000, 2000000000,
223    -1000000000000, 10000000000000
224  );
225  SELECT * FROM rtF;
226} {
227  0 -2000000000.0 2000000000.0 -1000000126976.0 10000000876544.0
228}
229
230# EVIDENCE-OF: R-47371-54529 Unlike regular SQLite tables which can
231# store data in a variety of datatypes and formats, the R*Tree rigidly
232# enforce these storage types.
233#
234# EVIDENCE-OF: R-39153-14977 If any other type of value is inserted into
235# such a column, the r-tree module silently converts it to the required
236# type before writing the new record to the database.
237do_execsql_test 8.1 {
238  DELETE FROM rtI;
239  INSERT INTO rtI VALUES(
240    1, 'hello world', X'616263', NULL, 44.5, 1000, 9999.9999
241  );
242  SELECT * FROM rtI;
243} {
244  1   0 0    0 44    1000 9999
245}
246
247do_execsql_test 8.2 {
248  SELECT
249    typeof(x1), typeof(x2), typeof(y1), typeof(y2), typeof(z1), typeof(z2)
250  FROM rtI
251} {integer integer integer integer integer integer}
252
253do_execsql_test 8.3 {
254  DELETE FROM rtF;
255  INSERT INTO rtF VALUES(
256    1, 'hello world', X'616263', NULL, 44
257  );
258  SELECT * FROM rtF;
259} {
260  1   0.0 0.0    0.0 44.0
261}
262do_execsql_test 8.4 {
263  SELECT
264    typeof(x1), typeof(x2), typeof(y1), typeof(y2)
265  FROM rtF
266} {real real real real}
267
268
269
270
271#-------------------------------------------------------------------------
272#-------------------------------------------------------------------------
273# Section 3.1 of documentation.
274#-------------------------------------------------------------------------
275#-------------------------------------------------------------------------
276set testprefix rtreedoc-2
277reset_db
278
279foreach {tn name clist} {
280  1 t1 "id x1 x2"
281  2 t2 "id x1 x2   y1 y2   z1 z2"
282} {
283# EVIDENCE-OF: R-15142-18077 A new R*Tree index is created as follows:
284# CREATE VIRTUAL TABLE <name> USING rtree(<column-names>);
285  do_execsql_test 1.$tn.1 "
286    CREATE VIRTUAL TABLE $name USING rtree([join $clist ,])
287  "
288
289# EVIDENCE-OF: R-51698-09302 The <name> is the name your
290# application chooses for the R*Tree index and <column-names> is a
291# comma separated list of between 3 and 11 columns.
292  do_test 1.$tn.2 { column_name_list db $name } [list {*}$clist]
293
294# EVIDENCE-OF: R-50130-53472 The virtual <name> table creates
295# three shadow tables to actually store its content.
296  do_execsql_test 1.$tn.3 {
297    SELECT count(*) FROM sqlite_schema
298  } [expr 1+3]
299
300# EVIDENCE-OF: R-45256-35998 The names of these shadow tables are:
301# <name>_node <name>_rowid <name>_parent
302  do_execsql_test 1.$tn.4 {
303    SELECT name FROM sqlite_schema WHERE rootpage>0 ORDER BY 1
304  } [list ${name}_node ${name}_parent ${name}_rowid]
305
306  do_execsql_test 1.$tn.5 "DROP TABLE $name"
307}
308
309# EVIDENCE-OF: R-11241-54478 As an example, consider creating a
310# two-dimensional R*Tree index for use in spatial queries: CREATE
311# VIRTUAL TABLE demo_index USING rtree( id, -- Integer primary key minX,
312# maxX, -- Minimum and maximum X coordinate minY, maxY -- Minimum and
313# maximum Y coordinate );
314do_execsql_test 2.0 {
315  CREATE VIRTUAL TABLE demo_index USING rtree(
316      id,              -- Integer primary key
317      minX, maxX,      -- Minimum and maximum X coordinate
318      minY, maxY       -- Minimum and maximum Y coordinate
319  );
320  INSERT INTO demo_index VALUES(1,2,3,4,5);
321  INSERT INTO demo_index VALUES(6,7,8,9,10);
322}
323
324# EVIDENCE-OF: R-02287-33529 The shadow tables are ordinary SQLite data
325# tables.
326#
327# Ordinary tables. With ordinary sqlite_schema entries.
328do_execsql_test 2.1 {
329  SELECT type, name, sql FROM sqlite_schema WHERE sql NOT LIKE '%virtual%'
330} {
331  table demo_index_rowid
332    {CREATE TABLE "demo_index_rowid"(rowid INTEGER PRIMARY KEY,nodeno)}
333  table demo_index_node
334    {CREATE TABLE "demo_index_node"(nodeno INTEGER PRIMARY KEY,data)}
335  table demo_index_parent
336    {CREATE TABLE "demo_index_parent"(nodeno INTEGER PRIMARY KEY,parentnode)}
337}
338
339# EVIDENCE-OF: R-10863-13089 You can query them directly if you like,
340# though this unlikely to reveal anything particularly useful.
341#
342# Querying:
343do_execsql_test 2.2 {
344  SELECT count(*) FROM demo_index_node;
345  SELECT count(*) FROM demo_index_rowid;
346  SELECT count(*) FROM demo_index_parent;
347} {1 2 0}
348
349# EVIDENCE-OF: R-05650-46070 And you can UPDATE, DELETE, INSERT or even
350# DROP the shadow tables, though doing so will corrupt your R*Tree
351# index.
352do_execsql_test 2.3 {
353  DELETE FROM demo_index_rowid;
354  INSERT INTO demo_index_parent VALUES(2, 3);
355  UPDATE demo_index_node SET data = 'hello world'
356}
357do_catchsql_test 2.4 {
358  SELECT * FROM demo_index WHERE minX>10 AND maxX<30
359} {1 {database disk image is malformed}}
360do_execsql_test 2.5 {
361  DROP TABLE demo_index_rowid
362}
363
364#-------------------------------------------------------------------------
365#-------------------------------------------------------------------------
366# Section 3.1.1 of documentation.
367#-------------------------------------------------------------------------
368#-------------------------------------------------------------------------
369set testprefix rtreedoc-3
370reset_db
371
372# EVIDENCE-OF: R-44253-50720 In the argments to "rtree" in the CREATE
373# VIRTUAL TABLE statement, the names of the columns are taken from the
374# first token of each argument. All subsequent tokens within each
375# argument are silently ignored.
376#
377foreach {tn cols lCol} {
378  1 {(id TEXT, x1 TEXT, x2 TEXT, y1 TEXT, y2 TEXT)} {id x1 x2 y1 y2}
379  2 {(id TEXT, x1 UNIQUE, x2 TEXT, y1 NOT NULL, y2 TEXT)} {id x1 x2 y1 y2}
380  3 {(id, x1 DEFAULT 4, x2 TEXT, y1 NOT NULL, y2 TEXT)} {id x1 x2 y1 y2}
381} {
382  do_execsql_test 1.$tn.1 " CREATE VIRTUAL TABLE abc USING rtree $cols "
383  do_test 1.$tn.2 { column_name_list db abc } $lCol
384
385# EVIDENCE-OF: R-52032-06717 This means, for example, that if you try to
386# give a column a type affinity or add a constraint such as UNIQUE or
387# NOT NULL or DEFAULT to a column, those extra tokens are accepted as
388# valid, but they do not change the behavior of the rtree.
389
390  # Show there are no UNIQUE constraints
391  do_execsql_test 1.$tn.3 {
392    INSERT INTO abc VALUES(1, 10.0, 20.0, 10.0, 20.0);
393    INSERT INTO abc VALUES(2, 10.0, 20.0, 10.0, 20.0);
394  }
395
396  # Show the default values have not been modified
397  do_execsql_test 1.$tn.4 {
398    INSERT INTO abc DEFAULT VALUES;
399    SELECT * FROM abc WHERE rowid NOT IN (1,2)
400  } {3 0.0 0.0 0.0 0.0}
401
402  # Show that there are no NOT NULL constraints
403  do_execsql_test 1.$tn.5 {
404    INSERT INTO abc VALUES(NULL, NULL, NULL, NULL, NULL);
405    SELECT * FROM abc WHERE rowid NOT IN (1,2,3)
406  } {4 0.0 0.0 0.0 0.0}
407
408# EVIDENCE-OF: R-06893-30579 In an RTREE virtual table, the first column
409# always has a type affinity of INTEGER and all other data columns have
410# a type affinity of REAL.
411  do_execsql_test 1.$tn.5 {
412    INSERT INTO abc VALUES('5', '5', '5', '5', '5');
413    SELECT * FROM abc WHERE rowid NOT IN (1,2,3,4)
414  } {5 5.0 5.0 5.0 5.0}
415  do_execsql_test 1.$tn.6 {
416    SELECT type FROM pragma_table_info('abc') ORDER BY cid
417  } {INT REAL REAL REAL REAL}
418
419  do_execsql_test 1.$tn.7 " CREATE VIRTUAL TABLE abc2 USING rtree_i32 $cols "
420
421# EVIDENCE-OF: R-06224-52418 In an RTREE_I32 virtual table, all columns
422# have type affinity of INTEGER.
423  do_execsql_test 1.$tn.8 {
424    INSERT INTO abc2 VALUES('6.0', '6.0', '6.0', '6.0', '6.0');
425    SELECT * FROM abc2
426  } {6 6 6 6 6}
427  do_execsql_test 1.$tn.9 {
428    SELECT type FROM pragma_table_info('abc2') ORDER BY cid
429  } {INT INT INT INT INT}
430
431
432  do_execsql_test 1.$tn.10 {
433    DROP TABLE abc;
434    DROP TABLE abc2;
435  }
436}
437
438#-------------------------------------------------------------------------
439#-------------------------------------------------------------------------
440# Section 3.2 of documentation.
441#-------------------------------------------------------------------------
442#-------------------------------------------------------------------------
443set testprefix rtreedoc-4
444reset_db
445
446# EVIDENCE-OF: R-36195-31555 The usual INSERT, UPDATE, and DELETE
447# commands work on an R*Tree index just like on regular tables.
448#
449# Create a regular table and an rtree table. Perform INSERT, UPDATE and
450# DELETE operations, then observe that the contents of the two tables
451# are identical.
452do_execsql_test 1.0 {
453  CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2);
454  CREATE TABLE t1(id INTEGER PRIMARY KEY, x1 REAL, x2 REAL);
455}
456foreach {tn sql} {
457  1 "INSERT INTO %TBL% VALUES(5, 11,12)"
458  2 "INSERT INTO %TBL% VALUES(11, -11,14.5)"
459  3 "UPDATE %TBL% SET x1=-99 WHERE id=11"
460  4 "DELETE FROM %TBL% WHERE x2=14.5"
461  5 "DELETE FROM %TBL%"
462} {
463  set sql1 [string map {%TBL% rt} $sql]
464  set sql2 [string map {%TBL% t1} $sql]
465  do_execsql_test 1.$tn.0 $sql1
466  do_execsql_test 1.$tn.1 $sql2
467
468  set data1 [execsql {SELECT * FROM rt ORDER BY 1}]
469  set data2 [execsql {SELECT * FROM t1 ORDER BY 1}]
470
471  set res [expr {$data1==$data2}]
472  do_test 1.$tn.2 {set res} 1
473}
474
475# EVIDENCE-OF: R-56987-45305
476do_execsql_test 2.0 {
477  CREATE VIRTUAL TABLE demo_index USING rtree(
478      id,              -- Integer primary key
479      minX, maxX,      -- Minimum and maximum X coordinate
480      minY, maxY       -- Minimum and maximum Y coordinate
481  );
482
483  INSERT INTO demo_index VALUES
484    (28215, -80.781227, -80.604706, 35.208813, 35.297367),
485    (28216, -80.957283, -80.840599, 35.235920, 35.367825),
486    (28217, -80.960869, -80.869431, 35.133682, 35.208233),
487    (28226, -80.878983, -80.778275, 35.060287, 35.154446),
488    (28227, -80.745544, -80.555382, 35.130215, 35.236916),
489    (28244, -80.844208, -80.841988, 35.223728, 35.225471),
490    (28262, -80.809074, -80.682938, 35.276207, 35.377747),
491    (28269, -80.851471, -80.735718, 35.272560, 35.407925),
492    (28270, -80.794983, -80.728966, 35.059872, 35.161823),
493    (28273, -80.994766, -80.875259, 35.074734, 35.172836),
494    (28277, -80.876793, -80.767586, 35.001709, 35.101063),
495    (28278, -81.058029, -80.956375, 35.044701, 35.223812),
496    (28280, -80.844208, -80.841972, 35.225468, 35.227203),
497    (28282, -80.846382, -80.844193, 35.223972, 35.225655);
498}
499
500#-------------------------------------------------------------------------
501#-------------------------------------------------------------------------
502# Section 3.3 of documentation.
503#-------------------------------------------------------------------------
504#-------------------------------------------------------------------------
505set testprefix rtreedoc-5
506
507do_execsql_test 1.0 {
508  INSERT INTO demo_index
509    SELECT NULL, minX, maxX, minY+0.2, maxY+0.2 FROM demo_index;
510  INSERT INTO demo_index
511    SELECT NULL, minX+0.2, maxX+0.2, minY, maxY FROM demo_index;
512  INSERT INTO demo_index
513    SELECT NULL, minX, maxX, minY+0.4, maxY+0.4 FROM demo_index;
514  INSERT INTO demo_index
515    SELECT NULL, minX+0.4, maxX+0.4, minY, maxY FROM demo_index;
516  INSERT INTO demo_index
517    SELECT NULL, minX, maxX, minY+0.8, maxY+0.8 FROM demo_index;
518  INSERT INTO demo_index
519    SELECT NULL, minX+0.8, maxX+0.8, minY, maxY FROM demo_index;
520
521  SELECT count(*) FROM demo_index;
522} {896}
523
524proc do_vmstep_test {tn sql expr} {
525  execsql $sql
526  set step [db status vmstep]
527  do_test $tn.$step "expr {[subst $expr]}" 1
528}
529
530# EVIDENCE-OF: R-45880-07724 Any valid query will work against an R*Tree
531# index.
532do_execsql_test 1.1.0 {
533  CREATE TABLE demo_tbl AS SELECT * FROM demo_index;
534}
535foreach {tn sql} {
536  1  {SELECT * FROM %TBL% ORDER BY 1}
537  2  {SELECT max(minX) FROM %TBL% ORDER BY 1}
538  3  {SELECT max(minX) FROM %TBL% GROUP BY round(minY) ORDER BY 1}
539} {
540  set sql1 [string map {%TBL% demo_index} $sql]
541  set sql2 [string map {%TBL% demo_tbl} $sql]
542
543  do_execsql_test 1.1.$tn $sql1 [execsql $sql2]
544}
545
546# EVIDENCE-OF: R-60814-18273 The R*Tree implementation just makes some
547# kinds of queries especially efficient.
548#
549# The second query is more efficient than the first.
550do_vmstep_test 1.2.1 {SELECT * FROM demo_index WHERE +rowid=28269} {$step>2000}
551do_vmstep_test 1.2.2 {SELECT * FROM demo_index WHERE rowid=28269} {$step<100}
552
553# EVIDENCE-OF: R-37800-50174 Queries against the primary key are
554# efficient: SELECT * FROM demo_index WHERE id=28269;
555do_vmstep_test 2.2 { SELECT * FROM demo_index WHERE id=28269 } {$step < 100}
556
557# EVIDENCE-OF: R-35847-18866 The big reason for using an R*Tree is so
558# that you can efficiently do range queries against the coordinate
559# ranges.
560#
561# EVIDENCE-OF: R-49927-54202
562do_vmstep_test 2.3 {
563  SELECT id FROM demo_index
564    WHERE minX<=-80.77470 AND maxX>=-80.77470
565    AND minY<=35.37785  AND maxY>=35.37785;
566} {$step < 100}
567
568# EVIDENCE-OF: R-12823-37176 The query above will quickly locate all
569# zipcodes that contain the SQLite main office in their bounding box,
570# even if the R*Tree contains many entries.
571#
572do_execsql_test 2.4 {
573  SELECT id FROM demo_index
574    WHERE minX<=-80.77470 AND maxX>=-80.77470
575    AND minY<=35.37785  AND maxY>=35.37785;
576} {
577  28322 28269
578}
579
580# EVIDENCE-OF: R-07351-00257 For example, to find all zipcode bounding
581# boxes that overlap with the 28269 zipcode: SELECT A.id FROM demo_index
582# AS A, demo_index AS B WHERE A.maxX>=B.minX AND A.minX<=B.maxX
583# AND A.maxY>=B.minY AND A.minY<=B.maxY AND B.id=28269;
584#
585# Also check that it is efficient
586#
587# EVIDENCE-OF: R-39094-01937 This second query will find both 28269
588# entry (since every bounding box overlaps with itself) and also other
589# zipcode that is close enough to 28269 that their bounding boxes
590# overlap.
591#
592# 28269 is there in the result.
593#
594do_vmstep_test 2.5.1 {
595  SELECT A.id FROM demo_index AS A, demo_index AS B
596    WHERE A.maxX>=B.minX AND A.minX<=B.maxX
597    AND A.maxY>=B.minY AND A.minY<=B.maxY
598    AND B.id=28269
599} {$step < 100}
600do_execsql_test 2.5.2 {
601  SELECT A.id FROM demo_index AS A, demo_index AS B
602    WHERE A.maxX>=B.minX AND A.minX<=B.maxX
603    AND A.maxY>=B.minY AND A.minY<=B.maxY
604    AND B.id=28269;
605} {
606  28293 28216 28322 28286 28269
607  28215 28336 28262 28291 28320
608  28313 28298 28287
609}
610
611# EVIDENCE-OF: R-02723-34107 Note that it is not necessary for all
612# coordinates in an R*Tree index to be constrained in order for the
613# index search to be efficient.
614#
615# EVIDENCE-OF: R-22490-27246 One might, for example, want to query all
616# objects that overlap with the 35th parallel: SELECT id FROM demo_index
617# WHERE maxY>=35.0 AND minY<=35.0;
618do_vmstep_test 2.6.1 {
619  SELECT id FROM demo_index
620   WHERE maxY>=35.0  AND minY<=35.0;
621} {$step < 100}
622do_execsql_test 2.6.2 {
623  SELECT id FROM demo_index
624   WHERE maxY>=35.0  AND minY<=35.0;
625} {}
626
627
628#-------------------------------------------------------------------------
629#-------------------------------------------------------------------------
630# Section 3.4 of documentation.
631#-------------------------------------------------------------------------
632#-------------------------------------------------------------------------
633set testprefix rtreedoc-6
634reset_db
635
636# EVIDENCE-OF: R-08327-00674 By default, coordinates are stored in an
637# R*Tree using 32-bit floating point values.
638#
639# EVIDENCE-OF: R-22000-53613 The default virtual table ("rtree") stores
640# coordinates as single-precision (4-byte) floating point numbers.
641#
642# Show this by showing that rounding is consistent with 32-bit float
643# rounding.
644do_execsql_test 1.0 {
645  CREATE VIRTUAL TABLE rt USING rtree(id, a,b);
646}
647do_execsql_test 1.1 {
648  INSERT INTO rt VALUES(14, -1000000000000, 1000000000000);
649  SELECT * FROM rt;
650} {14 -1000000126976.0 1000000126976.0}
651
652# EVIDENCE-OF: R-39127-51288 When a coordinate cannot be exactly
653# represented by a 32-bit floating point number, the lower-bound
654# coordinates are rounded down and the upper-bound coordinates are
655# rounded up.
656foreach {tn val} {
657  1 100000000000
658  2 200000000000
659  3 300000000000
660  4 400000000000
661
662  5 -100000000000
663  6 -200000000000
664  7 -300000000000
665  8 -400000000000
666} {
667  set val [expr $val]
668  do_execsql_test 2.$tn.0 {DELETE FROM rt}
669  do_execsql_test 2.$tn.1 {INSERT INTO rt VALUES(23, $val, $val)}
670  do_execsql_test 2.$tn.2 {
671    SELECT $val>=a, $val<=b, a!=b FROM rt
672  } {1 1 1}
673}
674
675do_execsql_test 3.0 {
676  DROP TABLE rt;
677  CREATE VIRTUAL TABLE rt USING rtree(id, x1,x2, y1,y2);
678}
679
680# EVIDENCE-OF: R-45870-62834 Thus, bounding boxes might be slightly
681# larger than specified, but will never be any smaller.
682foreach {tn x1 x2 y1 y2} {
683  1 100000000000 200000000000 300000000000 400000000000
684} {
685  set val [expr $val]
686  do_execsql_test 3.$tn.0 {DELETE FROM rt}
687  do_execsql_test 3.$tn.1 {INSERT INTO rt VALUES(23, $x1, $x2, $y1, $y2)}
688  do_execsql_test 3.$tn.2 {
689    SELECT (x2-x1)*(y2-y1) >= ($x2-$x1)*($y2-$y1) FROM rt
690  } {1}
691}
692
693#-------------------------------------------------------------------------
694#-------------------------------------------------------------------------
695# Section 3.5 of documentation.
696#-------------------------------------------------------------------------
697#-------------------------------------------------------------------------
698set testprefix rtreedoc-7
699reset_db
700
701# EVIDENCE-OF: R-55979-39402 It is the nature of the Guttman R-Tree
702# algorithm that any write might radically restructure the tree, and in
703# the process change the scan order of the nodes.
704#
705# In the test below, the INSERT marked "THIS INSERT!!" does not affect
706# the results of queries with an ORDER BY, but does affect the results
707# of one without an ORDER BY. Therefore the INSERT changed the scan
708# order.
709do_execsql_test 1.0 {
710  CREATE VIRTUAL TABLE rt USING rtree(id, minX, maxX);
711  WITH s(i) AS (
712    SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<51
713  )
714  INSERT INTO rt SELECT NULL, i%10, (i%10)+5 FROM s
715}
716do_execsql_test 1.1 { SELECT count(*) FROM rt_node } 1
717do_test 1.2 {
718  set res1 [db eval {SELECT * FROM rt WHERE maxX < 30}]
719  set res1o [db eval {SELECT * FROM rt WHERE maxX < 30 ORDER BY +id}]
720
721  db eval { INSERT INTO rt VALUES(NULL, 50, 50) }   ;# THIS INSERT!!
722
723  set res2 [db eval {SELECT * FROM rt WHERE maxX < 30}]
724  set res2o [db eval {SELECT * FROM rt WHERE maxX < 30 ORDER BY +id}]
725  list [expr {$res1==$res2}] [expr {$res1o==$res2o}]
726} {0 1}
727
728do_execsql_test 1.3 { SELECT count(*) FROM rt_node } 3
729
730# EVIDENCE-OF: R-00683-48865 For this reason, it is not generally
731# possible to modify the R-Tree in the middle of a query of the R-Tree.
732# Attempts to do so will fail with a SQLITE_LOCKED "database table is
733# locked" error.
734#
735# SQLITE_LOCKED==6
736#
737do_test 1.4 {
738  set nCnt 3
739  db eval { SELECT * FROM rt WHERE minX>0 AND maxX<12 } {
740    incr nCnt -1
741    if {$nCnt==0} {
742      set rc [catch {db eval {
743        INSERT INTO rt VALUES(NULL, 51, 51);
744      }} msg]
745      set errorcode [db errorcode]
746      break
747    }
748  }
749
750  list $errorcode $rc $msg
751} {6 1 {database table is locked}}
752
753# EVIDENCE-OF: R-19740-29710 So, for example, suppose an application
754# runs one query against an R-Tree like this: SELECT id FROM demo_index
755# WHERE maxY>=35.0 AND minY<=35.0; Then for each "id" value
756# returned, suppose the application creates an UPDATE statement like the
757# following and binds the "id" value returned against the "?1"
758# parameter: UPDATE demo_index SET maxY=maxY+0.5 WHERE id=?1;
759#
760# EVIDENCE-OF: R-52919-32711 Then the UPDATE might fail with an
761# SQLITE_LOCKED error.
762do_execsql_test 2.0 {
763  CREATE VIRTUAL TABLE demo_index USING rtree(
764      id,              -- Integer primary key
765      minX, maxX,      -- Minimum and maximum X coordinate
766      minY, maxY       -- Minimum and maximum Y coordinate
767  );
768  INSERT INTO demo_index VALUES
769    (28215, -80.781227, -80.604706, 35.208813, 35.297367),
770    (28216, -80.957283, -80.840599, 35.235920, 35.367825),
771    (28217, -80.960869, -80.869431, 35.133682, 35.208233),
772    (28226, -80.878983, -80.778275, 35.060287, 35.154446);
773}
774do_test 2.1 {
775  db eval { SELECT id FROM demo_index WHERE maxY>=35.0  AND minY<=35.0 } {
776    set rc [catch {
777      db eval { UPDATE demo_index SET maxY=maxY+0.5 WHERE id=$id }
778    } msg]
779    set errorcode [db errorcode]
780    break
781  }
782  list $errorcode $rc $msg
783} {6 1 {database table is locked}}
784
785# EVIDENCE-OF: R-32604-49843 Ordinary tables in SQLite are able to read
786# and write at the same time.
787#
788do_execsql_test 3.0 {
789  CREATE TABLE x1(a INTEGER PRIMARY KEY, b, c);
790  INSERT INTO x1 VALUES(1, 1, 1);
791  INSERT INTO x1 VALUES(2, 2, 2);
792  INSERT INTO x1 VALUES(3, 3, 3);
793  INSERT INTO x1 VALUES(4, 4, 4);
794}
795do_test 3.1 {
796  unset -nocomplain res
797  set res [list]
798  db eval { SELECT * FROM x1 } {
799    lappend res $a $b $c
800    switch -- $a {
801      1 {
802        db eval { INSERT INTO x1 VALUES(5, 5, 5) }
803      }
804      2 {
805        db eval { UPDATE x1 SET c=20 WHERE a=2 }
806      }
807      3 {
808        db eval { DELETE FROM x1 WHERE c IN (3,4) }
809      }
810    }
811  }
812  set res
813} {1 1 1 2 2 2 3 3 3 5 5 5}
814do_execsql_test 3.2 {
815  SELECT * FROM x1
816} {1 1 1  2 2 20  5 5 5}
817
818# EVIDENCE-OF: R-06177-00576 And R-Tree can appear to read and write at
819# the same time in some circumstances, if it can figure out how to
820# reliably run the query to completion before starting the update.
821#
822# In 8.2, it can, it 8.1, it cannot.
823do_test 8.1 {
824  db eval { SELECT * FROM rt } {
825    set rc [catch { db eval { INSERT INTO rt VALUES(53,53,53) } } msg]
826    break;
827  }
828  list $rc $msg
829} {1 {database table is locked}}
830do_test 8.2 {
831  db eval { SELECT * FROM rt ORDER BY +id } {
832    set rc [catch { db eval { INSERT INTO rt VALUES(53,53,53) } } msg]
833    break
834  }
835  list $rc $msg
836} {0 {}}
837
838#-------------------------------------------------------------------------
839#-------------------------------------------------------------------------
840# Section 4 of documentation.
841#-------------------------------------------------------------------------
842#-------------------------------------------------------------------------
843set testprefix rtreedoc-8
844reset_db
845
846# EVIDENCE-OF: R-21062-30088 For the example above, one might create an
847# auxiliary table as follows: CREATE TABLE demo_data( id INTEGER PRIMARY
848# KEY, -- primary key objname TEXT, -- name of the object objtype TEXT,
849# -- object type boundary BLOB -- detailed boundary of object );
850#
851# One might.
852#
853do_execsql_test 1.0 {
854  CREATE TABLE demo_data(
855      id INTEGER PRIMARY KEY,  -- primary key
856      objname TEXT,            -- name of the object
857      objtype TEXT,            -- object type
858      boundary BLOB            -- detailed boundary of object
859  );
860}
861
862do_execsql_test 1.1 {
863  CREATE VIRTUAL TABLE demo_index USING rtree(
864      id,              -- Integer primary key
865      minX, maxX,      -- Minimum and maximum X coordinate
866      minY, maxY       -- Minimum and maximum Y coordinate
867  );
868
869  INSERT INTO demo_index VALUES
870    (28215, -80.781227, -80.604706, 35.208813, 35.297367),
871    (28216, -80.957283, -80.840599, 35.235920, 35.367825),
872    (28217, -80.960869, -80.869431, 35.133682, 35.208233),
873    (28226, -80.878983, -80.778275, 35.060287, 35.154446),
874    (28227, -80.745544, -80.555382, 35.130215, 35.236916),
875    (28244, -80.844208, -80.841988, 35.223728, 35.225471),
876    (28262, -80.809074, -80.682938, 35.276207, 35.377747),
877    (28269, -80.851471, -80.735718, 35.272560, 35.407925),
878    (28270, -80.794983, -80.728966, 35.059872, 35.161823),
879    (28273, -80.994766, -80.875259, 35.074734, 35.172836),
880    (28277, -80.876793, -80.767586, 35.001709, 35.101063),
881    (28278, -81.058029, -80.956375, 35.044701, 35.223812),
882    (28280, -80.844208, -80.841972, 35.225468, 35.227203),
883    (28282, -80.846382, -80.844193, 35.223972, 35.225655);
884
885  INSERT INTO demo_index
886    SELECT NULL, minX, maxX, minY+0.2, maxY+0.2 FROM demo_index;
887  INSERT INTO demo_index
888    SELECT NULL, minX+0.2, maxX+0.2, minY, maxY FROM demo_index;
889  INSERT INTO demo_index
890    SELECT NULL, minX, maxX, minY+0.4, maxY+0.4 FROM demo_index;
891  INSERT INTO demo_index
892    SELECT NULL, minX+0.4, maxX+0.4, minY, maxY FROM demo_index;
893  INSERT INTO demo_index
894    SELECT NULL, minX, maxX, minY+0.8, maxY+0.8 FROM demo_index;
895  INSERT INTO demo_index
896    SELECT NULL, minX+0.8, maxX+0.8, minY, maxY FROM demo_index;
897
898  INSERT INTO demo_data(id) SELECT id FROM demo_index;
899
900  SELECT count(*) FROM demo_index;
901} {896}
902
903set ::contained_in 0
904proc contained_in {args} {incr ::contained_in ; return 0}
905db func contained_in contained_in
906
907# EVIDENCE-OF: R-32671-43888 Then an efficient way to find the specific
908# ZIP code for the main SQLite office would be to run a query like this:
909# SELECT objname FROM demo_data, demo_index WHERE
910# demo_data.id=demo_index.id AND contained_in(demo_data.boundary,
911# 35.37785, -80.77470) AND minX<=-80.77470 AND maxX>=-80.77470 AND
912# minY<=35.37785 AND maxY>=35.37785;
913do_vmstep_test 1.2 {
914  SELECT objname FROM demo_data, demo_index
915    WHERE demo_data.id=demo_index.id
916    AND contained_in(demo_data.boundary, 35.37785, -80.77470)
917    AND minX<=-80.77470 AND maxX>=-80.77470
918    AND minY<=35.37785  AND maxY>=35.37785;
919} {$step<100}
920set ::contained_in1 $::contained_in
921
922# EVIDENCE-OF: R-32761-23915 One would get the same answer without the
923# use of the R*Tree index using the following simpler query: SELECT
924# objname FROM demo_data WHERE contained_in(demo_data.boundary,
925# 35.37785, -80.77470);
926set ::contained_in 0
927do_vmstep_test 1.3 {
928  SELECT objname FROM demo_data
929    WHERE contained_in(demo_data.boundary, 35.37785, -80.77470);
930} {$step>3200}
931
932# EVIDENCE-OF: R-40261-32799 The problem with this latter query is that
933# it must apply the contained_in() function to all entries in the
934# demo_data table.
935#
936# 896 of them, IIRC.
937do_test 1.4 {
938  set ::contained_in
939} 896
940
941# EVIDENCE-OF: R-24212-52761 The use of the R*Tree in the penultimate
942# query reduces the number of calls to contained_in() function to a
943# small subset of the entire table.
944#
945# 2 is a small subset of 896.
946#
947# EVIDENCE-OF: R-39057-63901 The R*Tree index did not find the exact
948# answer itself, it merely limited the search space.
949#
950# contained_in() filtered out those 2 rows.
951do_test 1.5 {
952  set ::contained_in1
953} {2}
954
955
956#-------------------------------------------------------------------------
957#-------------------------------------------------------------------------
958# Section 4.1 of documentation.
959#-------------------------------------------------------------------------
960#-------------------------------------------------------------------------
961set testprefix rtreedoc-9
962reset_db
963
964# EVIDENCE-OF: R-46566-43213 Beginning with SQLite version 3.24.0
965# (2018-06-04), r-tree tables can have auxiliary columns that store
966# arbitrary data. Auxiliary columns can be used in place of secondary
967# tables such as "demo_data".
968#
969# EVIDENCE-OF: R-41287-48160 Auxiliary columns are marked with a "+"
970# symbol before the column name.
971#
972# This interface cannot conveniently be used to prove anything about
973# versions of SQLite prior to 3.24.0.
974#
975do_execsql_test 1.0 {
976  CREATE VIRTUAL TABLE rta USING rtree(
977    id, u1,u2,  v1,v2,   +aux
978  );
979
980  INSERT INTO rta(aux) VALUES(NULL);
981  INSERT INTO rta(aux) VALUES(45);
982  INSERT INTO rta(aux) VALUES(22.3);
983  INSERT INTO rta(aux) VALUES('hello');
984  INSERT INTO rta(aux) VALUES(X'ABCD');
985
986  SELECT typeof(aux), quote(aux) FROM rta;
987} {
988  null NULL
989  integer 45
990  real 22.3
991  text 'hello'
992  blob X'ABCD'
993}
994
995# EVIDENCE-OF: R-30514-26093 Auxiliary columns must come after all of
996# the coordinate boundary columns.
997foreach {tn cols} {
998  1 "id x1,x2, +extra,  y1,y2"
999  2 "extra, +id x1,x2, y1,y2"
1000  3 "id, x1,+x2, extra, y1,y2"
1001} {
1002  do_catchsql_test 2.$tn "
1003    CREATE VIRTUAL TABLE rrr USING rtree($cols)
1004  " {1 {Auxiliary rtree columns must be last}}
1005}
1006do_catchsql_test 3.0 {
1007  CREATE VIRTUAL TABLE rrr USING rtree(+id, extra, x1, x2);
1008} {1 {near "+": syntax error}}
1009
1010# EVIDENCE-OF: R-01280-03635 An RTREE table can have no more than 100
1011# columns total. In other words, the count of columns including the
1012# integer primary key column, the coordinate boundary columns, and all
1013# auxiliary columns must be 100 or less.
1014do_catchsql_test 3.1 {
1015  CREATE VIRTUAL TABLE r1 USING rtree(intid, u1,u2,
1016    +c00, +c01, +c02, +c03, +c04, +c05, +c06, +c07, +c08, +c09,
1017    +c10, +c11, +c12, +c13, +c14, +c15, +c16, +c17, +c18, +c19,
1018    +c20, +c21, +c22, +c23, +c24, +c25, +c26, +c27, +c28, +c29,
1019    +c30, +c31, +c32, +c33, +c34, +c35, +c36, +c37, +c38, +c39,
1020    +c40, +c41, +c42, +c43, +c44, +c45, +c46, +c47, +c48, +c49,
1021    +c50, +c51, +c52, +c53, +c54, +c55, +c56, +c57, +c58, +c59,
1022    +c60, +c61, +c62, +c63, +c64, +c65, +c66, +c67, +c68, +c69,
1023    +c70, +c71, +c72, +c73, +c74, +c75, +c76, +c77, +c78, +c79,
1024    +c80, +c81, +c82, +c83, +c84, +c85, +c86, +c87, +c88, +c89,
1025    +c90, +c91, +c92, +c93, +c94, +c95, +c96
1026  );
1027} {0 {}}
1028do_catchsql_test 3.2 {
1029  DROP TABLE r1;
1030  CREATE VIRTUAL TABLE r1 USING rtree(intid, u1,u2,
1031    +c00, +c01, +c02, +c03, +c04, +c05, +c06, +c07, +c08, +c09,
1032    +c10, +c11, +c12, +c13, +c14, +c15, +c16, +c17, +c18, +c19,
1033    +c20, +c21, +c22, +c23, +c24, +c25, +c26, +c27, +c28, +c29,
1034    +c30, +c31, +c32, +c33, +c34, +c35, +c36, +c37, +c38, +c39,
1035    +c40, +c41, +c42, +c43, +c44, +c45, +c46, +c47, +c48, +c49,
1036    +c50, +c51, +c52, +c53, +c54, +c55, +c56, +c57, +c58, +c59,
1037    +c60, +c61, +c62, +c63, +c64, +c65, +c66, +c67, +c68, +c69,
1038    +c70, +c71, +c72, +c73, +c74, +c75, +c76, +c77, +c78, +c79,
1039    +c80, +c81, +c82, +c83, +c84, +c85, +c86, +c87, +c88, +c89,
1040    +c90, +c91, +c92, +c93, +c94, +c95, +c96, +c97
1041  );
1042} {1 {Too many columns for an rtree table}}
1043do_catchsql_test 3.3 {
1044  CREATE VIRTUAL TABLE r1 USING rtree(intid, u1,u2, v1,v2,
1045    +c00, +c01, +c02, +c03, +c04, +c05, +c06, +c07, +c08, +c09,
1046    +c10, +c11, +c12, +c13, +c14, +c15, +c16, +c17, +c18, +c19,
1047    +c20, +c21, +c22, +c23, +c24, +c25, +c26, +c27, +c28, +c29,
1048    +c30, +c31, +c32, +c33, +c34, +c35, +c36, +c37, +c38, +c39,
1049    +c40, +c41, +c42, +c43, +c44, +c45, +c46, +c47, +c48, +c49,
1050    +c50, +c51, +c52, +c53, +c54, +c55, +c56, +c57, +c58, +c59,
1051    +c60, +c61, +c62, +c63, +c64, +c65, +c66, +c67, +c68, +c69,
1052    +c70, +c71, +c72, +c73, +c74, +c75, +c76, +c77, +c78, +c79,
1053    +c80, +c81, +c82, +c83, +c84, +c85, +c86, +c87, +c88, +c89,
1054    +c90, +c91, +c92, +c93, +c94,
1055  );
1056} {0 {}}
1057do_catchsql_test 3.4 {
1058  DROP TABLE r1;
1059  CREATE VIRTUAL TABLE r1 USING rtree(intid, u1,u2, v1,v2,
1060    +c00, +c01, +c02, +c03, +c04, +c05, +c06, +c07, +c08, +c09,
1061    +c10, +c11, +c12, +c13, +c14, +c15, +c16, +c17, +c18, +c19,
1062    +c20, +c21, +c22, +c23, +c24, +c25, +c26, +c27, +c28, +c29,
1063    +c30, +c31, +c32, +c33, +c34, +c35, +c36, +c37, +c38, +c39,
1064    +c40, +c41, +c42, +c43, +c44, +c45, +c46, +c47, +c48, +c49,
1065    +c50, +c51, +c52, +c53, +c54, +c55, +c56, +c57, +c58, +c59,
1066    +c60, +c61, +c62, +c63, +c64, +c65, +c66, +c67, +c68, +c69,
1067    +c70, +c71, +c72, +c73, +c74, +c75, +c76, +c77, +c78, +c79,
1068    +c80, +c81, +c82, +c83, +c84, +c85, +c86, +c87, +c88, +c89,
1069    +c90, +c91, +c92, +c93, +c94, +c95,
1070  );
1071} {1 {Too many columns for an rtree table}}
1072
1073# EVIDENCE-OF: R-05552-15084
1074do_execsql_test 4.0 {
1075  CREATE VIRTUAL TABLE demo_index2 USING rtree(
1076      id,              -- Integer primary key
1077      minX, maxX,      -- Minimum and maximum X coordinate
1078      minY, maxY,      -- Minimum and maximum Y coordinate
1079      +objname TEXT,   -- name of the object
1080      +objtype TEXT,   -- object type
1081      +boundary BLOB   -- detailed boundary of object
1082  );
1083}
1084do_execsql_test 4.1 {
1085  CREATE VIRTUAL TABLE demo_index USING rtree(
1086      id,              -- Integer primary key
1087      minX, maxX,      -- Minimum and maximum X coordinate
1088      minY, maxY       -- Minimum and maximum Y coordinate
1089  );
1090  CREATE TABLE demo_data(
1091      id INTEGER PRIMARY KEY,  -- primary key
1092      objname TEXT,            -- name of the object
1093      objtype TEXT,            -- object type
1094      boundary BLOB            -- detailed boundary of object
1095  );
1096
1097  INSERT INTO demo_index2(id) VALUES(1);
1098  INSERT INTO demo_index(id) VALUES(1);
1099  INSERT INTO demo_data(id) VALUES(1);
1100}
1101do_test 4.2 {
1102  catch { array unset R }
1103  db eval {SELECT * FROM demo_index2} R { set r1 [array names R] }
1104  catch { array unset R }
1105  db eval {SELECT * FROM demo_index NATURAL JOIN demo_data } R {
1106    set r2 [array names R]
1107  }
1108  expr {$r1==$r2}
1109} {1}
1110
1111# EVIDENCE-OF: R-26099-32169 SELECT objname FROM demo_index2 WHERE
1112# contained_in(boundary, 35.37785, -80.77470) AND minX<=-80.77470 AND
1113# maxX>=-80.77470 AND minY<=35.37785 AND maxY>=35.37785;
1114do_execsql_test 4.3.1 {
1115  DELETE FROM demo_index2;
1116  INSERT INTO demo_index2(id,minX,maxX,minY,maxY) VALUES
1117    (28215, -80.781227, -80.604706, 35.208813, 35.297367),
1118    (28216, -80.957283, -80.840599, 35.235920, 35.367825),
1119    (28217, -80.960869, -80.869431, 35.133682, 35.208233),
1120    (28226, -80.878983, -80.778275, 35.060287, 35.154446),
1121    (28227, -80.745544, -80.555382, 35.130215, 35.236916),
1122    (28244, -80.844208, -80.841988, 35.223728, 35.225471),
1123    (28262, -80.809074, -80.682938, 35.276207, 35.377747),
1124    (28269, -80.851471, -80.735718, 35.272560, 35.407925),
1125    (28270, -80.794983, -80.728966, 35.059872, 35.161823),
1126    (28273, -80.994766, -80.875259, 35.074734, 35.172836),
1127    (28277, -80.876793, -80.767586, 35.001709, 35.101063),
1128    (28278, -81.058029, -80.956375, 35.044701, 35.223812),
1129    (28280, -80.844208, -80.841972, 35.225468, 35.227203),
1130    (28282, -80.846382, -80.844193, 35.223972, 35.225655);
1131}
1132set ::contained_in 0
1133proc contained_in {args} {
1134  incr ::contained_in
1135  return 0
1136}
1137db func contained_in contained_in
1138do_execsql_test 4.3.2 {
1139  SELECT objname FROM demo_index2
1140    WHERE contained_in(boundary, 35.37785, -80.77470)
1141    AND minX<=-80.77470 AND maxX>=-80.77470
1142    AND minY<=35.37785  AND maxY>=35.37785;
1143}
1144do_test 4.3.3 {
1145  # Function invoked only once because r-tree filtering happened first.
1146  set ::contained_in
1147} 1
1148set ::contained_in 0
1149do_execsql_test 4.3.4 {
1150  SELECT objname FROM demo_index2
1151    WHERE contained_in(boundary, 35.37785, -80.77470)
1152}
1153do_test 4.3.3 {
1154  # Function invoked 14 times because no r-tree filtering. Inefficient.
1155  set ::contained_in
1156} 14
1157
1158#-------------------------------------------------------------------------
1159#-------------------------------------------------------------------------
1160# Section 4.1.1 of documentation.
1161#-------------------------------------------------------------------------
1162#-------------------------------------------------------------------------
1163set testprefix rtreedoc-9
1164reset_db
1165
1166# EVIDENCE-OF: R-24021-02490 For auxiliary columns, only the name of the
1167# column matters. The type affinity is ignored.
1168#
1169# EVIDENCE-OF: R-39906-44154 Constraints such as NOT NULL, UNIQUE,
1170# REFERENCES, or CHECK are also ignored.
1171do_execsql_test 1.0 { PRAGMA foreign_keys = on }
1172foreach {tn auxcol nm} {
1173  1 "+extra INTEGER" extra
1174  2 "+extra TEXT"    extra
1175  3 "+extra BLOB"    extra
1176  4 "+extra REAL"    extra
1177
1178  5 "+col NOT NULL"                 col
1179  6 "+col CHECK (col IS NOT NULL)"  col
1180  7 "+col REFERENCES tbl(x)"        col
1181} {
1182  do_execsql_test 1.$tn.1 "
1183    CREATE VIRTUAL TABLE rt USING rtree_i32(k, a,b, $auxcol)
1184  "
1185
1186  # Check that the aux column has no affinity. Or NOT NULL constraint.
1187  # And that the aux column is the child key of an FK constraint.
1188  #
1189  do_execsql_test 1.$tn.2 "
1190    INSERT INTO rt($nm) VALUES(NULL), (45), (-123.2), ('456'), (X'ABCD');
1191    SELECT typeof($nm), quote($nm) FROM rt;
1192  " {
1193    null NULL
1194    integer 45
1195    real -123.2
1196    text '456'
1197    blob X'ABCD'
1198  }
1199
1200  # Check that there is no UNIQUE constraint either.
1201  #
1202  do_execsql_test 1.$tn.3 "
1203    INSERT INTO rt($nm) VALUES('xyz'), ('xyz'), ('xyz');
1204  "
1205
1206  do_execsql_test 1.$tn.2 {
1207    DROP TABLE rt
1208  }
1209}
1210
1211#-------------------------------------------------------------------------
1212#-------------------------------------------------------------------------
1213# Section 5 of documentation.
1214#-------------------------------------------------------------------------
1215#-------------------------------------------------------------------------
1216set testprefix rtreedoc-10
1217
1218# EVIDENCE-OF: R-21011-43790 If integer coordinates are desired, declare
1219# the table using "rtree_i32" instead: CREATE VIRTUAL TABLE intrtree
1220# USING rtree_i32(id,x0,x1,y0,y1,z0,z1);
1221do_execsql_test 1.0 {
1222  CREATE VIRTUAL TABLE intrtree USING rtree_i32(id,x0,x1,y0,y1,z0,z1);
1223  INSERT INTO intrtree DEFAULT VALUES;
1224  SELECT typeof(x0) FROM intrtree;
1225} {integer}
1226
1227# EVIDENCE-OF: R-09193-49806 An rtree_i32 stores coordinates as 32-bit
1228# signed integers.
1229#
1230# Show that coordinates are cast in a way consistent with casting to
1231# a signed 32-bit integer.
1232do_execsql_test 1.1 {
1233  DELETE FROM intrtree;
1234  INSERT INTO intrtree VALUES(333,
1235      1<<44, (1<<44)+1,
1236      10000000000, 10000000001,
1237      -10000000001, -10000000000
1238  );
1239  SELECT * FROM intrtree;
1240} {
1241  333 0 1 1410065408 1410065409 -1410065409 -1410065408
1242}
1243
1244#-------------------------------------------------------------------------
1245#-------------------------------------------------------------------------
1246# Section 7.1 of documentation.
1247#-------------------------------------------------------------------------
1248#-------------------------------------------------------------------------
1249set testprefix rtreedoc-11
1250reset_db
1251
1252# This command assumes that the argument is a node blob for a 2 dimensional
1253# i32 r-tree table. It decodes and returns a list of cells from the node
1254# as a list. Each cell is itself a list of the following form:
1255#
1256#    {$rowid $minX $maxX $minY $maxY}
1257#
1258# For internal (non-leaf) nodes, the rowid is replaced by the child node
1259# number.
1260#
1261proc rnode {aData} {
1262  set nDim 2
1263
1264  set nData [string length $aData]
1265  set nBytePerCell [expr (8 + 2*$nDim*4)]
1266  binary scan [string range $aData 2 3] S nCell
1267
1268  set res [list]
1269  for {set i 0} {$i < $nCell} {incr i} {
1270    set iOff [expr $i*$nBytePerCell+4]
1271    set cell [string range $aData $iOff [expr $iOff+$nBytePerCell-1]]
1272    binary scan $cell WIIII rowid x1 x2 y1 y2
1273    lappend res [list $rowid $x1 $x2 $y1 $y2]
1274  }
1275
1276  return $res
1277}
1278
1279# aData must be a node blob. This command returns true if the node contains
1280# rowid $rowid, or false otherwise.
1281#
1282proc rnode_contains {aData rowid} {
1283  set L [rnode $aData]
1284  foreach cell $L {
1285    set r [lindex $cell 0]
1286    if {$r==$rowid} { return 1 }
1287  }
1288  return 0
1289}
1290
1291proc rnode_replace_cell {aData iCell cell} {
1292  set aCell [binary format WIIII {*}$cell]
1293  set nDim 2
1294  set nBytePerCell [expr (8 + 2*$nDim*4)]
1295  set iOff [expr $iCell*$nBytePerCell+4]
1296
1297  set aNew [binary format a*a*a* \
1298      [string range $aData 0 $iOff-1]     \
1299      $aCell     \
1300      [string range $aData $iOff+$nBytePerCell end] \
1301  ]
1302  return $aNew
1303}
1304
1305db function rnode rnode
1306db function rnode_contains rnode_contains
1307db function rnode_replace_cell rnode_replace_cell
1308
1309foreach {tn nm} {
1310  1 x1
1311  2 asdfghjkl
1312  3 hello_world
1313} {
1314  do_execsql_test 1.$tn.1 "
1315    CREATE VIRTUAL TABLE $nm USING rtree(a,b,c,d,e);
1316  "
1317
1318  # EVIDENCE-OF: R-33789-46762 The content of an R*Tree index is actually
1319  # stored in three ordinary SQLite tables with names derived from the
1320  # name of the R*Tree.
1321  #
1322  # EVIDENCE-OF: R-39849-06566 This is their schema: CREATE TABLE
1323  # %_node(nodeno INTEGER PRIMARY KEY, data) CREATE TABLE %_parent(nodeno
1324  # INTEGER PRIMARY KEY, parentnode) CREATE TABLE %_rowid(rowid INTEGER
1325  # PRIMARY KEY, nodeno)
1326  #
1327  # EVIDENCE-OF: R-07489-10051 The "%" in the name of each shadow table is
1328  # replaced by the name of the R*Tree virtual table. So, if the name of
1329  # the R*Tree table is "xyz" then the three shadow tables would be
1330  # "xyz_node", "xyz_parent", and "xyz_rowid".
1331  do_execsql_test 1.$tn.2 {
1332    SELECT sql FROM sqlite_schema WHERE name!=$nm ORDER BY 1
1333  } [string map [list % $nm] "
1334    {CREATE TABLE \"%_node\"(nodeno INTEGER PRIMARY KEY,data)}
1335    {CREATE TABLE \"%_parent\"(nodeno INTEGER PRIMARY KEY,parentnode)}
1336    {CREATE TABLE \"%_rowid\"(rowid INTEGER PRIMARY KEY,nodeno)}
1337  "]
1338
1339  do_execsql_test 1.$tn "DROP TABLE $nm"
1340}
1341
1342
1343# EVIDENCE-OF: R-51070-59303 There is one entry in the %_node table for
1344# each R*Tree node.
1345#
1346# The following creates a 6 node r-tree structure.
1347#
1348do_execsql_test 2.0 {
1349  CREATE VIRTUAL TABLE r1 USING rtree_i32(i, x1,x2, y1,y2);
1350  WITH t(i) AS (
1351    VALUES(1) UNION SELECT i+1 FROM t WHERE i<110
1352  )
1353  INSERT INTO r1 SELECT i, (i%10), (i%10)+2, (i%6), (i%7)+6 FROM t;
1354}
1355do_execsql_test 2.1 {
1356  SELECT count(*) FROM r1_node;
1357} 6
1358
1359# EVIDENCE-OF: R-27261-09153 All nodes other than the root have an entry
1360# in the %_parent shadow table that identifies the parent node.
1361#
1362# In this case nodes 2-6 are the children of node 1.
1363#
1364do_execsql_test 2.3 {
1365  SELECT nodeno, parentnode FROM r1_parent
1366} {2 1  3 1  4 1  5 1  6 1}
1367
1368# EVIDENCE-OF: R-02358-35037 The %_rowid shadow table maps entry rowids
1369# to the node that contains that entry.
1370#
1371do_execsql_test 2.4 {
1372  SELECT 'failed' FROM r1_rowid WHERE 0==rnode_contains(
1373    (SELECT data FROM r1_node WHERE nodeno=r1_rowid.nodeno), rowid
1374  )
1375}
1376do_test 2.5 {
1377  db eval { SELECT nodeno, data FROM r1_node WHERE nodeno!=1 } {
1378    set L [rnode $data]
1379    foreach cell $L {
1380      set rowid [lindex $cell 0]
1381      set rowid_nodeno 0
1382      db eval {SELECT nodeno AS rowid_nodeno FROM r1_rowid WHERE rowid=$rowid} {
1383        break
1384      }
1385      if {$rowid_nodeno!=$nodeno} { error "data mismatch!" }
1386    }
1387  }
1388} {}
1389
1390# EVIDENCE-OF: R-65201-22208 Extra columns appended to the %_rowid table
1391# hold the content of auxiliary columns.
1392#
1393# EVIDENCE-OF: R-44161-28345 The names of these extra %_rowid columns
1394# are probably not the same as the actual auxiliary column names.
1395#
1396# In this case, the auxiliary columns are named "e1" and "e2". The
1397# extra %_rowid columns are named "a0" and "a1".
1398#
1399do_execsql_test 3.0 {
1400  CREATE VIRTUAL TABLE rtaux USING rtree(id, x1,x2, y1,y2, +e1, +e2);
1401  SELECT sql FROM sqlite_schema WHERE name='rtaux_rowid';
1402} {
1403  {CREATE TABLE "rtaux_rowid"(rowid INTEGER PRIMARY KEY,nodeno,a0,a1)}
1404}
1405do_execsql_test 3.1 {
1406  INSERT INTO rtaux(e1, e2) VALUES('hello', 'world'), (123, 456);
1407}
1408do_execsql_test 3.2 {
1409  SELECT a0, a1 FROM rtaux_rowid;
1410} {
1411  hello world  123 456
1412}
1413
1414#-------------------------------------------------------------------------
1415#-------------------------------------------------------------------------
1416# Section 7.2 of documentation.
1417#-------------------------------------------------------------------------
1418#-------------------------------------------------------------------------
1419set testprefix rtreedoc-12
1420reset_db
1421forcedelete test.db2
1422
1423db function rnode rnode
1424db function rnode_contains rnode_contains
1425db function rnode_replace_cell rnode_replace_cell
1426
1427# EVIDENCE-OF: R-13571-45795 The scalar SQL function rtreecheck(R) or
1428# rtreecheck(S,R) runs an integrity check on the rtree table named R
1429# contained within database S.
1430#
1431# EVIDENCE-OF: R-36011-59963 The function returns a human-language
1432# description of any problems found, or the string 'ok' if everything is
1433# ok.
1434#
1435do_execsql_test 1.0 {
1436  CREATE VIRTUAL TABLE rt1 USING rtree(id, a, b);
1437  WITH s(i) AS (
1438    VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<200
1439  )
1440  INSERT INTO rt1 SELECT i, i, i FROM s;
1441
1442  ATTACH 'test.db2' AS 'aux';
1443  CREATE VIRTUAL TABLE aux.rt1 USING rtree(id, a, b);
1444  INSERT INTO aux.rt1 SELECT * FROM rt1;
1445}
1446
1447do_execsql_test 1.1.1 { SELECT rtreecheck('rt1'); } {ok}
1448do_execsql_test 1.1.2 { SELECT rtreecheck('main', 'rt1'); } {ok}
1449do_execsql_test 1.1.3 { SELECT rtreecheck('aux', 'rt1'); } {ok}
1450do_catchsql_test 1.1.4 {
1451  SELECT rtreecheck('nosuchdb', 'rt1');
1452} {1 {SQL logic error}}
1453
1454# Corrupt the table in database 'main':
1455do_execsql_test 1.2.1 { UPDATE rt1_node SET nodeno=21 WHERE nodeno=3; }
1456do_execsql_test 1.2.1 { SELECT rtreecheck('rt1')=='ok'; } {0}
1457do_execsql_test 1.2.2 { SELECT rtreecheck('main', 'rt1')=='ok'; } {0}
1458do_execsql_test 1.2.3 { SELECT rtreecheck('aux', 'rt1')=='ok'; } {1}
1459do_execsql_test 1.2.4 { UPDATE rt1_node SET nodeno=3 WHERE nodeno=21; }
1460
1461# Corrupt the table in database 'aux':
1462do_execsql_test 1.2.1 { UPDATE aux.rt1_node SET nodeno=21 WHERE nodeno=3; }
1463do_execsql_test 1.2.1 { SELECT rtreecheck('rt1')=='ok'; } {1}
1464do_execsql_test 1.2.2 { SELECT rtreecheck('main', 'rt1')=='ok'; } {1}
1465do_execsql_test 1.2.3 { SELECT rtreecheck('aux', 'rt1')=='ok'; } {0}
1466do_execsql_test 1.2.4 { UPDATE rt1_node SET nodeno=3 WHERE nodeno=21; }
1467
1468# EVIDENCE-OF: R-45759-33459 Example: To verify that an R*Tree named
1469# "demo_index" is well-formed and internally consistent, run: SELECT
1470# rtreecheck('demo_index');
1471do_execsql_test 2.0 {
1472  CREATE VIRTUAL TABLE demo_index USING rtree(id, x1,x2, y1,y2);
1473  INSERT INTO demo_index SELECT id, a, b, a, b FROM rt1;
1474}
1475do_execsql_test 2.1 { SELECT rtreecheck('demo_index') } {ok}
1476do_execsql_test 2.2 {
1477  UPDATE demo_index_rowid SET nodeno=44 WHERE rowid=44;
1478  SELECT rtreecheck('demo_index');
1479} {{Found (44 -> 44) in %_rowid table, expected (44 -> 4)}}
1480
1481
1482do_execsql_test 3.0 {
1483  CREATE VIRTUAL TABLE rt2 USING rtree_i32(id, a, b, c, d);
1484  WITH s(i) AS (
1485    VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<200
1486  )
1487  INSERT INTO rt2 SELECT i, i, i+2, i, i+2 FROM s;
1488}
1489
1490# EVIDENCE-OF: R-02555-31045 for each dimension, (coord1 <= coord2).
1491#
1492execsql BEGIN
1493do_test 3.1 {
1494  set cell [
1495    lindex [execsql {SELECT rnode(data) FROM rt2_node WHERE nodeno=3}] 0 3
1496  ]
1497  set cell [list [lindex $cell 0]       \
1498    [lindex $cell 2] [lindex $cell 1]   \
1499    [lindex $cell 3] [lindex $cell 4]   \
1500  ]
1501  execsql {
1502    UPDATE rt2_node SET data=rnode_replace_cell(data, 3, $cell) WHERE nodeno=3
1503  }
1504  execsql { SELECT rtreecheck('rt2') }
1505} {{Dimension 0 of cell 3 on node 3 is corrupt}}
1506execsql ROLLBACK
1507
1508# EVIDENCE-OF: R-13844-15873 unless the cell is on the root node, that
1509# the cell is bounded by the parent cell on the parent node.
1510#
1511execsql BEGIN
1512do_test 3.2 {
1513  set cell [
1514    lindex [execsql {SELECT rnode(data) FROM rt2_node WHERE nodeno=3}] 0 3
1515  ]
1516  lset cell 3 450
1517  lset cell 4 451
1518  execsql {
1519    UPDATE rt2_node SET data=rnode_replace_cell(data, 3, $cell) WHERE nodeno=3
1520  }
1521  execsql { SELECT rtreecheck('rt2') }
1522} {{Dimension 1 of cell 3 on node 3 is corrupt relative to parent}}
1523execsql ROLLBACK
1524
1525# EVIDENCE-OF: R-02505-03621 for leaf nodes, that there is an entry in
1526# the %_rowid table corresponding to the cell's rowid value that points
1527# to the correct node.
1528#
1529execsql BEGIN
1530do_test 3.3 {
1531  execsql {
1532    UPDATE rt2_rowid SET rowid=452 WHERE rowid=100
1533  }
1534  execsql { SELECT rtreecheck('rt2') }
1535} {{Mapping (100 -> 6) missing from %_rowid table}}
1536execsql ROLLBACK
1537
1538# EVIDENCE-OF: R-50927-02218 for cells on non-leaf nodes, that there is
1539# an entry in the %_parent table mapping from the cell's child node to
1540# the node that it resides on.
1541#
1542execsql BEGIN
1543do_test 3.4.1 {
1544  execsql {
1545    UPDATE rt2_parent SET parentnode=123 WHERE nodeno=3
1546  }
1547  execsql { SELECT rtreecheck('rt2') }
1548} {{Found (3 -> 123) in %_parent table, expected (3 -> 1)}}
1549execsql ROLLBACK
1550execsql BEGIN
1551do_test 3.4.2 {
1552  execsql {
1553    UPDATE rt2_parent SET nodeno=123 WHERE nodeno=3
1554  }
1555  execsql { SELECT rtreecheck('rt2') }
1556} {{Mapping (3 -> 1) missing from %_parent table}}
1557execsql ROLLBACK
1558
1559# EVIDENCE-OF: R-23235-09153 That there are the same number of entries
1560# in the %_rowid table as there are leaf cells in the r-tree structure,
1561# and that there is a leaf cell that corresponds to each entry in the
1562# %_rowid table.
1563execsql BEGIN
1564do_test 3.5 {
1565  execsql { INSERT INTO rt2_rowid VALUES(1000, 1000) }
1566  execsql { SELECT rtreecheck('rt2') }
1567} {{Wrong number of entries in %_rowid table - expected 200, actual 201}}
1568execsql ROLLBACK
1569
1570# EVIDENCE-OF: R-62800-43436 That there are the same number of entries
1571# in the %_parent table as there are non-leaf cells in the r-tree
1572# structure, and that there is a non-leaf cell that corresponds to each
1573# entry in the %_parent table.
1574execsql BEGIN
1575do_test 3.6 {
1576  execsql { INSERT INTO rt2_parent VALUES(1000, 1000) }
1577  execsql { SELECT rtreecheck('rt2') }
1578} {{Wrong number of entries in %_parent table - expected 9, actual 10}}
1579execsql ROLLBACK
1580
1581
1582
1583finish_test
1584