aboutsummaryrefslogtreecommitdiff
path: root/src/window.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/window.c')
-rw-r--r--src/window.c146
1 files changed, 120 insertions, 26 deletions
diff --git a/src/window.c b/src/window.c
index 395d6733b..459d05e29 100644
--- a/src/window.c
+++ b/src/window.c
@@ -1236,6 +1236,12 @@ static void windowReturnRows(
sqlite3VdbeJumpHere(v, addr+1); /* The OP_Goto */
}
+/*
+** Generate code to set the accumulator register for each window function
+** in the linked list passed as the second argument to NULL. And perform
+** any equivalent initialization required by any built-in window functions
+** in the list.
+*/
static int windowInitAccum(Parse *pParse, Window *pMWin){
Vdbe *v = sqlite3GetVdbe(pParse);
int regArg;
@@ -1258,15 +1264,11 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){
/*
-** ROWS BETWEEN <expr1> PRECEDING AND <expr2> FOLLOWING
-** ----------------------------------------------------
+** This function does the work of sqlite3WindowCodeStep() for all "ROWS"
+** window frame types except for "BETWEEN UNBOUNDED PRECEDING AND CURRENT
+** ROW". Pseudo-code for each follows.
**
-** Pseudo-code for the implementation of this window frame type is as
-** follows. sqlite3WhereBegin() has already been called to generate the
-** top of the main loop when this function is called.
-**
-** Each time the sub-routine at addrGosub is invoked, a single output
-** row is generated based on the current row indicated by Window.iEphCsr.
+** ROWS BETWEEN <expr1> PRECEDING AND <expr2> FOLLOWING
**
** ...
** if( new partition ){
@@ -1551,6 +1553,16 @@ static void windowCodeRowExprStep(
}
/*
+** This function does the work of sqlite3WindowCodeStep() for cases that
+** would normally be handled by windowCodeDefaultStep() when there are
+** one or more built-in window-functions that require the entire partition
+** to be cached in a temp table before any rows can be returned. Additionally.
+** "RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING" is always handled by
+** this function.
+**
+** Pseudo-code corresponding to the VM code generated by this function
+** for each type of window follows.
+**
** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
**
** flush_partition:
@@ -1581,8 +1593,64 @@ static void windowCodeRowExprStep(
** Return
**
** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
-** RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
+**
+** As above, except that the "if( new peer )" branch is always taken.
+**
** RANGE BETWEEN CURRENT ROW AND CURRENT ROW
+**
+** As above, except that each of the for() loops becomes:
+**
+** for(i=0; i<ctr; i++){
+** Gosub addrGosub
+** AggStep (xInverse, iEphCsr)
+** Next iEphCsr
+** }
+**
+** RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
+**
+** flush_partition:
+** Once {
+** OpenDup (iEphCsr -> csrLead)
+** }
+** foreach row (csrLead) {
+** AggStep (csrLead)
+** }
+** foreach row (iEphCsr) {
+** Gosub addrGosub
+** }
+**
+** RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
+**
+** flush_partition:
+** Once {
+** OpenDup (iEphCsr -> csrLead)
+** }
+** foreach row (csrLead){
+** AggStep (csrLead)
+** }
+** Rewind (csrLead)
+** Integer ctr 0
+** foreach row (csrLead){
+** if( new peer ){
+** AggFinal (xValue)
+** for(i=0; i<ctr; i++){
+** Gosub addrGosub
+** AggStep (xInverse, iEphCsr)
+** Next iEphCsr
+** }
+** Integer ctr 0
+** }
+** Incr ctr
+** }
+**
+** AggFinal (xFinalize)
+** for(i=0; i<ctr; i++){
+** Gosub addrGosub
+** Next iEphCsr
+** }
+**
+** ResetSorter (csr)
+** Return
*/
static void windowCodeCacheStep(
Parse *pParse,
@@ -1598,7 +1666,7 @@ static void windowCodeCacheStep(
int addr;
ExprList *pPart = pMWin->pPartition;
ExprList *pOrderBy = pMWin->pOrderBy;
- int nPeer = pOrderBy->nExpr;
+ int nPeer = pOrderBy ? pOrderBy->nExpr : 0;
int regNewPeer;
int addrGoto; /* Address of Goto used to jump flush_par.. */
@@ -1610,8 +1678,9 @@ static void windowCodeCacheStep(
int regArg; /* Register array to martial function args */
int regSize;
int nArg;
- int bReverse;
int lblEmpty;
+ int bReverse = pMWin->pOrderBy && pMWin->eStart==TK_CURRENT
+ && pMWin->eEnd==TK_UNBOUNDED;
assert( (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_CURRENT)
|| (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_UNBOUNDED)
@@ -1620,7 +1689,6 @@ static void windowCodeCacheStep(
);
lblEmpty = sqlite3VdbeMakeLabel(v);
- bReverse = (pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_UNBOUNDED);
regNewPeer = pParse->nMem+1;
pParse->nMem += nPeer;
@@ -1878,34 +1946,60 @@ void sqlite3WindowCodeStep(
int addrGosub /* OP_Gosub here to return each row */
){
Window *pMWin = p->pWin;
- ExprList *pOrderBy = pMWin->pOrderBy;
- /* Call windowCodeRowExprStep() for all "ROWS" window modes except:
+ /* There are three different functions that may be used to do the work
+ ** of this one, depending on the window frame and the specific built-in
+ ** window functions used (if any).
+ **
+ ** windowCodeRowExprStep() handles all "ROWS" window frames, except for:
**
** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+ **
+ ** The exception is because windowCodeRowExprStep() implements all window
+ ** frame types by caching the entire partition in a temp table, and
+ ** "ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW" is easy enough to
+ ** implement without such a cache.
+ **
+ ** windowCodeCacheStep() is used for:
+ **
+ ** RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
+ **
+ ** It is also used for anything not handled by windowCodeRowExprStep()
+ ** that invokes a built-in window function that requires the entire
+ ** partition to be cached in a temp table before any rows are returned
+ ** (e.g. nth_value() or percent_rank()).
+ **
+ ** Finally, assuming there is no built-in window function that requires
+ ** the partition to be cached, windowCodeDefaultStep() is used for:
+ **
+ ** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+ ** RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
+ ** RANGE BETWEEN CURRENT ROW AND CURRENT ROW
+ ** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+ **
+ ** windowCodeDefaultStep() is the only one of the three functions that
+ ** does not cache each partition in a temp table before beginning to
+ ** return rows.
*/
- if( (pMWin->eType==TK_ROWS
- && (pMWin->eStart!=TK_UNBOUNDED || pMWin->eEnd!=TK_CURRENT || !pOrderBy))
+ if( pMWin->eType==TK_ROWS
+ && (pMWin->eStart!=TK_UNBOUNDED||pMWin->eEnd!=TK_CURRENT||!pMWin->pOrderBy)
){
windowCodeRowExprStep(pParse, p, pWInfo, regGosub, addrGosub);
}else{
Window *pWin;
- int bCache = 0;
+ int bCache = 0; /* True to use CacheStep() */
- if( pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_UNBOUNDED && pOrderBy ){
+ if( pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_UNBOUNDED ){
bCache = 1;
}else{
- /* Call windowCodeCacheStep() if there is a window function that requires
- ** that the entire partition be cached in a temp table before any rows
- ** are returned. */
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
FuncDef *pFunc = pWin->pFunc;
if( (pFunc->funcFlags & SQLITE_FUNC_WINDOW_SIZE)
- || (pFunc->xSFunc==nth_valueStepFunc)
- || (pFunc->xSFunc==first_valueStepFunc)
- || (pFunc->xSFunc==leadStepFunc)
- || (pFunc->xSFunc==lagStepFunc)
- ){
+ || (pFunc->xSFunc==nth_valueStepFunc)
+ || (pFunc->xSFunc==first_valueStepFunc)
+ || (pFunc->xSFunc==leadStepFunc)
+ || (pFunc->xSFunc==lagStepFunc)
+ ){
bCache = 1;
break;
}