** This file contains code for implementations of the r-tree and r*-tree
** algorithms packaged as an SQLite virtual table module.
**
-** $Id: rtree.c,v 1.3 2008/05/26 20:49:03 drh Exp $
+** $Id: rtree.c,v 1.4 2008/05/27 00:06:02 drh Exp $
*/
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RTREE)
*/
static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
int rc = SQLITE_OK;
- int ii;
+ int ii, cCol;
int iIdx = 0;
- char zIdxStr[RTREE_MAX_DIMENSIONS*2+1];
- memset(zIdxStr, 0, RTREE_MAX_DIMENSIONS*2+1);
+ char zIdxStr[RTREE_MAX_DIMENSIONS*8+1];
+ memset(zIdxStr, 0, sizeof(zIdxStr));
assert( pIdxInfo->idxStr==0 );
for(ii=0; ii<pIdxInfo->nConstraint; ii++){
case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break;
}
if( op ){
+ /* Make sure this particular constraint has not been used before.
+ ** If it has been used before, ignore it.
+ **
+ ** A <= or < can be used if there is a prior >= or >.
+ ** A >= or > can be used if there is a prior < or <=.
+ ** A <= or < is disqualified if there is a prior <=, <, or ==.
+ ** A >= or > is disqualified if there is a prior >=, >, or ==.
+ ** A == is disqualifed if there is any prior constraint.
+ */
+ int j, opmsk;
+ static const unsigned char compatible[] = { 0, 0, 1, 1, 2, 2 };
+ assert( compatible[RTREE_EQ & 7]==0 );
+ assert( compatible[RTREE_LT & 7]==1 );
+ assert( compatible[RTREE_LE & 7]==1 );
+ assert( compatible[RTREE_GT & 7]==2 );
+ assert( compatible[RTREE_GE & 7]==2 );
+ cCol = p->iColumn - 1 + 'a';
+ opmsk = compatible[op & 7];
+ for(j=0; j<iIdx; j+=2){
+ if( zIdxStr[j+1]==cCol && (compatible[zIdxStr[j] & 7] & opmsk)!=0 ){
+ op = 0;
+ break;
+ }
+ }
+ }
+ if( op ){
+ assert( iIdx<sizeof(zIdxStr)-1 );
zIdxStr[iIdx++] = op;
- zIdxStr[iIdx++] = (char)(p->iColumn-1) + 'a';
+ zIdxStr[iIdx++] = cCol;
pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2);
pIdxInfo->aConstraintUsage[ii].omit = 1;
}
#
# The focus of this file is testing the r-tree extension.
#
-# $Id: rtree2.test,v 1.1 2008/05/26 18:41:54 danielk1977 Exp $
+# $Id: rtree2.test,v 1.2 2008/05/27 00:06:02 drh Exp $
#
set testdir [file join [file dirname $argv0] .. .. test]
do_test rtree2-$nDim.2 {
db transaction {
for {set ii 0} {$ii < $::NROW} {incr ii} {
-#puts "Row $ii"
+ #puts "Row $ii"
set values [list]
for {set jj 0} {$jj<$nDim*2} {incr jj} {
lappend values [expr int(rand()*1000)]
}
set values [join $values ,]
-#puts [rtree_treedump db t1]
-#puts "INSERT INTO t2 VALUES($ii, $values)"
+ #puts [rtree_treedump db t1]
+ #puts "INSERT INTO t2 VALUES($ii, $values)"
set rc [catch {db eval "INSERT INTO t1 VALUES($ii, $values)"}]
if {$rc} {
incr ii -1
} else {
db eval "INSERT INTO t2 VALUES($ii, $values)"
}
-#if {[rtree_check db t1]} {
-#puts [rtree_treedump db t1]
-#exit
-#}
+ #if {[rtree_check db t1]} {
+ #puts [rtree_treedump db t1]
+ #exit
+ #}
}
}
set t2 [execsql "SELECT * FROM t2 WHERE $where ORDER BY ii"]
set rc [expr {$t1 eq $t2}]
if {$rc != 1} {
-puts $where
+ #puts $where
puts $t1
puts $t2
-puts [rtree_treedump db t1]
-breakpoint
-set t1 [execsql "SELECT * FROM t1 WHERE $where ORDER BY ii"]
-exit
+ #puts [rtree_treedump db t1]
+ #breakpoint
+ #set t1 [execsql "SELECT * FROM t1 WHERE $where ORDER BY ii"]
+ #exit
}
set rc
} {1}
}
finish_test
-
--- /dev/null
+# 2008 May 23
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# Randomized test cases for the rtree extension.
+#
+# $Id: rtree4.test,v 1.1 2008/05/27 00:06:02 drh Exp $
+#
+
+set testdir [file join [file dirname $argv0] .. .. test]
+source $testdir/tester.tcl
+
+ifcapable !rtree {
+ finish_test
+ return
+}
+
+# Return a floating point number between -X and X.
+#
+proc rand {X} {
+ return [expr {int((rand()-0.5)*1024.0*$X)/512.0}]
+}
+
+# Return a positive floating point number less than or equal to X
+#
+proc randincr {X} {
+ while 1 {
+ set r [expr {int(rand()*$X*32.0)/32.0}]
+ if {$r>0.0} {return $r}
+ }
+}
+
+# Scramble the $inlist into a random order.
+#
+proc scramble {inlist} {
+ set y {}
+ foreach x $inlist {
+ lappend y [list [expr {rand()}] $x]
+ }
+ set y [lsort $y]
+ set outlist {}
+ foreach x $y {
+ lappend outlist [lindex $x 1]
+ }
+ return $outlist
+}
+
+# Always use the same random seed so that the sequence of tests
+# is repeatable.
+#
+expr {srand(1234)}
+
+# Run these tests for all number of dimensions between 1 and 5.
+#
+for {set nDim 1} {$nDim<=5} {incr nDim} {
+
+ # Construct an rtree virtual table and an ordinary btree table
+ # to mirror it. The ordinary table should be much slower (since
+ # it has to do a full table scan) but should give the exact same
+ # answers.
+ #
+ do_test rtree4-$nDim.1 {
+ set clist {}
+ set cklist {}
+ for {set i 0} {$i<$nDim} {incr i} {
+ lappend clist mn$i mx$i
+ lappend cklist "mn$i<mx$i"
+ }
+ db eval "DROP TABLE IF EXISTS rx"
+ db eval "DROP TABLE IF EXISTS bx"
+ db eval "CREATE VIRTUAL TABLE rx USING rtree(id, [join $clist ,])"
+ db eval "CREATE TABLE bx(id INTEGER PRIMARY KEY,\
+ [join $clist ,], CHECK( [join $cklist { AND }] ))"
+ } {}
+
+ # Do many insertions of small objects. Do both overlapping and
+ # contained-within queries after each insert to verify that all
+ # is well.
+ #
+ unset -nocomplain where
+ for {set i 1} {$i<2500} {incr i} {
+ # Do a random insert
+ #
+ do_test rtree-$nDim.2.$i.1 {
+ set vlist {}
+ for {set j 0} {$j<$nDim} {incr j} {
+ set mn [rand 10000]
+ set mx [expr {$mn+[randincr 50]}]
+ lappend vlist $mn $mx
+ }
+ db eval "INSERT INTO rx VALUES(NULL, [join $vlist ,])"
+ db eval "INSERT INTO bx VALUES(NULL, [join $vlist ,])"
+ } {}
+
+ # Do a contained-in query on all dimensions
+ #
+ set where {}
+ for {set j 0} {$j<$nDim} {incr j} {
+ set mn [rand 10000]
+ set mx [expr {$mn+[randincr 500]}]
+ lappend where mn$j>=$mn mx$j<=$mx
+ }
+ set where "WHERE [join $where { AND }]"
+ do_test rtree-$nDim.2.$i.2 {
+ list $where [db eval "SELECT id FROM rx $where ORDER BY id"]
+ } [list $where [db eval "SELECT id FROM bx $where ORDER BY id"]]
+
+ # Do an overlaps query on all dimensions
+ #
+ set where {}
+ for {set j 0} {$j<$nDim} {incr j} {
+ set mn [rand 10000]
+ set mx [expr {$mn+[randincr 500]}]
+ lappend where mx$j>=$mn mn$j<=$mx
+ }
+ set where "WHERE [join $where { AND }]"
+ do_test rtree-$nDim.2.$i.3 {
+ list $where [db eval "SELECT id FROM rx $where ORDER BY id"]
+ } [list $where [db eval "SELECT id FROM bx $where ORDER BY id"]]
+
+ # Do a contained-in query with surplus contraints at the beginning.
+ # This should force a full-table scan on the rtree.
+ #
+ set where {}
+ for {set j 0} {$j<$nDim} {incr j} {
+ lappend where mn$j>-10000 mx$j<10000
+ }
+ for {set j 0} {$j<$nDim} {incr j} {
+ set mn [rand 10000]
+ set mx [expr {$mn+[randincr 500]}]
+ lappend where mn$j>=$mn mx$j<=$mx
+ }
+ set where "WHERE [join $where { AND }]"
+ do_test rtree-$nDim.2.$i.3 {
+ list $where [db eval "SELECT id FROM rx $where ORDER BY id"]
+ } [list $where [db eval "SELECT id FROM bx $where ORDER BY id"]]
+
+ # Do an overlaps query with surplus contraints at the beginning.
+ # This should force a full-table scan on the rtree.
+ #
+ set where {}
+ for {set j 0} {$j<$nDim} {incr j} {
+ lappend where mn$j>=-10000 mx$j<=10000
+ }
+ for {set j 0} {$j<$nDim} {incr j} {
+ set mn [rand 10000]
+ set mx [expr {$mn+[randincr 500]}]
+ lappend where mx$j>$mn mn$j<$mx
+ }
+ set where "WHERE [join $where { AND }]"
+ do_test rtree-$nDim.2.$i.4 {
+ list $where [db eval "SELECT id FROM rx $where ORDER BY id"]
+ } [list $where [db eval "SELECT id FROM bx $where ORDER BY id"]]
+
+ # Do a contained-in query with surplus contraints at the end
+ #
+ set where {}
+ for {set j 0} {$j<$nDim} {incr j} {
+ set mn [rand 10000]
+ set mx [expr {$mn+[randincr 500]}]
+ lappend where mn$j>=$mn mx$j<$mx
+ }
+ for {set j [expr {$nDim-1}]} {$j>=0} {incr j -1} {
+ lappend where mn$j>=-10000 mx$j<10000
+ }
+ set where "WHERE [join $where { AND }]"
+ do_test rtree-$nDim.2.$i.5 {
+ list $where [db eval "SELECT id FROM rx $where ORDER BY id"]
+ } [list $where [db eval "SELECT id FROM bx $where ORDER BY id"]]
+
+ # Do an overlaps query with surplus contraints at the end
+ #
+ set where {}
+ for {set j [expr {$nDim-1}]} {$j>=0} {incr j -1} {
+ set mn [rand 10000]
+ set mx [expr {$mn+[randincr 500]}]
+ lappend where mx$j>$mn mn$j<=$mx
+ }
+ for {set j 0} {$j<$nDim} {incr j} {
+ lappend where mx$j>-10000 mn$j<=10000
+ }
+ set where "WHERE [join $where { AND }]"
+ do_test rtree-$nDim.2.$i.6 {
+ list $where [db eval "SELECT id FROM rx $where ORDER BY id"]
+ } [list $where [db eval "SELECT id FROM bx $where ORDER BY id"]]
+
+ # Do a contained-in query with surplus contraints where the
+ # constraints appear in a random order.
+ #
+ set where {}
+ for {set j 0} {$j<$nDim} {incr j} {
+ set mn1 [rand 10000]
+ set mn2 [expr {$mn1+[randincr 100]}]
+ set mx1 [expr {$mn2+[randincr 400]}]
+ set mx2 [expr {$mx1+[randincr 100]}]
+ lappend where mn$j>=$mn1 mn$j>$mn2 mx$j<$mx1 mx$j<=$mx2
+ }
+ set where "WHERE [join [scramble $where] { AND }]"
+ do_test rtree-$nDim.2.$i.7 {
+ list $where [db eval "SELECT id FROM rx $where ORDER BY id"]
+ } [list $where [db eval "SELECT id FROM bx $where ORDER BY id"]]
+
+ # Do an overlaps query with surplus contraints where the
+ # constraints appear in a random order.
+ #
+ set where {}
+ for {set j 0} {$j<$nDim} {incr j} {
+ set mn1 [rand 10000]
+ set mn2 [expr {$mn1+[randincr 100]}]
+ set mx1 [expr {$mn2+[randincr 400]}]
+ set mx2 [expr {$mx1+[randincr 100]}]
+ lappend where mx$j>=$mn1 mx$j>$mn2 mn$j<$mx1 mn$j<=$mx2
+ }
+ set where "WHERE [join [scramble $where] { AND }]"
+ do_test rtree-$nDim.2.$i.8 {
+ list $where [db eval "SELECT id FROM rx $where ORDER BY id"]
+ } [list $where [db eval "SELECT id FROM bx $where ORDER BY id"]]
+
+ }
+
+}
+
+finish_test
-C Use\s%w\sinstead\sof\s%q\swhen\sconstructing\sshadow\stable\snames\sfor\srtree.\s(CVS\s5161)
-D 2008-05-26T20:49:03
+C Fix\sa\sbug\sin\srtree\sthat\soccurs\swhen\stoo\smany\sconstraints\sare\spassed\nin\son\sa\squery.\s(CVS\s5162)
+D 2008-05-27T00:06:02
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
F Makefile.in 79aeba12300a54903f1b1257c1e7c190234045dd
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
F ext/icu/README.txt 3b130aa66e7a681136f6add198b076a2f90d1e33
F ext/icu/icu.c 12e763d288d23b5a49de37caa30737b971a2f1e2
F ext/rtree/README 64b8300581ba2553a4522ec78812dc940482906b
-F ext/rtree/rtree.c 8b849f0460545eca83b23878914aca7891657b4f
+F ext/rtree/rtree.c 28b8650cb1594b6a26a47db0b0a3269c8c8d1d43
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
F ext/rtree/rtree.test ec173a9420ff012e4d29b3063add143583a597a7
F ext/rtree/rtree1.test 7504a4bd3aaad379d2d712bbb05fc75460e8537d
-F ext/rtree/rtree2.test 98f3c39b03577330566abf3c7e1e0baf8f9aa521
+F ext/rtree/rtree2.test 3402e9d57cac67651779130bafd4162772d2420e
F ext/rtree/rtree3.test 46d1959aa651d3df8b64d93762d3061c62b38105
+F ext/rtree/rtree4.test f285c08f664804558c267dc8e222e7ecd4dfbc6d
F ext/rtree/rtree_perf.tcl 0fabb6d5c48cb8024e042ce5d4bb88998b6ec1cb
F ext/rtree/rtree_util.tcl ee0a0311eb12175319d78bfb37302320496cee6e
F ext/rtree/viewrtree.tcl 09526398dae87a5a87c5aac2b3854dbaf8376869
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c e74126bc12178fa29904f711bb100212a5448041
F tool/speedtest8inst1.c 025879132979a5fdec11218472cba6cf8f6ec854
-P aa8eba3360c31182f5238e96b83a382374f40fab
-R 6ae55ee931b382f2653693522f39d2a9
+P 78f4ba974d9b768b62391d8cd2ed407d49584cb8
+R 1a1f7b7755f4d5c027e202044942e3ee
U drh
-Z 38ba8ba8b7fad64dd7f56bc5220bc609
+Z d4c09f4b49e195721c249033176d5e36