diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/vdbe.h | 1 | ||||
-rw-r--r-- | src/vdbeapi.c | 12 | ||||
-rw-r--r-- | src/window.c | 52 |
3 files changed, 54 insertions, 11 deletions
diff --git a/src/vdbe.h b/src/vdbe.h index 51995e384..8bf0a2c3f 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -243,6 +243,7 @@ void sqlite3VdbeResolveLabel(Vdbe*, int); int sqlite3VdbeCurrentAddr(Vdbe*); #ifdef SQLITE_DEBUG int sqlite3VdbeAssertMayAbort(Vdbe *, int); + int sqlite3VdbeAssertAggContext(sqlite3_context*); #endif void sqlite3VdbeResetStepResult(Vdbe*); void sqlite3VdbeRewind(Vdbe*); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index fcc315bc6..270756c29 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -825,6 +825,18 @@ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ } /* +** 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. ** diff --git a/src/window.c b/src/window.c index 9d5cadcdd..c025e5ab2 100644 --- a/src/window.c +++ b/src/window.c @@ -172,7 +172,10 @@ struct CallCount { }; /* -** Implementation of built-in window function dense_rank(). +** Implementation of built-in window function dense_rank(). Assumes that +** the window frame has been set to: +** +** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW */ static void dense_rankStepFunc( sqlite3_context *pCtx, @@ -202,7 +205,10 @@ static void dense_rankValueFunc(sqlite3_context *pCtx){ } /* -** Implementation of built-in window function rank(). +** Implementation of built-in window function rank(). Assumes that +** the window frame has been set to: +** +** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW */ static void rankStepFunc( sqlite3_context *pCtx, @@ -234,7 +240,10 @@ static void rankValueFunc(sqlite3_context *pCtx){ } /* -** Implementation of built-in window function percent_rank(). +** Implementation of built-in window function percent_rank(). Assumes that +** the window frame has been set to: +** +** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW */ static void percent_rankStepFunc( sqlite3_context *pCtx, @@ -244,8 +253,9 @@ static void percent_rankStepFunc( 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]); } @@ -275,6 +285,12 @@ static void percent_rankValueFunc(sqlite3_context *pCtx){ } } +/* +** Implementation of built-in window function cume_dist(). Assumes that +** the window frame has been set to: +** +** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW +*/ static void cume_distStepFunc( sqlite3_context *pCtx, int nArg, @@ -283,8 +299,9 @@ static void cume_distStepFunc( 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]); } @@ -328,8 +345,9 @@ static void ntileStepFunc( ){ struct NtileCtx *p; assert( nArg==2 ); + assert( sqlite3VdbeAssertAggContext(pCtx) ); p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); - if( p ){ + if( ALWAYS(p) ){ if( p->nTotal==0 ){ p->nParam = sqlite3_value_int64(apArg[0]); p->nTotal = sqlite3_value_int64(apArg[1]); @@ -388,7 +406,7 @@ static void last_valueStepFunc( sqlite3_value **apArg ){ struct LastValueCtx *p; - p = (struct LastValueCtx *)sqlite3_aggregate_context(pCtx, sizeof(*p)); + p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ sqlite3_value_free(p->pVal); p->pVal = sqlite3_value_dup(apArg[0]); @@ -405,8 +423,8 @@ static void last_valueInvFunc( sqlite3_value **apArg ){ struct LastValueCtx *p; - p = (struct LastValueCtx *)sqlite3_aggregate_context(pCtx, sizeof(*p)); - if( p ){ + p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( ALWAYS(p) ){ p->nVal--; if( p->nVal==0 ){ sqlite3_value_free(p->pVal); @@ -416,14 +434,14 @@ static void last_valueInvFunc( } static void last_valueValueFunc(sqlite3_context *pCtx){ struct LastValueCtx *p; - p = (struct LastValueCtx *)sqlite3_aggregate_context(pCtx, sizeof(*p)); + p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p && p->pVal ){ sqlite3_result_value(pCtx, p->pVal); } } static void last_valueFinalizeFunc(sqlite3_context *pCtx){ struct LastValueCtx *p; - p = (struct LastValueCtx *)sqlite3_aggregate_context(pCtx, sizeof(*p)); + p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p && p->pVal ){ sqlite3_result_value(pCtx, p->pVal); sqlite3_value_free(p->pVal); @@ -737,6 +755,18 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){ sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); } + /* If there is no ORDER BY or PARTITION BY clause, and the window + ** function accepts zero arguments, and there are no other columns + ** selected (e.g. "SELECT row_number() OVER () FROM t1"), it is possible + ** that pSublist is still NULL here. Add a constant expression here to + ** keep everything legal in this case. + */ + if( pSublist==0 ){ + pSublist = sqlite3ExprListAppend(pParse, 0, + sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[0], 0) + ); + } + pSub = sqlite3SelectNew( pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0 ); |