Index: src/expr.c ================================================================== --- src/expr.c +++ src/expr.c @@ -1180,28 +1180,10 @@ } } return nByte; } -static Window *winDup(sqlite3 *db, Window *p){ - Window *pNew = 0; - if( p ){ - pNew = sqlite3DbMallocZero(db, sizeof(Window)); - if( pNew ){ - pNew->pFilter = sqlite3ExprDup(db, p->pFilter, 0); - 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; - pNew->pStart = sqlite3ExprDup(db, pNew->pStart, 0); - pNew->pEnd = sqlite3ExprDup(db, pNew->pEnd, 0); - } - } - return pNew; -} - /* ** This function is similar to sqlite3ExprDup(), except that if pzBuffer ** is not NULL then *pzBuffer is assumed to point to a buffer large enough ** to store the copy of expression p, the copies of p->u.zToken ** (if applicable), and the copies of the p->pLeft and p->pRight expressions, @@ -1287,11 +1269,11 @@ } }else{ if( ExprHasProperty(p, EP_Reduced|EP_TokenOnly) ){ pNew->pWin = 0; }else{ - pNew->pWin = winDup(db, p->pWin); + pNew->pWin = sqlite3WindowDup(db, p->pWin); } if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ if( pNew->op==TK_SELECT_COLUMN ){ pNew->pLeft = p->pLeft; assert( p->iColumn==0 || p->pRight==0 ); Index: src/select.c ================================================================== --- src/select.c +++ src/select.c @@ -3710,11 +3710,11 @@ pSubitem = &pSrc->a[iFrom]; iParent = pSubitem->iCursor; pSub = pSubitem->pSelect; assert( pSub!=0 ); - if( p->pWin ) return 0; + if( p->pWin || pSub->pWin ) return 0; pSubSrc = pSub->pSrc; assert( pSubSrc ); /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants, ** not arbitrary expressions, we allowed some combining of LIMIT and OFFSET @@ -5896,30 +5896,22 @@ } assert( p->pEList==pEList ); if( pWin ){ int addrGosub = sqlite3VdbeMakeLabel(v); + int iCont = sqlite3VdbeMakeLabel(v); int regGosub = ++pParse->nMem; int addr = 0; - int bLoop = 0; + + sqlite3WindowCodeStep(pParse, p, pWInfo, regGosub, addrGosub); - sqlite3WindowCodeStep(pParse, p, pWInfo, regGosub, addrGosub, &bLoop); - - sqlite3VdbeAddOp0(v, OP_Goto); + addr = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeResolveLabel(v, addrGosub); - if( bLoop ){ - addr = sqlite3VdbeAddOp1(v, OP_Rewind, pWin->iEphCsr); - }else{ - addr = sqlite3VdbeCurrentAddr(v); - } - selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, addr+1, 0); - if( bLoop ){ - sqlite3VdbeAddOp2(v, OP_Next, pWin->iEphCsr, addr+1); - sqlite3VdbeJumpHere(v, addr); - } + selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, iCont, 0); + sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp1(v, OP_Return, regGosub); - sqlite3VdbeJumpHere(v, addr-1); /* OP_Goto jumps here */ + sqlite3VdbeJumpHere(v, addr); }else{ /* Use the standard inner loop. */ selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, sqlite3WhereContinueLabel(pWInfo), Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -3500,14 +3500,15 @@ void sqlite3WindowDelete(sqlite3*, Window*); Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*); void sqlite3WindowAttach(Parse*, Expr*, Window*); int sqlite3WindowCompare(Parse*, Window*, Window*); void sqlite3WindowCodeInit(Parse*, Window*); -void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int, int*); +void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int); int sqlite3WindowRewrite(Parse*, Select*); int sqlite3ExpandSubquery(Parse*, struct SrcList_item*); void sqlite3WindowUpdate(Parse*, Window*, FuncDef*); +Window *sqlite3WindowDup(sqlite3 *db, Window *p); /* ** Assuming zIn points to the first byte of a UTF-8 character, ** advance zIn to point to the first byte of the next UTF-8 character. */ Index: src/window.c ================================================================== --- src/window.c +++ src/window.c @@ -1558,11 +1558,14 @@ } windowAggFinal(pParse, pMWin, pMWin->eStart==TK_CURRENT); if( addrGoto ) sqlite3VdbeJumpHere(v, addrGoto); } + sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr,sqlite3VdbeCurrentAddr(v)+3); sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub); + sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)-1); + sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr); sqlite3VdbeAddOp3( v, OP_Copy, reg+pMWin->nBufferCol, pMWin->regPart, nPart+nPeer-1 ); @@ -1584,13 +1587,32 @@ /* End the database scan loop. */ sqlite3WhereEnd(pWInfo); windowAggFinal(pParse, pMWin, 1); + sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr,sqlite3VdbeCurrentAddr(v)+3); sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub); + sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)-1); } +Window *sqlite3WindowDup(sqlite3 *db, Window *p){ + Window *pNew = 0; + if( p ){ + pNew = sqlite3DbMallocZero(db, sizeof(Window)); + if( pNew ){ + pNew->pFilter = sqlite3ExprDup(db, p->pFilter, 0); + 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; + pNew->pStart = sqlite3ExprDup(db, pNew->pStart, 0); + pNew->pEnd = sqlite3ExprDup(db, pNew->pEnd, 0); + } + } + return pNew; +} /* ** RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ** ** As above, except take no action for a "new peer". Invoke @@ -1647,17 +1669,15 @@ void sqlite3WindowCodeStep( Parse *pParse, Select *p, WhereInfo *pWInfo, int regGosub, - int addrGosub, - int *pbLoop + int addrGosub ){ Window *pMWin = p->pWin; Window *pWin; - *pbLoop = 0; if( (pMWin->eType==TK_ROWS && (pMWin->eStart!=TK_UNBOUNDED||pMWin->eEnd!=TK_CURRENT||!pMWin->pOrderBy)) || (pMWin->eStart==TK_CURRENT&&pMWin->eEnd==TK_UNBOUNDED&&pMWin->pOrderBy) ){ windowCodeRowExprStep(pParse, p, pWInfo, regGosub, addrGosub); @@ -1675,9 +1695,8 @@ windowCodeCacheStep(pParse, p, pWInfo, regGosub, addrGosub); return; } } - *pbLoop = 1; windowCodeDefaultStep(pParse, p, pWInfo, regGosub, addrGosub); } Index: test/window1.test ================================================================== --- test/window1.test +++ test/window1.test @@ -192,8 +192,27 @@ } {1 {argument of ntile must be a positive integer}} do_execsql_test 5.4 { CREATE TABLE t4(a, b); SELECT ntile(1) OVER (ORDER BY a) FROM t4; } {} + +#------------------------------------------------------------------------- +reset_db +do_execsql_test 6.1 { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(7), (6), (5), (4), (3), (2), (1); + + CREATE TABLE t2(x); + INSERT INTO t2 VALUES('b'), ('a'); + + SELECT x, count(*) OVER (ORDER BY x) FROM t1; +} {1 1 2 2 3 3 4 4 5 5 6 6 7 7} + +do_execsql_test 6.2 { + SELECT * FROM t2, (SELECT x, count(*) OVER (ORDER BY x) FROM t1); +} { + b 1 1 b 2 2 b 3 3 b 4 4 b 5 5 b 6 6 b 7 7 + a 1 1 a 2 2 a 3 3 a 4 4 a 5 5 a 6 6 a 7 7 +} finish_test