]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Refactor the code that figures out which SELECT in a cascade of nested queries
authordrh <>
Mon, 8 Nov 2021 23:24:00 +0000 (23:24 +0000)
committerdrh <>
Mon, 8 Nov 2021 23:24:00 +0000 (23:24 +0000)
a particular aggregate function belongs to.  This fixes the problem
reported by [forum:/forumpost/c7cc2aa3546e39c1|forum post c7cc2aa3546e39c1].
New test cases in dbsqlfuzz and th3.

FossilOrigin-Name: 74aec5dd1df95b5635f4da1f13753f113ea1d61de3dc3a1523ba51089c1900e4

manifest
manifest.uuid
src/expr.c
src/resolve.c
src/sqliteInt.h

index 79bcb4dc172d090b0922d84097dc100a61491e92..04f46c17c0a40354752560b6ebe9b5e475ba7d34 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sthe\szeroblob()\sfunction\sand\srelated\sAPIs\sso\sthat\sthey\swork\swith\sSQLITE_OMIT_INCRBLOB\sbuilds.
-D 2021-11-08T19:35:26.655
+C Refactor\sthe\scode\sthat\sfigures\sout\swhich\sSELECT\sin\sa\scascade\sof\snested\squeries\na\sparticular\saggregate\sfunction\sbelongs\sto.\s\sThis\sfixes\sthe\sproblem\nreported\sby\s[forum:/forumpost/c7cc2aa3546e39c1|forum\spost\sc7cc2aa3546e39c1].\nNew\stest\scases\sin\sdbsqlfuzz\sand\sth3.
+D 2021-11-08T23:24:00.417
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -502,7 +502,7 @@ F src/date.c fa928630fecf1d436cdc7a7a5c950c781709023ca782c21b7a43cc7361a9451e
 F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a
 F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d
 F src/delete.c 0c151975fa99560767d7747f9b60543d0093d9f8b89f13d2d6058e9c83ad19e7
-F src/expr.c f96439c1c58fd8dbb42254ad45339b8487f7e2c0b59eb43b4652ffe458205bdb
+F src/expr.c 5c021ca2495b1e908610276cf5d462133d63ec47863235c8958d36e61841c72d
 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
 F src/fkey.c 187b67af20c5795953a592832c5d985e4313fe503ebd8f95e3e9e9ad5a730bb5
 F src/func.c 1cfb09d7ffca81238eccefdb0293e1f5b7cfebbd1816dfad5ec6024742a7496b
@@ -548,14 +548,14 @@ F src/pragma.h 87330ed2fbfa2a1274de93ca0ab850fba336189228cb256089202c3b52766fad
 F src/prepare.c 7520a371f1de8a53e3023eba75bc0d3473196833c6363d285cad8d002eabef0b
 F src/printf.c 5901672228f305f7d493cbc4e7d76a61a5caecdbc1cd06b1f9ec42ea4265cf8d
 F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
-F src/resolve.c ae65c88f5d0d4bc0052b203773d407efa2387c2bd6b202f87178006c7bb8632c
+F src/resolve.c 4a1db4aadd802683db40ca2dbbb268187bd195f10cbdb7206dbd8ac988795571
 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
 F src/select.c b4b3a0f32e70d93efbb357783846853dbd8b266ec0d7035aa0a245c33eecf72d
 F src/shell.c.in f8854bcb0d14707d661732698d5210d7f01694000c46e8014b323ad18f575be6
 F src/sqlite.h.in 5cd209ac7dc4180f0e19292846f40440b8488015849ca0110c70b906b57d68f0
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 8ff2fd2c166150b2e48639f5e506fb44e29f1a3f65031710b9e89d1c126ac839
-F src/sqliteInt.h c280f33f023f87864fa660925f5d5cb49ccfc82eea223fec4e37177c86a26b5a
+F src/sqliteInt.h 8e770859062a87254dabd183b3f7bd29f89fd5905515beac00877958e88e06ce
 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -1932,7 +1932,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P b1e2929860557cf88f98f0a4f2472e1a16be126bbb8050f0d728350f0cfe987a
-R 38e6cac2f0504419221900502859a6b1
-U dan
-Z 081f4998dc35a67aaba184a060c36c98
+P bc401a75dd9f3c29c5969ae36264e68ccefc0937e44e232ca1f6b550f7fd6e22
+R 39b8c22200792487bab0b61ad66853dd
+U drh
+Z c1621993dac1862e5659d8b61900625a
index bd630146fad77ba9d4b25f2d285cbb7f88223e6a..e462d1c5cebe89898cc23710e73982d9045d902a 100644 (file)
@@ -1 +1 @@
-bc401a75dd9f3c29c5969ae36264e68ccefc0937e44e232ca1f6b550f7fd6e22
\ No newline at end of file
+74aec5dd1df95b5635f4da1f13753f113ea1d61de3dc3a1523ba51089c1900e4
\ No newline at end of file
index 61e84e56baef67ca8206b960ad1927802fa17dd6..62d2691bc4a5c5429fcefc2aca325caa2daae5a8 100644 (file)
@@ -5879,81 +5879,109 @@ int sqlite3ExprCoveredByIndex(
 }
 
 
-/*
-** An instance of the following structure is used by the tree walker
-** to count references to table columns in the arguments of an 
-** aggregate function, in order to implement the
-** sqlite3FunctionThisSrc() routine.
-*/
-struct SrcCount {
-  SrcList *pSrc;   /* One particular FROM clause in a nested query */
-  int iSrcInner;   /* Smallest cursor number in this context */
-  int nThis;       /* Number of references to columns in pSrcList */
-  int nOther;      /* Number of references to columns in other FROM clauses */
+/* Structure used to pass information throught the Walker in order to
+** implement sqlite3ReferencesSrcList().
+*/
+struct RefSrcList {
+  sqlite3 *db;         /* Database connection used for sqlite3DbRealloc() */
+  SrcList *pRef;       /* Looking for references to these tables */
+  int nExclude;        /* Number of tables to exclude from the search */
+  int *aiExclude;      /* Cursor IDs for tables to exclude from the search */
 };
 
 /*
-** xSelect callback for sqlite3FunctionUsesThisSrc(). If this is the first
-** SELECT with a FROM clause encountered during this iteration, set
-** SrcCount.iSrcInner to the cursor number of the leftmost object in
-** the FROM cause.
+** Walker SELECT callbacks for sqlite3ReferencesSrcList().
+**
+** When entering a new subquery on the pExpr argument, add all FROM clause
+** entries for that subquery to the exclude list.
+**
+** When leaving the subquery, remove those entries from the exclude list.
 */
-static int selectSrcCount(Walker *pWalker, Select *pSel){
-  struct SrcCount *p = pWalker->u.pSrcCount;
-  if( p->iSrcInner==0x7FFFFFFF && ALWAYS(pSel->pSrc) && pSel->pSrc->nSrc ){
-    pWalker->u.pSrcCount->iSrcInner = pSel->pSrc->a[0].iCursor;
+static int selectRefEnter(Walker *pWalker, Select *pSelect){
+  struct RefSrcList *p = pWalker->u.pRefSrcList;
+  SrcList *pSrc = pSelect->pSrc;
+  int i, j, *piNew;
+  if( pSrc->nSrc==0 ) return WRC_Continue;
+  j = p->nExclude;
+  p->nExclude += pSrc->nSrc;
+  piNew = sqlite3DbRealloc(p->db, p->aiExclude, p->nExclude*sizeof(int));
+  if( piNew==0 ){
+    p->nExclude = 0;
+    return WRC_Abort;
+  }else{
+    p->aiExclude = piNew;
+  }
+  for(i=0; i<pSrc->nSrc; i++, j++){
+     p->aiExclude[j] = pSrc->a[i].iCursor;
   }
   return WRC_Continue;
 }
+static void selectRefLeave(Walker *pWalker, Select *pSelect){
+  struct RefSrcList *p = pWalker->u.pRefSrcList;
+  SrcList *pSrc = pSelect->pSrc;
+  if( p->nExclude ){
+    assert( p->nExclude>=pSrc->nSrc );
+    p->nExclude -= pSrc->nSrc;
+  }
+}
 
-/*
-** Count the number of references to columns.
+/* This is the Walker EXPR callback for sqlite3ReferencesSrcList().
+** 
+** Set the 0x01 bit of pWalker->eCode if there is a reference to any
+** of the tables shown in RefSrcList.pRef.
+**
+** Set the 0x02 bit of pWalker->eCode if there is a reference to a
+** table is in neither RefSrcList.pRef nor RefSrcList.aiExclude.
 */
-static int exprSrcCount(Walker *pWalker, Expr *pExpr){
-  /* There was once a NEVER() on the second term on the grounds that
-  ** sqlite3FunctionUsesThisSrc() was always called before 
-  ** sqlite3ExprAnalyzeAggregates() and so the TK_COLUMNs have not yet 
-  ** been converted into TK_AGG_COLUMN. But this is no longer true due
-  ** to window functions - sqlite3WindowRewrite() may now indirectly call
-  ** FunctionUsesThisSrc() when creating a new sub-select. */
-  if( pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN ){
+static int exprRefToSrcList(Walker *pWalker, Expr *pExpr){
+  if( pExpr->op==TK_COLUMN
+   || pExpr->op==TK_AGG_COLUMN
+  ){
     int i;
-    struct SrcCount *p = pWalker->u.pSrcCount;
-    SrcList *pSrc = p->pSrc;
+    struct RefSrcList *p = pWalker->u.pRefSrcList;
+    SrcList *pSrc = p->pRef;
     int nSrc = pSrc ? pSrc->nSrc : 0;
     for(i=0; i<nSrc; i++){
-      if( pExpr->iTable==pSrc->a[i].iCursor ) break;
+      if( pExpr->iTable==pSrc->a[i].iCursor ){
+        pWalker->eCode |= 1;
+        return WRC_Continue;
+      }
     }
-    if( i<nSrc ){
-      p->nThis++;
-    }else if( pExpr->iTable<p->iSrcInner ){
-      /* In a well-formed parse tree (no name resolution errors),
-      ** TK_COLUMN nodes with smaller Expr.iTable values are in an
-      ** outer context.  Those are the only ones to count as "other" */
-      p->nOther++;
+    for(i=0; i<p->nExclude && p->aiExclude[i]!=pExpr->iTable; i++){}
+    if( i>=p->nExclude ){
+      pWalker->eCode |= 2;
     }
   }
   return WRC_Continue;
 }
 
 /*
-** Determine if any of the arguments to the pExpr Function reference
-** pSrcList.  Return true if they do.  Also return true if the function
-** has no arguments or has only constant arguments.  Return false if pExpr
-** references columns but not columns of tables found in pSrcList.
+** Check to see if pExpr references any tables in pSrcList.
+** Possible return values:
+**
+**    1         pExpr does references a table in pSrcList.
+**
+**    0         pExpr references some table that is not defined in either
+**              pSrcList or in subqueries of pExpr itself.
+**
+**   -1         pExpr only references no tables at all, or it only
+**              references tables defined in subqueries of pExpr itself.
+**
+** As currently used, pExpr is always an aggregate function call.  That
+** fact is exploited for efficiency.
 */
-int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
+int sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList *pSrcList){
   Walker w;
-  struct SrcCount cnt;
-  assert( pExpr->op==TK_AGG_FUNCTION );
+  struct RefSrcList x;
   memset(&w, 0, sizeof(w));
-  w.xExprCallback = exprSrcCount;
-  w.xSelectCallback = selectSrcCount;
-  w.u.pSrcCount = &cnt;
-  cnt.pSrc = pSrcList;
-  cnt.iSrcInner = (pSrcList&&pSrcList->nSrc)?pSrcList->a[0].iCursor:0x7FFFFFFF;
-  cnt.nThis = 0;
-  cnt.nOther = 0;
+  memset(&x, 0, sizeof(x));
+  w.xExprCallback = exprRefToSrcList;
+  w.xSelectCallback = selectRefEnter;
+  w.xSelectCallback2 = selectRefLeave;
+  w.u.pRefSrcList = &x;
+  x.db = pParse->db;
+  x.pRef = pSrcList;
+  assert( pExpr->op==TK_AGG_FUNCTION );
   assert( ExprUseXList(pExpr) );
   sqlite3WalkExprList(&w, pExpr->x.pList);
 #ifndef SQLITE_OMIT_WINDOWFUNC
@@ -5961,7 +5989,14 @@ int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
     sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter);
   }
 #endif
-  return cnt.nThis>0 || cnt.nOther==0;
+  sqlite3DbFree(pParse->db, x.aiExclude);
+  if( w.eCode & 0x01 ){
+    return 1;
+  }else if( w.eCode ){
+    return 0;
+  }else{
+    return -1;
+  }
 }
 
 /*
index c55fc514cbfd437641162097afb2b60b7f06be04..27b260e059fc4536051e0b514a04a700145b2553 100644 (file)
@@ -1092,7 +1092,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
         }else
 #endif /* SQLITE_OMIT_WINDOWFUNC */
         {
-          NameContext *pNC2 = pNC;
+          NameContext *pNC2;          /* For looping up thru outer contexts */
           pExpr->op = TK_AGG_FUNCTION;
           pExpr->op2 = 0;
 #ifndef SQLITE_OMIT_WINDOWFUNC
@@ -1100,7 +1100,10 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
             sqlite3WalkExpr(pWalker, pExpr->y.pWin->pFilter);
           }
 #endif
-          while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){
+          pNC2 = pNC;
+          while( pNC2 
+              && sqlite3ReferencesSrcList(pParse, pExpr, pNC2->pSrcList)==0
+          ){
             pExpr->op2++;
             pNC2 = pNC2->pNext;
           }
index 984b3c680c035b3e0c200aaa2ed603a2a4a4f9b9..75f3bfca2d65a5ee13f26472fe1ec6da442b46f7 100644 (file)
@@ -3964,8 +3964,8 @@ struct Walker {
     int n;                                    /* A counter */
     int iCur;                                 /* A cursor number */
     SrcList *pSrcList;                        /* FROM clause */
-    struct SrcCount *pSrcCount;               /* Counting column references */
     struct CCurHint *pCCurHint;               /* Used by codeCursorHint() */
+    struct RefSrcList *pRefSrcList;           /* sqlite3ReferencesSrcList() */
     int *aiCol;                               /* array of column indexes */
     struct IdxCover *pIdxCover;               /* Check for index coverage */
     struct IdxExprTrans *pIdxTrans;           /* Convert idxed expr to column */
@@ -4623,7 +4623,7 @@ void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*);
 void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
 void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
 int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx);
-int sqlite3FunctionUsesThisSrc(Expr*, SrcList*);
+int sqlite3ReferencesSrcList(Parse*, Expr*, SrcList*);
 Vdbe *sqlite3GetVdbe(Parse*);
 #ifndef SQLITE_UNTESTABLE
 void sqlite3PrngSaveState(void);