Subject: [PATCH] When rewriting a query for window functions, if the rewrite changes the depth of TK_AGG_FUNCTION nodes, be sure to adjust the Expr.op2 field appropriately. diff --git a/src/resolve.c b/src/resolve.c index cdcf4d9..c47f6bb 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -24,6 +24,8 @@ ** ** incrAggFunctionDepth(pExpr,n) is the main routine. incrAggDepth(..) ** is a helper function - a callback for the tree walker. +** +** See also the sqlite3WindowExtraAggFuncDepth() routine in window.c */ static int incrAggDepth(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n; diff --git a/src/select.c b/src/select.c index a6d1757..6f5570c 100644 --- a/src/select.c +++ b/src/select.c @@ -1961,7 +1961,7 @@ int sqlite3ColumnsFromExprList( assert( pColExpr!=0 ); } assert( pColExpr->op!=TK_AGG_COLUMN ); - if( pColExpr->op==TK_COLUMN ){ + if( pColExpr->op==TK_COLUMN && pColExpr->y.pTab ){ /* For columns use the column name name */ int iCol = pColExpr->iColumn; Table *pTab = pColExpr->y.pTab; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 1cf6937..ea9a7ae 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3579,6 +3579,8 @@ void sqlite3WindowUpdate(Parse*, Window*, Window*, FuncDef*); Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p); Window *sqlite3WindowListDup(sqlite3 *db, Window *p); void sqlite3WindowFunctions(void); +int sqlite3WalkerDepthIncrease(Walker*,Select*); +void sqlite3WalkerDepthDecrease(Walker*,Select*); #else # define sqlite3WindowDelete(a,b) # define sqlite3WindowFunctions() diff --git a/src/walker.c b/src/walker.c index c31d94f..8cd3b65 100644 --- a/src/walker.c +++ b/src/walker.c @@ -165,3 +165,16 @@ int sqlite3WalkSelect(Walker *pWalker, Select *p){ }while( p!=0 ); return WRC_Continue; } + +/* Increase the walkerDepth when entering a subquery, and +** descrease when leaving the subquery. +*/ +int sqlite3WalkerDepthIncrease(Walker *pWalker, Select *pSelect){ + UNUSED_PARAMETER(pSelect); + pWalker->walkerDepth++; + return WRC_Continue; +} +void sqlite3WalkerDepthDecrease(Walker *pWalker, Select *pSelect){ + UNUSED_PARAMETER(pSelect); + pWalker->walkerDepth--; +} \ No newline at end of file diff --git a/src/window.c b/src/window.c index c65eadd..48d8090 100644 --- a/src/window.c +++ b/src/window.c @@ -738,6 +738,23 @@ static ExprList *exprListAppendList( return pList; } +/* +** When rewriting a query, if the new subquery in the FROM clause +** contains TK_AGG_FUNCTION nodes that refer to an outer query, +** then we have to increase the Expr->op2 values of those nodes +** due to the extra subquery layer that was added. +** +** See also the incrAggDepth() routine in resolve.c +*/ +static int sqlite3WindowExtraAggFuncDepth(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_AGG_FUNCTION + && pExpr->op2>=pWalker->walkerDepth + ){ + pExpr->op2++; + } + return WRC_Continue; +} + /* ** If the SELECT statement passed as the second argument does not invoke ** any SQL window functions, this function is a no-op. Otherwise, it @@ -827,14 +844,24 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){ p->pSrc = sqlite3SrcListAppend(db, 0, 0, 0); assert( p->pSrc || db->mallocFailed ); if( p->pSrc ){ + Table *pTab2; + Walker w; p->pSrc->a[0].pSelect = pSub; sqlite3SrcListAssignCursors(pParse, p->pSrc); - if( sqlite3ExpandSubquery(pParse, &p->pSrc->a[0]) ){ + pTab2 = sqlite3ResultSetOfSelect(pParse, pSub); + if( pTab2==0 ){ rc = SQLITE_NOMEM; }else{ pSub->selFlags |= SF_Expanded; p->selFlags &= ~SF_Aggregate; sqlite3SelectPrep(pParse, pSub, 0); + pTab2->tabFlags |= TF_Ephemeral; + p->pSrc->a[0].pTab = pTab2; + memset(&w, 0, sizeof(w)); + w.xExprCallback = sqlite3WindowExtraAggFuncDepth; + w.xSelectCallback = sqlite3WalkerDepthIncrease; + w.xSelectCallback2 = sqlite3WalkerDepthDecrease; + sqlite3WalkSelect(&w, pSub); } sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, pSublist->nExpr); diff --git a/test/window1.test b/test/window1.test index a8399a8..13ecc32 100644 --- a/test/window1.test +++ b/test/window1.test @@ -594,4 +594,20 @@ do_execsql_test 13.5 { } { } +# 2020-05-23 +# ticket 7a5279a25c57adf1 +# +reset_db +do_execsql_test 53.0 { + CREATE TABLE a(c UNIQUE); + INSERT INTO a VALUES(4),(0),(9),(-9); + SELECT a.c + FROM a + JOIN a AS b ON a.c=4 + JOIN a AS e ON a.c=e.c + WHERE a.c=(SELECT (SELECT coalesce(lead(2) OVER(),0) + sum(d.c)) + FROM a AS d + WHERE a.c); +} {4 4 4 4} + finish_test