Index: src/expr.c ================================================================== --- src/expr.c +++ src/expr.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.221 2005/08/25 12:45:04 drh Exp $ +** $Id: expr.c,v 1.222 2005/08/30 00:54:02 drh Exp $ */ #include "sqliteInt.h" #include /* @@ -2069,32 +2069,34 @@ ** ** This routine analyzes the aggregate function at pExpr. */ static int analyzeAggregate(void *pArg, Expr *pExpr){ int i; - AggExpr *aAgg; + AggExpr *pAgg; NameContext *pNC = (NameContext *)pArg; Parse *pParse = pNC->pParse; SrcList *pSrcList = pNC->pSrcList; + Expr *pAggExpr; switch( pExpr->op ){ case TK_COLUMN: { for(i=0; pSrcList && inSrc; i++){ if( pExpr->iTable==pSrcList->a[i].iCursor ){ - aAgg = pParse->aAgg; - for(i=0; inAgg; i++){ - if( aAgg[i].isAgg ) continue; - if( aAgg[i].pExpr->iTable==pExpr->iTable - && aAgg[i].pExpr->iColumn==pExpr->iColumn ){ + pAgg = pParse->aAgg; + for(i=0; inAgg; i++, pAgg++){ + if( pAgg->isAgg ) continue; + if( (pAggExpr = pAgg->pExpr)->iTable==pExpr->iTable + && pAggExpr->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; + pAgg = &pParse->aAgg[i]; + pAgg->isAgg = 0; + pAgg->pExpr = pExpr; } pExpr->iAgg = i; pExpr->iAggCtx = pNC->nDepth; return 1; } @@ -2101,24 +2103,25 @@ } return 1; } case TK_AGG_FUNCTION: { if( pNC->nDepth==0 ){ - aAgg = pParse->aAgg; - for(i=0; inAgg; i++){ - if( !aAgg[i].isAgg ) continue; - if( sqlite3ExprCompare(aAgg[i].pExpr, pExpr) ){ + pAgg = pParse->aAgg; + for(i=0; inAgg; i++, pAgg++){ + if( !pAgg->isAgg ) continue; + if( sqlite3ExprCompare(pAgg->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, + pAgg = &pParse->aAgg[i]; + pAgg->isAgg = 1; + pAgg->pExpr = pExpr; + pAgg->pFunc = sqlite3FindFunction(pParse->db, pExpr->token.z, pExpr->token.n, pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0); } pExpr->iAgg = i; return 1; @@ -2147,5 +2150,23 @@ int sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){ int nErr = pNC->pParse->nErr; walkExprTree(pExpr, analyzeAggregate, pNC); return pNC->pParse->nErr - nErr; } + +/* +** Call sqlite3ExprAnalyzeAggregates() for every expression in an +** expression list. Return the number of errors. +** +** If an error is found, the analysis is cut short. +*/ +int sqlite3ExprAnalyzeAggList(NameContext *pNC, ExprList *pList){ + struct ExprList_item *pItem; + int i; + int nErr = 0; + if( pList ){ + for(pItem=pList->a, i=0; nErr==0 && inExpr; i++, pItem++){ + nErr += sqlite3ExprAnalyzeAggregates(pNC, pItem->pExpr); + } + } + return nErr; +} Index: src/select.c ================================================================== --- src/select.c +++ src/select.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.255 2005/08/28 01:34:22 drh Exp $ +** $Id: select.c,v 1.256 2005/08/30 00:54:03 drh Exp $ */ #include "sqliteInt.h" /* @@ -2630,14 +2630,14 @@ /* If there is an ORDER BY clause, resolve any collation sequences ** names that have been explicitly specified. */ if( pOrderBy ){ - for(i=0; inExpr; i++){ - if( pOrderBy->a[i].zName ){ - pOrderBy->a[i].pExpr->pColl = - sqlite3LocateCollSeq(pParse, pOrderBy->a[i].zName, -1); + struct ExprList_item *pTerm; + for(i=0, pTerm=pOrderBy->a; inExpr; i++, pTerm++){ + if( pTerm->zName ){ + pTerm->pExpr->pColl = sqlite3LocateCollSeq(pParse, pTerm->zName, -1); } } if( pParse->nErr ){ goto select_end; } @@ -2662,31 +2662,21 @@ sNC.pParse = pParse; sNC.pSrcList = pTabList; assert( pParse->nAgg==0 ); isAgg = 1; - for(i=0; inExpr; i++){ - if( sqlite3ExprAnalyzeAggregates(&sNC, pEList->a[i].pExpr) ){ - goto select_end; - } - } - if( pGroupBy ){ - for(i=0; inExpr; i++){ - if( sqlite3ExprAnalyzeAggregates(&sNC, pGroupBy->a[i].pExpr) ){ - goto select_end; - } - } + if( sqlite3ExprAnalyzeAggList(&sNC, pEList) ){ + goto select_end; + } + if( sqlite3ExprAnalyzeAggList(&sNC, pGroupBy) ){ + goto select_end; } if( pHaving && sqlite3ExprAnalyzeAggregates(&sNC, pHaving) ){ goto select_end; } - if( pOrderBy ){ - for(i=0; inExpr; i++){ - if( sqlite3ExprAnalyzeAggregates(&sNC, pOrderBy->a[i].pExpr) ){ - goto select_end; - } - } + if( sqlite3ExprAnalyzeAggList(&sNC, pOrderBy) ){ + goto select_end; } } /* Reset the aggregator */ Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -9,11 +9,11 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.405 2005/08/29 23:00:04 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.406 2005/08/30 00:54:03 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* @@ -890,10 +890,11 @@ Expr *pExpr; /* The list of expressions */ char *zName; /* Token associated with this expression */ u8 sortOrder; /* 1 for DESC or 0 for ASC */ u8 isAgg; /* True if this is an aggregate like count(*) */ u8 done; /* A flag to indicate when processing is finished */ + u8 orderByDup[2]; /* Corresponding term in OrderBy/GroupBy clause */ } *a; /* One entry for each expression */ }; /* ** An instance of this structure can hold a simple list of identifiers, @@ -1450,10 +1451,11 @@ int sqlite3ExprCheck(Parse*, Expr*, int, int*); int sqlite3ExprCompare(Expr*, Expr*); int sqliteFuncId(Token*); int sqlite3ExprResolveNames(NameContext *, Expr *); int sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); +int sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); Vdbe *sqlite3GetVdbe(Parse*); void sqlite3Randomness(int, void*); void sqlite3RollbackAll(sqlite3*); void sqlite3CodeVerifySchema(Parse*, int); void sqlite3BeginTransaction(Parse*, int);