]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Where possible, take advantage of the rowid at the end of index records to optimize...
authordan <dan@noemail.net>
Wed, 16 Nov 2011 15:27:09 +0000 (15:27 +0000)
committerdan <dan@noemail.net>
Wed, 16 Nov 2011 15:27:09 +0000 (15:27 +0000)
FossilOrigin-Name: 3b58f5f06648205a47e5cace0201269c406e476a

manifest
manifest.uuid
src/insert.c
src/vdbe.c
src/vdbeaux.c
src/where.c
test/whereC.test [new file with mode: 0644]

index cd931ca42a31b78ac3690eeb91124ca7611e77e5..ce4d2b370f508a4660daf627dad021fa5cda5883 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Update\smemsubsys1.test\sto\saccount\sfor\sthe\srecently\sincreased\ssize\sof\sthe\sMemPage\sstructure\sin\sbtreeInt.h.
-D 2011-11-16T08:18:20.698
+C Where\spossible,\stake\sadvantage\sof\sthe\srowid\sat\sthe\send\sof\sindex\srecords\sto\soptimize\srange\sconstraints\s(<,\s>,\s<=,\s>=)\son\sthe\srowid\scolumn.
+D 2011-11-16T15:27:09.116
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -142,7 +142,7 @@ F src/global.c e230227de13601714b29f9363028514aada5ae2f
 F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
 F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
-F src/insert.c 9794a963911da8157ad0dc39726c9c695b1c4692
+F src/insert.c 8f283d6734dd837ed7531b26d7622fda70874390
 F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
 F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
 F src/lempar.c 0ee69fca0be54cd93939df98d2aca4ca46f44416
@@ -239,11 +239,11 @@ F src/update.c 25e046a8f69d5e557aabde2000487b8545509d8d
 F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84
 F src/util.c 01238e2b0f24a14779181dbf991fe02620a80e31
 F src/vacuum.c 0c0ba2242355c6048d65e2b333abe0f7c06348fa
-F src/vdbe.c 326994a64a9a08853122200dc9f62cb96b8f0831
+F src/vdbe.c a7ab9993ec5a4d9479dc99671faec061fbf9b889
 F src/vdbe.h f0725ee997db869ecae5bb70a71612aabeca7755
 F src/vdbeInt.h 9498fc98a2c9e349a4ef13455ff5a3e898f40176
 F src/vdbeapi.c 4dbba7f94f127f6ea8d2d0505ee1f98e5ffbf546
-F src/vdbeaux.c a950e34449a508d48d90475acc287943a4094f3a
+F src/vdbeaux.c 17bee21d513b8567f2e010aea287e81e9e6e273f
 F src/vdbeblob.c 32f2a4899d67f69634ea4dd93e3f651936d732cb
 F src/vdbemem.c 2fc78b3e0fabcc1eaa23cd79dd2e30e6dcfe1e56
 F src/vdbesort.c 468d43c057063e54da4f1988b38b4f46d60e7790
@@ -252,7 +252,7 @@ F src/vtab.c e9318d88feac85be8e27ee783ac8f5397933fc8a
 F src/wal.c 5fe1ba55b8fab9d3936bc9093af61ab9f1c580a1
 F src/wal.h 66b40bd91bc29a5be1c88ddd1f5ade8f3f48728a
 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
-F src/where.c 7c85f4c93058e27100d404f0777aaeb0d1b296ae
+F src/where.c f73752ca85c0ed221753fda98aeaf6b9d4616e0e
 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
@@ -927,6 +927,7 @@ F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
 F test/where9.test bed66dcfc69a54a99661c0c9906189cb5e58f4e2
 F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a
 F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
+F test/whereC.test 13ff5ec0dba407c0e0c075980c75b3275a6774e5
 F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
 F test/win32lock.test b2a539e85ae6b2d78475e016a9636b4451dc7fb9
 F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
@@ -974,7 +975,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
 F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
-P ebf6eb6ed756c0a3158b4cb5fb4b460c79d93c29
-R caea05edce79a54f0d9a19e01ae7581d
+P 4fb3ca756a3a7c66baa4745a9b2c1e246a67c699
+R 131e1406052949b0c9af0dcdeb54bce6
 U dan
-Z 63891b2b7447d3ac397ed0d8ca697472
+Z 4ed1ee25329fe5dbd728820234ee8619
index 1c039625bc1504841347f5925f2d52e74fdc55cc..c2ae2e6bb39ee39c9bedfdb194a71df96f5a1778 100644 (file)
@@ -1 +1 @@
-4fb3ca756a3a7c66baa4745a9b2c1e246a67c699
\ No newline at end of file
+3b58f5f06648205a47e5cace0201269c406e476a
\ No newline at end of file
index bfcd2c25361a730880fb5725e7fbc327827b895c..eca3c12ddc6811fc6b47c59b1edb4623b17ab77b 100644 (file)
@@ -47,7 +47,7 @@ void sqlite3OpenTable(
 **  'd'            INTEGER
 **  'e'            REAL
 **
-** An extra 'b' is appended to the end of the string to cover the
+** An extra 'd' is appended to the end of the string to cover the
 ** rowid that appears as the last column in every index.
 **
 ** Memory for the buffer containing the column index affinity string
@@ -75,7 +75,7 @@ const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
     for(n=0; n<pIdx->nColumn; n++){
       pIdx->zColAff[n] = pTab->aCol[pIdx->aiColumn[n]].affinity;
     }
-    pIdx->zColAff[n++] = SQLITE_AFF_NONE;
+    pIdx->zColAff[n++] = SQLITE_AFF_INTEGER;
     pIdx->zColAff[n] = 0;
   }
  
index 22e6d9c5b676149dd761188e9695de9015c2f2cb..e7fa05037d1fa9d522cae4e919a3397fc9c035e5 100644 (file)
@@ -4616,9 +4616,9 @@ case OP_IdxGE: {        /* jump */
     r.pKeyInfo = pC->pKeyInfo;
     r.nField = (u16)pOp->p4.i;
     if( pOp->p5 ){
-      r.flags = UNPACKED_INCRKEY | UNPACKED_IGNORE_ROWID;
+      r.flags = UNPACKED_INCRKEY | UNPACKED_PREFIX_MATCH;
     }else{
-      r.flags = UNPACKED_IGNORE_ROWID;
+      r.flags = UNPACKED_PREFIX_MATCH;
     }
     r.aMem = &aMem[pOp->p3];
 #ifdef SQLITE_DEBUG
index 75250238ecb83c9a73a66119233b96d1f532155d..67b4ec7593f7e83433a3f100733c08d8940c8505 100644 (file)
@@ -3166,7 +3166,7 @@ int sqlite3VdbeIdxKeyCompare(
   if( rc ){
     return rc;
   }
-  assert( pUnpacked->flags & UNPACKED_IGNORE_ROWID );
+  assert( pUnpacked->flags & UNPACKED_PREFIX_SEARCH );
   *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked);
   sqlite3VdbeMemRelease(&m);
   return SQLITE_OK;
index 05414da58b4cf02dcca176d42a25ab192eca4426..a604d788c43ae125e8e0b806c09ba642fee256f6 100644 (file)
@@ -604,7 +604,7 @@ static WhereTerm *findTerm(
          && pTerm->u.leftColumn==iColumn
          && (pTerm->eOperator & op)!=0
       ){
-        if( pIdx && pTerm->eOperator!=WO_ISNULL ){
+        if( iColumn>=0 && pIdx && pTerm->eOperator!=WO_ISNULL ){
           Expr *pX = pTerm->pExpr;
           CollSeq *pColl;
           char idxaff;
@@ -3052,10 +3052,24 @@ static void bestBtreeIndex(
 #endif
       used |= pTerm->prereqRight;
     }
-
-    /* Determine the value of rangeDiv */
-    if( nEq<pProbe->nColumn && pProbe->bUnordered==0 ){
-      int j = pProbe->aiColumn[nEq];
+    /* If the index being considered is UNIQUE, and there is an equality 
+    ** constraint for all columns in the index, then this search will find
+    ** at most a single row. In this case set the WHERE_UNIQUE flag to 
+    ** indicate this to the caller.
+    **
+    ** Otherwise, if the search may find more than one row, test to see if
+    ** there is a range constraint on indexed column (nEq+1) that can be 
+    ** optimized using the index. 
+    */
+    if( nEq==pProbe->nColumn && pProbe->onError!=OE_None ){
+      testcase( wsFlags & WHERE_COLUMN_IN );
+      testcase( wsFlags & WHERE_COLUMN_NULL );
+      if( (wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){
+        wsFlags |= WHERE_UNIQUE;
+      }
+    }else if( pProbe->bUnordered==0 ){
+      int j = (nEq==pProbe->nColumn ? -1 : pProbe->aiColumn[nEq]);
       if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){
         WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx);
         WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx);
@@ -3074,12 +3088,6 @@ static void bestBtreeIndex(
         }
         wsFlags |= (WHERE_COLUMN_RANGE|WHERE_ROWID_RANGE);
       }
-    }else if( pProbe->onError!=OE_None ){
-      testcase( wsFlags & WHERE_COLUMN_IN );
-      testcase( wsFlags & WHERE_COLUMN_NULL );
-      if( (wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){
-        wsFlags |= WHERE_UNIQUE;
-      }
     }
 
     /* If there is an ORDER BY clause and the index being considered will
@@ -3690,10 +3698,12 @@ static char *explainIndexRange(sqlite3 *db, WhereLevel *pLevel, Table *pTab){
 
   j = i;
   if( pPlan->wsFlags&WHERE_BTM_LIMIT ){
-    explainAppendTerm(&txt, i++, aCol[aiColumn[j]].zName, ">");
+    char *z = (j==pIndex->nColumn ) ? "rowid" : aCol[aiColumn[j]].zName;
+    explainAppendTerm(&txt, i++, z, ">");
   }
   if( pPlan->wsFlags&WHERE_TOP_LIMIT ){
-    explainAppendTerm(&txt, i, aCol[aiColumn[j]].zName, "<");
+    char *z = (j==pIndex->nColumn ) ? "rowid" : aCol[aiColumn[j]].zName;
+    explainAppendTerm(&txt, i, z, "<");
   }
   sqlite3StrAccumAppend(&txt, ")", 1);
   return sqlite3StrAccumFinish(&txt);
@@ -4051,7 +4061,7 @@ static Bitmask codeOneLoopStart(
 
     pIdx = pLevel->plan.u.pIdx;
     iIdxCur = pLevel->iIdxCur;
-    k = pIdx->aiColumn[nEq];     /* Column for inequality constraints */
+    k = (nEq==pIdx->nColumn ? -1 : pIdx->aiColumn[nEq]);
 
     /* If this loop satisfies a sort order (pOrderBy) request that 
     ** was passed to this function to implement a "SELECT min(x) ..." 
@@ -4097,7 +4107,9 @@ static Bitmask codeOneLoopStart(
     ** a forward order scan on a descending index, interchange the 
     ** start and end terms (pRangeStart and pRangeEnd).
     */
-    if( nEq<pIdx->nColumn && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC) ){
+    if( (nEq<pIdx->nColumn && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC))
+     || (bRev && pIdx->nColumn==nEq)
+    ){
       SWAP(WhereTerm *, pRangeEnd, pRangeStart);
     }
 
diff --git a/test/whereC.test b/test/whereC.test
new file mode 100644 (file)
index 0000000..9fa1bba
--- /dev/null
@@ -0,0 +1,70 @@
+# 2011 November 16
+#
+# 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.
+#
+#***********************************************************************
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix whereC
+
+do_execsql_test 1.0 {
+  CREATE TABLE t1(i INTEGER PRIMARY KEY, a, b INTEGER);
+
+  INSERT INTO t1 VALUES(1, 1, 1);
+  INSERT INTO t1 VALUES(2, 1, 1);
+  INSERT INTO t1 VALUES(3, 1, 2);
+  INSERT INTO t1 VALUES(4, 1, 2);
+  INSERT INTO t1 VALUES(5, 1, 2);
+  INSERT INTO t1 VALUES(6, 1, 3);
+  INSERT INTO t1 VALUES(7, 1, 3);
+
+  INSERT INTO t1 VALUES(8, 2, 1);
+  INSERT INTO t1 VALUES(9, 2, 1);
+  INSERT INTO t1 VALUES(10, 2, 2);
+  INSERT INTO t1 VALUES(11, 2, 2);
+  INSERT INTO t1 VALUES(12, 2, 2);
+  INSERT INTO t1 VALUES(13, 2, 3);
+  INSERT INTO t1 VALUES(14, 2, 3);
+
+  INSERT INTO t1 VALUES(15, 2, 1);
+  INSERT INTO t1 VALUES(16, 2, 1);
+  INSERT INTO t1 VALUES(17, 2, 2);
+  INSERT INTO t1 VALUES(18, 2, 2);
+  INSERT INTO t1 VALUES(19, 2, 2);
+  INSERT INTO t1 VALUES(20, 2, 3);
+  INSERT INTO t1 VALUES(21, 2, 3);
+
+  CREATE INDEX i1 ON t1(a, b);
+}
+
+foreach {tn sql res} {
+  1   "SELECT i FROM t1 WHERE a=1 AND b=2 AND i>3"         {4 5}
+  2   "SELECT i FROM t1 WHERE rowid='12'"                  {12}
+  3   "SELECT i FROM t1 WHERE a=1 AND b='2'"               {3 4 5}
+  4   "SELECT i FROM t1 WHERE a=1 AND b='2' AND i>'3'"     {4 5}
+  5   "SELECT i FROM t1 WHERE a=1 AND b='2' AND i<5"       {3 4}
+  6   "SELECT i FROM t1 WHERE a=2 AND b=2 AND i<12"        {10 11}
+  7   "SELECT i FROM t1 WHERE a IN(1, 2) AND b=2 AND i<11" {3 4 5 10}
+  8   "SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 10 AND 12" {10 11 12}
+  9   "SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 11 AND 12" {11 12}
+ 10   "SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 10 AND 11" {10 11}
+ 11   "SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 12 AND 10" {}
+ 12   "SELECT i FROM t1 WHERE a=2 AND b=2 AND i<NULL"      {}
+ 13   "SELECT i FROM t1 WHERE a=2 AND b=2 AND i>=NULL"     {}
+ 14   "SELECT i FROM t1 WHERE a=1 AND b='2' AND i<4.5"     {3 4}
+} {
+  do_execsql_test 1.$tn.1 $sql $res
+  do_execsql_test 1.$tn.2 "$sql ORDER BY i ASC"  [lsort -integer -inc  $res]
+  do_execsql_test 1.$tn.3 "$sql ORDER BY i DESC" [lsort -integer -dec  $res]
+}
+
+
+finish_test
+