diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/expr.c | 27 | ||||
-rw-r--r-- | src/parse.y | 23 | ||||
-rw-r--r-- | src/resolve.c | 11 | ||||
-rw-r--r-- | src/select.c | 24 | ||||
-rw-r--r-- | src/sqliteInt.h | 8 | ||||
-rw-r--r-- | src/walker.c | 3 | ||||
-rw-r--r-- | src/window.c | 12 |
7 files changed, 77 insertions, 31 deletions
diff --git a/src/expr.c b/src/expr.c index c4f201a13..75d0dbe9d 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1027,7 +1027,7 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ assert( !ExprHasProperty(p, EP_WinFunc) || p->y.pWin!=0 || db->mallocFailed ); assert( p->op!=TK_FUNCTION || ExprHasProperty(p, EP_TokenOnly|EP_Reduced) - || p->y.pWin==0 || ExprHasProperty(p, EP_WinFunc) ); + || p->y.pWin==0 || ExprHasProperty(p, EP_WinFunc|EP_Filter) ); #ifdef SQLITE_DEBUG if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){ assert( p->pLeft==0 ); @@ -1046,10 +1046,15 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ }else{ sqlite3ExprListDelete(db, p->x.pList); } +#ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(p, EP_WinFunc) ){ - assert( p->op==TK_FUNCTION ); + assert( p->op==TK_FUNCTION && !ExprHasProperty(p, EP_Filter) ); sqlite3WindowDelete(db, p->y.pWin); + }else if( ExprHasProperty(p, EP_Filter) ){ + assert( p->op==TK_FUNCTION || p->op==TK_AGG_FUNCTION ); + sqlite3ExprDelete(db, p->y.pFilter); } +#endif } if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken); if( !ExprHasProperty(p, EP_Static) ){ @@ -1264,7 +1269,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ } /* Fill in pNew->pLeft and pNew->pRight. */ - if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly|EP_WinFunc) ){ + if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly|EP_WinFunc|EP_Filter) ){ zAlloc += dupedExprNodeSize(p, dupFlags); if( !ExprHasProperty(pNew, EP_TokenOnly|EP_Leaf) ){ pNew->pLeft = p->pLeft ? @@ -1277,6 +1282,10 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ pNew->y.pWin = sqlite3WindowDup(db, pNew, p->y.pWin); assert( ExprHasProperty(pNew, EP_WinFunc) ); } + if( ExprHasProperty(p, EP_Filter) ){ + pNew->y.pFilter = sqlite3ExprDup(db, p->y.pFilter, 0); + assert( ExprHasProperty(pNew, EP_Filter) ); + } #endif /* SQLITE_OMIT_WINDOWFUNC */ if( pzBuffer ){ *pzBuffer = zAlloc; @@ -1332,8 +1341,8 @@ static With *withDup(sqlite3 *db, With *p){ ** objects found there, assembling them onto the linked list at Select->pWin. */ static int gatherSelectWindowsCallback(Walker *pWalker, Expr *pExpr){ - if( pExpr->op==TK_FUNCTION && pExpr->y.pWin!=0 ){ - assert( ExprHasProperty(pExpr, EP_WinFunc) ); + if( pExpr->op==TK_FUNCTION && ExprHasProperty(pExpr, EP_WinFunc) ){ + assert( pExpr->y.pWin ); pExpr->y.pWin->pNextWin = pWalker->u.pSelect->pWin; pWalker->u.pSelect->pWin = pExpr->y.pWin; } @@ -4862,6 +4871,14 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){ }else if( ALWAYS(pB->u.zToken!=0) && strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ return 2; } +#ifndef SQLITE_OMIT_WINDOWFUNC + else if( pA->op==TK_AGG_FUNCTION ){ + assert( ExprHasProperty(pA, EP_WinFunc)==0 ); + if( sqlite3ExprCompare(pParse, pA->y.pFilter, pB->y.pFilter, iTab) ){ + return 2; + } + } +#endif } if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2; if( (combinedFlags & EP_TokenOnly)==0 ){ diff --git a/src/parse.y b/src/parse.y index fc5bff16d..dda9f627a 100644 --- a/src/parse.y +++ b/src/parse.y @@ -1036,21 +1036,23 @@ expr(A) ::= CAST LP expr(E) AS typetoken(T) RP. { %endif SQLITE_OMIT_CAST +%ifdef SQLITE_OMIT_WINDOWFUNC expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP. { A = sqlite3ExprFunction(pParse, Y, &X, D); } expr(A) ::= id(X) LP STAR RP. { A = sqlite3ExprFunction(pParse, 0, &X, 0); } +%endif %ifndef SQLITE_OMIT_WINDOWFUNC -expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP over_clause(Z). { +expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP filter_opt(F) over_opt(Z). { A = sqlite3ExprFunction(pParse, Y, &X, D); - sqlite3WindowAttach(pParse, A, Z); + sqlite3WindowAttach(pParse, A, F, Z); } -expr(A) ::= id(X) LP STAR RP over_clause(Z). { +expr(A) ::= id(X) LP STAR RP filter_opt(F) over_opt(Z). { A = sqlite3ExprFunction(pParse, 0, &X, 0); - sqlite3WindowAttach(pParse, A, Z); + sqlite3WindowAttach(pParse, A, F, Z); } %endif @@ -1724,20 +1726,17 @@ frame_exclude(A) ::= GROUP|TIES(X). {A = @X; /*A-overwrites-X*/} %destructor window_clause {sqlite3WindowListDelete(pParse->db, $$);} window_clause(A) ::= WINDOW windowdefn_list(B). { A = B; } -%type over_clause {Window*} -%destructor over_clause {sqlite3WindowDelete(pParse->db, $$);} -over_clause(A) ::= filter_opt(W) OVER LP window(Z) RP. { +%type over_opt {Window*} +%destructor over_opt {sqlite3WindowDelete(pParse->db, $$);} +over_opt(A) ::= . { A=0; } +over_opt(A) ::= OVER LP window(Z) RP. { A = Z; assert( A!=0 ); - A->pFilter = W; } -over_clause(A) ::= filter_opt(W) OVER nm(Z). { +over_opt(A) ::= OVER nm(Z). { A = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( A ){ A->zName = sqlite3DbStrNDup(pParse->db, Z.z, Z.n); - A->pFilter = W; - }else{ - sqlite3ExprDelete(pParse->db, W); } } diff --git a/src/resolve.c b/src/resolve.c index 8dac077ee..0a8aff565 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -849,6 +849,12 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()",zType,nId,zId); pNC->nErr++; is_agg = 0; + }else if( is_agg==0 && ExprHasProperty(pExpr, EP_Filter) ){ + sqlite3ErrorMsg(pParse, + "filter clause may not be used with non-aggregate %.*s()", + nId, zId + ); + pNC->nErr++; } #else if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) ){ @@ -883,7 +889,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ sqlite3WalkExprList(pWalker, pList); if( is_agg ){ #ifndef SQLITE_OMIT_WINDOWFUNC - if( pExpr->y.pWin ){ + if( ExprHasProperty(pExpr, EP_WinFunc) ){ Select *pSel = pNC->pWinSelect; if( IN_RENAME_OBJECT==0 ){ sqlite3WindowUpdate(pParse, pSel->pWinDefn, pExpr->y.pWin, pDef); @@ -904,6 +910,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ NameContext *pNC2 = pNC; pExpr->op = TK_AGG_FUNCTION; pExpr->op2 = 0; +#ifndef SQLITE_OMIT_WINDOWFUNC + sqlite3WalkExpr(pWalker, pExpr->y.pFilter); +#endif while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){ pExpr->op2++; pNC2 = pNC2->pNext; diff --git a/src/select.c b/src/select.c index bd16acb02..e5f57fede 100644 --- a/src/select.c +++ b/src/select.c @@ -4406,7 +4406,9 @@ static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){ assert( *ppMinMax==0 ); assert( pFunc->op==TK_AGG_FUNCTION ); - if( pEList==0 || pEList->nExpr!=1 ) return eRet; + if( pEList==0 || pEList->nExpr!=1 || ExprHasProperty(pFunc, EP_Filter) ){ + return eRet; + } zFunc = pFunc->u.zToken; if( sqlite3StrICmp(zFunc, "min")==0 ){ eRet = WHERE_ORDERBY_MIN; @@ -4453,7 +4455,7 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){ if( pExpr->op!=TK_AGG_FUNCTION ) return 0; if( NEVER(pAggInfo->nFunc==0) ) return 0; if( (pAggInfo->aFunc[0].pFunc->funcFlags&SQLITE_FUNC_COUNT)==0 ) return 0; - if( pExpr->flags&EP_Distinct ) return 0; + if( ExprHasProperty(pExpr, EP_Distinct|EP_Filter) ) return 0; return pTab; } @@ -5333,6 +5335,11 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){ int regAgg; ExprList *pList = pF->pExpr->x.pList; assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) ); + if( ExprHasProperty(pF->pExpr, EP_Filter) ){ + Expr *pFilter = pF->pExpr->y.pFilter; + addrNext = sqlite3VdbeMakeLabel(pParse); + sqlite3ExprIfFalse(pParse, pFilter, addrNext, SQLITE_JUMPIFNULL); + } if( pList ){ nArg = pList->nExpr; regAgg = sqlite3GetTempRange(pParse, nArg); @@ -5342,7 +5349,9 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){ regAgg = 0; } if( pF->iDistinct>=0 ){ - addrNext = sqlite3VdbeMakeLabel(pParse); + if( addrNext==0 ){ + addrNext = sqlite3VdbeMakeLabel(pParse); + } testcase( nArg==0 ); /* Error condition */ testcase( nArg>1 ); /* Also an error */ codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg); @@ -6225,9 +6234,14 @@ int sqlite3Select( minMaxFlag = WHERE_ORDERBY_NORMAL; } for(i=0; i<sAggInfo.nFunc; i++){ - assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) ); + Expr *pExpr = sAggInfo.aFunc[i].pExpr; + assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); sNC.ncFlags |= NC_InAggFunc; - sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList); + sqlite3ExprAnalyzeAggList(&sNC, pExpr->x.pList); +#ifndef SQLITE_OMIT_WINDOWFUNC + assert( !ExprHasProperty(pExpr, EP_WinFunc) ); + sqlite3ExprAnalyzeAggregates(&sNC, pExpr->y.pFilter); +#endif sNC.ncFlags &= ~NC_InAggFunc; } sAggInfo.mxReg = pParse->nMem; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 1c4618331..c0f2e0a18 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2491,7 +2491,8 @@ struct Expr { union { Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL ** for a column of an index on an expression */ - Window *pWin; /* TK_FUNCTION: Window definition for the func */ + Window *pWin; /* EP_WinFunc: Window definition for the func */ + Expr *pFilter; /* EP_Filter: Filter definition for the func */ struct { /* TK_IN, TK_SELECT, and TK_EXISTS */ int iAddr; /* Subroutine entry address */ int regReturn; /* Register used to hold return address */ @@ -2536,6 +2537,7 @@ struct Expr { #define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */ #define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */ #define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */ +#define EP_Filter 0x40000000 /* TK_[AGG_]FUNCTION with Expr.y.pFilter set */ /* ** The EP_Propagate mask is a set of properties that automatically propagate @@ -3602,7 +3604,7 @@ struct Window { void sqlite3WindowDelete(sqlite3*, Window*); void sqlite3WindowListDelete(sqlite3 *db, Window *p); Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8); -void sqlite3WindowAttach(Parse*, Expr*, Window*); +void sqlite3WindowAttach(Parse*, Expr*, Expr*, Window*); int sqlite3WindowCompare(Parse*, Window*, Window*); void sqlite3WindowCodeInit(Parse*, Window*); void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int); @@ -3617,7 +3619,7 @@ Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprList*, Token*); #else # define sqlite3WindowDelete(a,b) # define sqlite3WindowFunctions() -# define sqlite3WindowAttach(a,b,c) +# define sqlite3WindowAttach(a,b,c,d) #endif /* diff --git a/src/walker.c b/src/walker.c index eff358525..766a345ad 100644 --- a/src/walker.c +++ b/src/walker.c @@ -74,6 +74,9 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){ if( ExprHasProperty(pExpr, EP_WinFunc) ){ if( walkWindowList(pWalker, pExpr->y.pWin) ) return WRC_Abort; } + if( ExprHasProperty(pExpr, EP_Filter) ){ + if( walkExpr(pWalker, pExpr->y.pFilter) ) return WRC_Abort; + } #endif } break; diff --git a/src/window.c b/src/window.c index 737261e85..4d7ebf608 100644 --- a/src/window.c +++ b/src/window.c @@ -1178,13 +1178,10 @@ void sqlite3WindowChain(Parse *pParse, Window *pWin, Window *pList){ /* ** Attach window object pWin to expression p. */ -void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ +void sqlite3WindowAttach(Parse *pParse, Expr *p, Expr *pFilter, Window *pWin){ if( p ){ assert( p->op==TK_FUNCTION ); - /* This routine is only called for the parser. If pWin was not - ** allocated due to an OOM, then the parser would fail before ever - ** invoking this routine */ - if( ALWAYS(pWin) ){ + if( pWin ){ p->y.pWin = pWin; ExprSetProperty(p, EP_WinFunc); pWin->pOwner = p; @@ -1192,9 +1189,14 @@ void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ sqlite3ErrorMsg(pParse, "DISTINCT is not supported for window functions"); } + pWin->pFilter = pFilter; + }else if( pFilter ){ + p->y.pFilter = pFilter; + ExprSetProperty(p, EP_Filter); } }else{ sqlite3WindowDelete(pParse->db, pWin); + sqlite3ExprDelete(pParse->db, pFilter); } } |