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