diff --git a/manifest b/manifest index 8189768335..72ccb1dac4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Simplifications\sto\sthe\simplementation\sof\sthe\ssum()\sSQL\sfunction. -D 2018-07-07T20:55:16.666 +C Identify\sspecific\sFuncDef\sobjects\sfor\swindow\sfunctions\susing\sthe\spointer\sto\nthe\sfunction\sname\s(FuncDef.zName)\srather\sthan\sthe\spointer\sto\sthe\sxStep\smethod.\nThis\sallows\sxStep\smethod\spointer\sto\sbe\sreplaced\swith\sa\ssingle\snoopStepFunc()\nprocedure,\sand\sthus\ssave\shaving\slots\sof\sdifferent\sno-op\sstep\sfunctions. +D 2018-07-08T01:02:26.110 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6 @@ -584,7 +584,7 @@ F src/where.c 0bcbf9e191ca07f9ea2008aa80e70ded46bcdffd26560c83397da501f00aece6 F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4 F src/wherecode.c 3317f2b083a66d3e65a03edf316ade4ccb0a99c9956273282ebb579b95d4ba96 F src/whereexpr.c 571618c67a3eb5ce0f1158c2792c1aee9b4a4a264392fc4fb1b35467f80abf9a -F src/window.c 0ff9000757e6634f4bbf59e8273ba21d47992b7b782db5bde76db0eee90964e3 +F src/window.c e42415fb8d1421fd9353872244e8a90f4025cd6a4a215f1603f06735e9be20b6 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d @@ -1745,7 +1745,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P ae3fc7652f27ba0a86f4c26f64c2e148d9496a5edb7f54dc9980edd91c326e4f -R 7fefa3b6e3f1ad000f6b20afb58dadef +P a8b13002378fc4ef0b41c367b44b67bf2b28b6624303c087a3c6d657b5bfe32e +R 8358a593d4ce0687282d59db38a347ed U drh -Z a5540dd7ff49b20c02f142203cdf3720 +Z 0694fc0bf0c4178f6f522b94761738e7 diff --git a/manifest.uuid b/manifest.uuid index 3934e737f3..cc5c5bf1d4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a8b13002378fc4ef0b41c367b44b67bf2b28b6624303c087a3c6d657b5bfe32e \ No newline at end of file +410e13b0e0fb6e040808f076014d55ecf2b541c5439b4fd53c5bdcb8d800098e \ No newline at end of file diff --git a/src/window.c b/src/window.c index 7c120a5ffc..3ff88f79a0 100644 --- a/src/window.c +++ b/src/window.c @@ -152,12 +152,6 @@ static void row_numberStepFunc( i64 *p = (i64*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ) (*p)++; } -static void row_numberInvFunc( - sqlite3_context *pCtx, - int nArg, - sqlite3_value **apArg -){ -} static void row_numberValueFunc(sqlite3_context *pCtx){ i64 *p = (i64*)sqlite3_aggregate_context(pCtx, sizeof(*p)); sqlite3_result_int64(pCtx, (p ? *p : 0)); @@ -188,12 +182,6 @@ static void dense_rankStepFunc( p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ) p->nStep = 1; } -static void dense_rankInvFunc( - sqlite3_context *pCtx, - int nArg, - sqlite3_value **apArg -){ -} static void dense_rankValueFunc(sqlite3_context *pCtx){ struct CallCount *p; p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); @@ -226,12 +214,6 @@ static void rankStepFunc( } } } -static void rankInvFunc( - sqlite3_context *pCtx, - int nArg, - sqlite3_value **apArg -){ -} static void rankValueFunc(sqlite3_context *pCtx){ struct CallCount *p; p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); @@ -266,12 +248,6 @@ static void percent_rankStepFunc( } } } -static void percent_rankInvFunc( - sqlite3_context *pCtx, - int nArg, - sqlite3_value **apArg -){ -} static void percent_rankValueFunc(sqlite3_context *pCtx){ struct CallCount *p; p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); @@ -308,12 +284,6 @@ static void cume_distStepFunc( p->nStep++; } } -static void cume_distInvFunc( - sqlite3_context *pCtx, - int nArg, - sqlite3_value **apArg -){ -} static void cume_distValueFunc(sqlite3_context *pCtx){ struct CallCount *p; p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); @@ -359,12 +329,6 @@ static void ntileStepFunc( p->iRow++; } } -static void ntileInvFunc( - sqlite3_context *pCtx, - int nArg, - sqlite3_value **apArg -){ -} static void ntileValueFunc(sqlite3_context *pCtx){ struct NtileCtx *p; p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); @@ -449,50 +413,89 @@ static void last_valueFinalizeFunc(sqlite3_context *pCtx){ } /* -** No-op implementations of nth_value(), first_value(), lead() and lag(). -** These are all implemented inline using VDBE instructions. +** Static names for the built-in window function names. These static +** names are used, rather than string literals, so that FuncDef objects +** can be associated with a particular window function by direct +** comparison of the zName pointer. Example: +** +** if( pFuncDef->zName==row_valueName ){ ... } */ -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){} +static const char row_numberName[] = "row_number"; +static const char dense_rankName[] = "dense_rank"; +static const char rankName[] = "rank"; +static const char percent_rankName[] = "percent_rank"; +static const char cume_distName[] = "cume_dist"; +static const char ntileName[] = "ntile"; +static const char last_valueName[] = "last_value"; +static const char nth_valueName[] = "nth_value"; +static const char first_valueName[] = "first_value"; +static const char leadName[] = "lead"; +static const char lagName[] = "lag"; -#define WINDOWFUNC(name,nArg,extra) { \ - nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ - name ## StepFunc, name ## ValueFunc, name ## ValueFunc, \ - name ## InvFunc, #name \ -} +/* +** No-op implementations of xStep() and xFinalize(). Used as place-holders +** for built-in window functions that never call those interfaces. +** +** The noopValueFunc() is called but is expected to do nothing. The +** noopStepFunc() is never called, and so it is marked with NO_TEST to +** let the test coverage routine know not to expect this function to be +** invoked. +*/ +static void noopStepFunc( /*NO_TEST*/ + sqlite3_context *p, /*NO_TEST*/ + int n, /*NO_TEST*/ + sqlite3_value **a /*NO_TEST*/ +){ /*NO_TEST*/ + assert(0); /*NO_TEST*/ +} /*NO_TEST*/ +static void noopValueFunc(sqlite3_context *p){ /*no-op*/; } -#define WINDOWFUNCF(name,nArg,extra) { \ +/* Window functions that use all window interfaces: xStep, xFinal, +** xValue, and xInverse */ +#define WINDOWFUNCALL(name,nArg,extra) { \ nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ name ## StepFunc, name ## FinalizeFunc, name ## ValueFunc, \ - name ## InvFunc, #name \ + name ## InvFunc, name ## Name \ } +/* Window functions that are implemented using bytecode and thus have +** no-op routines for their methods */ +#define WINDOWFUNCNOOP(name,nArg,extra) { \ + nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ + noopStepFunc, noopValueFunc, noopValueFunc, \ + noopStepFunc, name ## Name \ +} + +/* Window functions that use all window interfaces: xStep, the +** same routine for xFinalize and xValue and which never call +** xInverse. */ +#define WINDOWFUNCX(name,nArg,extra) { \ + nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ + name ## StepFunc, name ## ValueFunc, name ## ValueFunc, \ + noopStepFunc, name ## Name \ +} + + /* ** Register those built-in window functions that are not also aggregates. */ void sqlite3WindowFunctions(void){ static FuncDef aWindowFuncs[] = { - WINDOWFUNC(row_number, 0, 0), - WINDOWFUNC(dense_rank, 0, 0), - WINDOWFUNC(rank, 0, 0), - WINDOWFUNC(percent_rank, 0, SQLITE_FUNC_WINDOW_SIZE), - WINDOWFUNC(cume_dist, 0, SQLITE_FUNC_WINDOW_SIZE), - WINDOWFUNC(ntile, 1, SQLITE_FUNC_WINDOW_SIZE), - WINDOWFUNCF(last_value, 1, 0), - WINDOWFUNC(nth_value, 2, 0), - WINDOWFUNC(first_value, 1, 0), - WINDOWFUNC(lead, 1, 0), WINDOWFUNC(lead, 2, 0), WINDOWFUNC(lead, 3, 0), - WINDOWFUNC(lag, 1, 0), WINDOWFUNC(lag, 2, 0), WINDOWFUNC(lag, 3, 0), + WINDOWFUNCX(row_number, 0, 0), + WINDOWFUNCX(dense_rank, 0, 0), + WINDOWFUNCX(rank, 0, 0), + WINDOWFUNCX(percent_rank, 0, SQLITE_FUNC_WINDOW_SIZE), + WINDOWFUNCX(cume_dist, 0, SQLITE_FUNC_WINDOW_SIZE), + WINDOWFUNCX(ntile, 1, SQLITE_FUNC_WINDOW_SIZE), + WINDOWFUNCALL(last_value, 1, 0), + WINDOWFUNCNOOP(nth_value, 2, 0), + WINDOWFUNCNOOP(first_value, 1, 0), + WINDOWFUNCNOOP(lead, 1, 0), + WINDOWFUNCNOOP(lead, 2, 0), + WINDOWFUNCNOOP(lead, 3, 0), + WINDOWFUNCNOOP(lag, 1, 0), + WINDOWFUNCNOOP(lag, 2, 0), + WINDOWFUNCNOOP(lag, 3, 0), }; sqlite3InsertBuiltinFuncs(aWindowFuncs, ArraySize(aWindowFuncs)); } @@ -544,7 +547,7 @@ void sqlite3WindowUpdate( "FILTER clause may only be used with aggregate window functions" ); }else - if( pFunc->xSFunc==row_numberStepFunc || pFunc->xSFunc==ntileStepFunc ){ + if( pFunc->zName==row_numberName || pFunc->zName==ntileName ){ sqlite3ExprDelete(db, pWin->pStart); sqlite3ExprDelete(db, pWin->pEnd); pWin->pStart = pWin->pEnd = 0; @@ -553,8 +556,8 @@ void sqlite3WindowUpdate( pWin->eEnd = TK_CURRENT; }else - if( pFunc->xSFunc==dense_rankStepFunc || pFunc->xSFunc==rankStepFunc - || pFunc->xSFunc==percent_rankStepFunc || pFunc->xSFunc==cume_distStepFunc + if( pFunc->zName==dense_rankName || pFunc->zName==rankName + || pFunc->zName==percent_rankName || pFunc->zName==cume_distName ){ sqlite3ExprDelete(db, pWin->pStart); sqlite3ExprDelete(db, pWin->pEnd); @@ -981,7 +984,7 @@ void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){ sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO); sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); } - else if( p->xSFunc==nth_valueStepFunc || p->xSFunc==first_valueStepFunc ){ + else if( p->zName==nth_valueName || p->zName==first_valueName ){ /* Allocate two registers at pWin->regApp. These will be used to ** store the start and end index of the current frame. */ assert( pMWin->iEphCsr ); @@ -990,7 +993,7 @@ void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){ pParse->nMem += 2; sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr); } - else if( p->xSFunc==leadStepFunc || p->xSFunc==lagStepFunc ){ + else if( p->zName==leadName || p->zName==lagName ){ assert( pMWin->iEphCsr ); pWin->csrApp = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr); @@ -1101,13 +1104,13 @@ static void windowAggStep( } sqlite3VdbeJumpHere(v, addrIsNull); }else if( pWin->regApp ){ - assert( pWin->pFunc->xSFunc==nth_valueStepFunc - || pWin->pFunc->xSFunc==first_valueStepFunc + assert( pWin->pFunc->zName==nth_valueName + || pWin->pFunc->zName==first_valueName ); assert( bInverse==0 || bInverse==1 ); sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1); - }else if( pWin->pFunc->xSFunc==leadStepFunc - || pWin->pFunc->xSFunc==lagStepFunc + }else if( pWin->pFunc->zName==leadName + || pWin->pFunc->zName==lagName ){ /* no-op */ }else{ @@ -1263,15 +1266,15 @@ static void windowReturnOneRow( Window *pWin; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ FuncDef *pFunc = pWin->pFunc; - if( pFunc->xSFunc==nth_valueStepFunc - || pFunc->xSFunc==first_valueStepFunc + if( pFunc->zName==nth_valueName + || pFunc->zName==first_valueName ){ int csr = pWin->csrApp; int lbl = sqlite3VdbeMakeLabel(v); int tmpReg = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); - if( pFunc->xSFunc==nth_valueStepFunc ){ + if( pFunc->zName==nth_valueName ){ sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+1,tmpReg); }else{ sqlite3VdbeAddOp2(v, OP_Integer, 1, tmpReg); @@ -1285,7 +1288,7 @@ static void windowReturnOneRow( sqlite3VdbeResolveLabel(v, lbl); sqlite3ReleaseTempReg(pParse, tmpReg); } - else if( pFunc->xSFunc==leadStepFunc || pFunc->xSFunc==lagStepFunc ){ + else if( pFunc->zName==leadName || pFunc->zName==lagName ){ int nArg = pWin->pOwner->x.pList->nExpr; int iEph = pMWin->iEphCsr; int csr = pWin->csrApp; @@ -1299,10 +1302,10 @@ static void windowReturnOneRow( } sqlite3VdbeAddOp2(v, OP_Rowid, iEph, tmpReg); if( nArg<2 ){ - int val = (pFunc->xSFunc==leadStepFunc ? 1 : -1); + int val = (pFunc->zName==leadName ? 1 : -1); sqlite3VdbeAddOp2(v, OP_AddImm, tmpReg, val); }else{ - int op = (pFunc->xSFunc==leadStepFunc ? OP_Add : OP_Subtract); + int op = (pFunc->zName==leadName ? OP_Add : OP_Subtract); int tmpReg2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_Column, iEph, pWin->iArgCol+1, tmpReg2); sqlite3VdbeAddOp3(v, op, tmpReg2, tmpReg, tmpReg); @@ -1373,8 +1376,8 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){ FuncDef *pFunc = pWin->pFunc; sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); nArg = MAX(nArg, windowArgCount(pWin)); - if( pFunc->xSFunc==nth_valueStepFunc - || pFunc->xSFunc==first_valueStepFunc + if( pFunc->zName==nth_valueName + || pFunc->zName==first_valueName ){ sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp); sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); @@ -2160,10 +2163,10 @@ void sqlite3WindowCodeStep( 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->zName==nth_valueName) + || (pFunc->zName==first_valueName) + || (pFunc->zName==leadName) + || (pFunc->zName==lagName) ){ bCache = 1; break;