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