]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Identify specific FuncDef objects for window functions using the pointer to
authordrh <drh@noemail.net>
Sun, 8 Jul 2018 01:02:26 +0000 (01:02 +0000)
committerdrh <drh@noemail.net>
Sun, 8 Jul 2018 01:02:26 +0000 (01:02 +0000)
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

manifest
manifest.uuid
src/window.c

index 8189768335918712cc65953692237418ed2a1858..72ccb1dac42f683d368a36e94e78b2f7f5d846ab 100644 (file)
--- 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
index 3934e737f3d140a7553a6bbfaef6464a190dc31d..cc5c5bf1d46620a3cfb61651b2bc3c2b724e14e7 100644 (file)
@@ -1 +1 @@
-a8b13002378fc4ef0b41c367b44b67bf2b28b6624303c087a3c6d657b5bfe32e
\ No newline at end of file
+410e13b0e0fb6e040808f076014d55ecf2b541c5439b4fd53c5bdcb8d800098e
\ No newline at end of file
index 7c120a5ffcfe96931ff8afdbc4f1f073cf0a109a..3ff88f79a0fc522a09ce378b95a40712e31b1d8a 100644 (file)
@@ -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;