-C Fix\shandling\sof\swindow\sframes\scontaining\snegative\snumber\sof\srows.\se.g.\s"ROWS\sx\nPRECEDING\sAND\sy\sPRECEDING"\swhere\s(x<y).
-D 2018-06-11T18:16:51.622
+C Clarify\sthe\srelationship\sbetween\sa\sWindow\sobject\sand\sits\sassociated\sExpr.
+D 2018-06-11T20:50:25.844
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F Makefile.in 498b77b89a8cb42f2ee20fcd6317f279a45c0d6ff40d27825f94b69884c09bbe
F src/dbpage.c 4aa7f26198934dbd002e69418220eae3dbc71b010bbac32bd78faf86b52ce6c3
F src/dbstat.c edabb82611143727511a45ca0859b8cd037851ebe756ae3db289859dd18b6f91
F src/delete.c 4c8c7604277a2041647f96b78f4b9a47858e9217e4fb333d35e7b5ab32c5b57f
-F src/expr.c d6db67ebe0597f87381827513ae168b202956fca35add953e294afc80fa41675
+F src/expr.c 1963827d3ab4aaa006c0b72ff486c537f9690acece2ad5852f65bd6e1336cec7
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c b1da9ef8dc834603bb0d28972378a7ce65897847f9a1e89ab800bbdf24c788ee
F src/func.c a5ee3864264edea8fea4d2dfdf8296250cff9139343953da78d82837241659a9
F src/prepare.c e966ecc97c3671ff0e96227c8c877b83f2d33ea371ee190bbf1698b36b5605c0
F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
-F src/resolve.c 03791a761ede3a2cd71dffb92aa760d728122dbbdbf26010813da3edd01cb431
+F src/resolve.c a8cf3d6144f6a821f002dad72f80659691e827a96e6da6dedf8b263edefe3a80
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c 0b0ce29bd7b8a7232e6f7602ddb447caa954a1fc476ff5e23ce1e5aaa6a0e0ed
F src/shell.c.in 4d0ddf10c403710d241bf920163dcf032c21119aebb61e70840942c0eafecdf9
F src/sqlite.h.in 63b07f76731f2b1e55c48fdb9f0508dcc6fbe3971010b8612ffd847c3c56d9a1
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
-F src/sqliteInt.h 04c732e9e770d35c12f5e649b7288510f3a2abb238e32eadaf506678717ddb25
+F src/sqliteInt.h 939c1893f7a5fd34cb79e30ecd46d00e81c847e5026c75c213a49938f33e74ba
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4
F src/wherecode.c 3317f2b083a66d3e65a03edf316ade4ccb0a99c9956273282ebb579b95d4ba96
F src/whereexpr.c 6f022d6cc9daf56495f191b199352f783aff5cf268ba136b4d8cea3fb62d8c7d
-F src/window.c 0519e5a03ebbcf22ab692410d4b25f28cc2d0e4e37e6288ca1eb0820276d67ba
+F src/window.c a5ebf5b119f50a1c886a900cf817ada2d9e3cf30633471e1444423424443756c
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P e74f86f271d6ab1ecd17c1ee63ab2aa0885ca56624be7382872f04d46c48ed86
-R a123bfa3a94ae6460114239fab9e1170
+P b6d9c7eda853420ae46a05bd432711e8bf9ebaa448c7d90ccfc0bcc338a87706
+R 118974de7b2e01c35e697f59c5a4477b
U dan
-Z 6b49a0a9a9265834682b1c9c02ee1753
+Z 1841ea3c1d7c82f1a89ee2ea7c51ae4b
i64 *p = (i64*)sqlite3_aggregate_context(pCtx, sizeof(*p));
if( p ) (*p)++;
}
-static void row_numberInverseFunc(
+static void row_numberInvFunc(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **apArg
}
/*
-** Context object type used by rank() and dense_rank().
+** Context object type used by rank(), dense_rank(), percent_rank() and
+** cume_dist().
*/
struct CallCount {
i64 nValue;
p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
if( p ) p->nStep = 1;
}
-static void dense_rankInverseFunc(
+static void dense_rankInvFunc(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **apArg
}
}
}
-static void rankInverseFunc(
+static void rankInvFunc(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **apArg
}
}
}
-static void percent_rankInverseFunc(
+static void percent_rankInvFunc(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **apArg
p->nStep++;
}
}
-static void cume_distInverseFunc(
+static void cume_distInvFunc(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **apArg
}
}
+/*
+** Context object for ntile() window function.
+*/
struct NtileCtx {
i64 nTotal; /* Total rows in partition */
i64 nParam; /* Parameter passed to ntile(N) */
p->iRow++;
}
}
-static void ntileInverseFunc(
+static void ntileInvFunc(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **apArg
}
}
+/*
+** Context object for last_value() window function.
+*/
struct LastValueCtx {
sqlite3_value *pVal;
int nVal;
p->nVal++;
}
}
-static void last_valueInverseFunc(
+static void last_valueInvFunc(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **apArg
}
}
-static void nth_valueStepFunc(
- sqlite3_context *pCtx,
- int nArg,
- sqlite3_value **apArg
-){
-}
-static void nth_valueInverseFunc(
- sqlite3_context *pCtx,
- int nArg,
- sqlite3_value **apArg
-){
-}
-static void nth_valueValueFunc(sqlite3_context *pCtx){
-}
-
-static void first_valueStepFunc(
- sqlite3_context *pCtx,
- int nArg,
- sqlite3_value **apArg
-){
-}
-static void first_valueInverseFunc(
- sqlite3_context *pCtx,
- int nArg,
- sqlite3_value **apArg
-){
-}
-static void first_valueValueFunc(sqlite3_context *pCtx){
-}
-
-static void leadStepFunc(
- sqlite3_context *pCtx,
- int nArg,
- sqlite3_value **apArg
-){
-}
-static void leadInverseFunc(
- sqlite3_context *pCtx,
- int nArg,
- sqlite3_value **apArg
-){
-}
-static void leadValueFunc(sqlite3_context *pCtx){
-}
-
-static void lagStepFunc(
- sqlite3_context *pCtx,
- int nArg,
- sqlite3_value **apArg
-){
-}
-static void lagInverseFunc(
- sqlite3_context *pCtx,
- int nArg,
- sqlite3_value **apArg
-){
-}
-static void lagValueFunc(sqlite3_context *pCtx){
-}
+/*
+** No-op implementations of nth_value(), first_value(), lead() and lag().
+** These are all implemented inline using VDBE instructions.
+*/
+static void nth_valueStepFunc(sqlite3_context *pCtx, int n, sqlite3_value **a){}
+static void nth_valueInvFunc(sqlite3_context *pCtx, int n, sqlite3_value **ap){}
+static void nth_valueValueFunc(sqlite3_context *pCtx){}
+static void first_valueStepFunc(sqlite3_context *p, int n, sqlite3_value **ap){}
+static void first_valueInvFunc(sqlite3_context *p, int n, sqlite3_value **ap){}
+static void first_valueValueFunc(sqlite3_context *pCtx){}
+static void leadStepFunc(sqlite3_context *pCtx, int n, sqlite3_value **ap){}
+static void leadInvFunc(sqlite3_context *pCtx, int n, sqlite3_value **ap){}
+static void leadValueFunc(sqlite3_context *pCtx){}
+static void lagStepFunc(sqlite3_context *pCtx, int n, sqlite3_value **ap){}
+static void lagInvFunc(sqlite3_context *pCtx, int n, sqlite3_value **ap){}
+static void lagValueFunc(sqlite3_context *pCtx){}
#define WINDOWFUNC(name,nArg,extra) { \
nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
name ## StepFunc, name ## ValueFunc, name ## ValueFunc, \
- name ## InverseFunc, #name \
+ name ## InvFunc, #name \
}
#define WINDOWFUNCF(name,nArg,extra) { \
nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
name ## StepFunc, name ## FinalizeFunc, name ## ValueFunc, \
- name ## InverseFunc, #name \
+ name ## InvFunc, #name \
}
/*
pWin->eEnd = TK_CURRENT;
}
}
+ pWin->pFunc = pFunc;
}
typedef struct WindowRewrite WindowRewrite;
Window *pWin;
for(pWin=p->pWin; pWin; pWin=pWin->pNextWin){
if( pExpr->pWin==pWin ){
- pExpr->pWin->pOwner = pExpr;
+ assert( pWin->pOwner==pExpr );
return WRC_Prune;
}
}
void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){
if( p ){
p->pWin = pWin;
+ if( pWin ) pWin->pOwner = p;
}else{
sqlite3WindowDelete(pParse->db, pWin);
}
sqlite3VdbeAppendP4(v, (void*)azErr[bEnd], P4_STATIC);
}
+static int windowArgCount(Window *pWin){
+ ExprList *pList = pWin->pOwner->x.pList;
+ return (pList ? pList->nExpr : 0);
+}
+
/*
** Generate VM code to invoke either xStep() (if bInverse is 0) or
** xInverse (if bInverse is non-zero) for each window function in the
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
int flags = pWin->pFunc->funcFlags;
int regArg;
- int nArg = pWin->nArg;
+ int nArg = windowArgCount(pWin);
if( csr>=0 ){
int i;
- for(i=0; i<pWin->nArg; i++){
+ for(i=0; i<nArg; i++){
sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+i, reg+i);
}
regArg = reg;
int addrIf = 0;
if( pWin->pFilter ){
int regTmp;
+ assert( nArg==pWin->pOwner->x.pList->nExpr );
if( csr>0 ){
regTmp = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+pWin->nArg,regTmp);
+ sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp);
}else{
- regTmp = regArg + pWin->nArg;
+ regTmp = regArg + nArg;
}
addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1);
if( csr>0 ){
if( bFinal==0 ){
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
}
- sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, pWin->nArg);
+ sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, windowArgCount(pWin));
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
if( bFinal ){
sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult);
sqlite3ReleaseTempReg(pParse, tmpReg);
}
else if( pFunc->xSFunc==leadStepFunc || pFunc->xSFunc==lagStepFunc ){
+ int nArg = pWin->pOwner->x.pList->nExpr;
int iEph = pWin->iEphCsr;
int csr = pWin->csrApp;
int lbl = sqlite3VdbeMakeLabel(v);
int tmpReg = sqlite3GetTempReg(pParse);
- if( pWin->nArg<3 ){
+ if( nArg<3 ){
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
}else{
sqlite3VdbeAddOp3(v, OP_Column, iEph, pWin->iArgCol+2, pWin->regResult);
}
sqlite3VdbeAddOp2(v, OP_Rowid, iEph, tmpReg);
- if( pWin->nArg<2 ){
+ if( nArg<2 ){
int val = (pFunc->xSFunc==leadStepFunc ? 1 : -1);
sqlite3VdbeAddOp2(v, OP_AddImm, tmpReg, val);
}else{
Window *pWin;
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
- nArg = MAX(nArg, pWin->nArg);
+ nArg = MAX(nArg, windowArgCount(pWin));
if( pWin->pFunc->xSFunc==nth_valueStepFunc
|| pWin->pFunc->xSFunc==first_valueStepFunc
){
sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)-1);
}
-Window *sqlite3WindowDup(sqlite3 *db, Window *p){
+Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p){
Window *pNew = 0;
if( p ){
pNew = sqlite3DbMallocZero(db, sizeof(Window));
pNew->eStart = p->eStart;
pNew->pStart = sqlite3ExprDup(db, pNew->pStart, 0);
pNew->pEnd = sqlite3ExprDup(db, pNew->pEnd, 0);
+ pNew->pOwner = pOwner;
}
}
return pNew;
}
/*
-** RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
-**
-** As above, except take no action for a "new peer". Invoke
-** the sub-routine once only for each partition.
-**
-** RANGE BETWEEN CURRENT ROW AND CURRENT ROW
-**
-** As above, except that the "new peer" condition is handled in the
-** same way as "new partition" (so there is no "else if" block).
-**
-** RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
-**
-** One way is to just reverse the sort order and do as for BETWEEN
-** UNBOUNDED PRECEDING AND CURRENT ROW. But that is not quite the same for
-** things like group_concat(). And perhaps other user defined aggregates
-** as well.
-**
-** ...
-** if( new partition ){
-** Gosub flush_partition;
-** ResetSorter eph-table
-** }
-** AggStep
-** Insert (record into eph-table)
-** sqlite3WhereEnd()
-** Gosub flush_partition
-**
-** flush_partition:
-** OpenDup (csr -> csr2)
-** foreach (record in eph-table) {
-** if( new peer ){
-** while( csr2!=csr ){
-** AggStep (xInverse)
-** Next (csr2)
-** }
-** }
-** AggFinal (xValue)
-** Gosub addrGosub
-** }
-**
-**========================================================================
-**
-** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
-** ...
-** if( new partition ){
-** AggFinal (xFinalize)
-** }
-** AggStep
-** AggFinal (xValue)
-** Gosub addrGosub
-** sqlite3WhereEnd()
-**
+** 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 and
+** invoke the sub-routine at instruction addrGosub once for each row.
+** This function calls sqlite3WhereEnd() before returning.
*/
void sqlite3WindowCodeStep(
- Parse *pParse,
- Select *p,
- WhereInfo *pWInfo,
- int regGosub,
- int addrGosub
+ Parse *pParse, /* Parse context */
+ Select *p, /* Rewritten SELECT statement */
+ WhereInfo *pWInfo, /* Context returned by sqlite3WhereBegin() */
+ int regGosub, /* Register for OP_Gosub */
+ int addrGosub /* OP_Gosub here to return each row */
){
Window *pMWin = p->pWin;
Window *pWin;
- /*
- ** Call windowCodeRowExprStep() for all window modes *except*:
+ /* Call windowCodeRowExprStep() for all window modes *except*:
**
** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
** RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
return;
}
- /*
- ** Call windowCodeCacheStep() if there is a window function that requires
+ /* 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.
- */
+ ** are returned. */
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
FuncDef *pFunc = pWin->pFunc;
if( (pFunc->funcFlags & SQLITE_FUNC_WINDOW_SIZE)
}
}
+ /* Otherwise, call windowCodeDefaultStep(). */
windowCodeDefaultStep(pParse, p, pWInfo, regGosub, addrGosub);
}