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