From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 0C79626AAF for ; Thu, 8 Aug 2019 10:51:01 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id klNHkeP9cmY9 for ; Thu, 8 Aug 2019 10:51:00 -0400 (EDT) Received: from smtp5.mail.ru (smtp5.mail.ru [94.100.179.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id 9B7EE26A61 for ; Thu, 8 Aug 2019 10:51:00 -0400 (EDT) From: Kirill Shcherbatov Subject: [tarantool-patches] [PATCH v2 5/8] sql: introduce a signature_mask for functions Date: Thu, 8 Aug 2019 17:50:49 +0300 Message-Id: <6f6689986b1dd79adc478c5da9f1d458da42d483.1565275469.git.kshcherbatov@tarantool.org> In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-Help: List-Unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-Subscribe: List-Owner: List-post: List-Archive: To: tarantool-patches@freelists.org, korablev@tarantool.org Cc: Kirill Shcherbatov 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