]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Split FROM-clause subquery flattening and code generation into separate loops.
authordrh <drh@noemail.net>
Fri, 5 Jun 2015 22:33:39 +0000 (22:33 +0000)
committerdrh <drh@noemail.net>
Fri, 5 Jun 2015 22:33:39 +0000 (22:33 +0000)
FossilOrigin-Name: be8e3fc70e4c13b28b07985df3457960f58ffddd

manifest
manifest.uuid
src/expr.c
src/select.c

index 4d3f877745ed05beb9637c9d8b0667e72116150d..d868635d2ee3f812d220fd49defb627243550021 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Provide\sone\sfinal\sSelect\stree\sdump\sprior\sto\sWHERE\sclause\sanalysis\s\nwhen\s".selecttrace\s0x400"\stracing\sbit\sis\sset\swith\sSELECTTRACE_ENABLED.\nAnalysis\sand\sdebug\schanges\sonly\s-\snormal\sbuilds\sare\sunaffected.
-D 2015-06-05T20:27:26.103
+C Split\sFROM-clause\ssubquery\sflattening\sand\scode\sgeneration\sinto\sseparate\sloops.
+D 2015-06-05T22:33:39.408
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 994bab32a3a69e0c35bd148b65cde49879772964
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -202,7 +202,7 @@ F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b
 F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac
 F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a
 F src/delete.c 37964e6c1d73ff49cbea9ff690c9605fb15f600e
-F src/expr.c d953b9f03c3c0f701f87a418fcfb9cba8befc6e0
+F src/expr.c 12e04f322956076b1f8748ca572568968f8155d9
 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
 F src/fkey.c c9b63a217d86582c22121699a47f22f524608869
 F src/func.c 5b8b8e77a0fb644eaf8947d413804622e32692b6
@@ -250,7 +250,7 @@ F src/printf.c 13ce37e5574f9b0682fa86dbcf9faf76b9d82a15
 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
 F src/resolve.c 84c571794e3ee5806274d95158a4c0177c6c4708
 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
-F src/select.c b2dfbc9ca9e4d04a34c1b4defdfda7867fee0eb8
+F src/select.c 6a8f2c442dc69ff343411788e5146b45ddb87609
 F src/shell.c 07dda7cd692911d2f22269953418d049f2e2c0ee
 F src/sqlite.h.in d165beeceb6b40af60f352a4d4e37e02d9af7df0
 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
@@ -1282,7 +1282,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 6a9cf063379118dbb95c6cdc6d60af50e9867177
-R 7720d4f64678b0c7b4af503d2d9c054f
+P 283bf0b64da7acc5aa5812fc659954965002d409
+R 7215f59414fcbc308f2938a5f5f79857
+T *branch * view-optimization
+T *sym-view-optimization *
+T -sym-trunk *
 U drh
-Z 95e994f89cb6168fd34736cd7cbf5b60
+Z b4c3a234d5928895ab25f2763d32a4ad
index c711a8d149ddf0b2c5b77dc1af22047b4fb541f6..39d85502572790814c2aebe1b8243375b136fe96 100644 (file)
@@ -1 +1 @@
-283bf0b64da7acc5aa5812fc659954965002d409
\ No newline at end of file
+be8e3fc70e4c13b28b07985df3457960f58ffddd
\ No newline at end of file
index 56a62e0c3f87f063a221d89eaf2f2b6061d46b39..d62346e39d46168ef6413de763f457cbde929732 100644 (file)
@@ -3559,14 +3559,6 @@ void sqlite3TreeViewExprList(
     sqlite3TreeViewLine(pView, "%s", zLabel);
     for(i=0; i<pList->nExpr; i++){
       sqlite3TreeViewExpr(pView, pList->a[i].pExpr, i<pList->nExpr-1);
-#if 0
-     if( pList->a[i].zName ){
-        sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName);
-      }
-      if( pList->a[i].bSpanIsTab ){
-        sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan);
-      }
-#endif
     }
   }
   sqlite3TreeViewPop(pView);
index a3e92655b1eccb979126551ed653f246c60daee0..2341e84509db5c419b9be9e964d5821c1b290003 100644 (file)
@@ -4842,14 +4842,54 @@ int sqlite3Select(
   }
 #endif
 
-  /* Generate code for all sub-queries in the FROM clause
+  /* Try to flatten subqueries in the FROM clause into the main query
   */
 #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
   for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
     struct SrcList_item *pItem = &pTabList->a[i];
-    SelectDest dest;
     Select *pSub = pItem->pSelect;
     int isAggSub;
+    if( pSub==0 ) continue;
+    isAggSub = (pSub->selFlags & SF_Aggregate)!=0;
+    if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){
+      /* This subquery can be absorbed into its parent. */
+      if( isAggSub ){
+        isAgg = 1;
+        p->selFlags |= SF_Aggregate;
+      }
+      i = -1;
+    }
+    pTabList = p->pSrc;
+    if( db->mallocFailed ) goto select_end;
+    if( !IgnorableOrderby(pDest) ){
+      sSort.pOrderBy = p->pOrderBy;
+    }
+  }
+#endif
+
+
+#ifndef SQLITE_OMIT_COMPOUND_SELECT
+  /* Handle compound SELECT statements using the separate multiSelect()
+  ** procedure.
+  */
+  if( p->pPrior ){
+    rc = multiSelect(pParse, p, pDest);
+    explainSetInteger(pParse->iSelectId, iRestoreSelectId);
+#if SELECTTRACE_ENABLED
+    SELECTTRACE(1,pParse,p,("end compound-select processing\n"));
+    pParse->nSelectIndent--;
+#endif
+    return rc;
+  }
+#endif
+
+  /* Generate code for all sub-queries in the FROM clause
+  */
+#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
+  for(i=0; i<pTabList->nSrc; i++){
+    struct SrcList_item *pItem = &pTabList->a[i];
+    SelectDest dest;
+    Select *pSub = pItem->pSelect;
 
     if( pSub==0 ) continue;
 
@@ -4875,87 +4915,73 @@ int sqlite3Select(
     */
     pParse->nHeight += sqlite3SelectExprHeight(p);
 
-    isAggSub = (pSub->selFlags & SF_Aggregate)!=0;
-    if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){
-      /* This subquery can be absorbed into its parent. */
-      if( isAggSub ){
-        isAgg = 1;
-        p->selFlags |= SF_Aggregate;
-      }
-      i = -1;
-    }else{
-      if( (pItem->jointype & JT_OUTER)==0
-       && pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor)
-      ){
+    if( (pItem->jointype & JT_OUTER)==0
+     && pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor)
+    ){
 #if SELECTTRACE_ENABLED
-        if( sqlite3SelectTrace & 0x100 ){
-          SELECTTRACE(0x100,pParse,p,("After WHERE-clause push-down:\n"));
-          sqlite3TreeViewSelect(0, p, 0);
-        }
-#endif
+      if( sqlite3SelectTrace & 0x100 ){
+        SELECTTRACE(0x100,pParse,p,("After WHERE-clause push-down:\n"));
+        sqlite3TreeViewSelect(0, p, 0);
       }
-      if( pTabList->nSrc==1
-       && (p->selFlags & SF_All)==0
-       && OptimizationEnabled(db, SQLITE_SubqCoroutine)
-      ){
-        /* Implement a co-routine that will return a single row of the result
-        ** set on each invocation.
-        */
-        int addrTop = sqlite3VdbeCurrentAddr(v)+1;
-        pItem->regReturn = ++pParse->nMem;
-        sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
-        VdbeComment((v, "%s", pItem->pTab->zName));
-        pItem->addrFillSub = addrTop;
-        sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
-        explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
-        sqlite3Select(pParse, pSub, &dest);
-        pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
-        pItem->viaCoroutine = 1;
-        pItem->regResult = dest.iSdst;
-        sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
-        sqlite3VdbeJumpHere(v, addrTop-1);
-        sqlite3ClearTempRegCache(pParse);
+#endif
+    }
+    if( pTabList->nSrc==1
+     && (p->selFlags & SF_All)==0
+     && OptimizationEnabled(db, SQLITE_SubqCoroutine)
+    ){
+      /* Implement a co-routine that will return a single row of the result
+      ** set on each invocation.
+      */
+      int addrTop = sqlite3VdbeCurrentAddr(v)+1;
+      pItem->regReturn = ++pParse->nMem;
+      sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
+      VdbeComment((v, "%s", pItem->pTab->zName));
+      pItem->addrFillSub = addrTop;
+      sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
+      explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
+      sqlite3Select(pParse, pSub, &dest);
+      pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
+      pItem->viaCoroutine = 1;
+      pItem->regResult = dest.iSdst;
+      sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
+      sqlite3VdbeJumpHere(v, addrTop-1);
+      sqlite3ClearTempRegCache(pParse);
+    }else{
+      /* Generate a subroutine that will fill an ephemeral table with
+      ** the content of this subquery.  pItem->addrFillSub will point
+      ** to the address of the generated subroutine.  pItem->regReturn
+      ** is a register allocated to hold the subroutine return address
+      */
+      int topAddr;
+      int onceAddr = 0;
+      int retAddr;
+      assert( pItem->addrFillSub==0 );
+      pItem->regReturn = ++pParse->nMem;
+      topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
+      pItem->addrFillSub = topAddr+1;
+      if( pItem->isCorrelated==0 ){
+        /* If the subquery is not correlated and if we are not inside of
+        ** a trigger, then we only need to compute the value of the subquery
+        ** once. */
+        onceAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
+        VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName));
       }else{
-        /* Generate a subroutine that will fill an ephemeral table with
-        ** the content of this subquery.  pItem->addrFillSub will point
-        ** to the address of the generated subroutine.  pItem->regReturn
-        ** is a register allocated to hold the subroutine return address
-        */
-        int topAddr;
-        int onceAddr = 0;
-        int retAddr;
-        assert( pItem->addrFillSub==0 );
-        pItem->regReturn = ++pParse->nMem;
-        topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
-        pItem->addrFillSub = topAddr+1;
-        if( pItem->isCorrelated==0 ){
-          /* If the subquery is not correlated and if we are not inside of
-          ** a trigger, then we only need to compute the value of the subquery
-          ** once. */
-          onceAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
-          VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName));
-        }else{
-          VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
-        }
-        sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
-        explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
-        sqlite3Select(pParse, pSub, &dest);
-        pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
-        if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
-        retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
-        VdbeComment((v, "end %s", pItem->pTab->zName));
-        sqlite3VdbeChangeP1(v, topAddr, retAddr);
-        sqlite3ClearTempRegCache(pParse);
+        VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
       }
+      sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
+      explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
+      sqlite3Select(pParse, pSub, &dest);
+      pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
+      if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
+      retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
+      VdbeComment((v, "end %s", pItem->pTab->zName));
+      sqlite3VdbeChangeP1(v, topAddr, retAddr);
+      sqlite3ClearTempRegCache(pParse);
     }
     if( db->mallocFailed ){
       goto select_end;
     }
     pParse->nHeight -= sqlite3SelectExprHeight(p);
-    pTabList = p->pSrc;
-    if( !IgnorableOrderby(pDest) ){
-      sSort.pOrderBy = p->pOrderBy;
-    }
   }
   pEList = p->pEList;
 #endif
@@ -4971,20 +4997,6 @@ int sqlite3Select(
   }
 #endif
 
-#ifndef SQLITE_OMIT_COMPOUND_SELECT
-  /* If there is are a sequence of queries, do the earlier ones first.
-  */
-  if( p->pPrior ){
-    rc = multiSelect(pParse, p, pDest);
-    explainSetInteger(pParse->iSelectId, iRestoreSelectId);
-#if SELECTTRACE_ENABLED
-    SELECTTRACE(1,pParse,p,("end compound-select processing\n"));
-    pParse->nSelectIndent--;
-#endif
-    return rc;
-  }
-#endif
-
   /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and 
   ** if the select-list is the same as the ORDER BY list, then this query
   ** can be rewritten as a GROUP BY. In other words, this: