Index: ext/misc/json1.c ================================================================== --- ext/misc/json1.c +++ ext/misc/json1.c @@ -1846,13 +1846,11 @@ int i; int inStr = 0; char *z; JsonString *pStr; pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); - /* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will - ** always have been called to initalize it */ - if( NEVER(!pStr) ) return; + if( !pStr ) return; z = pStr->zBuf; for(i=1; z[i]!=',' || inStr; i++){ assert( inUsed ); if( z[i]=='"' ){ inStr = !inStr; Index: src/func.c ================================================================== --- src/func.c +++ src/func.c @@ -1519,13 +1519,11 @@ int type; assert( argc==1 ); UNUSED_PARAMETER(argc); p = sqlite3_aggregate_context(context, sizeof(*p)); type = sqlite3_value_numeric_type(argv[0]); - /* p is always non-NULL because sumStep() will have been called first - ** to initialize it */ - if( ALWAYS(p) && type!=SQLITE_NULL ){ + if( p && type!=SQLITE_NULL ){ p->cnt--; if( type==SQLITE_INTEGER ){ i64 v = sqlite3_value_int64(argv[0]); p->rSum -= v; if( (p->approx|p->overflow)==0 && sqlite3AddInt64(&p->iSum, -1*v) ){ @@ -1605,12 +1603,11 @@ } #ifndef SQLITE_OMIT_WINDOWFUNC static void countInverse(sqlite3_context *ctx, int argc, sqlite3_value **argv){ CountCtx *p; p = sqlite3_aggregate_context(ctx, sizeof(*p)); - /* p is always non-NULL since countStep() will have been called first */ - if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && ALWAYS(p) ){ + if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && p ){ p->n--; #ifdef SQLITE_DEBUG p->bInverse = 1; #endif } @@ -1725,13 +1722,11 @@ int n; assert( argc==1 || argc==2 ); StrAccum *pAccum; if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum)); - /* pAccum is always non-NULL since groupConcatStep() will have always - ** run frist to initialize it */ - if( ALWAYS(pAccum) ){ + if( pAccum ){ n = sqlite3_value_bytes(argv[0]); if( argc==2 ){ n += sqlite3_value_bytes(argv[1]); }else{ n++; Index: src/parse.y ================================================================== --- src/parse.y +++ src/parse.y @@ -1026,14 +1026,14 @@ . { if( Y && Y->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ sqlite3ErrorMsg(pParse, "too many arguments on function %T", &X); } A = sqlite3ExprFunction(pParse, Y, &X); + sqlite3WindowAttach(pParse, A, Z); if( D==SF_Distinct && A ){ A->flags |= EP_Distinct; } - sqlite3WindowAttach(pParse, A, Z); } expr(A) ::= id(X) LP STAR RP %ifndef SQLITE_OMIT_WINDOWFUNC over_opt(Z) %endif @@ -1639,14 +1639,10 @@ %type range_or_rows {int} %type frame_bound {struct FrameBound} %destructor frame_bound {sqlite3ExprDelete(pParse->db, $$.pExpr);} -%type frame_bound_s {struct FrameBound} -%destructor frame_bound_s {sqlite3ExprDelete(pParse->db, $$.pExpr);} -%type frame_bound_e {struct FrameBound} -%destructor frame_bound_e {sqlite3ExprDelete(pParse->db, $$.pExpr);} window_or_nm(A) ::= window(Z). {A = Z;} window_or_nm(A) ::= nm(Z). { A = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( A ){ @@ -1666,29 +1662,25 @@ part_opt(A) ::= . { A = 0; } frame_opt(A) ::= . { A = sqlite3WindowAlloc(pParse, TK_RANGE, TK_UNBOUNDED, 0, TK_CURRENT, 0); } -frame_opt(A) ::= range_or_rows(X) frame_bound_s(Y). { +frame_opt(A) ::= range_or_rows(X) frame_bound(Y). { A = sqlite3WindowAlloc(pParse, X, Y.eType, Y.pExpr, TK_CURRENT, 0); } -frame_opt(A) ::= range_or_rows(X) BETWEEN frame_bound_s(Y) AND frame_bound_e(Z). { +frame_opt(A) ::= range_or_rows(X) BETWEEN frame_bound(Y) AND frame_bound(Z). { A = sqlite3WindowAlloc(pParse, X, Y.eType, Y.pExpr, Z.eType, Z.pExpr); } range_or_rows(A) ::= RANGE. { A = TK_RANGE; } range_or_rows(A) ::= ROWS. { A = TK_ROWS; } - -frame_bound_s(A) ::= frame_bound(X). { A = X; } -frame_bound_s(A) ::= UNBOUNDED PRECEDING. {A.eType = TK_UNBOUNDED; A.pExpr = 0;} -frame_bound_e(A) ::= frame_bound(X). { A = X; } -frame_bound_e(A) ::= UNBOUNDED FOLLOWING. {A.eType = TK_UNBOUNDED; A.pExpr = 0;} - +frame_bound(A) ::= UNBOUNDED PRECEDING. { A.eType = TK_UNBOUNDED; A.pExpr = 0; } frame_bound(A) ::= expr(X) PRECEDING. { A.eType = TK_PRECEDING; A.pExpr = X; } frame_bound(A) ::= CURRENT ROW. { A.eType = TK_CURRENT ; A.pExpr = 0; } frame_bound(A) ::= expr(X) FOLLOWING. { A.eType = TK_FOLLOWING; A.pExpr = X; } +frame_bound(A) ::= UNBOUNDED FOLLOWING. { A.eType = TK_UNBOUNDED; A.pExpr = 0; } %type windowdefn_opt {Window*} %destructor windowdefn_opt {sqlite3WindowDelete(pParse->db, $$);} windowdefn_opt(A) ::= . { A = 0; } windowdefn_opt(A) ::= WINDOW windowdefn_list(B). { A = B; } Index: src/select.c ================================================================== --- src/select.c +++ src/select.c @@ -5185,11 +5185,11 @@ pColl = pParse->db->pDfltColl; } if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem; sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ); } - sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, pF->iMem); + sqlite3VdbeAddOp3(v, OP_AggStep0, 0, regAgg, pF->iMem); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nArg); sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg); sqlite3ReleaseTempRange(pParse, regAgg, nArg); if( addrNext ){ Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -1153,13 +1153,10 @@ pOut = out2Prerelease(p, pOp); cnt = pOp->p3-pOp->p2; assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null; pOut->n = 0; -#ifdef SQLITE_DEBUG - pOut->uTemp = 0; -#endif while( cnt>0 ){ pOut++; memAboutToChange(p, pOut); sqlite3VdbeMemSetNull(pOut); pOut->flags = nullFlag; @@ -6289,33 +6286,22 @@ if( pIn1->u.i==0 ) goto jump_to_p2; break; } -/* Opcode: AggStep * P2 P3 P4 P5 +/* Opcode: AggStep0 P1 P2 P3 P4 P5 ** Synopsis: accum=r[P3] step(r[P2@P5]) ** -** Execute the xStep function for an aggregate. -** The function has P5 arguments. P4 is a pointer to the +** Execute the xStep (if P1==0) or xInverse (if P1!=0) function for an +** aggregate. The function has P5 arguments. P4 is a pointer to the ** FuncDef structure that specifies the function. Register P3 is the ** accumulator. ** ** The P5 arguments are taken from register P2 and its ** successors. */ -/* Opcode: AggInverse * P2 P3 P4 P5 -** Synopsis: accum=r[P3] inverse(r[P2@P5]) -** -** Execute the xInverse function for an aggregate. -** The function has P5 arguments. P4 is a pointer to the -** FuncDef structure that specifies the function. Register P3 is the -** accumulator. -** -** The P5 arguments are taken from register P2 and its -** successors. -*/ -/* Opcode: AggStep1 P1 P2 P3 P4 P5 +/* Opcode: AggStep P1 P2 P3 P4 P5 ** Synopsis: accum=r[P3] step(r[P2@P5]) ** ** Execute the xStep (if P1==0) or xInverse (if P1!=0) function for an ** aggregate. The function has P5 arguments. P4 is a pointer to the ** FuncDef structure that specifies the function. Register P3 is the @@ -6328,12 +6314,11 @@ ** the FuncDef stored in P4 is converted into an sqlite3_context and ** the opcode is changed. In this way, the initialization of the ** sqlite3_context only happens once, instead of on each call to the ** step function. */ -case OP_AggInverse: -case OP_AggStep: { +case OP_AggStep0: { int n; sqlite3_context *pCtx; assert( pOp->p4type==P4_FUNCDEF ); n = pOp->p5; @@ -6352,37 +6337,22 @@ pCtx->skipFlag = 0; pCtx->isError = 0; pCtx->argc = n; pOp->p4type = P4_FUNCCTX; pOp->p4.pCtx = pCtx; - - /* OP_AggInverse must have P1==1 and OP_AggStep must have P1==0 */ - assert( pOp->p1==(pOp->opcode==OP_AggInverse) ); - - pOp->opcode = OP_AggStep1; + pOp->opcode = OP_AggStep; /* Fall through into OP_AggStep */ } -case OP_AggStep1: { +case OP_AggStep: { int i; sqlite3_context *pCtx; Mem *pMem; assert( pOp->p4type==P4_FUNCCTX ); pCtx = pOp->p4.pCtx; pMem = &aMem[pOp->p3]; -#ifdef SQLITE_DEBUG - if( pOp->p1 ){ - /* This is an OP_AggInverse call. Verify that xStep has always - ** been called at least once prior to any xInverse call. */ - assert( pMem->uTemp==0x1122e0e3 ); - }else{ - /* This is an OP_AggStep call. Mark it as such. */ - pMem->uTemp = 0x1122e0e3; - } -#endif - /* If this function is inside of a trigger, the register array in aMem[] ** might change from one evaluation to the next. The next block of code ** checks to see if the register array has changed, and if so it ** reinitializes the relavant parts of the sqlite3_context object */ if( pCtx->pMem != pMem ){ @@ -6427,52 +6397,37 @@ assert( pCtx->pOut->flags==MEM_Null ); assert( pCtx->skipFlag==0 ); break; } -/* Opcode: AggFinal P1 P2 * P4 * +/* Opcode: AggFinal P1 P2 P3 P4 * ** Synopsis: accum=r[P1] N=P2 ** ** P1 is the memory location that is the accumulator for an aggregate -** or window function. Execute the finalizer function -** for an aggregate and store the result in P1. +** or window function. If P3 is zero, then execute the finalizer function +** for an aggregate and store the result in P1. Or, if P3 is non-zero, +** invoke the xValue() function and store the result in register P3. ** ** P2 is the number of arguments that the step function takes and ** P4 is a pointer to the FuncDef for this function. The P2 ** argument is not used by this opcode. It is only there to disambiguate ** functions that can take varying numbers of arguments. The ** P4 argument is only needed for the case where ** the step function was not previously called. */ -/* Opcode: AggValue * P2 P3 P4 * -** Synopsis: r[P3]=value N=P2 -** -** Invoke the xValue() function and store the result in register P3. -** -** P2 is the number of arguments that the step function takes and -** P4 is a pointer to the FuncDef for this function. The P2 -** argument is not used by this opcode. It is only there to disambiguate -** functions that can take varying numbers of arguments. The -** P4 argument is only needed for the case where -** the step function was not previously called. -*/ -case OP_AggValue: case OP_AggFinal: { Mem *pMem; assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); - assert( pOp->p3==0 || pOp->opcode==OP_AggValue ); pMem = &aMem[pOp->p1]; assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 ); #ifndef SQLITE_OMIT_WINDOWFUNC if( pOp->p3 ){ rc = sqlite3VdbeMemAggValue(pMem, &aMem[pOp->p3], pOp->p4.pFunc); pMem = &aMem[pOp->p3]; }else #endif - { - rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc); - } + rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc); if( rc ){ sqlite3VdbeError(p, "%s", sqlite3_value_text(pMem)); goto abort_due_to_error; } Index: src/vdbe.h ================================================================== --- src/vdbe.h +++ src/vdbe.h @@ -241,10 +241,11 @@ int sqlite3VdbeLabelHasBeenResolved(Vdbe*,int); #endif int sqlite3VdbeCurrentAddr(Vdbe*); #ifdef SQLITE_DEBUG int sqlite3VdbeAssertMayAbort(Vdbe *, int); + int sqlite3VdbeAssertAggContext(sqlite3_context*); #endif void sqlite3VdbeResetStepResult(Vdbe*); void sqlite3VdbeRewind(Vdbe*); int sqlite3VdbeReset(Vdbe*); void sqlite3VdbeSetNumCols(Vdbe*,int); Index: src/vdbeapi.c ================================================================== --- src/vdbeapi.c +++ src/vdbeapi.c @@ -822,10 +822,22 @@ }else{ return (void*)p->pMem->z; } } +/* +** This function is only used within assert() statements to check that the +** aggregate context has already been allocated. i.e.: +** +** assert( sqlite3VdbeAssertAggContext(p) ); +*/ +#ifdef SQLITE_DEBUG +int sqlite3VdbeAssertAggContext(sqlite3_context *p){ + return ((p->pMem->flags & MEM_Agg)!=0); +} +#endif /* SQLITE_DEBUG */ + /* ** Return the auxiliary data pointer, if any, for the iArg'th argument to ** the user-function defined by pCtx. ** ** The left-most argument is 0. Index: src/vdbemem.c ================================================================== --- src/vdbemem.c +++ src/vdbemem.c @@ -433,11 +433,10 @@ assert( pAccum->db==0 || sqlite3_mutex_held(pAccum->db->mutex) ); memset(&ctx, 0, sizeof(ctx)); memset(&t, 0, sizeof(t)); t.flags = MEM_Null; t.db = pAccum->db; - sqlite3VdbeMemSetNull(pOut); ctx.pOut = pOut; ctx.pMem = pAccum; ctx.pFunc = pFunc; pFunc->xValue(&ctx); return ctx.isError; Index: src/window.c ================================================================== --- src/window.c +++ src/window.c @@ -253,12 +253,13 @@ sqlite3_value **apArg ){ struct CallCount *p; assert( nArg==1 ); + assert( sqlite3VdbeAssertAggContext(pCtx) ); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); - if( p ){ + if( ALWAYS(p) ){ if( p->nTotal==0 ){ p->nTotal = sqlite3_value_int64(apArg[0]); } p->nStep++; if( p->nValue==0 ){ @@ -298,12 +299,13 @@ sqlite3_value **apArg ){ struct CallCount *p; assert( nArg==1 ); + assert( sqlite3VdbeAssertAggContext(pCtx) ); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); - if( p ){ + if( ALWAYS(p) ){ if( p->nTotal==0 ){ p->nTotal = sqlite3_value_int64(apArg[0]); } p->nStep++; } @@ -825,104 +827,50 @@ p = pNext; } } /* -** The argument expression is an PRECEDING or FOLLOWING offset. The -** value should be a non-negative integer. If the value is not a -** constant, change it to NULL. The fact that it is then a non-negative -** integer will be caught later. But it is important not to leave -** variable values in the expression tree. -*/ -static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){ - if( 0==sqlite3ExprIsConstant(pExpr) ){ - sqlite3ExprDelete(pParse->db, pExpr); - pExpr = sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0); - } - return pExpr; -} - -/* -** Allocate and return a new Window object describing a Window Definition. +** Allocate and return a new Window object. */ Window *sqlite3WindowAlloc( - Parse *pParse, /* Parsing context */ - int eType, /* Frame type. TK_RANGE or TK_ROWS */ - int eStart, /* Start type: CURRENT, PRECEDING, FOLLOWING, UNBOUNDED */ - Expr *pStart, /* Start window size if TK_PRECEDING or FOLLOWING */ - int eEnd, /* End type: CURRENT, FOLLOWING, TK_UNBOUNDED, PRECEDING */ - Expr *pEnd /* End window size if TK_FOLLOWING or PRECEDING */ + Parse *pParse, + int eType, + int eStart, Expr *pStart, + int eEnd, Expr *pEnd ){ Window *pWin = 0; - /* Parser assures the following: */ - assert( eType==TK_RANGE || eType==TK_ROWS ); - assert( eStart==TK_CURRENT || eStart==TK_PRECEDING - || eStart==TK_UNBOUNDED || eStart==TK_FOLLOWING ); - assert( eEnd==TK_CURRENT || eEnd==TK_FOLLOWING - || eEnd==TK_UNBOUNDED || eEnd==TK_PRECEDING ); - assert( (eStart==TK_PRECEDING || eStart==TK_FOLLOWING)==(pStart!=0) ); - assert( (eEnd==TK_FOLLOWING || eEnd==TK_PRECEDING)==(pEnd!=0) ); - - - /* If a frame is declared "RANGE" (not "ROWS"), then it may not use - ** either " PRECEDING" or " FOLLOWING". - */ - if( eType==TK_RANGE && (pStart!=0 || pEnd!=0) ){ - sqlite3ErrorMsg(pParse, "RANGE must use only UNBOUNDED or CURRENT ROW"); - goto windowAllocErr; - } - - /* Additionally, the - ** starting boundary type may not occur earlier in the following list than - ** the ending boundary type: - ** - ** UNBOUNDED PRECEDING - ** PRECEDING - ** CURRENT ROW - ** FOLLOWING - ** UNBOUNDED FOLLOWING - ** - ** The parser ensures that "UNBOUNDED PRECEDING" cannot be used as an ending - ** boundary, and than "UNBOUNDED FOLLOWING" cannot be used as a starting - ** frame boundary. - */ - if( (eStart==TK_CURRENT && eEnd==TK_PRECEDING) - || (eStart==TK_FOLLOWING && (eEnd==TK_PRECEDING || eEnd==TK_CURRENT)) - ){ - sqlite3ErrorMsg(pParse, "unsupported frame delimiter for ROWS"); - goto windowAllocErr; - } - - pWin = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); - if( pWin==0 ) goto windowAllocErr; - pWin->eType = eType; - pWin->eStart = eStart; - pWin->eEnd = eEnd; - pWin->pEnd = sqlite3WindowOffsetExpr(pParse, pEnd); - pWin->pStart = sqlite3WindowOffsetExpr(pParse, pStart); - return pWin; - -windowAllocErr: - sqlite3ExprDelete(pParse->db, pEnd); - sqlite3ExprDelete(pParse->db, pStart); - return 0; + if( eType==TK_RANGE && (pStart || pEnd) ){ + sqlite3ErrorMsg(pParse, "RANGE %s is only supported with UNBOUNDED", + (pStart ? "PRECEDING" : "FOLLOWING") + ); + }else{ + pWin = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); + } + + if( pWin ){ + assert( eType ); + pWin->eType = eType; + pWin->eStart = eStart; + pWin->eEnd = eEnd; + pWin->pEnd = pEnd; + pWin->pStart = pStart; + }else{ + sqlite3ExprDelete(pParse->db, pEnd); + sqlite3ExprDelete(pParse->db, pStart); + } + + return pWin; } /* ** Attach window object pWin to expression p. */ void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ if( p ){ - if( pWin ){ - p->pWin = pWin; - pWin->pOwner = p; - if( p->flags & EP_Distinct ){ - sqlite3ErrorMsg(pParse, - "DISTINCT is not supported for window functions"); - } - } + p->pWin = pWin; + if( pWin ) pWin->pOwner = p; }else{ sqlite3WindowDelete(pParse->db, pWin); } } @@ -1002,20 +950,19 @@ ** A "PRECEDING " (bEnd==0) or "FOLLOWING " (bEnd==1) has just ** been evaluated and the result left in register reg. This function generates ** VM code to check that the value is a non-negative integer and throws ** an exception if it is not. */ -static void windowCheckFrameOffset(Parse *pParse, int reg, int bEnd){ +static void windowCheckFrameValue(Parse *pParse, int reg, int bEnd){ static const char *azErr[] = { "frame starting offset must be a non-negative integer", "frame ending offset must be a non-negative integer" }; Vdbe *v = sqlite3GetVdbe(pParse); int regZero = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_Integer, 0, regZero); sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2); - VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Ge, regZero, sqlite3VdbeCurrentAddr(v)+2, reg); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_ERROR, OE_Abort); sqlite3VdbeAppendP4(v, (void*)azErr[bEnd], P4_STATIC); sqlite3ReleaseTempReg(pParse, regZero); @@ -1039,11 +986,11 @@ ** ** If argument csr is greater than or equal to 0, then argument reg is ** the first register in an array of registers guaranteed to be large ** enough to hold the array of arguments for each function. In this case ** the arguments are extracted from the current row of csr into the -** array of registers before invoking OP_AggStep or OP_AggInverse +** array of registers before invoking OP_AggStep. ** ** Or, if csr is less than zero, then the array of registers at reg is ** already populated with all columns from the current row of the sub-query. ** ** If argument regPartSize is non-zero, then it is a register containing the @@ -1084,12 +1031,10 @@ } if( (pWin->pFunc->funcFlags & SQLITE_FUNC_MINMAX) && pWin->eStart!=TK_UNBOUNDED ){ - int addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regArg); - VdbeCoverage(v); if( bInverse==0 ){ sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1, 1); sqlite3VdbeAddOp2(v, OP_SCopy, regArg, pWin->regApp); sqlite3VdbeAddOp3(v, OP_MakeRecord, pWin->regApp, 2, pWin->regApp+2); sqlite3VdbeAddOp2(v, OP_IdxInsert, pWin->csrApp, pWin->regApp+2); @@ -1097,11 +1042,10 @@ sqlite3VdbeAddOp4Int(v, OP_SeekGE, pWin->csrApp, 0, regArg, 1); VdbeCoverage(v); sqlite3VdbeAddOp1(v, OP_Delete, pWin->csrApp); sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); } - sqlite3VdbeJumpHere(v, addrIsNull); }else if( pWin->regApp ){ assert( pWin->pFunc->xSFunc==nth_valueStepFunc || pWin->pFunc->xSFunc==first_valueStepFunc ); assert( bInverse==0 || bInverse==1 ); @@ -1130,12 +1074,11 @@ if( pWin->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ CollSeq *pColl; pColl = sqlite3ExprNNCollSeq(pParse, pWin->pOwner->x.pList->a[0].pExpr); sqlite3VdbeAddOp4(v, OP_CollSeq, 0,0,0, (const char*)pColl, P4_COLLSEQ); } - sqlite3VdbeAddOp3(v, bInverse? OP_AggInverse : OP_AggStep, - bInverse, regArg, pWin->regAccum); + sqlite3VdbeAddOp3(v, OP_AggStep0, bInverse, regArg, pWin->regAccum); sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nArg); if( addrIf ) sqlite3VdbeJumpHere(v, addrIf); } } @@ -1163,19 +1106,20 @@ if( bFinal ){ sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->csrApp); } }else if( pWin->regApp ){ }else{ + if( bFinal==0 ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); + } + sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, windowArgCount(pWin)); + sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); if( bFinal ){ - sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, windowArgCount(pWin)); - sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult); sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); }else{ - sqlite3VdbeAddOp3(v, OP_AggValue, pWin->regAccum, windowArgCount(pWin), - pWin->regResult); - sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); + sqlite3VdbeChangeP3(v, -1, pWin->regResult); } } } } @@ -1327,11 +1271,11 @@ ** ** while( regCtr>0 ){ ** regCtr--; ** windowReturnOneRow() ** if( bInverse ){ -** AggInverse +** AggStep (xInverse) ** } ** Next (Window.iEphCsr) ** } */ static void windowReturnRows( @@ -1421,11 +1365,11 @@ ** if( (regEnd--)<=0 ){ ** AggFinal (xValue) ** Gosub addrGosub ** Next(csr) // if EOF goto flush_partition_done ** if( (regStart--)<=0 ){ -** AggInverse (csrStart) +** AggStep (csrStart, xInverse) ** Next(csrStart) ** } ** } ** flush_partition_done: ** ResetSorter (csr) @@ -1449,11 +1393,11 @@ ** while( 1 ){ ** AggFinal (xValue) ** Gosub addrGosub ** Next(csr) // if EOF goto flush_partition_done ** if( (regStart--)<=0 ){ -** AggInverse (csrStart) +** AggStep (csrStart, xInverse) ** Next(csrStart) ** } ** } ** ** For the "CURRENT ROW AND UNBOUNDED FOLLOWING" case, the final if() @@ -1472,11 +1416,11 @@ ** Gosub addrGosub ** Next(csr) // if EOF goto flush_partition_done ** if( new peer ) break; ** } ** while( (regPeer--)>0 ){ -** AggInverse (csrStart) +** AggStep (csrStart, xInverse) ** Next(csrStart) ** } ** } ** ** ROWS BETWEEN FOLLOWING AND FOLLOWING @@ -1489,11 +1433,11 @@ ** if( (regStart--)<=0 ){ ** AggFinal (xValue) ** Gosub addrGosub ** Next(csr) // if EOF goto flush_partition_done ** } -** AggInverse (csrStart) +** AggStep (csrStart, xInverse) ** Next (csrStart) ** } ** ** ROWS BETWEEN PRECEDING AND PRECEDING ** @@ -1505,11 +1449,11 @@ ** } ** AggFinal (xValue) ** Gosub addrGosub ** Next(csr) // if EOF goto flush_partition_done ** if( (regStart--)<=0 ){ -** AggInverse (csr2) +** AggStep (csr2, xInverse) ** Next (csr2) ** } ** */ static void windowCodeRowExprStep( @@ -1569,15 +1513,15 @@ /* If either regStart or regEnd are not non-negative integers, throw ** an exception. */ if( pMWin->pStart ){ sqlite3ExprCode(pParse, pMWin->pStart, regStart); - windowCheckFrameOffset(pParse, regStart, 0); + windowCheckFrameValue(pParse, regStart, 0); } if( pMWin->pEnd ){ sqlite3ExprCode(pParse, pMWin->pEnd, regEnd); - windowCheckFrameOffset(pParse, regEnd, 1); + windowCheckFrameValue(pParse, regEnd, 1); } /* If this is "ROWS FOLLOWING AND ROWS FOLLOWING", do: ** ** if( regEnd