]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Begin adding code to support multiple IN constraints on the same index. (CVS 2557)
authordrh <drh@noemail.net>
Fri, 22 Jul 2005 00:31:39 +0000 (00:31 +0000)
committerdrh <drh@noemail.net>
Fri, 22 Jul 2005 00:31:39 +0000 (00:31 +0000)
FossilOrigin-Name: 103f8ccb9013689a480766ebffbf570d4aa8bac5

manifest
manifest.uuid
src/sqliteInt.h
src/where.c

index 1bdabd69065e23f6304753109f23bb46dceb5f68..7f1083bcf798c2341dec06de74ed293ecb4b77e5 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Split\sthe\sOP_Integer\sopcode\sinto\sOP_Integer\sand\sOP_Int64.\s\sThis\sallows\ncomments\sto\sbe\sadded\sto\sOP_Integer.\s\sCleanup\sin\sthe\soptimizer.\s\sAllow\nterms\sof\sthe\sFROM\sclause\sto\sbe\sreordered\sautomatically.\s(CVS\s2556)
-D 2005-07-21T18:23:20
+C Begin\sadding\scode\sto\ssupport\smultiple\sIN\sconstraints\son\sthe\ssame\sindex.\s(CVS\s2557)
+D 2005-07-22T00:31:40
 F Makefile.in 22ea9c0fe748f591712d8fe3c6d972c6c173a165
 F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -64,7 +64,7 @@ F src/random.c 90adff4e73a3b249eb4f1fc2a6ff9cf78c7233a4
 F src/select.c c611471052773b94af771693686bd5bcdbbb0dba
 F src/shell.c 25b3217d7c64e6497225439d261a253a23efff26
 F src/sqlite.h.in 838382ed6b48d392366a55e07f49d9d71263e1fe
-F src/sqliteInt.h 89ace2d46348c2924368ff97d41adec5cacacfdc
+F src/sqliteInt.h 810f2ccd49338944ec53c95182e5a8b56da42fa0
 F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
 F src/tclsqlite.c cccaf6b78c290d824cf8ea089b8b27377e545830
 F src/test1.c 722c1444b5774705eb6eb11163343fc94ffe17f7
@@ -85,7 +85,7 @@ F src/vdbeapi.c 7f392f0792d1258c958083d7de9eae7c3530c9a6
 F src/vdbeaux.c 3732a86566a6be4da4c606e9334baf3fd98667af
 F src/vdbefifo.c b8805850afe13b43f1de78d58088cb5d66f88e1e
 F src/vdbemem.c da8e8d6f29dd1323f782f000d7cd120027c9ff03
-F src/where.c 65d9b27edaf29edaba95442f65a3cfc36ae6dbdb
+F src/where.c 70b2195b4732ce785be32140f982b2ed471d205d
 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
 F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3
 F test/alter.test 9d6837a3d946b73df692b7cef2a7644d2e2f6bc6
@@ -286,7 +286,7 @@ F www/tclsqlite.tcl 425be741b8ae664f55cb1ef2371aab0a75109cf9
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
 F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b
-P ef3a157f469d72cbd2f713f997598ddf47f340d2
-R 36cfab460ee644fb8d42d82df874b83c
+P e2f822ac82d0a5a59de0b63cce65d4fd6c178ff1
+R 156ee4225ef63d3a2b0a126183a1b6ad
 U drh
-Z b75bf1e0203a3ee4b4ae420ba35e8ecb
+Z b87a4baf4ad23e926496089f67763fa0
index 0e108c626c1f3a33dedb319bff924e7140147afb..a14f0a8bb5f4440731f0cf1a9a82a65249589a7e 100644 (file)
@@ -1 +1 @@
-e2f822ac82d0a5a59de0b63cce65d4fd6c178ff1
\ No newline at end of file
+103f8ccb9013689a480766ebffbf570d4aa8bac5
\ No newline at end of file
index 1883a4dfb47169ac2452f5d1d68f3f7ec07e8554..cb6b1194b3acd173baff82c9641ce65cefe45ae8 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.396 2005/07/21 18:23:20 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.397 2005/07/22 00:31:40 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -960,7 +960,8 @@ struct WhereLevel {
   int cont;             /* Jump here to continue with the next loop cycle */
   int top;              /* First instruction of interior of the loop */
   int op, p1, p2;       /* Opcode used to terminate the loop */
-  int inOp, inP1, inP2; /* Opcode used to implement an IN operator */
+  int nIn;              /* Number of IN operators constraining this loop */
+  int *aInLoop;         /* Loop terminators for IN operators */
 };
 
 /*
index 7b1e5a7d3fbdbf87a05b6634b06c1cbccc666620..5082cdd24a5720fd2e1ef88efad2840b6e684cb4 100644 (file)
@@ -16,7 +16,7 @@
 ** so is applicable.  Because this module is responsible for selecting
 ** indices, you might also think of this module as the "query optimizer".
 **
-** $Id: where.c,v 1.150 2005/07/21 18:23:20 drh Exp $
+** $Id: where.c,v 1.151 2005/07/22 00:31:40 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -97,6 +97,35 @@ struct WhereClause {
   WhereTerm aStatic[10];   /* Initial static space for the terms */
 };
 
+/*
+** When WhereTerms are used to select elements from an index, we
+** call those terms "constraints".  For example, consider the following
+** SQL:
+**
+**       CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d);
+**       CREATE INDEX t1i1 ON t1(b,c);
+**
+**       SELECT * FROM t1 WHERE d=5 AND b=7 AND c>11;
+**
+** In the SELECT statement, the "b=7" and "c>11" terms are constraints
+** because they can be used to choose rows out of the t1i1 index.  But
+** the "d=5" term is not a constraint because it is not indexed.
+**
+** When generating code to access an index, we have to keep track of
+** all of the constraints associated with that index.  This is done
+** using an array of instanaces of the following structure.  There is
+** one instance of this structure for each constraint on the index.
+**
+** Actually, we allocate the array of this structure based on the total
+** number of terms in the entire WHERE clause (because the number of
+** constraints can never be more than that) and reuse it when coding
+** each index.
+*/
+typedef struct WhereConstraint WhereConstraint;
+struct WhereConstraint {
+  int iMem;            /* Mem cell used to hold <expr> part of constraint */
+};
+
 /*
 ** An instance of the following structure keeps track of a mapping
 ** between VDBE cursor numbers and bits of the bitmasks in WhereTerm.
@@ -242,11 +271,6 @@ static void createMask(ExprMaskSet *pMaskSet, int iCursor){
   pMaskSet->ix[pMaskSet->n++] = iCursor;
 }
 
-/*
-** Destroy an expression mask set
-*/
-#define freeMaskSet(P)   /* NO-OP */
-
 /*
 ** This routine walks (recursively) an expression tree and generates
 ** a bitmask indicating which tables are used in that expression
@@ -576,16 +600,18 @@ static int sortableByRowid(
 /*
 ** Value for flags returned by bestIndex()
 */
-#define WHERE_ROWID_EQ       0x001    /* rowid=EXPR or rowid IN (...) */
-#define WHERE_ROWID_RANGE    0x002    /* rowid<EXPR and/or rowid>EXPR */
-#define WHERE_COLUMN_EQ      0x004    /* x=EXPR or x IN (...) */
-#define WHERE_COLUMN_RANGE   0x008    /* x<EXPR and/or x>EXPR */
-#define WHERE_SCAN           0x010    /* Do a full table scan */
-#define WHERE_REVERSE        0x020    /* Scan in reverse order */
-#define WHERE_ORDERBY        0x040    /* Output will appear in correct order */
-#define WHERE_IDX_ONLY       0x080    /* Use index only - omit table */
-#define WHERE_TOP_LIMIT      0x100    /* x<EXPR or x<=EXPR constraint */
-#define WHERE_BTM_LIMIT      0x200    /* x>EXPR or x>=EXPR constraint */
+#define WHERE_ROWID_EQ       0x0001   /* rowid=EXPR or rowid IN (...) */
+#define WHERE_ROWID_RANGE    0x0002   /* rowid<EXPR and/or rowid>EXPR */
+#define WHERE_COLUMN_EQ      0x0004   /* x=EXPR or x IN (...) */
+#define WHERE_COLUMN_RANGE   0x0008   /* x<EXPR and/or x>EXPR */
+#define WHERE_SCAN           0x0010   /* Do a full table scan */
+#define WHERE_REVERSE        0x0020   /* Scan in reverse order */
+#define WHERE_ORDERBY        0x0040   /* Output will appear in correct order */
+#define WHERE_IDX_ONLY       0x0080   /* Use index only - omit table */
+#define WHERE_TOP_LIMIT      0x0100   /* x<EXPR or x<=EXPR constraint */
+#define WHERE_BTM_LIMIT      0x0200   /* x>EXPR or x>=EXPR constraint */
+#define WHERE_USES_IN        0x0400   /* True if the IN operator is used */
+#define WHERE_UNIQUE         0x0800   /* True if fully specifies a unique idx */
 
 /*
 ** Find the best index for accessing a particular table.  Return the index,
@@ -619,7 +645,7 @@ static double bestIndex(
       if( pOrderBy ) *pFlags |= WHERE_ORDERBY;
       return 1.0e10;
     }else{
-      *pFlags = WHERE_ROWID_EQ;
+      *pFlags = WHERE_ROWID_EQ | WHERE_USES_IN;
       return 1.0e9;
     }
   }
@@ -675,12 +701,22 @@ static double bestIndex(
 
     /* The optimization type is RANGE if there are no == or IN constraints
     */
-    if( usesIN || nEq ){
+    if( usesIN ){
+      flags = WHERE_COLUMN_EQ | WHERE_USES_IN;
+    }else if( nEq ){
       flags = WHERE_COLUMN_EQ;
     }else{
       flags = WHERE_COLUMN_RANGE;
     }
 
+    /* Check for a uniquely specified row
+    */
+#if 0
+    if( nEq==pProbe->nColumn && pProbe->isUnique ){
+      flags |= WHERE_UNIQUE;
+    }
+#endif
+
     /* Look for range constraints
     */
     if( !usesIN && nEq<pProbe->nColumn ){
@@ -819,7 +855,7 @@ static void buildIndexProbe(Vdbe *v, int nColumn, int brk, Index *pIdx){
 */
 static void codeEqualityTerm(
   Parse *pParse,      /* The parsing context */
-  WhereTerm *pTerm,    /* The term of the WHERE clause to be coded */
+  WhereTerm *pTerm,   /* The term of the WHERE clause to be coded */
   int brk,            /* Jump here to abandon the loop */
   WhereLevel *pLevel  /* When level of the FROM clause we are working on */
 ){
@@ -830,15 +866,22 @@ static void codeEqualityTerm(
 #ifndef SQLITE_OMIT_SUBQUERY
   }else{
     int iTab;
+    int *aIn;
     Vdbe *v = pParse->pVdbe;
 
     sqlite3CodeSubselect(pParse, pX);
     iTab = pX->iTable;
     sqlite3VdbeAddOp(v, OP_Rewind, iTab, brk);
     VdbeComment((v, "# %.*s", pX->span.n, pX->span.z));
-    pLevel->inP2 = sqlite3VdbeAddOp(v, OP_Column, iTab, 0);
-    pLevel->inOp = OP_Next;
-    pLevel->inP1 = iTab;
+    pLevel->nIn++;
+    pLevel->aInLoop = aIn = sqliteRealloc(pLevel->aInLoop,
+                                 sizeof(pLevel->aInLoop[0])*3*pLevel->nIn);
+    if( aIn ){
+      aIn += pLevel->nIn*3 - 3;
+      aIn[0] = OP_Next;
+      aIn[1] = iTab;
+      aIn[2] = sqlite3VdbeAddOp(v, OP_Column, iTab, 0);
+    }
 #endif
   }
   disableTerm(pLevel, pTerm);
@@ -961,6 +1004,7 @@ WhereInfo *sqlite3WhereBegin(
   struct SrcList_item *pTabItem;  /* A single entry from pTabList */
   WhereLevel *pLevel;             /* A single level in the pWInfo list */
   int iFrom;                      /* First unused FROM clause element */
+  WhereConstraint *aConstraint;   /* Information on constraints */
 
   /* The number of tables in the FROM clause is limited by the number of
   ** bits in a Bitmask 
@@ -982,9 +1026,7 @@ WhereInfo *sqlite3WhereBegin(
   */
   pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel));
   if( sqlite3_malloc_failed ){
-    sqliteFree(pWInfo); /* Avoid leaking memory when malloc fails */
-    whereClauseClear(&wc);
-    return 0;
+    goto whereBeginNoMem;
   }
   pWInfo->pParse = pParse;
   pWInfo->pTabList = pTabList;
@@ -1009,6 +1051,10 @@ WhereInfo *sqlite3WhereBegin(
   for(i=wc.nTerm-1; i>=0; i--){
     exprAnalyze(pTabList, &maskSet, &wc.a[i]);
   }
+  aConstraint = sqliteMalloc( wc.nTerm*sizeof(aConstraint[0]) );
+  if( aConstraint==0 && wc.nTerm>0 ){
+    goto whereBeginNoMem;
+  }
 
   /* Chose the best index to use for each table in the FROM clause.
   **
@@ -1057,6 +1103,8 @@ WhereInfo *sqlite3WhereBegin(
     }
     pLevel->flags = bestFlags;
     pLevel->pIdx = pBest;
+    pLevel->aInLoop = 0;
+    pLevel->nIn = 0;
     if( pBest ){
       pLevel->iIdxCur = pParse->nTab++;
     }else{
@@ -1113,7 +1161,6 @@ WhereInfo *sqlite3WhereBegin(
     iCur = pTabItem->iCursor;
     pIdx = pLevel->pIdx;
     iIdxCur = pLevel->iIdxCur;
-    pLevel->inOp = OP_Noop;
     bRev = (pLevel->flags & WHERE_REVERSE)!=0;
     omitTable = (pLevel->flags & WHERE_IDX_ONLY)!=0;
 
@@ -1511,9 +1558,15 @@ WhereInfo *sqlite3WhereBegin(
   ** clean up and return.
   */
   pWInfo->iContinue = cont;
-  freeMaskSet(&maskSet);
   whereClauseClear(&wc);
+  sqliteFree(aConstraint);
   return pWInfo;
+
+  /* Jump here if malloc fails */
+whereBeginNoMem:
+  whereClauseClear(&wc);
+  sqliteFree(pWInfo);
+  return 0;
 }
 
 /*
@@ -1535,8 +1588,13 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
       sqlite3VdbeAddOp(v, pLevel->op, pLevel->p1, pLevel->p2);
     }
     sqlite3VdbeResolveLabel(v, pLevel->brk);
-    if( pLevel->inOp!=OP_Noop ){
-      sqlite3VdbeAddOp(v, pLevel->inOp, pLevel->inP1, pLevel->inP2);
+    if( pLevel->nIn ){
+      int *a;
+      int j;
+      for(j=pLevel->nIn, a=&pLevel->aInLoop[j*3-3]; j>0; j--, a-=3){
+        sqlite3VdbeAddOp(v, a[0], a[1], a[2]);
+      }
+      sqliteFree(pLevel->aInLoop);
     }
     if( pLevel->iLeftJoin ){
       int addr;