]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix a bug in rtree that occurs when too many constraints are passed
authordrh <drh@noemail.net>
Tue, 27 May 2008 00:06:02 +0000 (00:06 +0000)
committerdrh <drh@noemail.net>
Tue, 27 May 2008 00:06:02 +0000 (00:06 +0000)
in on a query. (CVS 5162)

FossilOrigin-Name: 54b84a3ddba9d27814c2f613dd197f691ac549a4

ext/rtree/rtree.c
ext/rtree/rtree2.test
ext/rtree/rtree4.test [new file with mode: 0644]
manifest
manifest.uuid

index b39ff67c1c584e11096bfdd75def5ba5cc8d6c9c..6b37d2c51d276cdc34df35a638de3f3c1338b100 100644 (file)
@@ -12,7 +12,7 @@
 ** 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)
@@ -1080,11 +1080,11 @@ static int rtreeFilter(
 */
 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++){
@@ -1113,8 +1113,35 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
         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;
       }
index 43c455f924a0b0f3d299b670c70ece71b2062f59..e9f395e807d06032acfe81d19715b3b7499ce7e2 100644 (file)
@@ -11,7 +11,7 @@
 #
 # 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]
@@ -44,24 +44,24 @@ for {set nDim 1} {$nDim <= 5} {incr nDim} {
   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
+        #}
       }
     }
 
@@ -100,13 +100,13 @@ for {set nDim 1} {$nDim <= 5} {incr nDim} {
       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}
@@ -141,4 +141,3 @@ exit
 }
 
 finish_test
-
diff --git a/ext/rtree/rtree4.test b/ext/rtree/rtree4.test
new file mode 100644 (file)
index 0000000..9f584af
--- /dev/null
@@ -0,0 +1,230 @@
+# 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
index 4c06f2711befb0366be727d17001305759d2cfa9..7edfced992fa62ae896cba4cda123fa76ad49eb7 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-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
@@ -64,12 +64,13 @@ F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
 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
@@ -589,7 +590,7 @@ F tool/speedtest16.c 6f5bc019dcf8b6537f379bbac0408a9e1a86f0b6
 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
index 85b4a2215253b5c7af65157c0c13054a9c43b1c6..91b11adeeeb8155138435d31f251f08e01bf616b 100644 (file)
@@ -1 +1 @@
-78f4ba974d9b768b62391d8cd2ed407d49584cb8
\ No newline at end of file
+54b84a3ddba9d27814c2f613dd197f691ac549a4
\ No newline at end of file