mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-05 15:55:57 +03:00
Add a C-source spell-checking facility. make misspell (on Nix)
FossilOrigin-Name: 26c1bb4bd9e9f56613c3aa87407a7f562fd4ebde5bfd6dece02078001d9a45f8
This commit is contained in:
226
src/window.c
226
src/window.c
@@ -40,12 +40,12 @@
|
||||
** (in this case max()) to process rows sorted in order of (c, d), which
|
||||
** makes things easier for obvious reasons. More generally:
|
||||
**
|
||||
** * FROM, WHERE, GROUP BY and HAVING clauses are all moved to
|
||||
** * FROM, WHERE, GROUP BY and HAVING clauses are all moved to
|
||||
** the sub-query.
|
||||
**
|
||||
** * ORDER BY, LIMIT and OFFSET remain part of the parent query.
|
||||
**
|
||||
** * Terminals from each of the expression trees that make up the
|
||||
** * Terminals from each of the expression trees that make up the
|
||||
** select-list and ORDER BY expressions in the parent query are
|
||||
** selected by the sub-query. For the purposes of the transformation,
|
||||
** terminals are column references and aggregate functions.
|
||||
@@ -54,14 +54,14 @@
|
||||
** the same window declaration (the OVER bit), then a single scan may
|
||||
** be used to process more than one window function. For example:
|
||||
**
|
||||
** SELECT max(b) OVER (PARTITION BY c ORDER BY d),
|
||||
** min(e) OVER (PARTITION BY c ORDER BY d)
|
||||
** SELECT max(b) OVER (PARTITION BY c ORDER BY d),
|
||||
** min(e) OVER (PARTITION BY c ORDER BY d)
|
||||
** FROM t1;
|
||||
**
|
||||
** is transformed in the same way as the example above. However:
|
||||
**
|
||||
** SELECT max(b) OVER (PARTITION BY c ORDER BY d),
|
||||
** min(e) OVER (PARTITION BY a ORDER BY b)
|
||||
** SELECT max(b) OVER (PARTITION BY c ORDER BY d),
|
||||
** min(e) OVER (PARTITION BY a ORDER BY b)
|
||||
** FROM t1;
|
||||
**
|
||||
** Must be transformed to:
|
||||
@@ -114,15 +114,15 @@
|
||||
** first_value(expr)
|
||||
** last_value(expr)
|
||||
** nth_value(expr, N)
|
||||
**
|
||||
** These are the same built-in window functions supported by Postgres.
|
||||
**
|
||||
** These are the same built-in window functions supported by Postgres.
|
||||
** Although the behaviour of aggregate window functions (functions that
|
||||
** can be used as either aggregates or window funtions) allows them to
|
||||
** can be used as either aggregates or window functions) allows them to
|
||||
** be implemented using an API, built-in window functions are much more
|
||||
** esoteric. Additionally, some window functions (e.g. nth_value())
|
||||
** esoteric. Additionally, some window functions (e.g. nth_value())
|
||||
** may only be implemented by caching the entire partition in memory.
|
||||
** As such, some built-in window functions use the same API as aggregate
|
||||
** window functions and some are implemented directly using VDBE
|
||||
** window functions and some are implemented directly using VDBE
|
||||
** instructions. Additionally, for those functions that use the API, the
|
||||
** window frame is sometimes modified before the SELECT statement is
|
||||
** rewritten. For example, regardless of the specified window frame, the
|
||||
@@ -134,7 +134,7 @@
|
||||
**
|
||||
** As well as some of the built-in window functions, aggregate window
|
||||
** functions min() and max() are implemented using VDBE instructions if
|
||||
** the start of the window frame is declared as anything other than
|
||||
** the start of the window frame is declared as anything other than
|
||||
** UNBOUNDED PRECEDING.
|
||||
*/
|
||||
|
||||
@@ -145,7 +145,7 @@
|
||||
** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
|
||||
*/
|
||||
static void row_numberStepFunc(
|
||||
sqlite3_context *pCtx,
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
@@ -173,10 +173,10 @@ struct CallCount {
|
||||
** Implementation of built-in window function dense_rank(). Assumes that
|
||||
** the window frame has been set to:
|
||||
**
|
||||
** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
|
||||
** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
|
||||
*/
|
||||
static void dense_rankStepFunc(
|
||||
sqlite3_context *pCtx,
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
@@ -208,7 +208,7 @@ struct NthValueCtx {
|
||||
sqlite3_value *pValue;
|
||||
};
|
||||
static void nth_valueStepFunc(
|
||||
sqlite3_context *pCtx,
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
@@ -261,7 +261,7 @@ static void nth_valueFinalizeFunc(sqlite3_context *pCtx){
|
||||
#define nth_valueValueFunc noopValueFunc
|
||||
|
||||
static void first_valueStepFunc(
|
||||
sqlite3_context *pCtx,
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
@@ -292,10 +292,10 @@ static void first_valueFinalizeFunc(sqlite3_context *pCtx){
|
||||
** Implementation of built-in window function rank(). Assumes that
|
||||
** the window frame has been set to:
|
||||
**
|
||||
** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
|
||||
** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
|
||||
*/
|
||||
static void rankStepFunc(
|
||||
sqlite3_context *pCtx,
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
@@ -326,7 +326,7 @@ static void rankValueFunc(sqlite3_context *pCtx){
|
||||
** GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
|
||||
*/
|
||||
static void percent_rankStepFunc(
|
||||
sqlite3_context *pCtx,
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
@@ -339,7 +339,7 @@ static void percent_rankStepFunc(
|
||||
}
|
||||
}
|
||||
static void percent_rankInvFunc(
|
||||
sqlite3_context *pCtx,
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
@@ -371,7 +371,7 @@ static void percent_rankValueFunc(sqlite3_context *pCtx){
|
||||
** GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING
|
||||
*/
|
||||
static void cume_distStepFunc(
|
||||
sqlite3_context *pCtx,
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
@@ -384,7 +384,7 @@ static void cume_distStepFunc(
|
||||
}
|
||||
}
|
||||
static void cume_distInvFunc(
|
||||
sqlite3_context *pCtx,
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
@@ -420,7 +420,7 @@ struct NtileCtx {
|
||||
** ROWS CURRENT ROW AND UNBOUNDED FOLLOWING
|
||||
*/
|
||||
static void ntileStepFunc(
|
||||
sqlite3_context *pCtx,
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
@@ -440,7 +440,7 @@ static void ntileStepFunc(
|
||||
}
|
||||
}
|
||||
static void ntileInvFunc(
|
||||
sqlite3_context *pCtx,
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
@@ -486,7 +486,7 @@ struct LastValueCtx {
|
||||
** Implementation of last_value().
|
||||
*/
|
||||
static void last_valueStepFunc(
|
||||
sqlite3_context *pCtx,
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
@@ -504,7 +504,7 @@ static void last_valueStepFunc(
|
||||
}
|
||||
}
|
||||
static void last_valueInvFunc(
|
||||
sqlite3_context *pCtx,
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
@@ -647,7 +647,7 @@ static Window *windowFind(Parse *pParse, Window *pList, const char *zName){
|
||||
** is the Window object representing the associated OVER clause. This
|
||||
** function updates the contents of pWin as follows:
|
||||
**
|
||||
** * If the OVER clause refered to a named window (as in "max(x) OVER win"),
|
||||
** * If the OVER clause referred to a named window (as in "max(x) OVER win"),
|
||||
** search list pList for a matching WINDOW definition, and update pWin
|
||||
** accordingly. If no such WINDOW clause can be found, leave an error
|
||||
** in pParse.
|
||||
@@ -657,7 +657,7 @@ static Window *windowFind(Parse *pParse, Window *pList, const char *zName){
|
||||
** of this file), pWin is updated here.
|
||||
*/
|
||||
void sqlite3WindowUpdate(
|
||||
Parse *pParse,
|
||||
Parse *pParse,
|
||||
Window *pList, /* List of named windows for this SELECT */
|
||||
Window *pWin, /* Window frame to update */
|
||||
FuncDef *pFunc /* Window function definition */
|
||||
@@ -677,17 +677,17 @@ void sqlite3WindowUpdate(
|
||||
sqlite3WindowChain(pParse, pWin, pList);
|
||||
}
|
||||
if( (pWin->eFrmType==TK_RANGE)
|
||||
&& (pWin->pStart || pWin->pEnd)
|
||||
&& (pWin->pStart || pWin->pEnd)
|
||||
&& (pWin->pOrderBy==0 || pWin->pOrderBy->nExpr!=1)
|
||||
){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"RANGE with offset PRECEDING/FOLLOWING requires one ORDER BY expression"
|
||||
);
|
||||
}else
|
||||
if( pFunc->funcFlags & SQLITE_FUNC_WINDOW ){
|
||||
sqlite3 *db = pParse->db;
|
||||
if( pWin->pFilter ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"FILTER clause may only be used with aggregate window functions"
|
||||
);
|
||||
}else{
|
||||
@@ -697,14 +697,14 @@ void sqlite3WindowUpdate(
|
||||
int eStart;
|
||||
int eEnd;
|
||||
} aUp[] = {
|
||||
{ row_numberName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT },
|
||||
{ dense_rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT },
|
||||
{ rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT },
|
||||
{ percent_rankName, TK_GROUPS, TK_CURRENT, TK_UNBOUNDED },
|
||||
{ cume_distName, TK_GROUPS, TK_FOLLOWING, TK_UNBOUNDED },
|
||||
{ ntileName, TK_ROWS, TK_CURRENT, TK_UNBOUNDED },
|
||||
{ leadName, TK_ROWS, TK_UNBOUNDED, TK_UNBOUNDED },
|
||||
{ lagName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT },
|
||||
{ row_numberName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT },
|
||||
{ dense_rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT },
|
||||
{ rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT },
|
||||
{ percent_rankName, TK_GROUPS, TK_CURRENT, TK_UNBOUNDED },
|
||||
{ cume_distName, TK_GROUPS, TK_FOLLOWING, TK_UNBOUNDED },
|
||||
{ ntileName, TK_ROWS, TK_CURRENT, TK_UNBOUNDED },
|
||||
{ leadName, TK_ROWS, TK_UNBOUNDED, TK_UNBOUNDED },
|
||||
{ lagName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<ArraySize(aUp); i++){
|
||||
@@ -742,7 +742,7 @@ struct WindowRewrite {
|
||||
|
||||
/*
|
||||
** Callback function used by selectWindowRewriteEList(). If necessary,
|
||||
** this function appends to the output expression-list and updates
|
||||
** this function appends to the output expression-list and updates
|
||||
** expression (*ppExpr) in place.
|
||||
*/
|
||||
static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
|
||||
@@ -847,16 +847,16 @@ static int selectWindowRewriteSelectCb(Walker *pWalker, Select *pSelect){
|
||||
**
|
||||
** * TK_COLUMN,
|
||||
** * aggregate function, or
|
||||
** * window function with a Window object that is not a member of the
|
||||
** * window function with a Window object that is not a member of the
|
||||
** Window list passed as the second argument (pWin).
|
||||
**
|
||||
** Append the node to output expression-list (*ppSub). And replace it
|
||||
** with a TK_COLUMN that reads the (N-1)th element of table
|
||||
** with a TK_COLUMN that reads the (N-1)th element of table
|
||||
** pWin->iEphCsr, where N is the number of elements in (*ppSub) after
|
||||
** appending the new one.
|
||||
*/
|
||||
static void selectWindowRewriteEList(
|
||||
Parse *pParse,
|
||||
Parse *pParse,
|
||||
Window *pWin,
|
||||
SrcList *pSrc,
|
||||
ExprList *pEList, /* Rewrite expressions in this list */
|
||||
@@ -950,7 +950,7 @@ static int disallowAggregatesInOrderByCb(Walker *pWalker, Expr *pExpr){
|
||||
|
||||
/*
|
||||
** If the SELECT statement passed as the second argument does not invoke
|
||||
** any SQL window functions, this function is a no-op. Otherwise, it
|
||||
** any SQL window functions, this function is a no-op. Otherwise, it
|
||||
** rewrites the SELECT statement so that window function xStep functions
|
||||
** are invoked in the correct order as described under "SELECT REWRITING"
|
||||
** at the top of this file.
|
||||
@@ -1023,8 +1023,8 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
selectWindowRewriteEList(pParse, pMWin, pSrc, p->pOrderBy, pTab, &pSublist);
|
||||
pMWin->nBufferCol = (pSublist ? pSublist->nExpr : 0);
|
||||
|
||||
/* Append the PARTITION BY and ORDER BY expressions to the to the
|
||||
** sub-select expression list. They are required to figure out where
|
||||
/* Append the PARTITION BY and ORDER BY expressions to the to the
|
||||
** sub-select expression list. They are required to figure out where
|
||||
** boundaries for partitions and sets of peer rows lie. */
|
||||
pSublist = exprListAppendList(pParse, pSublist, pMWin->pPartition, 0);
|
||||
pSublist = exprListAppendList(pParse, pSublist, pMWin->pOrderBy, 0);
|
||||
@@ -1058,11 +1058,11 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
/* 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.
|
||||
** 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,
|
||||
pSublist = sqlite3ExprListAppend(pParse, 0,
|
||||
sqlite3Expr(db, TK_INTEGER, "0")
|
||||
);
|
||||
}
|
||||
@@ -1248,10 +1248,10 @@ windowAllocErr:
|
||||
** equivalent nul-terminated string.
|
||||
*/
|
||||
Window *sqlite3WindowAssemble(
|
||||
Parse *pParse,
|
||||
Window *pWin,
|
||||
ExprList *pPartition,
|
||||
ExprList *pOrderBy,
|
||||
Parse *pParse,
|
||||
Window *pWin,
|
||||
ExprList *pPartition,
|
||||
ExprList *pOrderBy,
|
||||
Token *pBase
|
||||
){
|
||||
if( pWin ){
|
||||
@@ -1268,7 +1268,7 @@ Window *sqlite3WindowAssemble(
|
||||
}
|
||||
|
||||
/*
|
||||
** Window *pWin has just been created from a WINDOW clause. Tokne pBase
|
||||
** Window *pWin has just been created from a WINDOW clause. Token pBase
|
||||
** is the base window. Earlier windows from the same WINDOW clause are
|
||||
** stored in the linked list starting at pWin->pNextWin. This function
|
||||
** either updates *pWin according to the base specification, or else
|
||||
@@ -1289,7 +1289,7 @@ void sqlite3WindowChain(Parse *pParse, Window *pWin, Window *pList){
|
||||
zErr = "frame specification";
|
||||
}
|
||||
if( zErr ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"cannot override %s of window: %s", zErr, pWin->zBase
|
||||
);
|
||||
}else{
|
||||
@@ -1540,7 +1540,7 @@ struct WindowCsrAndReg {
|
||||
};
|
||||
|
||||
/*
|
||||
** A single instance of this structure is allocated on the stack by
|
||||
** A single instance of this structure is allocated on the stack by
|
||||
** sqlite3WindowCodeStep() and a pointer to it passed to the various helper
|
||||
** routines. This is to reduce the number of arguments required by each
|
||||
** helper function.
|
||||
@@ -1587,7 +1587,7 @@ struct WindowCsrAndReg {
|
||||
**
|
||||
** Each cursor (start, current and end) consists of a VDBE cursor
|
||||
** (WindowCsrAndReg.csr) and an array of registers (starting at
|
||||
** WindowCodeArg.reg) that always contains a copy of the peer values
|
||||
** WindowCodeArg.reg) that always contains a copy of the peer values
|
||||
** read from the corresponding cursor.
|
||||
**
|
||||
** Depending on the window-frame in question, all three cursors may not
|
||||
@@ -1632,8 +1632,8 @@ static void windowReadPeerValues(
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate VM code to invoke either xStep() (if bInverse is 0) or
|
||||
** xInverse (if bInverse is non-zero) for each window function in the
|
||||
** Generate VM code to invoke either xStep() (if bInverse is 0) or
|
||||
** xInverse (if bInverse is non-zero) for each window function in the
|
||||
** linked list starting at pMWin. Or, for built-in window functions
|
||||
** that do not use the standard function API, generate the required
|
||||
** inline VM code.
|
||||
@@ -1682,7 +1682,7 @@ static void windowAggStep(
|
||||
regArg = reg;
|
||||
|
||||
if( pMWin->regStartRowid==0
|
||||
&& (pFunc->funcFlags & SQLITE_FUNC_MINMAX)
|
||||
&& (pFunc->funcFlags & SQLITE_FUNC_MINMAX)
|
||||
&& (pWin->eStart!=TK_UNBOUNDED)
|
||||
){
|
||||
int addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regArg);
|
||||
@@ -1718,7 +1718,7 @@ static void windowAggStep(
|
||||
VdbeCoverage(v);
|
||||
sqlite3ReleaseTempReg(pParse, regTmp);
|
||||
}
|
||||
|
||||
|
||||
if( pWin->bExprArgs ){
|
||||
int iOp = sqlite3VdbeCurrentAddr(v);
|
||||
int iEnd;
|
||||
@@ -1742,7 +1742,7 @@ static void windowAggStep(
|
||||
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,
|
||||
sqlite3VdbeAddOp3(v, bInverse? OP_AggInverse : OP_AggStep,
|
||||
bInverse, regArg, pWin->regAccum);
|
||||
sqlite3VdbeAppendP4(v, pFunc, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, (u8)nArg);
|
||||
@@ -1775,7 +1775,7 @@ static void windowAggFinal(WindowCodeArg *p, int bFin){
|
||||
|
||||
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||
if( pMWin->regStartRowid==0
|
||||
&& (pWin->pWFunc->funcFlags & SQLITE_FUNC_MINMAX)
|
||||
&& (pWin->pWFunc->funcFlags & SQLITE_FUNC_MINMAX)
|
||||
&& (pWin->eStart!=TK_UNBOUNDED)
|
||||
){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
|
||||
@@ -1932,7 +1932,7 @@ static void windowReturnOneRow(WindowCodeArg *p){
|
||||
int lbl = sqlite3VdbeMakeLabel(pParse);
|
||||
int tmpReg = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
|
||||
|
||||
|
||||
if( pFunc->zName==nth_valueName ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column,pMWin->iEphCsr,pWin->iArgCol+1,tmpReg);
|
||||
windowCheckValue(pParse, tmpReg, 2);
|
||||
@@ -1954,7 +1954,7 @@ static void windowReturnOneRow(WindowCodeArg *p){
|
||||
int lbl = sqlite3VdbeMakeLabel(pParse);
|
||||
int tmpReg = sqlite3GetTempReg(pParse);
|
||||
int iEph = pMWin->iEphCsr;
|
||||
|
||||
|
||||
if( nArg<3 ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
|
||||
}else{
|
||||
@@ -1971,7 +1971,7 @@ static void windowReturnOneRow(WindowCodeArg *p){
|
||||
sqlite3VdbeAddOp3(v, op, tmpReg2, tmpReg, tmpReg);
|
||||
sqlite3ReleaseTempReg(pParse, tmpReg2);
|
||||
}
|
||||
|
||||
|
||||
sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, lbl, tmpReg);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult);
|
||||
@@ -2017,7 +2017,7 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){
|
||||
return regArg;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
** Return true if the current frame should be cached in the ephemeral table,
|
||||
** even if there are no xInverse() calls required.
|
||||
*/
|
||||
@@ -2041,9 +2041,9 @@ static int windowCacheFrame(Window *pMWin){
|
||||
** regOld and regNew are each the first register in an array of size
|
||||
** pOrderBy->nExpr. This function generates code to compare the two
|
||||
** arrays of registers using the collation sequences and other comparison
|
||||
** parameters specified by pOrderBy.
|
||||
** parameters specified by pOrderBy.
|
||||
**
|
||||
** If the two arrays are not equal, the contents of regNew is copied to
|
||||
** If the two arrays are not equal, the contents of regNew is copied to
|
||||
** regOld and control falls through. Otherwise, if the contents of the arrays
|
||||
** are equal, an OP_Goto is executed. The address of the OP_Goto is returned.
|
||||
*/
|
||||
@@ -2060,7 +2060,7 @@ static void windowIfNewPeer(
|
||||
KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0);
|
||||
sqlite3VdbeAddOp3(v, OP_Compare, regOld, regNew, nVal);
|
||||
sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
|
||||
sqlite3VdbeAddOp3(v, OP_Jump,
|
||||
sqlite3VdbeAddOp3(v, OP_Jump,
|
||||
sqlite3VdbeCurrentAddr(v)+1, addr, sqlite3VdbeCurrentAddr(v)+1
|
||||
);
|
||||
VdbeCoverageEqNe(v);
|
||||
@@ -2094,7 +2094,7 @@ static void windowIfNewPeer(
|
||||
** or subtraction is a a copy of csr1.peerVal.
|
||||
*/
|
||||
static void windowCodeRangeTest(
|
||||
WindowCodeArg *p,
|
||||
WindowCodeArg *p,
|
||||
int op, /* OP_Ge, OP_Gt, or OP_Le */
|
||||
int csr1, /* Cursor number for cursor 1 */
|
||||
int regVal, /* Register containing non-negative number */
|
||||
@@ -2132,8 +2132,8 @@ static void windowCodeRangeTest(
|
||||
((op==OP_Ge) ? ">=" : (op==OP_Le) ? "<=" : (op==OP_Gt) ? ">" : "<"), reg2
|
||||
));
|
||||
|
||||
/* If the BIGNULL flag is set for the ORDER BY, then it is required to
|
||||
** consider NULL values to be larger than all other values, instead of
|
||||
/* If the BIGNULL flag is set for the ORDER BY, then it is required to
|
||||
** consider NULL values to be larger than all other values, instead of
|
||||
** the usual smaller. The VDBE opcodes OP_Ge and so on do not handle this
|
||||
** (and adding that capability causes a performance regression), so
|
||||
** instead if the BIGNULL flag is set then cases where either reg1 or
|
||||
@@ -2148,23 +2148,23 @@ static void windowCodeRangeTest(
|
||||
** if( op==OP_Le ) goto lbl;
|
||||
** }
|
||||
**
|
||||
** Additionally, if either reg1 or reg2 are NULL but the jump to lbl is
|
||||
** Additionally, if either reg1 or reg2 are NULL but the jump to lbl is
|
||||
** not taken, control jumps over the comparison operator coded below this
|
||||
** block. */
|
||||
if( pOrderBy->a[0].fg.sortFlags & KEYINFO_ORDER_BIGNULL ){
|
||||
/* This block runs if reg1 contains a NULL. */
|
||||
int addr = sqlite3VdbeAddOp1(v, OP_NotNull, reg1); VdbeCoverage(v);
|
||||
switch( op ){
|
||||
case OP_Ge:
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, lbl);
|
||||
case OP_Ge:
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, lbl);
|
||||
break;
|
||||
case OP_Gt:
|
||||
sqlite3VdbeAddOp2(v, OP_NotNull, reg2, lbl);
|
||||
VdbeCoverage(v);
|
||||
case OP_Gt:
|
||||
sqlite3VdbeAddOp2(v, OP_NotNull, reg2, lbl);
|
||||
VdbeCoverage(v);
|
||||
break;
|
||||
case OP_Le:
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl);
|
||||
VdbeCoverage(v);
|
||||
case OP_Le:
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl);
|
||||
VdbeCoverage(v);
|
||||
break;
|
||||
default: assert( op==OP_Lt ); /* no-op */ break;
|
||||
}
|
||||
@@ -2221,7 +2221,7 @@ static void windowCodeRangeTest(
|
||||
|
||||
/*
|
||||
** Helper function for sqlite3WindowCodeStep(). Each call to this function
|
||||
** generates VM code for a single RETURN_ROW, AGGSTEP or AGGINVERSE
|
||||
** generates VM code for a single RETURN_ROW, AGGSTEP or AGGINVERSE
|
||||
** operation. Refer to the header comment for sqlite3WindowCodeStep() for
|
||||
** details.
|
||||
*/
|
||||
@@ -2280,8 +2280,8 @@ static int windowCodeOp(
|
||||
addrContinue = sqlite3VdbeCurrentAddr(v);
|
||||
|
||||
/* If this is a (RANGE BETWEEN a FOLLOWING AND b FOLLOWING) or
|
||||
** (RANGE BETWEEN b PRECEDING AND a PRECEDING) frame, ensure the
|
||||
** start cursor does not advance past the end cursor within the
|
||||
** (RANGE BETWEEN b PRECEDING AND a PRECEDING) frame, ensure the
|
||||
** start cursor does not advance past the end cursor within the
|
||||
** temporary table. It otherwise might, if (a>b). Also ensure that,
|
||||
** if the input cursor is still finding new rows, that the end
|
||||
** cursor does not go past it to EOF. */
|
||||
@@ -2422,11 +2422,11 @@ Window *sqlite3WindowListDup(sqlite3 *db, Window *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if it can be determined at compile time that expression
|
||||
** pExpr evaluates to a value that, when cast to an integer, is greater
|
||||
** Return true if it can be determined at compile time that expression
|
||||
** pExpr evaluates to a value that, when cast to an integer, is greater
|
||||
** than zero. False otherwise.
|
||||
**
|
||||
** If an OOM error occurs, this function sets the Parse.db.mallocFailed
|
||||
** If an OOM error occurs, this function sets the Parse.db.mallocFailed
|
||||
** flag and returns zero.
|
||||
*/
|
||||
static int windowExprGtZero(Parse *pParse, Expr *pExpr){
|
||||
@@ -2442,11 +2442,11 @@ static int windowExprGtZero(Parse *pParse, Expr *pExpr){
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3WhereBegin() has already been called for the SELECT statement
|
||||
** sqlite3WhereBegin() has already been called for the SELECT statement
|
||||
** passed as the second argument when this function is invoked. It generates
|
||||
** code to populate the Window.regResult register for each window function
|
||||
** code to populate the Window.regResult register for each window function
|
||||
** and invoke the sub-routine at instruction addrGosub once for each row.
|
||||
** sqlite3WhereEnd() is always called before returning.
|
||||
** sqlite3WhereEnd() is always called before returning.
|
||||
**
|
||||
** This function handles several different types of window frames, which
|
||||
** require slightly different processing. The following pseudo code is
|
||||
@@ -2461,17 +2461,17 @@ static int windowExprGtZero(Parse *pParse, Expr *pExpr){
|
||||
** Gosub flush
|
||||
** }
|
||||
** Insert new row into eph table.
|
||||
**
|
||||
**
|
||||
** if( first row of partition ){
|
||||
** // Rewind three cursors, all open on the eph table.
|
||||
** Rewind(csrEnd);
|
||||
** Rewind(csrStart);
|
||||
** Rewind(csrCurrent);
|
||||
**
|
||||
**
|
||||
** regEnd = <expr2> // FOLLOWING expression
|
||||
** regStart = <expr1> // PRECEDING expression
|
||||
** }else{
|
||||
** // First time this branch is taken, the eph table contains two
|
||||
** // First time this branch is taken, the eph table contains two
|
||||
** // rows. The first row in the partition, which all three cursors
|
||||
** // currently point to, and the following row.
|
||||
** AGGSTEP
|
||||
@@ -2500,17 +2500,17 @@ static int windowExprGtZero(Parse *pParse, Expr *pExpr){
|
||||
** with arguments read from the current row of cursor csrEnd, then
|
||||
** step cursor csrEnd forward one row (i.e. sqlite3BtreeNext()).
|
||||
**
|
||||
** RETURN_ROW: return a row to the caller based on the contents of the
|
||||
** current row of csrCurrent and the current state of all
|
||||
** RETURN_ROW: return a row to the caller based on the contents of the
|
||||
** current row of csrCurrent and the current state of all
|
||||
** aggregates. Then step cursor csrCurrent forward one row.
|
||||
**
|
||||
** AGGINVERSE: invoke the aggregate xInverse() function for each window
|
||||
** AGGINVERSE: invoke the aggregate xInverse() function for each window
|
||||
** functions with arguments read from the current row of cursor
|
||||
** csrStart. Then step csrStart forward one row.
|
||||
**
|
||||
** There are two other ROWS window frames that are handled significantly
|
||||
** differently from the above - "BETWEEN <expr> PRECEDING AND <expr> PRECEDING"
|
||||
** and "BETWEEN <expr> FOLLOWING AND <expr> FOLLOWING". These are special
|
||||
** and "BETWEEN <expr> FOLLOWING AND <expr> FOLLOWING". These are special
|
||||
** cases because they change the order in which the three cursors (csrStart,
|
||||
** csrCurrent and csrEnd) iterate through the ephemeral table. Cases that
|
||||
** use UNBOUNDED or CURRENT ROW are much simpler variations on one of these
|
||||
@@ -2583,7 +2583,7 @@ static int windowExprGtZero(Parse *pParse, Expr *pExpr){
|
||||
**
|
||||
** For the most part, the patterns above are adapted to support UNBOUNDED by
|
||||
** assuming that it is equivalent to "infinity PRECEDING/FOLLOWING" and
|
||||
** CURRENT ROW by assuming that it is equivilent to "0 PRECEDING/FOLLOWING".
|
||||
** CURRENT ROW by assuming that it is equivalent to "0 PRECEDING/FOLLOWING".
|
||||
** This is optimized of course - branches that will never be taken and
|
||||
** conditions that are always true are omitted from the VM code. The only
|
||||
** exceptional case is:
|
||||
@@ -2660,15 +2660,15 @@ static int windowExprGtZero(Parse *pParse, Expr *pExpr){
|
||||
** regEnd = <expr2>
|
||||
** regStart = <expr1>
|
||||
** }else if( new group ){
|
||||
** ...
|
||||
** ...
|
||||
** }
|
||||
** }
|
||||
**
|
||||
** 2. Instead of processing a single row, each RETURN_ROW, AGGSTEP or
|
||||
** 2. Instead of processing a single row, each RETURN_ROW, AGGSTEP or
|
||||
** AGGINVERSE step processes the current row of the relevant cursor and
|
||||
** all subsequent rows belonging to the same group.
|
||||
**
|
||||
** RANGE window frames are a little different again. As for GROUPS, the
|
||||
** RANGE window frames are a little different again. As for GROUPS, the
|
||||
** main loop runs once per group only. And RETURN_ROW, AGGSTEP and AGGINVERSE
|
||||
** deal in groups instead of rows. As for ROWS and GROUPS, there are three
|
||||
** basic cases:
|
||||
@@ -2705,7 +2705,7 @@ static int windowExprGtZero(Parse *pParse, Expr *pExpr){
|
||||
** }
|
||||
** }
|
||||
**
|
||||
** In the above notation, "csr.key" means the current value of the ORDER BY
|
||||
** In the above notation, "csr.key" means the current value of the ORDER BY
|
||||
** expression (there is only ever 1 for a RANGE that uses an <expr> FOLLOWING
|
||||
** or <expr PRECEDING) read from cursor csr.
|
||||
**
|
||||
@@ -2804,11 +2804,11 @@ void sqlite3WindowCodeStep(
|
||||
int regStart = 0; /* Value of <expr> PRECEDING */
|
||||
int regEnd = 0; /* Value of <expr> FOLLOWING */
|
||||
|
||||
assert( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_CURRENT
|
||||
|| pMWin->eStart==TK_FOLLOWING || pMWin->eStart==TK_UNBOUNDED
|
||||
assert( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_CURRENT
|
||||
|| pMWin->eStart==TK_FOLLOWING || pMWin->eStart==TK_UNBOUNDED
|
||||
);
|
||||
assert( pMWin->eEnd==TK_FOLLOWING || pMWin->eEnd==TK_CURRENT
|
||||
|| pMWin->eEnd==TK_UNBOUNDED || pMWin->eEnd==TK_PRECEDING
|
||||
assert( pMWin->eEnd==TK_FOLLOWING || pMWin->eEnd==TK_CURRENT
|
||||
|| pMWin->eEnd==TK_UNBOUNDED || pMWin->eEnd==TK_PRECEDING
|
||||
);
|
||||
assert( pMWin->eExclude==0 || pMWin->eExclude==TK_CURRENT
|
||||
|| pMWin->eExclude==TK_GROUP || pMWin->eExclude==TK_TIES
|
||||
@@ -2830,9 +2830,9 @@ void sqlite3WindowCodeStep(
|
||||
s.end.csr = s.current.csr+3;
|
||||
|
||||
/* Figure out when rows may be deleted from the ephemeral table. There
|
||||
** are four options - they may never be deleted (eDelete==0), they may
|
||||
** are four options - they may never be deleted (eDelete==0), they may
|
||||
** be deleted as soon as they are no longer part of the window frame
|
||||
** (eDelete==WINDOW_AGGINVERSE), they may be deleted as after the row
|
||||
** (eDelete==WINDOW_AGGINVERSE), they may be deleted as after the row
|
||||
** has been returned to the caller (WINDOW_RETURN_ROW), or they may
|
||||
** be deleted after they enter the frame (WINDOW_AGGSTEP). */
|
||||
switch( pMWin->eStart ){
|
||||
@@ -2862,7 +2862,7 @@ void sqlite3WindowCodeStep(
|
||||
}
|
||||
|
||||
/* Allocate registers for the array of values from the sub-query, the
|
||||
** samve values in record form, and the rowid used to insert said record
|
||||
** same values in record form, and the rowid used to insert said record
|
||||
** into the ephemeral table. */
|
||||
regNew = pParse->nMem+1;
|
||||
pParse->nMem += nInput;
|
||||
@@ -2880,7 +2880,7 @@ void sqlite3WindowCodeStep(
|
||||
}
|
||||
|
||||
/* If this is not a "ROWS BETWEEN ..." frame, then allocate arrays of
|
||||
** registers to store copies of the ORDER BY expressions (peer values)
|
||||
** registers to store copies of the ORDER BY expressions (peer values)
|
||||
** for the main loop, and for each cursor (start, current and end). */
|
||||
if( pMWin->eFrmType!=TK_ROWS ){
|
||||
int nPeer = (pOrderBy ? pOrderBy->nExpr : 0);
|
||||
@@ -2901,7 +2901,7 @@ void sqlite3WindowCodeStep(
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regNew, nInput, regRecord);
|
||||
|
||||
/* An input row has just been read into an array of registers starting
|
||||
** at regNew. If the window has a PARTITION clause, this block generates
|
||||
** at regNew. If the window has a PARTITION clause, this block generates
|
||||
** VM code to check if the input row is the start of a new partition.
|
||||
** If so, it does an OP_Gosub to an address to be filled in later. The
|
||||
** address of the OP_Gosub is stored in local variable addrGosubFlush. */
|
||||
|
Reference in New Issue
Block a user