Index: src/expr.c ================================================================== --- src/expr.c +++ src/expr.c @@ -1327,10 +1327,39 @@ return pRet; } #else # define withDup(x,y) 0 #endif + +#ifndef SQLITE_OMIT_WINDOWFUNC +/* +** The gatherSelectWindows() procedure and its helper routine +** gatherSelectWindowsCallback() are used to scan all the expressions +** an a newly duplicated SELECT statement and gather all of the Window +** 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) ); + pExpr->y.pWin->pNextWin = pWalker->u.pSelect->pWin; + pWalker->u.pSelect->pWin = pExpr->y.pWin; + } + return WRC_Continue; +} +static int gatherSelectWindowsSelectCallback(Walker *pWalker, Select *p){ + return p==pWalker->u.pSelect ? WRC_Continue : WRC_Prune; +} +static void gatherSelectWindows(Select *p){ + Walker w; + w.xExprCallback = gatherSelectWindowsCallback; + w.xSelectCallback = gatherSelectWindowsSelectCallback; + w.xSelectCallback2 = 0; + w.u.pSelect = p; + sqlite3WalkSelect(&w, p); +} +#endif + /* ** The following group of routines make deep copies of expressions, ** expression lists, ID lists, and select statements. The copies can ** be deleted (by being passed to their respective ...Delete() routines) @@ -1495,10 +1524,11 @@ pNew->nSelectRow = p->nSelectRow; pNew->pWith = withDup(db, p->pWith); #ifndef SQLITE_OMIT_WINDOWFUNC pNew->pWin = 0; pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn); + if( p->pWin ) gatherSelectWindows(pNew); #endif pNew->selId = p->selId; *pp = pNew; pp = &pNew->pPrior; pNext = pNew; Index: src/select.c ================================================================== --- src/select.c +++ src/select.c @@ -3459,10 +3459,11 @@ ifNullRow.op = TK_IF_NULL_ROW; ifNullRow.pLeft = pCopy; ifNullRow.iTable = pSubst->iNewTable; pCopy = &ifNullRow; } + testcase( ExprHasProperty(pCopy, EP_Subquery) ); pNew = sqlite3ExprDup(db, pCopy, 0); if( pNew && pSubst->isLeftJoin ){ ExprSetProperty(pNew, EP_CanBeNull); } if( pNew && ExprHasProperty(pExpr,EP_FromJoin) ){ @@ -4023,11 +4024,12 @@ } assert( pParent->pOrderBy==0 ); pParent->pOrderBy = pOrderBy; pSub->pOrderBy = 0; } - pWhere = sqlite3ExprDup(db, pSub->pWhere, 0); + pWhere = pSub->pWhere; + pSub->pWhere = 0; if( isLeftJoin>0 ){ setJoinExpr(pWhere, iNewParent); } pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere); if( db->mallocFailed==0 ){ Index: src/window.c ================================================================== --- src/window.c +++ src/window.c @@ -2131,10 +2131,11 @@ if( ALWAYS(p) ){ pNew = sqlite3DbMallocZero(db, sizeof(Window)); if( pNew ){ pNew->zName = sqlite3DbStrDup(db, p->zName); pNew->pFilter = sqlite3ExprDup(db, p->pFilter, 0); + pNew->pFunc = p->pFunc; pNew->pPartition = sqlite3ExprListDup(db, p->pPartition, 0); pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, 0); pNew->eType = p->eType; pNew->eEnd = p->eEnd; pNew->eStart = p->eStart; Index: test/window1.test ================================================================== --- test/window1.test +++ test/window1.test @@ -591,7 +591,34 @@ SELECT a, rank() OVER(ORDER BY b) FROM t1 INTERSECT SELECT a, rank() OVER(ORDER BY b DESC) FROM t1; } { } + +# 2018-12-06 +# https://www.sqlite.org/src/info/f09fcd17810f65f7 +# Assertion fault when window functions are used. +# +# Root cause is the query flattener invoking sqlite3ExprDup() on +# expressions that contain subqueries with window functions. The +# sqlite3ExprDup() routine is not making correctly initializing +# Select.pWin field of the subqueries. +# +sqlite3 db :memory: +do_execsql_test 14.0 { + SELECT * FROM( + SELECT * FROM (SELECT 1 AS c) WHERE c IN ( + SELECT (row_number() OVER()) FROM (VALUES (0)) + ) + ); +} {1} +do_execsql_test 14.1 { + CREATE TABLE t1(x); INSERT INTO t1(x) VALUES(12345); + CREATE TABLE t2(c); INSERT INTO t2(c) VALUES(1); + SELECT y, y+1, y+2 FROM ( + SELECT c IN ( + SELECT (row_number() OVER()) FROM t1 + ) AS y FROM t2 + ); +} {1 2 3} finish_test