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:
parent
a32536b498
commit
90cf38be63
18
manifest
18
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
|
||||
|
@ -1 +1 @@
|
||||
bc401a75dd9f3c29c5969ae36264e68ccefc0937e44e232ca1f6b550f7fd6e22
|
||||
74aec5dd1df95b5635f4da1f13753f113ea1d61de3dc3a1523ba51089c1900e4
|
141
src/expr.c
141
src/expr.c
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user