145 lines
4.6 KiB
Diff
145 lines
4.6 KiB
Diff
|
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
|