]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Reuse the same materialization of a view when that view appears in a query
authordrh <drh@noemail.net>
Tue, 2 May 2017 17:54:19 +0000 (17:54 +0000)
committerdrh <drh@noemail.net>
Tue, 2 May 2017 17:54:19 +0000 (17:54 +0000)
more than once, such as in a self-join.

FossilOrigin-Name: 9e35c89dbe744312f612e507b51ff9a5bb656def75392d25bc19fc638548cd1e

1  2 
manifest
manifest.uuid
src/select.c
src/vdbe.c

diff --cc manifest
index 36affcf4252288d936226ef748ecbabe9d897aa1,221fc04ec8126a5a96e40f14aeee01049daa8b1e..1395c271ddc8ea78891d7880ddada72edb1dae85
+++ b/manifest
@@@ -1,5 -1,5 +1,5 @@@
- C Move\sterms\sof\sthe\sHAVING\sclause\sthat\sreference\sonly\scolumns\sin\sthe\sGROUP\sBY\nclause\sover\sto\sthe\sWHERE\sclause,\sresulting\sin\sa\sfaster\squery\splan.
- D 2017-05-02T16:55:07.827
 -C Futher\sbug\sfixes\sto\sthe\sfunction\sthat\sdetermines\swhen\sa\smaterialized\sview\ncan\sbe\sreused.
 -D 2017-05-01T17:04:35.162
++C Reuse\sthe\ssame\smaterialization\sof\sa\sview\swhen\sthat\sview\sappears\sin\sa\squery\nmore\sthan\sonce,\ssuch\sas\sin\sa\sself-join.
++D 2017-05-02T17:54:19.760
  F Makefile.in 1cc758ce3374a32425e4d130c2fe7b026b20de5b8843243de75f087c0a2661fb
  F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
  F Makefile.msc 6a8c838220f7c00820e1fc0ac1bccaaa8e5676067e1dbfa1bafa7a4ffecf8ae6
@@@ -402,12 -402,12 +402,12 @@@ F src/printf.c 8757834f1b54dae512fb25eb
  F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
  F src/resolve.c 3e518b962d932a997fae373366880fc028c75706
  F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
- F src/select.c 4bbdacd119f22b3b7712b1c1f54bb52fdc7d97d24e131440cc5f235b9df42b0c
 -F src/select.c 2546672c84240e9b9870d93fdccd7f2de98392fd6836d9bf6611aa60a5ace85f
++F src/select.c 4f0adefaa5e9417459b07757e0f6060cac97930a86f0fba9797bab233ced66c0
  F src/shell.c 21b79c0e1b93f8e35fd7b4087d6ba438326c3d7e285d0dd51dfd741475f858a1
 -F src/sqlite.h.in 40233103e3e4e10f8a63523498d0259d232e42aba478e2d3fb914799185aced6
 +F src/sqlite.h.in eeb1da70a61d52e1d58e5b55446b85bbac571699421d3cf857421c56214013ce
  F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
  F src/sqlite3ext.h 58fd0676d3111d02e62e5a35992a7d3da5d3f88753acc174f2d37b774fbbdd28
 -F src/sqliteInt.h 9affb53bb405dcea1d86e85198ebaf6232a684cc2b2af6b3c181869f1c8f3e93
 +F src/sqliteInt.h aea3aa1b81e0d07d5b1c39b8c5a54a1dc5e4f10136cb63da392aef9eb2a5108b
  F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
  F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
  F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@@@ -469,7 -469,7 +469,7 @@@ F src/update.c c443935c652af9365e033f75
  F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
  F src/util.c ca8440ede81e155d15cff7c101654f60b55a9ae6
  F src/vacuum.c 1fe4555cd8c9b263afb85b5b4ee3a4a4181ad569
- F src/vdbe.c 349eb6789cf8b03ef1aa42271aa9a17a6a7794c07448d27c5405904ba1b21715
 -F src/vdbe.c 7c37c36f3d528b10e5a5df76267ca42ed604fb3f15ff1d656afe1f33ff5d1f76
++F src/vdbe.c 9bac2bc2313ed682e6f48ccff6644d3263341885bfcbb3cdea7b720c722be2d5
  F src/vdbe.h f7d1456e28875c2dcb964056589b5b7149ab7edf39edeca801596a39bb3d3848
  F src/vdbeInt.h c070bc5c8b913bda0ceaa995cd4d939ded5e4fc96cf7c3c1c602d41b871f8ade
  F src/vdbeapi.c 5b08d82592bcff4470601fe78aaabebd50837860
@@@ -1578,8 -1577,7 +1578,8 @@@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a9
  F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
  F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
  F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
- P 6674814afb9e763e7f7060776586e26da28040b3208ce06c8a285dd647e5a53d 8424492eac506866d2918e5fe03c8f65fef960215d56012a3b52ed42789ed35a
- R 645ee5368137c061c8ff554b7c3cb973
- T +closed 8424492eac506866d2918e5fe03c8f65fef960215d56012a3b52ed42789ed35a
 -P b2aae559581d05e4e8caaddfbd137cb275d582e82d58872c6f42e462dc859b1c
 -R fb2a58136338dea6025ffd0d391dd6d5
++P 47cbb471d056c8e1834a5ca72491404a3bfb273b5ff7bdd84b98d263938ea874 c64fe3a1695925693385d313e9ad2a1d8cb37ddaa8cc19920ae0978c91bc4c2c
++R 250cb39f933147d7683c248b1fcd12aa
++T +closed c64fe3a1695925693385d313e9ad2a1d8cb37ddaa8cc19920ae0978c91bc4c2c
  U drh
- Z f125bc7c2e400862ed032d286e9e90a2
 -Z 522d6c582c8e206ece3fcf0a3e5fff13
++Z d1eca8aa444c2ea7562fa3a6e3e0ab31
diff --cc manifest.uuid
index 46b6c41181403c766eef84d5f19d92ea5cddcccc,ac2289d07e1033ae2e794f63d1bcb35b9f5ff1f0..d9ed7e802104a9fa430e54a2f901714f7de03132
@@@ -1,1 -1,1 +1,1 @@@
- 47cbb471d056c8e1834a5ca72491404a3bfb273b5ff7bdd84b98d263938ea874
 -c64fe3a1695925693385d313e9ad2a1d8cb37ddaa8cc19920ae0978c91bc4c2c
++9e35c89dbe744312f612e507b51ff9a5bb656def75392d25bc19fc638548cd1e
diff --cc src/select.c
index 9227be890e8f32eedf783940779b6f351825f025,e7a448343f5be6050cae659e7622d10cb7094c1e..573a6fa11e412c036ea6e088fde28f022868777c
@@@ -4879,77 -4879,32 +4879,103 @@@ static void explainSimpleCount
  # define explainSimpleCount(a,b,c)
  #endif
  
 +/*
 +** Context object for havingToWhereExprCb().
 +*/
 +struct HavingToWhereCtx {
 +  Expr **ppWhere;
 +  ExprList *pGroupBy;
 +};
 +
 +/*
 +** sqlite3WalkExpr() callback used by havingToWhere().
 +**
 +** If the node passed to the callback is a TK_AND node, return 
 +** WRC_Continue to tell sqlite3WalkExpr() to iterate through child nodes.
 +**
 +** Otherwise, return WRC_Prune. In this case, also check if the 
 +** sub-expression matches the criteria for being moved to the WHERE
 +** clause. If so, add it to the WHERE clause and replace the sub-expression
 +** within the HAVING expression with a constant "1".
 +*/
 +static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){
 +  if( pExpr->op!=TK_AND ){
 +    struct HavingToWhereCtx *p = pWalker->u.pHavingCtx;
 +    if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, p->pGroupBy) ){
 +      sqlite3 *db = pWalker->pParse->db;
 +      Expr *pNew = sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[1], 0);
 +      if( pNew ){
 +        Expr *pWhere = *(p->ppWhere);
 +        SWAP(Expr, *pNew, *pExpr);
 +        pNew = sqlite3ExprAnd(db, pWhere, pNew);
 +        *(p->ppWhere) = pNew;
 +      }
 +    }
 +    return WRC_Prune;
 +  }
 +  return WRC_Continue;
 +}
 +
 +/*
 +** Transfer eligible terms from the HAVING clause of a query, which is
 +** processed after grouping, to the WHERE clause, which is processed before
 +** grouping. For example, the query:
 +**
 +**   SELECT * FROM <tables> WHERE a=? GROUP BY b HAVING b=? AND c=?
 +**
 +** can be rewritten as:
 +**
 +**   SELECT * FROM <tables> WHERE a=? AND b=? GROUP BY b HAVING c=?
 +**
 +** A term of the HAVING expression is eligible for transfer if it consists
 +** entirely of constants and expressions that are also GROUP BY terms that
 +** use the "BINARY" collation sequence.
 +*/
 +static void havingToWhere(
 +  Parse *pParse,
 +  ExprList *pGroupBy,
 +  Expr *pHaving, 
 +  Expr **ppWhere
 +){
 +  struct HavingToWhereCtx sCtx;
 +  Walker sWalker;
 +
 +  sCtx.ppWhere = ppWhere;
 +  sCtx.pGroupBy = pGroupBy;
 +
 +  memset(&sWalker, 0, sizeof(sWalker));
 +  sWalker.pParse = pParse;
 +  sWalker.xExprCallback = havingToWhereExprCb;
 +  sWalker.u.pHavingCtx = &sCtx;
 +  sqlite3WalkExpr(&sWalker, pHaving);
 +}
 +
+ /*
+ ** Check to see if the pThis entry of pTabList is a self-join of a prior view.
+ ** If it is, then return the SrcList_item for the prior view.  If it is not,
+ ** then return 0.
+ */
+ static struct SrcList_item *isSelfJoinView(
+   SrcList *pTabList,           /* Search for self-joins in this FROM clause */
+   struct SrcList_item *pThis   /* Search for prior reference to this subquery */
+ ){
+   struct SrcList_item *pItem;
+   for(pItem = pTabList->a; pItem<pThis; pItem++){
+     if( pItem->pSelect==0 ) continue;
+     if( pItem->fg.viaCoroutine ) continue;
+     if( pItem->zName==0 ) continue;
+     if( sqlite3_stricmp(pItem->zDatabase, pThis->zDatabase)!=0 ) continue;
+     if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue;
+     if( sqlite3ExprCompare(pThis->pSelect->pWhere, pItem->pSelect->pWhere, -1) ){
+       /* The view was modified by some other optimization such as
+       ** pushDownWhereTerms() */
+       continue;
+     }
+     return pItem;
+   }
+   return 0;
+ }
  /*
  ** Generate code for the SELECT statement given in the p argument.  
  **
diff --cc src/vdbe.c
index 15f015a598402214759f0ffaf01a42b2f5939d9b,ebf80c8beb3afef07a832234a42bb9b1862df986..e6c964245faf53260165b7ceb956fc2b18b5450e
@@@ -3540,6 -3540,34 +3540,37 @@@ open_cursor_set_hints
    break;
  }
  
 -  if( rc ) goto abort_due_to_error;
+ /* Opcode: OpenDup P1 P2 * * *
+ **
+ ** Open a new cursor P1 that points to the same ephemeral table as
+ ** cursor P2.  The P2 cursor must have been opened by a prior OP_OpenEphemeral
+ ** opcode.  Only ephemeral cursors may be duplicated.
+ **
+ ** Duplicate ephemeral cursors are used for self-joins of materialized views.
+ */
+ case OP_OpenDup: {
+   VdbeCursor *pOrig;    /* The original cursor to be duplicated */
+   VdbeCursor *pCx;      /* The new cursor */
+   pOrig = p->apCsr[pOp->p2];
+   assert( pOrig->pBtx!=0 );  /* Only ephemeral cursors can be duplicated */
+   pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE);
+   if( pCx==0 ) goto no_mem;
+   pCx->nullRow = 1;
+   pCx->isEphemeral = 1;
+   pCx->pKeyInfo = pOrig->pKeyInfo;
+   pCx->isTable = pOrig->isTable;
+   rc = sqlite3BtreeCursor(pOrig->pBtx, MASTER_ROOT, BTREE_WRCSR,
+                           pCx->pKeyInfo, pCx->uc.pCursor);
++  /* The sqlite3BtreeCursor() routine can only fail for the first cursor
++  ** opened for a database.  Since there is already an open cursor when this
++  ** opcode is run, the sqlite3BtreeCursor() cannot fail */
++  assert( rc==SQLITE_OK );
+   break;
+ }
  /* Opcode: OpenEphemeral P1 P2 * P4 P5
  ** Synopsis: nColumn=P2
  **