From: drh Date: Sun, 8 Jul 2018 01:02:26 +0000 (+0000) Subject: Identify specific FuncDef objects for window functions using the pointer to X-Git-Tag: version-3.25.0~149 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=19dc4d40e765d5d47146b75a3b89a9921e592fe1;p=thirdparty%2Fsqlite.git Identify specific FuncDef objects for window functions using the pointer to the function name (FuncDef.zName) rather than the pointer to the xStep method. This allows xStep method pointer to be replaced with a single noopStepFunc() procedure, and thus save having lots of different no-op step functions. FossilOrigin-Name: 410e13b0e0fb6e040808f076014d55ecf2b541c5439b4fd53c5bdcb8d800098e --- 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){} - -#define WINDOWFUNC(name,nArg,extra) { \ +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"; + +/* +** 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*/; } + +/* 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 ## ValueFunc, name ## ValueFunc, \ - name ## InvFunc, #name \ + name ## StepFunc, name ## FinalizeFunc, name ## ValueFunc, \ + name ## InvFunc, name ## Name \ } -#define WINDOWFUNCF(name,nArg,extra) { \ +/* 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, \ - name ## StepFunc, name ## FinalizeFunc, name ## ValueFunc, \ - name ## InvFunc, #name \ + 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;