diff options
author | danielk1977 <danielk1977@noemail.net> | 2005-02-08 07:50:40 +0000 |
---|---|---|
committer | danielk1977 <danielk1977@noemail.net> | 2005-02-08 07:50:40 +0000 |
commit | a58fdfb16246b02268924cb60565e49a3b91dffd (patch) | |
tree | 392fdc5e0d2f0236dd1b59f194e2a995bdeb01bb /src/expr.c | |
parent | 7bec505e26ab86cc9663f9c384956a3df6e3dc54 (diff) | |
download | sqlite-a58fdfb16246b02268924cb60565e49a3b91dffd.tar.gz sqlite-a58fdfb16246b02268924cb60565e49a3b91dffd.zip |
Fix for correlated subqueries where the parent is an aggregate. Ticket #1105. (CVS 2318)
FossilOrigin-Name: f0d3ca10c5bccf8fca7143028ebb3e604c0e3f20
Diffstat (limited to 'src/expr.c')
-rw-r--r-- | src/expr.c | 131 |
1 files changed, 84 insertions, 47 deletions
diff --git a/src/expr.c b/src/expr.c index e28283328..487c5395f 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.192 2005/02/05 12:48:48 danielk1977 Exp $ +** $Id: expr.c,v 1.193 2005/02/08 07:50:41 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -189,6 +189,7 @@ Expr *sqlite3Expr(int op, Expr *pLeft, Expr *pRight, const Token *pToken){ pNew->op = op; pNew->pLeft = pLeft; pNew->pRight = pRight; + pNew->iAgg = -1; if( pToken ){ assert( pToken->dyn==0 ); pNew->span = pNew->token = *pToken; @@ -589,27 +590,48 @@ void sqlite3ExprListDelete(ExprList *pList){ ** The return value from this routine is 1 to abandon the tree walk ** and 0 to continue. */ +static int walkExprList(ExprList *, int (*)(void *, Expr*), void *); static int walkExprTree(Expr *pExpr, int (*xFunc)(void*,Expr*), void *pArg){ - ExprList *pList; int rc; if( pExpr==0 ) return 0; rc = (*xFunc)(pArg, pExpr); if( rc==0 ){ if( walkExprTree(pExpr->pLeft, xFunc, pArg) ) return 1; if( walkExprTree(pExpr->pRight, xFunc, pArg) ) return 1; - pList = pExpr->pList; - if( pList ){ - int i; - struct ExprList_item *pItem; - for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ - if( walkExprTree(pItem->pExpr, xFunc, pArg) ) return 1; - } - } + if( walkExprList(pExpr->pList, xFunc, pArg) ) return 1; } return rc>1; } /* +** Call walkExprTree() for every expression in list p. +*/ +static int walkExprList(ExprList *p, int (*xFunc)(void *, Expr*), void *pArg){ + int i; + struct ExprList_item *pItem; + if( !p ) return 0; + for(i=p->nExpr, pItem=p->a; i>0; i--, pItem++){ + if( walkExprTree(pItem->pExpr, xFunc, pArg) ) return 1; + } + return 0; +} + +/* +** Call walkExprTree() for every expression in Select p, not including +** expressions that are part of sub-selects in any FROM clause or the LIMIT +** or OFFSET expressions.. +*/ +static int walkSelectExpr(Select *p, int (*xFunc)(void *, Expr*), void *pArg){ + walkExprList(p->pEList, xFunc, pArg); + walkExprTree(p->pWhere, xFunc, pArg); + walkExprList(p->pGroupBy, xFunc, pArg); + walkExprTree(p->pHaving, xFunc, pArg); + walkExprList(p->pOrderBy, xFunc, pArg); + return 0; +} + + +/* ** This routine is designed as an xFunc for walkExprTree(). ** ** pArg is really a pointer to an integer. If we can tell by looking @@ -1356,8 +1378,8 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ op = pExpr->op; switch( op ){ case TK_COLUMN: { - if( pParse->useAgg ){ - sqlite3VdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg); + if( !pParse->fillAgg && pExpr->iAgg>=0 ){ + sqlite3VdbeAddOp(v, OP_AggGet, pExpr->iAggCtx, pExpr->iAgg); }else if( pExpr->iColumn>=0 ){ sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn); #ifndef NDEBUG @@ -1968,49 +1990,64 @@ static int appendAggInfo(Parse *pParse){ static int analyzeAggregate(void *pArg, Expr *pExpr){ int i; AggExpr *aAgg; - Parse *pParse = (Parse*)pArg; + NameContext *pNC = (NameContext *)pArg; + Parse *pParse = pNC->pParse; + SrcList *pSrcList = pNC->pSrcList; switch( pExpr->op ){ case TK_COLUMN: { - aAgg = pParse->aAgg; - for(i=0; i<pParse->nAgg; i++){ - if( aAgg[i].isAgg ) continue; - if( aAgg[i].pExpr->iTable==pExpr->iTable - && aAgg[i].pExpr->iColumn==pExpr->iColumn ){ - break; + for(i=0; pSrcList && i<pSrcList->nSrc; i++){ + if( pExpr->iTable==pSrcList->a[i].iCursor ){ + aAgg = pParse->aAgg; + for(i=0; i<pParse->nAgg; i++){ + if( aAgg[i].isAgg ) continue; + if( aAgg[i].pExpr->iTable==pExpr->iTable + && aAgg[i].pExpr->iColumn==pExpr->iColumn ){ + break; + } + } + if( i>=pParse->nAgg ){ + i = appendAggInfo(pParse); + if( i<0 ) return 1; + pParse->aAgg[i].isAgg = 0; + pParse->aAgg[i].pExpr = pExpr; + } + pExpr->iAgg = i; + pExpr->iAggCtx = pNC->nDepth; + return 1; } } - if( i>=pParse->nAgg ){ - i = appendAggInfo(pParse); - if( i<0 ) return 1; - pParse->aAgg[i].isAgg = 0; - pParse->aAgg[i].pExpr = pExpr; - } - pExpr->iAgg = i; return 1; } case TK_AGG_FUNCTION: { - aAgg = pParse->aAgg; - for(i=0; i<pParse->nAgg; i++){ - if( !aAgg[i].isAgg ) continue; - if( sqlite3ExprCompare(aAgg[i].pExpr, pExpr) ){ - break; + if( pNC->nDepth==0 ){ + aAgg = pParse->aAgg; + for(i=0; i<pParse->nAgg; i++){ + if( !aAgg[i].isAgg ) continue; + if( sqlite3ExprCompare(aAgg[i].pExpr, pExpr) ){ + break; + } } + if( i>=pParse->nAgg ){ + u8 enc = pParse->db->enc; + i = appendAggInfo(pParse); + if( i<0 ) return 1; + pParse->aAgg[i].isAgg = 1; + pParse->aAgg[i].pExpr = pExpr; + pParse->aAgg[i].pFunc = sqlite3FindFunction(pParse->db, + pExpr->token.z, pExpr->token.n, + pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0); + } + pExpr->iAgg = i; + return 1; } - if( i>=pParse->nAgg ){ - u8 enc = pParse->db->enc; - i = appendAggInfo(pParse); - if( i<0 ) return 1; - pParse->aAgg[i].isAgg = 1; - pParse->aAgg[i].pExpr = pExpr; - pParse->aAgg[i].pFunc = sqlite3FindFunction(pParse->db, - pExpr->token.z, pExpr->token.n, - pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0); - } - pExpr->iAgg = i; - return 1; } } + if( pExpr->pSelect ){ + pNC->nDepth++; + walkSelectExpr(pExpr->pSelect, analyzeAggregate, pNC); + pNC->nDepth--; + } return 0; } @@ -2025,10 +2062,10 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){ ** If errors are seen, leave an error message in zErrMsg and return ** the number of errors. */ -int sqlite3ExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){ - int nErr = pParse->nErr; - walkExprTree(pExpr, analyzeAggregate, pParse); - return pParse->nErr - nErr; +int sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){ + int nErr = pNC->pParse->nErr; + walkExprTree(pExpr, analyzeAggregate, pNC); + return pNC->pParse->nErr - nErr; } /* |