xref: /sqlite-3.40.0/ext/rtree/rtreedoc2.test (revision 5488e082)
101ed72f2Sdan# 2021 September 13
201ed72f2Sdan#
301ed72f2Sdan# The author disclaims copyright to this source code.  In place of
401ed72f2Sdan# a legal notice, here is a blessing:
501ed72f2Sdan#
601ed72f2Sdan#    May you do good and not evil.
701ed72f2Sdan#    May you find forgiveness for yourself and forgive others.
801ed72f2Sdan#    May you share freely, never taking more than you give.
901ed72f2Sdan#
1001ed72f2Sdan#***********************************************************************
1101ed72f2Sdan#
1201ed72f2Sdan# The focus of this file is testing the r-tree extension.
1301ed72f2Sdan#
1401ed72f2Sdan
1501ed72f2Sdanif {![info exists testdir]} {
1601ed72f2Sdan  set testdir [file join [file dirname [info script]] .. .. test]
1701ed72f2Sdan}
1801ed72f2Sdansource [file join [file dirname [info script]] rtree_util.tcl]
1901ed72f2Sdansource $testdir/tester.tcl
2001ed72f2Sdanset testprefix rtreedoc2
2101ed72f2Sdan
2201ed72f2Sdanifcapable !rtree {
2301ed72f2Sdan  finish_test
2401ed72f2Sdan  return
2501ed72f2Sdan}
2601ed72f2Sdan
2701ed72f2Sdan#-------------------------------------------------------------------------
2801ed72f2Sdan#-------------------------------------------------------------------------
2901ed72f2Sdan# Section 6 of documentation.
3001ed72f2Sdan#-------------------------------------------------------------------------
3101ed72f2Sdan#-------------------------------------------------------------------------
3201ed72f2Sdanset testprefix rtreedoc2-1
3301ed72f2Sdan
3401ed72f2Sdan# EVIDENCE-OF: R-35254-48865 A call to one of the above APIs creates a
3501ed72f2Sdan# new SQL function named by the second parameter (zQueryFunc or zGeom).
3601ed72f2Sdan#
3701ed72f2Sdan# [register_circle_geom db] registers new geometry callback "Qcircle"
3801ed72f2Sdan# and legacy implementation "circle". Test that these do actually appear.
3901ed72f2Sdan#
4001ed72f2Sdando_execsql_test 1.1.0 {
4101ed72f2Sdan  SELECT * FROM pragma_function_list WHERE name IN('circle', 'qcircle');
4201ed72f2Sdan} {
4301ed72f2Sdan}
4401ed72f2Sdando_test 1.1 {
4501ed72f2Sdan  register_circle_geom db
4601ed72f2Sdan} {SQLITE_OK}
4701ed72f2Sdando_execsql_test 1.1.2 {
4801ed72f2Sdan  SELECT * FROM pragma_function_list WHERE name = 'circle' AND enc='utf8';
4901ed72f2Sdan} {
5001ed72f2Sdan  circle 0 s utf8 -1 0
5101ed72f2Sdan}
5201ed72f2Sdando_execsql_test 1.1.3 {
5301ed72f2Sdan  SELECT * FROM pragma_function_list WHERE name = 'qcircle' AND enc='utf8';
5401ed72f2Sdan} {
5501ed72f2Sdan  qcircle 0 s utf8 -1 0
5601ed72f2Sdan}
5701ed72f2Sdan
5801ed72f2Sdando_execsql_test 1.2.0 { SELECT circle(1, 2, 3); } {{}}
5901ed72f2Sdando_execsql_test 1.2.1 { SELECT qcircle(1, 2, 3); } {{}}
6001ed72f2Sdan
6101ed72f2Sdan# EVIDENCE-OF: R-61427-46983
6201ed72f2Sdando_execsql_test 1.3.0 {
6301ed72f2Sdan  CREATE VIRTUAL TABLE demo_index USING rtree(id, x1,x2, y1,y2);
6401ed72f2Sdan  INSERT INTO demo_index VALUES(10, 45,45,  24,24);
6501ed72f2Sdan  INSERT INTO demo_index VALUES(20, 50,50,  28,28);
6601ed72f2Sdan  INSERT INTO demo_index VALUES(30, 43,43,  22,22);
6701ed72f2Sdan}
6801ed72f2Sdando_execsql_test 1.3.1 {
6901ed72f2Sdan  SELECT id FROM demo_index WHERE id MATCH circle(45.3, 22.9, 5.0)
7001ed72f2Sdan} {10 30}
7101ed72f2Sdan
7201ed72f2Sdan# EVIDENCE-OF: R-16907-50223 The SQL syntax for custom queries is the
7301ed72f2Sdan# same regardless of which interface, sqlite3_rtree_geometry_callback()
7401ed72f2Sdan# or sqlite3_rtree_query_callback(), is used to register the SQL
7501ed72f2Sdan# function.
7601ed72f2Sdando_execsql_test 1.3.2 {
7701ed72f2Sdan  SELECT id FROM demo_index WHERE id MATCH qcircle(45.3, 22.9, 5.0, 1)
7801ed72f2Sdan} {10 30}
7901ed72f2Sdan
8001ed72f2Sdan
8101ed72f2Sdan# EVIDENCE-OF: R-59634-51678 When that SQL function appears on the
8201ed72f2Sdan# right-hand side of the MATCH operator and the left-hand side of the
8301ed72f2Sdan# MATCH operator is any column in the R*Tree virtual table, then the
8401ed72f2Sdan# callback defined by the third argument (xQueryFunc or xGeom) is
8501ed72f2Sdan# invoked to determine if a particular object or subtree overlaps the
8601ed72f2Sdan# desired region.
8701ed72f2Sdanproc box_geom {args} {
8801ed72f2Sdan  lappend ::box_geom [concat [lindex $args 0] [lrange $args 2 end-1]]
8901ed72f2Sdan  return ""
9001ed72f2Sdan}
9101ed72f2Sdanregister_box_geom db box_geom
9201ed72f2Sdanset box_geom [list]
9301ed72f2Sdando_execsql_test 1.3.2 {
9401ed72f2Sdan  SELECT id FROM demo_index WHERE id MATCH box(43,46, 21,25);
9501ed72f2Sdan} {10 30}
9601ed72f2Sdando_test 1.3.3 {
9701ed72f2Sdan  set ::box_geom
9801ed72f2Sdan} [list {*}{
9901ed72f2Sdan  {box {43.0 46.0 21.0 25.0} {45.0 45.0 24.0 24.0}}
10001ed72f2Sdan  {box {43.0 46.0 21.0 25.0} {50.0 50.0 28.0 28.0}}
10101ed72f2Sdan  {box {43.0 46.0 21.0 25.0} {43.0 43.0 22.0 22.0}}
10201ed72f2Sdan}]
10301ed72f2Sdan
10401ed72f2Sdan#-------------------------------------------------------------------------
10501ed72f2Sdan#-------------------------------------------------------------------------
10601ed72f2Sdan# Section 6 of documentation.
10701ed72f2Sdan#-------------------------------------------------------------------------
10801ed72f2Sdan#-------------------------------------------------------------------------
10901ed72f2Sdanset testprefix rtreedoc2-2
11001ed72f2Sdan
11101ed72f2Sdan# EVIDENCE-OF: R-02424-24769 The second argument is the number of
11201ed72f2Sdan# coordinates in each r-tree entry, and is always the same for any given
11301ed72f2Sdan# R*Tree.
11401ed72f2Sdan#
11501ed72f2Sdan# EVIDENCE-OF: R-40260-16838 The number of coordinates is 2 for a
11601ed72f2Sdan# 1-dimensional R*Tree, 4 for a 2-dimensional R*Tree, 6 for a
11701ed72f2Sdan# 3-dimensional R*Tree, and so forth.
11801ed72f2Sdan#
11901ed72f2Sdan# The second argument refered to above is the length of the list passed
12001ed72f2Sdan# as the 3rd parameter to the Tcl script.
12101ed72f2Sdan#
12201ed72f2Sdando_execsql_test 1.0 {
12301ed72f2Sdan  CREATE VIRTUAL TABLE rt1 USING rtree(id, x1,x2);
12401ed72f2Sdan  CREATE VIRTUAL TABLE rt2 USING rtree(id, x1,x2, y1,y2);
12501ed72f2Sdan  CREATE VIRTUAL TABLE rt3 USING rtree(id, x1,x2, y1,y2, z1,z2);
12601ed72f2Sdan
12701ed72f2Sdan  INSERT INTO rt1 DEFAULT VALUES;
12801ed72f2Sdan  INSERT INTO rt2 DEFAULT VALUES;
12901ed72f2Sdan  INSERT INTO rt3 DEFAULT VALUES;
13001ed72f2Sdan}
13101ed72f2Sdanforeach {tn tbl nCoord} {
13201ed72f2Sdan  1 rt1 2
13301ed72f2Sdan  2 rt2 4
13401ed72f2Sdan  3 rt3 6
13501ed72f2Sdan} {
13601ed72f2Sdan  set ::box_geom [list]
13701ed72f2Sdan  do_catchsql_test 1.$tn.1 "
13801ed72f2Sdan    SELECT id FROM $tbl WHERE id MATCH box();
13901ed72f2Sdan  " {1 {SQL logic error}}
14001ed72f2Sdan
14101ed72f2Sdan  do_test 1.$tn.2 {
14201ed72f2Sdan    llength [lindex $::box_geom 0 2]
14301ed72f2Sdan  } $nCoord
14401ed72f2Sdan}
14501ed72f2Sdan
14601ed72f2Sdan# EVIDENCE-OF: R-28051-48608 If xGeom returns anything other than
14701ed72f2Sdan# SQLITE_OK, then the r-tree query will abort with an error.
14801ed72f2Sdanproc box_geom {args} {
14901ed72f2Sdan  error "an error!"
15001ed72f2Sdan}
15101ed72f2Sdando_catchsql_test 2.0 {
15201ed72f2Sdan  SELECT * FROM rt2 WHERE id MATCH box(22,23, 24,25);
15301ed72f2Sdan} {1 {SQL logic error}}
15401ed72f2Sdan
15501ed72f2Sdando_execsql_test 3.0 {
15601ed72f2Sdan  INSERT INTO rt1 VALUES(10, 10, 10);
15701ed72f2Sdan  INSERT INTO rt1 VALUES(11, 11, 11);
15801ed72f2Sdan  INSERT INTO rt1 VALUES(12, 12, 12);
15901ed72f2Sdan  INSERT INTO rt1 VALUES(13, 13, 13);
16001ed72f2Sdan  INSERT INTO rt1 VALUES(14, 14, 14);
16101ed72f2Sdan}
16201ed72f2Sdan
16301ed72f2Sdan# EVIDENCE-OF: R-53759-57366 The exact same sqlite3_rtree_geometry
16401ed72f2Sdan# structure is used for every callback for same MATCH operator in the
16501ed72f2Sdan# same query.
16601ed72f2Sdanproc box_geom {args} {
16701ed72f2Sdan  lappend ::ptr_list [lindex $args 4]
16801ed72f2Sdan  return 0
16901ed72f2Sdan}
17001ed72f2Sdanset ::ptr_list [list]
17101ed72f2Sdando_execsql_test 3.1 {
17201ed72f2Sdan  SELECT * FROM rt1 WHERE id MATCH box(1,1);
17301ed72f2Sdan}
17401ed72f2Sdando_test 3.2 {
17501ed72f2Sdan  set val [lindex $::ptr_list 0]
17601ed72f2Sdan  foreach p $::ptr_list {
17701ed72f2Sdan    if {$p!=$val} {error "pointer mismatch"}
17801ed72f2Sdan  }
17901ed72f2Sdan} {}
18001ed72f2Sdan
18101ed72f2Sdan# EVIDENCE-OF: R-60247-35692 The contents of the sqlite3_rtree_geometry
18201ed72f2Sdan# structure are initialized by SQLite but are not subsequently modified.
18301ed72f2Sdanproc box_geom {args} {
18401ed72f2Sdan  lappend ::box_geom [concat [lindex $args 0] [lrange $args 2 end-1]]
18501ed72f2Sdan  if {[llength $::box_geom]==3} {
18601ed72f2Sdan    return "zero"
18701ed72f2Sdan  }
18801ed72f2Sdan  return ""
18901ed72f2Sdan}
19001ed72f2Sdanset ::box_geom [list]
19101ed72f2Sdando_catchsql_test 3.2 {
19201ed72f2Sdan  SELECT * FROM rt1 WHERE id MATCH box(1,1);
19301ed72f2Sdan} {1 {SQL logic error}}
19401ed72f2Sdando_test 3.3 {
19501ed72f2Sdan  set ::box_geom
19601ed72f2Sdan} [list {*}{
19701ed72f2Sdan  {box {1.0 1.0} {0.0 0.0}}
19801ed72f2Sdan  {box {1.0 1.0} {10.0 10.0}}
19901ed72f2Sdan  {box {1.0 1.0} {11.0 11.0}}
20001ed72f2Sdan  {box 0.0 {12.0 12.0}}
20101ed72f2Sdan}]
20201ed72f2Sdan
20301ed72f2Sdan# EVIDENCE-OF: R-31246-29731 The pContext member of the
20401ed72f2Sdan# sqlite3_rtree_geometry structure is always set to a copy of the
20501ed72f2Sdan# pContext argument passed to sqlite3_rtree_geometry_callback() when the
20601ed72f2Sdan# callback is registered.
20701ed72f2Sdanreset_db
20801ed72f2Sdando_execsql_test 4.0 {
20901ed72f2Sdan  CREATE VIRTUAL TABLE r1 USING rtree(id, minX,maxX, minY,maxY);
21001ed72f2Sdan  WITH s(i) AS (
21101ed72f2Sdan    VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<120
21201ed72f2Sdan  )
21301ed72f2Sdan  INSERT INTO r1 SELECT i,i,i+1,  200,201 FROM s;
21401ed72f2Sdan}
21501ed72f2Sdanset ctx [register_box_geom db box_geom]
21601ed72f2Sdanset ::box_geom [list]
21701ed72f2Sdanproc box_geom {args} {
21801ed72f2Sdan  lappend ::box_geom [lindex $args 1]
21901ed72f2Sdan  return ""
22001ed72f2Sdan}
22101ed72f2Sdando_execsql_test 4.1 {
22201ed72f2Sdan  SELECT count(*) FROM r1 WHERE id MATCH box(0,150,199,201)
22301ed72f2Sdan} 120
22401ed72f2Sdando_test 4.2 {
22501ed72f2Sdan  foreach g $::box_geom {
22601ed72f2Sdan    if {$g!=$ctx} {error "pointer mismatch"}
22701ed72f2Sdan  }
22801ed72f2Sdan} {}
22901ed72f2Sdan
23001ed72f2Sdan# EVIDENCE-OF: R-09904-19077 The aParam[] array (size nParam) contains
23101ed72f2Sdan# the parameter values passed to the SQL function on the right-hand side
23201ed72f2Sdan# of the MATCH operator.
23301ed72f2Sdanproc box_geom {args} {
23401ed72f2Sdan  set ::box_geom [lindex $args 2]
23501ed72f2Sdan}
23601ed72f2Sdanforeach {tn q vals} {
23701ed72f2Sdan  1 "SELECT count(*) FROM r1 WHERE id MATCH box(1,2,3)" {1.0 2.0 3.0}
23801ed72f2Sdan  2 "SELECT count(*) FROM r1 WHERE id MATCH box(10001)" {10001.0}
23901ed72f2Sdan  3 "SELECT count(*) FROM r1 WHERE id MATCH box(-10001)" {-10001.0}
24001ed72f2Sdan} {
24101ed72f2Sdan  do_catchsql_test 5.$tn.1 $q {1 {SQL logic error}}
24201ed72f2Sdan  do_test 5.$tn.2 { set ::box_geom } $vals
24301ed72f2Sdan}
24401ed72f2Sdan
245*5488e082Sdando_execsql_test 5.0 {
246*5488e082Sdan  CREATE VIRTUAL TABLE myrtree USING rtree(id, x1,x2);
247*5488e082Sdan  INSERT INTO myrtree VALUES(1, 1, 1);
248*5488e082Sdan  INSERT INTO myrtree VALUES(2, 2, 2);
249*5488e082Sdan  INSERT INTO myrtree VALUES(3, 3, 3);
250*5488e082Sdan}
25101ed72f2Sdan
252*5488e082Sdan# EVIDENCE-OF: R-44448-00687 The pUser and xDelUser members of the
253*5488e082Sdan# sqlite3_rtree_geometry structure are initially set to NULL.
254*5488e082Sdanset ::box_geom_calls 0
255*5488e082Sdanproc box_geom {args} {
256*5488e082Sdan  incr ::box_geom_calls
257*5488e082Sdan  return user_is_zero
258*5488e082Sdan}
259*5488e082Sdando_execsql_test 5.1.1 {
260*5488e082Sdan  SELECT * FROM myrtree WHERE id MATCH box(4, 5);
261*5488e082Sdan}
262*5488e082Sdando_test 5.1.2 { set ::box_geom_calls } 3
263*5488e082Sdan
264*5488e082Sdan
265*5488e082Sdan# EVIDENCE-OF: R-55837-00155 The pUser variable may be set by the
266*5488e082Sdan# callback implementation to any arbitrary value that may be useful to
267*5488e082Sdan# subsequent invocations of the callback within the same query (for
268*5488e082Sdan# example, a pointer to a complicated data structure used to test for
269*5488e082Sdan# region intersection).
270*5488e082Sdan#
271*5488e082Sdan# EVIDENCE-OF: R-34745-08839 If the xDelUser variable is set to a
272*5488e082Sdan# non-NULL value, then after the query has finished running SQLite
273*5488e082Sdan# automatically invokes it with the value of the pUser variable as the
274*5488e082Sdan# only argument.
275*5488e082Sdan#
276*5488e082Sdanset ::box_geom_calls 0
277*5488e082Sdanproc box_geom {args} {
278*5488e082Sdan  incr ::box_geom_calls
279*5488e082Sdan  switch -- $::box_geom_calls {
280*5488e082Sdan    1 {
281*5488e082Sdan      return user_is_zero
282*5488e082Sdan    }
283*5488e082Sdan    2 {
284*5488e082Sdan      return [list user box_geom_finalizer]
285*5488e082Sdan    }
286*5488e082Sdan  }
287*5488e082Sdan  return ""
288*5488e082Sdan}
289*5488e082Sdanproc box_geom_finalizer {} {
290*5488e082Sdan  set ::box_geom_finalizer "::box_geom_calls is $::box_geom_calls"
291*5488e082Sdan}
292*5488e082Sdando_execsql_test 5.1.1 {
293*5488e082Sdan  SELECT * FROM myrtree WHERE id MATCH box(4, 5);
294*5488e082Sdan}
295*5488e082Sdando_test 5.1.2 { set ::box_geom_calls } 3
296*5488e082Sdando_test 5.1.3 {
297*5488e082Sdan  set ::box_geom_finalizer
298*5488e082Sdan} {::box_geom_calls is 3}
299*5488e082Sdan
300*5488e082Sdan
301*5488e082Sdan# EVIDENCE-OF: R-28176-28813 The xGeom callback always does a
302*5488e082Sdan# depth-first search of the r-tree.
303*5488e082Sdan#
304*5488e082Sdan# For a breadth first search, final test case would return "B L" only.
305*5488e082Sdan#
306*5488e082Sdando_execsql_test 6.0 {
307*5488e082Sdan  CREATE VIRTUAL TABLE xyz USING rtree(x, x1,x2, y1,y2);
308*5488e082Sdan  WITH s(i) AS (
309*5488e082Sdan    VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<15
310*5488e082Sdan  )
311*5488e082Sdan  INSERT INTO xyz SELECT NULL, one.i,one.i+1,  two.i,two.i+1 FROM s one, s two;
312*5488e082Sdan}
313*5488e082Sdando_execsql_test 6.1 {
314*5488e082Sdan  SELECT count(*) FROM xyz_node
315*5488e082Sdan} {10}
316*5488e082Sdanproc box_geom {args} {
317*5488e082Sdan  set coords [lindex $args 3]
318*5488e082Sdan  set area [expr {
319*5488e082Sdan    ([lindex $coords 1]-[lindex $coords 0]) *
320*5488e082Sdan    ([lindex $coords 3]-[lindex $coords 2])
321*5488e082Sdan  }]
322*5488e082Sdan  if {$area==1} {
323*5488e082Sdan    lappend ::box_geom_calls L
324*5488e082Sdan  } else {
325*5488e082Sdan    lappend ::box_geom_calls B
326*5488e082Sdan  }
327*5488e082Sdan}
328*5488e082Sdanset ::box_geom_calls [list]
329*5488e082Sdando_execsql_test 6.2 {
330*5488e082Sdan  SELECT count(*) FROM xyz WHERE x MATCH box(0,20,0,20)
331*5488e082Sdan} 225
332*5488e082Sdando_test 6.3 {
333*5488e082Sdan  set prev ""
334*5488e082Sdan  set box_calls [list]
335*5488e082Sdan  foreach c $::box_geom_calls {
336*5488e082Sdan    if {$c!=$prev} {
337*5488e082Sdan      lappend ::box_calls $c
338*5488e082Sdan      set prev $c
339*5488e082Sdan    }
340*5488e082Sdan  }
341*5488e082Sdan  set ::box_calls
342*5488e082Sdan} {B L B L B L B L B L B L B L B L B L}
34301ed72f2Sdan
34401ed72f2Sdan
34501ed72f2Sdanfinish_test
34601ed72f2Sdan
347