]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix the virtual table IN optimizer so that it work even if the virtual table
authordrh <drh@noemail.net>
Fri, 14 Dec 2012 15:36:17 +0000 (15:36 +0000)
committerdrh <drh@noemail.net>
Fri, 14 Dec 2012 15:36:17 +0000 (15:36 +0000)
implementation leaves the sqlite3_index_info.aConstraintUsage[].omit flag
clear for an equality constraint that it intends to use.

FossilOrigin-Name: d6e045f89c5a4b500b1da7ea1224b132909bafc6

manifest
manifest.uuid
src/where.c

index f9f1a4b2c98ee15f5e8446f7ace2a448db9c3fe2..054bc8cc9ae052c389be15a52d3e117adc096f7b 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Enable\soptimization\sof\sIN\soperators\son\sconstraints\sto\svirtual\stables.
-D 2012-10-16T23:17:14.207
+C Fix\sthe\svirtual\stable\sIN\soptimizer\sso\sthat\sit\swork\seven\sif\sthe\svirtual\stable\nimplementation\sleaves\sthe\ssqlite3_index_info.aConstraintUsage[].omit\sflag\nclear\sfor\san\sequality\sconstraint\sthat\sit\sintends\sto\suse.
+D 2012-12-14T15:36:17.947
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 5f4f26109f9d80829122e0e09f9cda008fa065fb
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -249,7 +249,7 @@ F src/vtab.c 9c64ae18af78c740610df841c6f49fc2d240a279
 F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2
 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6
 F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b
-F src/where.c 62f667db8cdbb81028bf1c55ba4b0e845b79622c
+F src/where.c 87c95ca9005909af852a3a1b62451a43cf76fb6a
 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/aggnested.test 0be144b453e0622a085fae8665c32f5676708e00
@@ -1021,10 +1021,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
 F tool/win/sqlite.vsix 67d8a99aceb56384a81b3f30d6c71743146d2cc9
-P 2c3af657fee6153842d660a6ce29aa7d791ebd38
-R 5cbef12c646a3899761eba454f8c4105
-T *branch * vtab-IN-opt
-T *sym-vtab-IN-opt *
-T -sym-trunk *
+P aa650746b19e4a6a373f7e47effff3ab2f48e78c
+R 53d6793b7f79df12237947dc6769b11d
 U drh
-Z 07568d163c180c755b6278e856d28eda
+Z b558501f7c6a3f6651858b319af65966
index 1c366b32f048f3e55ad3d548ba695d6cdc717230..22bae2629b2d0602d5e582cd2d8b67696ac3c037 100644 (file)
@@ -1 +1 @@
-aa650746b19e4a6a373f7e47effff3ab2f48e78c
\ No newline at end of file
+d6e045f89c5a4b500b1da7ea1224b132909bafc6
\ No newline at end of file
index 586d069b3f75acd4973fecd2c87a84bec5656f99..b07709581d8fb1abae2c41a8465bd1bdf8d63d7b 100644 (file)
@@ -2193,6 +2193,7 @@ static void bestVirtualIndex(WhereBestIdx *p){
   WhereTerm *pTerm;
   int i, j;
   int nOrderBy;
+  int bAllowIN;                   /* Allow IN optimizations */
   double rCost;
 
   /* Make sure wsFlags is initialized to some sane value. Otherwise, if the 
@@ -2227,59 +2228,83 @@ static void bestVirtualIndex(WhereBestIdx *p){
   assert( pTab->azModuleArg && pTab->azModuleArg[0] );
   assert( sqlite3GetVTable(pParse->db, pTab) );
 
-  /* Set the aConstraint[].usable fields and initialize all 
-  ** output variables to zero.
-  **
-  ** aConstraint[].usable is true for constraints where the right-hand
-  ** side contains only references to tables to the left of the current
-  ** table.  In other words, if the constraint is of the form:
-  **
-  **           column = expr
-  **
-  ** and we are evaluating a join, then the constraint on column is 
-  ** only valid if all tables referenced in expr occur to the left
-  ** of the table containing column.
-  **
-  ** The aConstraints[] array contains entries for all constraints
-  ** on the current table.  That way we only have to compute it once
-  ** even though we might try to pick the best index multiple times.
-  ** For each attempt at picking an index, the order of tables in the
-  ** join might be different so we have to recompute the usable flag
-  ** each time.
+  /* Try once or twice.  On the first attempt, allow IN optimizations.
+  ** If an IN optimization is accepted, but does not set the
+  ** pInfo->aConstrainUsage.omit flag, then it will not work (because it
+  ** will allow duplicate rows in the result set) so try again with
+  ** IN optimizations disabled.
   */
-  pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
-  pUsage = pIdxInfo->aConstraintUsage;
-  for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
-    j = pIdxCons->iTermOffset;
-    pTerm = &pWC->a[j];
-    pIdxCons->usable = (pTerm->prereqRight&p->notReady) ? 0 : 1;
-  }
-  memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint);
-  if( pIdxInfo->needToFreeIdxStr ){
-    sqlite3_free(pIdxInfo->idxStr);
-  }
-  pIdxInfo->idxStr = 0;
-  pIdxInfo->idxNum = 0;
-  pIdxInfo->needToFreeIdxStr = 0;
-  pIdxInfo->orderByConsumed = 0;
-  /* ((double)2) In case of SQLITE_OMIT_FLOATING_POINT... */
-  pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((double)2);
-  nOrderBy = pIdxInfo->nOrderBy;
-  if( !p->pOrderBy ){
-    pIdxInfo->nOrderBy = 0;
-  }
-
-  if( vtabBestIndex(pParse, pTab, pIdxInfo) ){
-    return;
-  }
-
-  pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
-  for(i=0; i<pIdxInfo->nConstraint; i++){
-    if( pUsage[i].argvIndex>0 ){
-      p->cost.used |= pWC->a[pIdxCons[i].iTermOffset].prereqRight;
+  for(bAllowIN=1; bAllowIN>=0; bAllowIN--){
+    /* Set the aConstraint[].usable fields and initialize all 
+    ** output variables to zero.
+    **
+    ** aConstraint[].usable is true for constraints where the right-hand
+    ** side contains only references to tables to the left of the current
+    ** table.  In other words, if the constraint is of the form:
+    **
+    **           column = expr
+    **
+    ** and we are evaluating a join, then the constraint on column is 
+    ** only valid if all tables referenced in expr occur to the left
+    ** of the table containing column.
+    **
+    ** The aConstraints[] array contains entries for all constraints
+    ** on the current table.  That way we only have to compute it once
+    ** even though we might try to pick the best index multiple times.
+    ** For each attempt at picking an index, the order of tables in the
+    ** join might be different so we have to recompute the usable flag
+    ** each time.
+    */
+    pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
+    pUsage = pIdxInfo->aConstraintUsage;
+    for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
+      j = pIdxCons->iTermOffset;
+      pTerm = &pWC->a[j];
+      if( (pTerm->prereqRight&p->notReady)==0
+       && (bAllowIN || pTerm->eOperator!=WO_IN)
+      ){
+        pIdxCons->usable = 1;
+      }else{
+        pIdxCons->usable = 0;
+      }
+    }
+    memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint);
+    if( pIdxInfo->needToFreeIdxStr ){
+      sqlite3_free(pIdxInfo->idxStr);
+    }
+    pIdxInfo->idxStr = 0;
+    pIdxInfo->idxNum = 0;
+    pIdxInfo->needToFreeIdxStr = 0;
+    pIdxInfo->orderByConsumed = 0;
+    /* ((double)2) In case of SQLITE_OMIT_FLOATING_POINT... */
+    pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((double)2);
+    nOrderBy = pIdxInfo->nOrderBy;
+    if( !p->pOrderBy ){
+      pIdxInfo->nOrderBy = 0;
+    }
+  
+    if( vtabBestIndex(pParse, pTab, pIdxInfo) ){
+      return;
+    }
+  
+    pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
+    for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
+      if( pUsage[i].argvIndex>0 ){
+        j = pIdxCons->iTermOffset;
+        pTerm = &pWC->a[j];
+        p->cost.used |= pTerm->prereqRight;
+        if( pTerm->eOperator==WO_IN && pUsage[i].omit==0 ){
+          /* Do not attempt to use an IN constraint if the virtual table
+          ** says that the equivalent EQ constraint cannot be safely omitted.
+          ** If we do attempt to use such a constraint, some rows might be
+          ** repeated in the output. */
+          break;
+        }
+      }
     }
+    if( i>=pIdxInfo->nConstraint ) break;
   }
-
+  
   /* If there is an ORDER BY clause, and the selected virtual table index
   ** does not satisfy it, increase the cost of the scan accordingly. This
   ** matches the processing for non-virtual tables in bestBtreeIndex().