]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the count-of-view optimization when compiled using
authordrh <drh@noemail.net>
Wed, 5 Jul 2017 14:54:24 +0000 (14:54 +0000)
committerdrh <drh@noemail.net>
Wed, 5 Jul 2017 14:54:24 +0000 (14:54 +0000)
SQLITE_COUNTOFVIEW_OPTIMIZATION.

FossilOrigin-Name: b7ae4b879fc086e9543493843377ae90ceff1fe49c97b4c23367012034c3c9d5

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

index bec6e52361f82377412b12c808036a69f7c360e7..d0b3c3e3d11a3b59a9ba9bc80c7b0fd738b62e2d 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\sSQLITE_DEFAULT_ROWEST\scompile-time\soption\sfor\schanging\sthe\sestimated\nnumber\sof\srows\sin\stables\sthat\slack\ssqlite_stat1\sentries.
-D 2017-06-06T18:22:05.443
+C Add\sthe\scount-of-view\soptimization\swhen\scompiled\susing\s\nSQLITE_COUNTOFVIEW_OPTIMIZATION.
+D 2017-07-05T14:54:24.911
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 00d12636df7a5b08af09116bcd6c7bfd49b8b3b4
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -230,12 +230,12 @@ F src/printf.c 8ae1fa9d30c1200a9268a390ba9e9cea9197b27a
 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
 F src/resolve.c 41aa91af56d960e9414ce1d7c17cfb68e0d1c6cb
 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
-F src/select.c ec96f4cdc5c39b83f54d8e0cf96bf91f2bb6fac0
+F src/select.c 296bf898a2d845ca9b58bf936e42b1122eab3cfab03848da0f684150548ff8a2
 F src/shell.c 84a1593bd86aaa14f4da8a8f9b16fbc239d262aa
 F src/sqlite.h.in 278602140d49575e8708e643161f4263e428a02a
 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
 F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
-F src/sqliteInt.h 81198400a63a72ac2864421a7be78172abe5cecf
+F src/sqliteInt.h 3b055fff776a257d0b2473edec5e121db8724c51c1034452c1be3b0faaf02f45
 F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46
 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179
 F src/table.c e7a09215315a978057fb42c640f890160dbcc45e
@@ -1250,8 +1250,8 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 19dad0a720c41d1d111f42cb2cb1f291c559957e76e3f88dc6cfc065e4845e77
-Q +234ede26e30f20e6c33002739ed8be35dbfb5c77700bd857ff31072b9b7df347
-R 0abd2b13af71300bd2b7a8ab9ad2e7ec
+P 802b82f342328762e3995825aed1b22e61361ef24b673cd5d66b55756ce2a461
+Q +d1ba200234f40b84327c7fc28c2584ed069da80e97578df71114d1a9ba9c559c
+R d1ab17963b33badcbff62fa608fc3eef
 U drh
-Z c7d056a26cdd67a2c8fba47da44b2255
+Z 7c072e36d0f6a6f55c9a69a4c236ee0f
index 5c6ecff1596e4f706d41238b81f09742b5b22aa5..6b7c3241758834d61c523e022b1951b83be0502f 100644 (file)
@@ -1 +1 @@
-802b82f342328762e3995825aed1b22e61361ef24b673cd5d66b55756ce2a461
\ No newline at end of file
+b7ae4b879fc086e9543493843377ae90ceff1fe49c97b4c23367012034c3c9d5
\ No newline at end of file
index 47880645976fe13b760cdeaaf77f532d191a25ca..8d31da3ddc1a73a034e03a57be35017852da9fc5 100644 (file)
@@ -4710,6 +4710,94 @@ static void explainSimpleCount(
 # define explainSimpleCount(a,b,c)
 #endif
 
+#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
+/*
+** Attempt to transform a query of the form
+**
+**    SELECT count(*) FROM (SELECT x FROM t1 UNION ALL SELECT y FROM t2)
+**
+** Into this:
+**
+**    SELECT (SELECT count(*) FROM t1)+(SELECT count(*) FROM t2)
+**
+** The transformation only works if all of the following are true:
+**
+**   *  The subquery is a UNION ALL of two or more terms
+**   *  There is no WHERE or GROUP BY or HAVING clauses on the subqueries
+**   *  The outer query is a simple count(*)
+**
+** Return TRUE if the optimization is undertaken.
+*/
+static int countOfViewOptimization(Parse *pParse, Select *p){
+  Select *pSub, *pPrior;
+  Expr *pExpr;
+  Expr *pCount;
+  sqlite3 *db;
+  if( (p->selFlags & SF_Aggregate)==0 ) return 0;   /* This is an aggregate query */
+  if( p->pEList->nExpr!=1 ) return 0;               /* Single result column */
+  pExpr = p->pEList->a[0].pExpr;
+  if( pExpr->op!=TK_AGG_FUNCTION ) return 0;        /* Result is an aggregate */
+  if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0;  /* Must be count() */
+  if( pExpr->x.pList!=0 ) return 0;                 /* Must be count(*) */
+  if( p->pSrc->nSrc!=1 ) return 0;                  /* One table in the FROM clause */
+  pSub = p->pSrc->a[0].pSelect;
+  if( pSub==0 ) return 0;                           /* The FROM is a subquery */
+  if( pSub->pPrior==0 ) return 0;                   /* Must be a compound subquery */
+  do{
+    if( pSub->op!=TK_ALL && pSub->pPrior ) return 0;  /* Must be UNION ALL */
+    if( pSub->pWhere ) return 0;                      /* No WHERE clause */
+    if( pSub->selFlags & SF_Aggregate ) return 0;     /* Not an aggregate */
+    pSub = pSub->pPrior;                              /* Repeat over compound terms */
+  }while( pSub );
+
+  /* If we reach this point, that means it is OK to perform the transformation */
+
+  db = pParse->db;
+  pCount = pExpr;
+  pExpr = 0;
+  pSub = p->pSrc->a[0].pSelect;
+  p->pSrc->a[0].pSelect = 0;
+  sqlite3SrcListDelete(db, p->pSrc);
+  p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc));
+  while( pSub ){
+    Expr *pTerm;
+    pPrior = pSub->pPrior;
+    pSub->pPrior = 0;
+    pSub->pNext = 0;
+    pSub->selFlags |= SF_Aggregate;
+    pSub->selFlags &= ~SF_Compound;
+    pSub->nSelectRow = 0;
+    sqlite3ExprListDelete(db, pSub->pEList);
+    pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount;
+    pSub->pEList = sqlite3ExprListAppend(pParse, 0, pTerm);
+    pTerm = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
+    if( pTerm ){
+      pTerm->x.pSelect = pSub;
+      ExprSetProperty(pTerm, EP_xIsSelect|EP_Subquery);
+      sqlite3ExprSetHeightAndFlags(pParse, pTerm);
+      if( pExpr==0 ){
+        pExpr = pTerm;
+      }else{
+        pExpr = sqlite3PExpr(pParse, TK_PLUS, pTerm, pExpr, 0);
+      }
+    }else{
+      sqlite3SelectDelete(db, pSub);
+    }
+    pSub = pPrior;
+  }
+  p->pEList->a[0].pExpr = pExpr;
+  p->selFlags &= ~SF_Aggregate;
+
+#if SELECTTRACE_ENABLED
+  if( sqlite3SelectTrace & 0x400 ){
+    SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n"));
+    sqlite3TreeViewSelect(0, p, 0);
+  }
+#endif
+  return 1;
+}
+#endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */
+
 /*
 ** Generate code for the SELECT statement given in the p argument.  
 **
@@ -4933,6 +5021,16 @@ int sqlite3Select(
   }
 #endif
 
+#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
+  if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView)
+   && countOfViewOptimization(pParse, p)
+  ){
+    if( db->mallocFailed ) goto select_end;
+    pEList = p->pEList;
+    pTabList = p->pSrc;
+  }
+#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:
index c7d729cf357481252a574031f3150b4f261b8c74..27f442ea92793cf65b81f9142c53a5ef35aaae31 100644 (file)
@@ -1245,6 +1245,7 @@ struct sqlite3 {
 #define SQLITE_Transitive     0x0200   /* Transitive constraints */
 #define SQLITE_OmitNoopJoin   0x0400   /* Omit unused tables in joins */
 #define SQLITE_Stat34         0x0800   /* Use STAT3 or STAT4 data */
+#define SQLITE_CountOfView    0x1000   /* The count-of-view optimization */
 #define SQLITE_AllOpts        0xffff   /* All optimizations */
 
 /*