Refactor the code that figures out which SELECT in a cascade of nested queries

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
This commit is contained in:
drh 2021-11-08 23:24:00 +00:00
parent a32536b498
commit 90cf38be63
5 changed files with 105 additions and 67 deletions

View File

@ -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

View File

@ -1 +1 @@
bc401a75dd9f3c29c5969ae36264e68ccefc0937e44e232ca1f6b550f7fd6e22
74aec5dd1df95b5635f4da1f13753f113ea1d61de3dc3a1523ba51089c1900e4

View 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.
/* Structure used to pass information throught the Walker in order to
** implement sqlite3ReferencesSrcList().
*/
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 */
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;
}
}
/*

View 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;
}

View 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);