[tarantool-patches] [PATCH v2 5/8] sql: introduce a signature_mask for functions
Kirill Shcherbatov
kshcherbatov at tarantool.org
Thu Aug 8 17:50:49 MSK 2019
This patch replaces nArgs field with signature_mask bitmask that
allows to use an only hash table entry for all builtin functions
overloads.
The code refactoring is not a goal of this patch: the most of
affected code would be removed in following patches. The role of
this patch itself is to introduce such mechanism (signature_mask)
in Tarantool's SQL.
Needed for #2200, #4113, #2233
---
src/box/sql/sqlInt.h | 70 ++++++++++++++++++++------------
src/box/sql/callback.c | 22 +++-------
src/box/sql/func.c | 91 ++++++++++++++++++------------------------
src/box/sql/main.c | 4 +-
src/box/sql/vdbeaux.c | 6 ++-
5 files changed, 94 insertions(+), 99 deletions(-)
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 941c87420..114ac0e4b 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -1254,7 +1254,20 @@ struct type_def {
* field is used by per-connection app-def functions.
*/
struct FuncDef {
- i8 nArg; /* Number of arguments. -1 means unlimited */
+ /**
+ * A bitmask representing all supported function
+ * overloads. The function supports argc == n iff this
+ * bitmask has bit n set 1. In particular case, a bitmask
+ * (~0) means this function works with any possible
+ * argument.
+ *
+ * The count of arguments for function is limited with
+ * (CHAR_BITS*sizeof(uint64_t) - 1). When the highest bit
+ * of the mask is set, this means that greater values
+ * are supported. E.g. greatest function works correctly
+ * with any number of input arguments.
+ */
+ uint64_t signature_mask;
u16 funcFlags; /* Some combination of sql_FUNC_* */
void *pUserData; /* User data parameter */
FuncDef *pNext; /* Next function with same name */
@@ -1342,9 +1355,9 @@ enum trim_side_mask {
* The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
* used to create the initializers for the FuncDef structures.
*
- * FUNCTION(zName, nArg, iArg, bNC, xFunc)
+ * FUNCTION(zName, mask, iArg, bNC, xFunc)
* Used to create a scalar function definition of a function zName
- * implemented by C function xFunc that accepts nArg arguments. The
+ * implemented by C function xFunc that accepts mask arguments. The
* value passed as iArg is cast to a (void*) and made available
* as the user-data (sql_user_data()) for the function. If
* argument bNC is true, then the sql_FUNC_NEEDCOLL flag is set.
@@ -1354,56 +1367,61 @@ enum trim_side_mask {
* STRING which collation should be derived from first
* argument (trim, substr etc).
*
- * VFUNCTION(zName, nArg, iArg, bNC, xFunc)
+ * VFUNCTION(zName, mask, iArg, bNC, xFunc)
* Like FUNCTION except it omits the sql_FUNC_CONSTANT flag.
*
- * DFUNCTION(zName, nArg, iArg, bNC, xFunc)
+ * DFUNCTION(zName, mask, iArg, bNC, xFunc)
* Like FUNCTION except it omits the sql_FUNC_CONSTANT flag and
* adds the sql_FUNC_SLOCHNG flag. Used for date & time functions,
* but not during a single query.
*
- * AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal)
+ * AGGREGATE(zName, mask, iArg, bNC, xStep, xFinal)
* Used to create an aggregate function definition implemented by
* the C functions xStep and xFinal. The first four parameters
* are interpreted in the same way as the first 4 parameters to
* FUNCTION().
*
- * LIKEFUNC(zName, nArg, pArg, flags)
+ * LIKEFUNC(zName, mask, pArg, flags)
* Used to create a scalar function definition of a function zName
- * that accepts nArg arguments and is implemented by a call to C
+ * that accepts mask arguments and is implemented by a call to C
* function likeFunc. Argument pArg is cast to a (void *) and made
* available as the function user-data (sql_user_data()). The
* FuncDef.flags variable is set to the value passed as the flags
* parameter.
*/
-#define FUNCTION(zName, nArg, iArg, bNC, xFunc, type) \
- {nArg, SQL_FUNC_CONSTANT|(bNC*SQL_FUNC_NEEDCOLL), \
+#define FUNCTION(zName, mask, iArg, bNC, xFunc, type) \
+ {mask, SQL_FUNC_CONSTANT|(bNC*SQL_FUNC_NEEDCOLL), \
SQL_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0}, type}
-#define FUNCTION_COLL(zName, nArg, iArg, bNC, xFunc) \
- {nArg, SQL_FUNC_CONSTANT|SQL_FUNC_DERIVEDCOLL|(bNC*SQL_FUNC_NEEDCOLL), \
+#define FUNCTION_COLL(zName, mask, iArg, bNC, xFunc) \
+ {mask, SQL_FUNC_CONSTANT|SQL_FUNC_DERIVEDCOLL|(bNC*SQL_FUNC_NEEDCOLL), \
SQL_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0}, FIELD_TYPE_STRING}
-#define VFUNCTION(zName, nArg, iArg, bNC, xFunc, type) \
- {nArg, (bNC*SQL_FUNC_NEEDCOLL), \
+#define VFUNCTION(zName, mask, iArg, bNC, xFunc, type) \
+ {mask, (bNC*SQL_FUNC_NEEDCOLL), \
SQL_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0}, type}
-#define DFUNCTION(zName, nArg, iArg, bNC, xFunc, type) \
- {nArg, SQL_FUNC_SLOCHNG|(bNC*SQL_FUNC_NEEDCOLL), \
+#define DFUNCTION(zName, mask, iArg, bNC, xFunc, type) \
+ {mask, SQL_FUNC_SLOCHNG|(bNC*SQL_FUNC_NEEDCOLL), \
SQL_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0}, type}
-#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags, type) \
- {nArg,SQL_FUNC_CONSTANT|(bNC*SQL_FUNC_NEEDCOLL)|extraFlags,\
+#define FUNCTION2(zName, mask, iArg, bNC, xFunc, extraFlags, type) \
+ {mask,SQL_FUNC_CONSTANT|(bNC*SQL_FUNC_NEEDCOLL)|extraFlags,\
SQL_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0}, type}
-#define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
- {nArg, SQL_FUNC_SLOCHNG|(bNC*SQL_FUNC_NEEDCOLL), \
+#define STR_FUNCTION(zName, mask, pArg, bNC, xFunc) \
+ {mask, SQL_FUNC_SLOCHNG|(bNC*SQL_FUNC_NEEDCOLL), \
pArg, 0, xFunc, 0, #zName, {SQL_AFF_STRING, {0}}}
-#define LIKEFUNC(zName, nArg, arg, flags, type) \
- {nArg, SQL_FUNC_NEEDCOLL|SQL_FUNC_CONSTANT|flags, \
+#define LIKEFUNC(zName, mask, arg, flags, type) \
+ {mask, SQL_FUNC_NEEDCOLL|SQL_FUNC_CONSTANT|flags, \
(void *)(SQL_INT_TO_PTR(arg)), 0, likeFunc, 0, #zName, {0}, type}
-#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal, type) \
- {nArg, (nc*SQL_FUNC_NEEDCOLL), \
+#define AGGREGATE(zName, mask, arg, nc, xStep, xFinal, type) \
+ {mask, (nc*SQL_FUNC_NEEDCOLL), \
SQL_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}, type}
-#define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags, type) \
- {nArg, (nc*SQL_FUNC_NEEDCOLL)|extraFlags, \
+#define AGGREGATE2(zName, mask, arg, nc, xStep, xFinal, extraFlags, type) \
+ {mask, (nc*SQL_FUNC_NEEDCOLL)|extraFlags, \
SQL_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}, type}
+#define ARGC_MASK_FULL (~0ULL)
+#define ARGC_MASK(a) (a < 0 ? ARGC_MASK_FULL : (1ULL << a))
+#define ARGC_MASK2(a, b) (ARGC_MASK(a) | ARGC_MASK(b))
+#define ARGC_MASK3(a, b, c) (ARGC_MASK2(a, b) | ARGC_MASK(c))
+
/*
* All current savepoints are stored in a linked list starting at
* sql.pSavepoint. The first element in the list is the most recently
diff --git a/src/box/sql/callback.c b/src/box/sql/callback.c
index 6c272de71..737c24d98 100644
--- a/src/box/sql/callback.c
+++ b/src/box/sql/callback.c
@@ -36,6 +36,7 @@
*/
#include "box/coll_id_cache.h"
+#include "box/column_mask.h"
#include "sqlInt.h"
#include "box/session.h"
@@ -91,26 +92,13 @@ matchQuality(FuncDef * p, /* The function we are evaluating for match quality */
int nArg /* Desired number of arguments. (-1)==any */
)
{
- int match;
-
/* nArg of -2 is a special case */
if (nArg == (-2))
- return (p->xSFunc == 0) ? 0 : FUNC_PERFECT_MATCH;
-
+ return FUNC_PERFECT_MATCH;
/* Wrong number of arguments means "no match" */
- if (p->nArg != nArg && p->nArg >= 0)
+ if (!column_mask_fieldno_is_set(p->signature_mask, (uint32_t)nArg))
return 0;
-
- /* Give a better score to a function with a specific number of arguments
- * than to function that accepts any number of arguments.
- */
- if (p->nArg == nArg) {
- match = 4;
- } else {
- match = 1;
- }
-
- return match;
+ return p->signature_mask == ARGC_MASK(nArg) ? FUNC_PERFECT_MATCH : 1;
}
/*
@@ -240,7 +228,7 @@ sqlFindFunction(sql * db, /* An open database */
sqlDbMallocZero(db, sizeof(*pBest) + nName + 1)) != 0) {
FuncDef *pOther;
pBest->zName = (const char *)&pBest[1];
- pBest->nArg = (u16) nArg;
+ pBest->signature_mask = ARGC_MASK(nArg);
pBest->funcFlags = 0;
memcpy((char *)&pBest[1], zName, nName + 1);
pOther =
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index e011fd958..8e07ce892 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -1859,73 +1859,60 @@ sqlRegisterBuiltinFunctions(void)
* For peak efficiency, put the most frequently used function last.
*/
static FuncDef aBuiltinFunc[] = {
- FUNCTION(soundex, 1, 0, 0, soundexFunc, FIELD_TYPE_STRING),
- FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQL_FUNC_UNLIKELY,
+ FUNCTION(soundex, ARGC_MASK(1), 0, 0, soundexFunc, FIELD_TYPE_STRING),
+ FUNCTION2(unlikely, ARGC_MASK(1), 0, 0, noopFunc, SQL_FUNC_UNLIKELY,
FIELD_TYPE_BOOLEAN),
- FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQL_FUNC_UNLIKELY,
+ FUNCTION2(likelihood, ARGC_MASK(2), 0, 0, noopFunc, SQL_FUNC_UNLIKELY,
FIELD_TYPE_BOOLEAN),
- FUNCTION2(likely, 1, 0, 0, noopFunc, SQL_FUNC_UNLIKELY,
+ FUNCTION2(likely, ARGC_MASK(1), 0, 0, noopFunc, SQL_FUNC_UNLIKELY,
FIELD_TYPE_BOOLEAN),
- FUNCTION_COLL(trim, 1, 3, 0, trim_func),
- FUNCTION_COLL(trim, 2, 3, 0, trim_func),
- FUNCTION_COLL(trim, 3, 3, 0, trim_func),
- FUNCTION(least, -1, 0, 1, minmaxFunc, FIELD_TYPE_SCALAR),
- AGGREGATE2(min, 1, 0, 1, minmaxStep, minMaxFinalize,
+ FUNCTION_COLL(trim, ARGC_MASK3(1, 2, 3), 3, 0, trim_func),
+ FUNCTION(least, ARGC_MASK_FULL, 0, 1, minmaxFunc, FIELD_TYPE_SCALAR),
+ AGGREGATE2(min, ARGC_MASK(1), 0, 1, minmaxStep, minMaxFinalize,
SQL_FUNC_MINMAX, FIELD_TYPE_SCALAR),
- FUNCTION(greatest, -1, 1, 1, minmaxFunc, FIELD_TYPE_SCALAR),
- AGGREGATE2(max, 1, 1, 1, minmaxStep, minMaxFinalize,
+ FUNCTION(greatest, ARGC_MASK_FULL, 1, 1, minmaxFunc, FIELD_TYPE_SCALAR),
+ AGGREGATE2(max, ARGC_MASK(1), 1, 1, minmaxStep, minMaxFinalize,
SQL_FUNC_MINMAX, FIELD_TYPE_SCALAR),
- FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQL_FUNC_TYPEOF,
+ FUNCTION2(typeof, ARGC_MASK(1), 0, 0, typeofFunc, SQL_FUNC_TYPEOF,
FIELD_TYPE_STRING),
- FUNCTION2(length, 1, 0, 0, lengthFunc, SQL_FUNC_LENGTH,
+ FUNCTION2(length, ARGC_MASK(1), 0, 0, lengthFunc, SQL_FUNC_LENGTH,
FIELD_TYPE_INTEGER),
- FUNCTION(char_length, 1, 0, 0, lengthFunc, FIELD_TYPE_INTEGER),
- FUNCTION(character_length, 1, 0, 0, lengthFunc,
+ FUNCTION(char_length, ARGC_MASK(1), 0, 0, lengthFunc, FIELD_TYPE_INTEGER),
+ FUNCTION(character_length, ARGC_MASK(1), 0, 0, lengthFunc,
FIELD_TYPE_INTEGER),
- FUNCTION(position, 2, 0, 1, position_func, FIELD_TYPE_INTEGER),
- FUNCTION(printf, -1, 0, 0, printfFunc, FIELD_TYPE_STRING),
- FUNCTION(unicode, 1, 0, 0, unicodeFunc, FIELD_TYPE_STRING),
- FUNCTION(char, -1, 0, 0, charFunc, FIELD_TYPE_STRING),
- FUNCTION(abs, 1, 0, 0, absFunc, FIELD_TYPE_NUMBER),
- FUNCTION(round, 1, 0, 0, roundFunc, FIELD_TYPE_INTEGER),
- FUNCTION(round, 2, 0, 0, roundFunc, FIELD_TYPE_INTEGER),
- FUNCTION_COLL(upper, 1, 0, 1, UpperICUFunc),
- FUNCTION_COLL(lower, 1, 0, 1, LowerICUFunc),
- FUNCTION(hex, 1, 0, 0, hexFunc, FIELD_TYPE_STRING),
- FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQL_FUNC_COALESCE,
+ FUNCTION(position, ARGC_MASK(2), 0, 1, position_func, FIELD_TYPE_INTEGER),
+ FUNCTION(printf, ARGC_MASK_FULL, 0, 0, printfFunc, FIELD_TYPE_STRING),
+ FUNCTION(unicode, ARGC_MASK(1), 0, 0, unicodeFunc, FIELD_TYPE_STRING),
+ FUNCTION(char, ARGC_MASK_FULL, 0, 0, charFunc, FIELD_TYPE_STRING),
+ FUNCTION(abs, ARGC_MASK(1), 0, 0, absFunc, FIELD_TYPE_NUMBER),
+ FUNCTION(round, ARGC_MASK2(1, 2), 0, 0, roundFunc, FIELD_TYPE_INTEGER),
+ FUNCTION_COLL(upper, ARGC_MASK(1), 0, 1, UpperICUFunc),
+ FUNCTION_COLL(lower, ARGC_MASK(1), 0, 1, LowerICUFunc),
+ FUNCTION(hex, ARGC_MASK(1), 0, 0, hexFunc, FIELD_TYPE_STRING),
+ FUNCTION2(ifnull, ARGC_MASK(2), 0, 0, noopFunc, SQL_FUNC_COALESCE,
FIELD_TYPE_INTEGER),
- VFUNCTION(random, 0, 0, 0, randomFunc, FIELD_TYPE_INTEGER),
- VFUNCTION(randomblob, 1, 0, 0, randomBlob, FIELD_TYPE_VARBINARY),
- FUNCTION(nullif, 2, 0, 1, nullifFunc, FIELD_TYPE_SCALAR),
- FUNCTION(version, 0, 0, 0, sql_func_version, FIELD_TYPE_STRING),
- FUNCTION(quote, 1, 0, 0, quoteFunc, FIELD_TYPE_STRING),
- VFUNCTION(row_count, 0, 0, 0, sql_row_count, FIELD_TYPE_INTEGER),
- FUNCTION_COLL(replace, 3, 0, 0, replaceFunc),
- FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc, FIELD_TYPE_VARBINARY),
- FUNCTION_COLL(substr, 2, 0, 0, substrFunc),
- FUNCTION_COLL(substr, 3, 0, 0, substrFunc),
- AGGREGATE(sum, 1, 0, 0, sum_step, sumFinalize,
+ VFUNCTION(random, ARGC_MASK(0), 0, 0, randomFunc, FIELD_TYPE_INTEGER),
+ VFUNCTION(randomblob, ARGC_MASK(1), 0, 0, randomBlob, FIELD_TYPE_VARBINARY),
+ FUNCTION(nullif, ARGC_MASK(2), 0, 1, nullifFunc, FIELD_TYPE_SCALAR),
+ FUNCTION(version, ARGC_MASK(0), 0, 0, sql_func_version, FIELD_TYPE_STRING),
+ FUNCTION(quote, ARGC_MASK(1), 0, 0, quoteFunc, FIELD_TYPE_STRING),
+ VFUNCTION(row_count, ARGC_MASK(0), 0, 0, sql_row_count, FIELD_TYPE_INTEGER),
+ FUNCTION_COLL(replace, ARGC_MASK(3), 0, 0, replaceFunc),
+ FUNCTION(zeroblob, ARGC_MASK(1), 0, 0, zeroblobFunc, FIELD_TYPE_VARBINARY),
+ FUNCTION_COLL(substr, ARGC_MASK2(2, 3), 0, 0, substrFunc),
+ AGGREGATE(sum, ARGC_MASK(1), 0, 0, sum_step, sumFinalize,
FIELD_TYPE_NUMBER),
- AGGREGATE(total, 1, 0, 0, sum_step, totalFinalize,
+ AGGREGATE(total, ARGC_MASK(1), 0, 0, sum_step, totalFinalize,
FIELD_TYPE_NUMBER),
- AGGREGATE(avg, 1, 0, 0, sum_step, avgFinalize,
+ AGGREGATE(avg, ARGC_MASK(1), 0, 0, sum_step, avgFinalize,
FIELD_TYPE_NUMBER),
- AGGREGATE(count, 0, 0, 0, countStep, countFinalize,
+ AGGREGATE(count, ARGC_MASK2(0, 1), 0, 0, countStep, countFinalize,
FIELD_TYPE_INTEGER),
- AGGREGATE(count, 1, 0, 0, countStep, countFinalize,
- FIELD_TYPE_INTEGER),
- AGGREGATE(group_concat, 1, 0, 0, groupConcatStep,
- groupConcatFinalize, FIELD_TYPE_STRING),
- AGGREGATE(group_concat, 2, 0, 0, groupConcatStep,
+ AGGREGATE(group_concat, ARGC_MASK2(1, 2), 0, 0, groupConcatStep,
groupConcatFinalize, FIELD_TYPE_STRING),
-
- LIKEFUNC(like, 2, 1, SQL_FUNC_LIKE,
- FIELD_TYPE_INTEGER),
- LIKEFUNC(like, 3, 1, SQL_FUNC_LIKE,
+ LIKEFUNC(like, ARGC_MASK2(2, 3), 1, SQL_FUNC_LIKE,
FIELD_TYPE_INTEGER),
- FUNCTION(coalesce, 1, 0, 0, 0, FIELD_TYPE_SCALAR),
- FUNCTION(coalesce, 0, 0, 0, 0, FIELD_TYPE_SCALAR),
- FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQL_FUNC_COALESCE,
+ FUNCTION2(coalesce, ARGC_MASK_FULL & ~ARGC_MASK2(0, 1), 0, 0, noopFunc, SQL_FUNC_COALESCE,
FIELD_TYPE_SCALAR),
};
sql_register_analyze_builtins();
diff --git a/src/box/sql/main.c b/src/box/sql/main.c
index 748dc1b8e..eb6e4a7db 100644
--- a/src/box/sql/main.c
+++ b/src/box/sql/main.c
@@ -321,7 +321,7 @@ sqlCreateFunc(sql * db,
* operation to continue but invalidate all precompiled statements.
*/
p = sqlFindFunction(db, zFunctionName, nArg, 0);
- if (p && p->nArg == nArg) {
+ if (p != NULL && (p->signature_mask & nArg) != 0) {
if (db->nVdbeActive) {
diag_set(ClientError, ER_CREATE_FUNCTION, zFunctionName,
"unable to create function due to active "\
@@ -351,7 +351,7 @@ sqlCreateFunc(sql * db,
p->xSFunc = xSFunc ? xSFunc : xStep;
p->xFinalize = xFinal;
p->pUserData = pUserData;
- p->nArg = (u16) nArg;
+ p->signature_mask = ARGC_MASK(nArg);
p->ret_type = type;
return 0;
}
diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
index e7accc745..d32404580 100644
--- a/src/box/sql/vdbeaux.c
+++ b/src/box/sql/vdbeaux.c
@@ -1151,13 +1151,15 @@ displayP4(Op * pOp, char *zTemp, int nTemp)
}
case P4_FUNCDEF:{
FuncDef *pDef = pOp->p4.pFunc;
- sqlXPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg);
+ sqlXPrintf(&x, "%s(%d)", pDef->zName,
+ pDef->signature_mask);
break;
}
#if defined(SQL_DEBUG) || defined(VDBE_PROFILE)
case P4_FUNCCTX:{
FuncDef *pDef = pOp->p4.pCtx->pFunc;
- sqlXPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg);
+ sqlXPrintf(&x, "%s(%d)", pDef->zName,
+ pDef->signature_mask);
break;
}
#endif
--
2.22.0
More information about the Tarantool-patches
mailing list