[tarantool-patches] [PATCH v2 7/8] sql: get rid of FuncDef function hash
Kirill Shcherbatov
kshcherbatov at tarantool.org
Thu Aug 8 17:50:51 MSK 2019
Now it is possible to move all SQL builtin functions to
Tarantool's function hash. An existent FuncDef function
representation was replaced with func_sql_builtin class.
It has a sql-specific method :call and :finalize typica while
port API call is not supported and protected with stub.
This patch removes FuncDef hash and sql_function_create endpoint,
but doesn't introduce something instead. Therefore few affected
tests are disabled. A required functionality would be fixed in
the next patch.
Following tests using sql_create_function are broken now.
They would be fixed in the following commit:
sql-tap/alias.test.lua sql-tap/check.test.lua
sql-tap/func5.test.lua sql-tap/lua_sql.test.lua
sql-tap/subquery.test.lua sql-tap/trigger9.test.lua
sql/errinj.result sql/errinj.test.lua
sql/func-recreate.test.lua
Part of #2200, #4113, #2233
---
src/box/lua/lua_sql.h | 39 -----
src/box/sql.h | 5 +
src/box/sql/sqlInt.h | 248 +++++++---------------------
src/box/sql/vdbe.h | 9 +-
src/box/sql/vdbeInt.h | 23 ++-
src/box/func.c | 34 +---
src/box/lua/call.c | 2 -
src/box/lua/lua_sql.c | 205 -----------------------
src/box/sql.c | 23 +++
src/box/sql/analyze.c | 35 ++--
src/box/sql/callback.c | 191 ----------------------
src/box/sql/date.c | 28 ----
src/box/sql/expr.c | 64 ++++----
src/box/sql/func.c | 309 ++++++++++++++++++++++++-----------
src/box/sql/global.c | 7 -
src/box/sql/main.c | 137 ----------------
src/box/sql/resolve.c | 50 +++---
src/box/sql/select.c | 6 +-
src/box/sql/vdbe.c | 20 ++-
src/box/sql/vdbeapi.c | 11 +-
src/box/sql/vdbeaux.c | 33 +---
src/box/sql/vdbemem.c | 50 +++---
src/box/sql/whereexpr.c | 2 +-
src/box/CMakeLists.txt | 1 -
test/sql-tap/where2.test.lua | 4 +-
25 files changed, 456 insertions(+), 1080 deletions(-)
delete mode 100644 src/box/lua/lua_sql.h
delete mode 100644 src/box/lua/lua_sql.c
diff --git a/src/box/lua/lua_sql.h b/src/box/lua/lua_sql.h
deleted file mode 100644
index b81093eca..000000000
--- a/src/box/lua/lua_sql.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2010-2017, Tarantool AUTHORS, please see AUTHORS file.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the
- * following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef TARANTOOL_LUA_SQL_H
-#define TARANTOOL_LUA_SQL_H
-
-int
-lbox_sql_create_function(struct lua_State *L);
-
-#endif //TARANTOOL_LUA_SQL_H
-
diff --git a/src/box/sql.h b/src/box/sql.h
index 9ccecf28c..6eaf5ba3a 100644
--- a/src/box/sql.h
+++ b/src/box/sql.h
@@ -68,6 +68,7 @@ struct Expr;
struct Parse;
struct Select;
struct Table;
+struct func_def;
struct sql_trigger;
struct space_def;
@@ -348,6 +349,10 @@ sql_src_list_entry_name(const struct SrcList *list, int i);
void
sqlSrcListDelete(struct sql *db, struct SrcList *list);
+/** Construct a SQL builtin function object. */
+struct func *
+func_sql_builtin_new(struct func_def *def);
+
/**
* Auxiliary VDBE structure to speed-up tuple data field access.
* A memory allocation that manage this structure must have
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 114ac0e4b..6ef1a1d4a 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -70,6 +70,8 @@
#include "box/column_mask.h"
#include "parse_def.h"
#include "box/field_def.h"
+#include "box/func.h"
+#include "box/func_def.h"
#include "box/sql.h"
#include "box/txn.h"
#include "trivia/util.h"
@@ -566,26 +568,6 @@ sql_initialize(void);
#define SQL_TRACE_ROW 0x04
#define SQL_TRACE_CLOSE 0x08
-#define SQL_DETERMINISTIC 0x800
-
-int
-sql_create_function_v2(sql * db,
- const char *zFunctionName,
- enum field_type type,
- int nArg,
- int flags,
- void *pApp,
- void (*xFunc) (sql_context *,
- int,
- sql_value **),
- void (*xStep) (sql_context *,
- int,
- sql_value **),
- void (*xFinal)
- (sql_context *),
- void (*xDestroy) (void *)
- );
-
#define SQL_OPEN_READONLY 0x00000001 /* Ok for sql_open_v2() */
#define SQL_OPEN_READWRITE 0x00000002 /* Ok for sql_open_v2() */
#define SQL_OPEN_CREATE 0x00000004 /* Ok for sql_open_v2() */
@@ -1039,9 +1021,6 @@ typedef struct Column Column;
typedef struct Expr Expr;
typedef struct ExprList ExprList;
typedef struct ExprSpan ExprSpan;
-typedef struct FuncDestructor FuncDestructor;
-typedef struct FuncDef FuncDef;
-typedef struct FuncDefHash FuncDefHash;
typedef struct IdList IdList;
typedef struct KeyClass KeyClass;
typedef struct Lookaside Lookaside;
@@ -1123,18 +1102,6 @@ struct LookasideSlot {
LookasideSlot *pNext; /* Next buffer in the list of free buffers */
};
-/*
- * A hash table for built-in function definitions. (Application-defined
- * functions use a regular table table from hash.h.)
- *
- * Hash each FuncDef structure into one of the FuncDefHash.a[] slots.
- * Collisions are on the FuncDef.u.pHash chain.
- */
-#define SQL_FUNC_HASH_SZ 23
-struct FuncDefHash {
- FuncDef *a[SQL_FUNC_HASH_SZ]; /* Hash table for functions */
-};
-
/*
* Each database connection is an instance of the following structure.
*/
@@ -1244,78 +1211,12 @@ struct type_def {
};
/*
- * Each SQL function is defined by an instance of the following
- * structure. For global built-in functions (ex: substr(), max(), count())
- * a pointer to this structure is held in the sqlBuiltinFunctions object.
- * For per-connection application-defined functions, a pointer to this
- * structure is held in the db->aHash hash table.
- *
- * The u.pHash field is used by the global built-ins. The u.pDestructor
- * field is used by per-connection app-def functions.
- */
-struct FuncDef {
- /**
- * 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 */
- void (*xSFunc) (sql_context *, int, sql_value **); /* func or agg-step */
- void (*xFinalize) (sql_context *); /* Agg finalizer */
- const char *zName; /* SQL name of the function. */
- union {
- FuncDef *pHash; /* Next with a different name but the same hash */
- FuncDestructor *pDestructor; /* Reference counted destructor function */
- } u;
- /* Return type. */
- enum field_type ret_type;
-};
-
-/*
- * This structure encapsulates a user-function destructor callback (as
- * configured using create_function_v2()) and a reference counter. When
- * create_function_v2() is called to create a function with a destructor,
- * a single object of this type is allocated. FuncDestructor.nRef is set to
- * the number of FuncDef objects created (either 1 or 3, depending on whether
- * or not the specified encoding is sql_ANY). The FuncDef.pDestructor
- * member of each of the new FuncDef objects is set to point to the allocated
- * FuncDestructor.
- *
- * Thereafter, when one of the FuncDef objects is deleted, the reference
- * count on this object is decremented. When it reaches 0, the destructor
- * is invoked and the FuncDestructor structure freed.
- */
-struct FuncDestructor {
- int nRef;
- void (*xDestroy) (void *);
- void *pUserData;
-};
-
-/*
- * Possible values for FuncDef.flags. Note that the _LENGTH and _TYPEOF
- * values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG. And
- * sql_FUNC_CONSTANT must be the same as sql_DETERMINISTIC. There
- * are assert() statements in the code to verify this.
- *
* Value constraints (enforced via assert()):
* SQL_FUNC_MINMAX == NC_MinMaxAgg == SF_MinMaxAgg
* SQL_FUNC_LENGTH == OPFLAG_LENGTHARG
* SQL_FUNC_TYPEOF == OPFLAG_TYPEOFARG
- * SQL_FUNC_CONSTANT == sql_DETERMINISTIC from the API
*/
#define SQL_FUNC_LIKE 0x0004 /* Candidate for the LIKE optimization */
-#define SQL_FUNC_EPHEM 0x0010 /* Ephemeral. Delete with VDBE */
#define SQL_FUNC_NEEDCOLL 0x0020 /* sqlGetFuncCollSeq() might be called.
* The flag is set when the collation
* of function arguments should be
@@ -1327,7 +1228,6 @@ struct FuncDestructor {
#define SQL_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */
#define SQL_FUNC_COALESCE 0x0200 /* Built-in coalesce() or ifnull() */
#define SQL_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
-#define SQL_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */
#define SQL_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */
#define SQL_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a
* single query - might change over time
@@ -1351,72 +1251,6 @@ enum trim_side_mask {
TRIM_BOTH = TRIM_LEADING | TRIM_TRAILING
};
-/*
- * The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
- * used to create the initializers for the FuncDef structures.
- *
- * FUNCTION(zName, mask, iArg, bNC, xFunc)
- * Used to create a scalar function definition of a function zName
- * 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.
- *
- * FUNCTION_COLL
- * Like FUNCTION except it assumes that function returns
- * STRING which collation should be derived from first
- * argument (trim, substr etc).
- *
- * VFUNCTION(zName, mask, iArg, bNC, xFunc)
- * Like FUNCTION except it omits the sql_FUNC_CONSTANT flag.
- *
- * 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, 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, mask, pArg, flags)
- * Used to create a scalar function definition of a function zName
- * 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, 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, 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, mask, iArg, bNC, xFunc, type) \
- {mask, (bNC*SQL_FUNC_NEEDCOLL), \
- SQL_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0}, type}
-#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, 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, mask, pArg, bNC, xFunc) \
- {mask, SQL_FUNC_SLOCHNG|(bNC*SQL_FUNC_NEEDCOLL), \
- pArg, 0, xFunc, 0, #zName, {SQL_AFF_STRING, {0}}}
-#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, 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, 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))
@@ -1614,7 +1448,8 @@ struct AggInfo {
*/
struct AggInfo_func { /* For each aggregate function */
Expr *pExpr; /* Expression encoding the function */
- FuncDef *pFunc; /* The aggregate function implementation */
+ /** The aggregate function implementation. */
+ struct func *func;
int iMem; /* Memory location that acts as accumulator */
int iDistinct; /* Ephemeral table used to enforce DISTINCT */
/**
@@ -3562,10 +3397,6 @@ void sqlSelectSetName(Select *, const char *);
#else
#define sqlSelectSetName(A,B)
#endif
-void sqlInsertBuiltinFuncs(FuncDef *, int);
-FuncDef *sqlFindFunction(sql *, const char *, int, u8);
-void sqlRegisterBuiltinFunctions(void);
-void sqlRegisterDateTimeFunctions(void);
/**
* Evaluate a view and store its result in an ephemeral table.
@@ -4138,7 +3969,6 @@ extern const unsigned char sqlUpperToLower[];
extern const unsigned char sqlCtypeMap[];
extern const Token sqlIntTokens[];
extern SQL_WSD struct sqlConfig sqlConfig;
-extern FuncDefHash sqlBuiltinFunctions;
extern int sqlPendingByte;
/**
@@ -4274,21 +4104,13 @@ sql_key_info_to_key_def(struct sql_key_info *key_info);
* Check if the function implements LIKE-style comparison & if it
* is appropriate to apply a LIKE query optimization.
*
- * @param db database structure.
* @param pExpr pointer to a function-implementing expression.
* @param[out] is_like_ci true if LIKE is case insensitive.
*
* @retval 1 if LIKE optimization can be used, 0 otherwise.
*/
int
-sql_is_like_func(struct sql *db, struct Expr *expr);
-
-int sqlCreateFunc(sql *, const char *, enum field_type,
- int, int, void *,
- void (*)(sql_context *, int, sql_value **),
- void (*)(sql_context *, int, sql_value **),
- void (*)(sql_context *),
- FuncDestructor * pDestructor);
+sql_is_like_func(struct Expr *expr);
/** Set OOM error flag. */
static inline void
@@ -4325,7 +4147,6 @@ sql_expr_new_column(struct sql *db, struct SrcList *src_list, int src_idx,
int sqlExprCheckIN(Parse *, Expr *);
-void sqlAnalyzeFunctions(void);
int sqlStat4ProbeSetValue(Parse *, struct index_def *, UnpackedRecord **, Expr *, int,
int, int *);
int sqlStat4ValueFromExpr(Parse *, Expr *, enum field_type type,
@@ -4516,9 +4337,62 @@ Expr *sqlExprForVectorField(Parse *, Expr *, int);
*/
extern int sqlSubProgramsRemaining;
-/** Register built-in functions to work with ANALYZE data. */
-void
-sql_register_analyze_builtins(void);
+struct func_sql_builtin {
+ /** Function object base class. */
+ struct func base;
+ /**
+ * 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;
+ /** A bitmask of SQL flags. */
+ uint16_t flags;
+ /** User data to pass in call method. */
+ void *user_data;
+ /** A call method for a function. */
+ void (*call)(sql_context *ctx, int argc, sql_value **argv);
+ /** Finalize method (only for aggregate function). */
+ void (*finalize)(sql_context *ctx);
+};
+
+/**
+ * A SQL method to find a function in a hash by it's name and
+ * count of arguments. Only functions that have 'SQL' engine
+ * export field set true and have exactly the same signature
+ * are returned.
+ *
+ * Returns not NULL function pointer when a valid and exported
+ * to SQL engine function was found and NULL otherwise.
+ */
+struct func *
+sql_func_by_signature(const char *name, uint32_t argc);
+
+/**
+ * Test whether SQL-specific flag is set for given function.
+ * Currently only SQL Builtin Functions have such hint flags,
+ * so function returns false for other functions. Such approach
+ * decreases code complexity and allows do not distinguish
+ * functions by implementation details where it is unnecessary.
+ *
+ * Returns true when given flag is set for a given function and
+ * false otherwise.
+ */
+static inline bool
+sql_func_flag_test(struct func *func, uint16_t flag)
+{
+ if (func->def->language != FUNC_LANGUAGE_SQL_BUILTIN)
+ return false;
+ return (((struct func_sql_builtin *)func)->flags & flag) != 0;
+}
/**
* Generate VDBE code to halt execution with correct error if
diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h
index 8f16202ba..4f639ec38 100644
--- a/src/box/sql/vdbe.h
+++ b/src/box/sql/vdbe.h
@@ -72,7 +72,11 @@ struct VdbeOp {
char *z; /* Pointer to data for string (char array) types */
i64 *pI64; /* Used when p4type is P4_INT64/UINT64 */
double *pReal; /* Used when p4type is P4_REAL */
- FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */
+ /**
+ * A pointer to function implementation.
+ * Used when p4type is P4_FUNC.
+ */
+ struct func *func;
sql_context *pCtx; /* Used when p4type is P4_FUNCCTX */
struct coll *pColl; /* Used when p4type is P4_COLLSEQ */
Mem *pMem; /* Used when p4type is P4_MEM */
@@ -122,7 +126,8 @@ struct SubProgram {
#define P4_DYNAMIC (-1) /* Pointer to a string obtained from sqlMalloc() */
#define P4_STATIC (-2) /* Pointer to a static string */
#define P4_COLLSEQ (-3) /* P4 is a pointer to a CollSeq structure */
-#define P4_FUNCDEF (-4) /* P4 is a pointer to a FuncDef structure */
+/** P4 is a pointer to a func structure. */
+#define P4_FUNC (-4)
#define P4_MEM (-7) /* P4 is a pointer to a Mem* structure */
#define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */
#define P4_REAL (-9) /* P4 is a 64-bit floating point value */
diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index f77c019fb..f085477c1 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -46,6 +46,8 @@
*/
typedef struct VdbeOp Op;
+struct func;
+
/*
* Boolean values
*/
@@ -168,7 +170,11 @@ struct Mem {
bool b; /* Boolean value used when MEM_Bool is set in flags */
int nZero; /* Used when bit MEM_Zero is set in flags */
void *p; /* Generic pointer */
- FuncDef *pDef; /* Used only when flags==MEM_Agg */
+ /**
+ * A pointer to function implementation.
+ * Used only when flags==MEM_Agg.
+ */
+ struct func *func;
VdbeFrame *pFrame; /* Used when flags==MEM_Frame */
} u;
u32 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
@@ -309,7 +315,8 @@ mem_apply_numeric_type(struct Mem *record);
*/
struct sql_context {
Mem *pOut; /* The return value is stored here */
- FuncDef *pFunc; /* Pointer to function information */
+ /* A pointer to function implementation. */
+ struct func *func;
Mem *pMem; /* Memory cell used to store aggregate context */
Vdbe *pVdbe; /* The VM that owns this context */
/** Instruction number of OP_BuiltinFunction0. */
@@ -516,7 +523,17 @@ int sqlVdbeMemNumerify(Mem *);
int sqlVdbeMemCast(Mem *, enum field_type type);
int sqlVdbeMemFromBtree(BtCursor *, u32, u32, Mem *);
void sqlVdbeMemRelease(Mem * p);
-int sqlVdbeMemFinalize(Mem *, FuncDef *);
+
+/**
+ * Memory cell pMem contains the context of an aggregate function.
+ * This routine calls the finalize method for that function. The
+ * result of the aggregate is stored back into pMem.
+ *
+ * Returns -1 if the finalizer reports an error. 0 otherwise.
+ */
+int
+sql_vdbemem_finalize(struct Mem *mem, struct func *func);
+
const char *sqlOpcodeName(int);
int sqlVdbeMemGrow(Mem * pMem, int n, int preserve);
int sqlVdbeMemClearAndResize(Mem * pMem, int n);
diff --git a/src/box/func.c b/src/box/func.c
index b35d05dca..12e603b3f 100644
--- a/src/box/func.c
+++ b/src/box/func.c
@@ -39,6 +39,7 @@
#include "port.h"
#include "schema.h"
#include "session.h"
+#include "sql.h"
#include <dlfcn.h>
/**
@@ -381,39 +382,6 @@ restore:
static struct func *
func_c_new(struct func_def *def);
-/** A stub object for SQL builtins to avoid name clash with UDF. */
-static struct func_vtab func_sql_builtin_vtab;
-
-/** Construct a SQL builtin function object. */
-struct func *
-func_sql_builtin_new(struct func_def *def)
-{
- assert(def->language == FUNC_LANGUAGE_SQL_BUILTIN);
- struct func *func =
- (struct func *) malloc(sizeof(*func));
- if (func == NULL) {
- diag_set(OutOfMemory, sizeof(*func), "malloc", "func");
- return NULL;
- }
- /** Don't export SQL builtins in Lua for now. */
- def->exports.lua = false;
- func->vtab = &func_sql_builtin_vtab;
- return func;
-}
-
-static void
-func_sql_builtin_destroy(struct func *func)
-{
- assert(func->vtab == &func_sql_builtin_vtab);
- assert(func->def->language == FUNC_LANGUAGE_SQL_BUILTIN);
- free(func);
-}
-
-static struct func_vtab func_sql_builtin_vtab = {
- .call = NULL,
- .destroy = func_sql_builtin_destroy,
-};
-
struct func *
func_new(struct func_def *def)
{
diff --git a/src/box/lua/call.c b/src/box/lua/call.c
index 0ac2eb7a6..001578b5a 100644
--- a/src/box/lua/call.c
+++ b/src/box/lua/call.c
@@ -44,7 +44,6 @@
#include "box/port.h"
#include "box/lua/tuple.h"
#include "small/obuf.h"
-#include "lua_sql.h"
#include "trivia/util.h"
#include "mpstream.h"
@@ -968,7 +967,6 @@ static struct trigger on_alter_func_in_lua = {
static const struct luaL_Reg boxlib_internal[] = {
{"call_loadproc", lbox_call_loadproc},
- {"sql_create_function", lbox_sql_create_function},
{"module_reload", lbox_module_reload},
{"func_call", lbox_func_call},
{NULL, NULL}
diff --git a/src/box/lua/lua_sql.c b/src/box/lua/lua_sql.c
deleted file mode 100644
index 67a51a82c..000000000
--- a/src/box/lua/lua_sql.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright 2010-2017, Tarantool AUTHORS, please see AUTHORS file.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the
- * following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "lua.h"
-#include "lua/utils.h"
-
-#include "box/lua/call.h"
-#include "box/sql/sqlInt.h"
-#include "box/sql/vdbeInt.h"
-
-struct lua_sql_func_info {
- int func_ref;
-};
-
-/**
- * This function is callback which is called by sql engine.
- *
- * Purpose of this function is to call lua func from sql.
- * Lua func should be previously registered in sql
- * (see lbox_sql_create_function).
- */
-static void
-lua_sql_call(sql_context *pCtx, int nVal, sql_value **apVal) {
- lua_State *L = lua_newthread(tarantool_L);
- int coro_ref = luaL_ref(tarantool_L, LUA_REGISTRYINDEX);
- struct lua_sql_func_info *func_info = sql_user_data(pCtx);
-
- lua_rawgeti(L, LUA_REGISTRYINDEX, func_info->func_ref);
- for (int i = 0; i < nVal; i++) {
- sql_value *param = apVal[i];
- switch (sql_value_type(param)) {
- case MP_INT:
- luaL_pushint64(L, sql_value_int64(param));
- break;
- case MP_UINT:
- luaL_pushuint64(L, sql_value_uint64(param));
- break;
- case MP_DOUBLE:
- lua_pushnumber(L, sql_value_double(param));
- break;
- case MP_STR:
- lua_pushstring(L, (const char *) sql_value_text(param));
- break;
- case MP_BIN:
- lua_pushlstring(L, sql_value_blob(param),
- (size_t) sql_value_bytes(param));
- break;
- case MP_NIL:
- lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_nil_ref);
- break;
- case MP_BOOL:
- lua_pushboolean(L, sql_value_boolean(param));
- break;
- default:
- diag_set(ClientError, ER_SQL_EXECUTE, "Unsupported "\
- "type passed to Lua");
- pCtx->is_aborted = true;
- goto error;
- }
- }
- if (lua_pcall(L, lua_gettop(L) - 1, 1, 0) != 0){
- diag_set(ClientError, ER_SQL_EXECUTE, lua_tostring(L, -1));
- pCtx->is_aborted = true;
- goto error;
- }
- switch(lua_type(L, -1)) {
- case LUA_TBOOLEAN:
- sql_result_bool(pCtx, lua_toboolean(L, -1));
- break;
- case LUA_TNUMBER:
- sql_result_double(pCtx, lua_tonumber(L, -1));
- break;
- case LUA_TSTRING:
- sql_result_text(pCtx, lua_tostring(L, -1), -1,
- SQL_TRANSIENT);
- break;
- case LUA_TNIL:
- sql_result_null(pCtx);
- break;
- default:
- diag_set(ClientError, ER_SQL_EXECUTE, "Unsupported type "\
- "passed from Lua");
- pCtx->is_aborted = true;
- goto error;
- }
-error:
- luaL_unref(tarantool_L, LUA_REGISTRYINDEX, coro_ref);
- return;
-}
-
-static void
-lua_sql_destroy(void *p)
-{
- struct lua_sql_func_info *func_info = p;
- luaL_unref(tarantool_L, LUA_REGISTRYINDEX, func_info->func_ref);
- free(func_info);
- return;
-}
-
-/**
- * A helper to register lua function in SQL during runtime.
- * It makes available queries like this: "SELECT lua_func(arg);"
- *
- * sql_create_function *p argument is used to store func ref
- * to lua function (it identifies actual lua func to call if there
- * are many of them). SQL function must have name and type of
- * returning value. Additionally, it can feature number of
- * arguments and deterministic flag.
- */
-int
-lbox_sql_create_function(struct lua_State *L)
-{
- struct sql *db = sql_get();
- if (db == NULL)
- return luaL_error(L, "Please call box.cfg{} first");
- int argc = lua_gettop(L);
- /*
- * Three function prototypes are possible:
- * 1. sql_create_function("func_name", "type", func);
- * 2. sql_create_function("func_name", "type", func,
- * func_arg_num);
- * 3. sql_create_function("func_name", "type", func,
- * func_arg_num, is_deterministic);
- */
- if (!(argc == 3 && lua_isstring(L, 1) && lua_isstring(L, 2) &&
- lua_isfunction(L, 3)) &&
- !(argc == 4 && lua_isstring(L, 1) && lua_isstring(L, 2) &&
- lua_isfunction(L, 3) && lua_isnumber(L, 4)) &&
- !(argc == 5 && lua_isstring(L, 1) && lua_isstring(L, 2) &&
- lua_isfunction(L, 3) && lua_isnumber(L, 4) &&
- lua_isboolean(L, 5)))
- return luaL_error(L, "Invalid arguments");
- enum field_type type;
- const char *type_arg = lua_tostring(L, 2);
- if (strcmp(type_arg, "INT") == 0 || strcmp(type_arg, "INTEGER") == 0)
- type = FIELD_TYPE_INTEGER;
- else if (strcmp(type_arg, "TEXT") == 0)
- type = FIELD_TYPE_STRING;
- else if (strcmp(type_arg, "NUMBER") == 0)
- type = FIELD_TYPE_NUMBER;
- else if (strcmp(type_arg, "VARBINARY") == 0)
- type = FIELD_TYPE_SCALAR;
- else if (strcmp(type_arg, "BOOL") == 0 ||
- strcmp(type_arg, "BOOLEAN") == 0)
- type = FIELD_TYPE_BOOLEAN;
- else
- return luaL_error(L, "Unknown type");
- /* -1 indicates any number of arguments. */
- int func_arg_num = -1;
- bool is_deterministic = false;
- if (argc == 4) {
- func_arg_num = lua_tointeger(L, 4);
- lua_pop(L, 1);
- } else if (argc == 5) {
- is_deterministic = lua_toboolean(L, 5);
- func_arg_num = lua_tointeger(L, 4);
- lua_pop(L, 2);
- }
- size_t name_len;
- const char *name = lua_tolstring(L, 1, &name_len);
- char *normalized_name =
- sql_normalized_name_region_new(&fiber()->gc, name, name_len);
- if (normalized_name == NULL)
- return luaT_error(L);
- struct lua_sql_func_info *func_info =
- (struct lua_sql_func_info *) malloc(sizeof(*func_info));
- if (func_info == NULL)
- return luaL_error(L, "out of memory");
- func_info->func_ref = luaL_ref(L, LUA_REGISTRYINDEX);
- int rc = sql_create_function_v2(db, normalized_name, type, func_arg_num,
- is_deterministic ? SQL_DETERMINISTIC : 0,
- func_info, lua_sql_call, NULL, NULL,
- lua_sql_destroy);
- if (rc != 0)
- return luaT_error(L);
- return 0;
-}
diff --git a/src/box/sql.c b/src/box/sql.c
index 0ab3a506f..a731332c7 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -1262,3 +1262,26 @@ vdbe_field_ref_prepare_tuple(struct vdbe_field_ref *field_ref,
vdbe_field_ref_create(field_ref, tuple, tuple_data(tuple),
tuple->bsize);
}
+
+struct func *
+sql_func_by_signature(const char *name, uint32_t argc)
+{
+ struct func *func = func_by_name(name, strlen(name));
+ if (func == NULL || !func->def->exports.sql)
+ return NULL;
+ if (func->def->language != FUNC_LANGUAGE_SQL_BUILTIN) {
+ return NULL;
+ } else {
+ /*
+ * The param_count field is not valid for sql
+ * builtin functions because they define an
+ * signature_mask with all supported overloads.
+ */
+ struct func_sql_builtin *builtin =
+ (struct func_sql_builtin *)func;
+ if (!column_mask_fieldno_is_set(builtin->signature_mask,
+ argc))
+ return NULL;
+ }
+ return func;
+}
diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
index bd52d12df..b68d86dfe 100644
--- a/src/box/sql/analyze.c
+++ b/src/box/sql/analyze.c
@@ -263,7 +263,7 @@ stat4Destructor(void *pOld)
* return value is BLOB, but it is really just a pointer to the Stat4Accum
* object.
*/
-static void
+MAYBE_UNUSED static void
statInit(sql_context * context, int argc, sql_value ** argv)
{
Stat4Accum *p;
@@ -535,7 +535,7 @@ samplePushPrevious(Stat4Accum * p, int iChng)
*
* The R parameter is only used for STAT4
*/
-static void
+MAYBE_UNUSED static void
statPush(sql_context * context, int argc, sql_value ** argv)
{
int i;
@@ -608,7 +608,7 @@ statPush(sql_context * context, int argc, sql_value ** argv)
* The content to returned is determined by the parameter J
* which is one of the STAT_GET_xxxx values defined above.
*/
-static void
+MAYBE_UNUSED static void
statGet(sql_context * context, int argc, sql_value ** argv)
{
Stat4Accum *p = (Stat4Accum *) sql_value_blob(argv[0]);
@@ -715,11 +715,11 @@ callStatGet(Vdbe * v, int regStat4, int iParam, int regOut)
{
assert(regOut != regStat4 && regOut != regStat4 + 1);
sqlVdbeAddOp2(v, OP_Integer, iParam, regStat4 + 1);
- struct FuncDef *func =
- sqlFindFunction(sql_get(), "_sql_stat_get", 2, 0);
+ struct func *func =
+ sql_func_by_signature("_sql_stat_get", 2);
assert(func != NULL);
sqlVdbeAddOp4(v, OP_BuiltinFunction0, 0, regStat4, regOut,
- (char *)func, P4_FUNCDEF);
+ (char *)func, P4_FUNC);
sqlVdbeChangeP5(v, 2);
}
@@ -855,11 +855,11 @@ vdbe_emit_analyze_space(struct Parse *parse, struct space *space)
sqlVdbeAddOp2(v, OP_Count, idx_cursor, stat4_reg + 3);
sqlVdbeAddOp2(v, OP_Integer, part_count, stat4_reg + 1);
sqlVdbeAddOp2(v, OP_Integer, part_count, stat4_reg + 2);
- struct FuncDef *init_func =
- sqlFindFunction(sql_get(), "_sql_stat_init", 3, 0);
+ struct func *init_func =
+ sql_func_by_signature("_sql_stat_init", 3);
assert(init_func != NULL);
sqlVdbeAddOp4(v, OP_BuiltinFunction0, 0, stat4_reg + 1,
- stat4_reg, (char *)init_func, P4_FUNCDEF);
+ stat4_reg, (char *)init_func, P4_FUNC);
sqlVdbeChangeP5(v, 3);
/*
* Implementation of the following:
@@ -956,11 +956,11 @@ vdbe_emit_analyze_space(struct Parse *parse, struct space *space)
sqlVdbeAddOp3(v, OP_MakeRecord, stat_key_reg,
pk_part_count, key_reg);
assert(chng_reg == (stat4_reg + 1));
- struct FuncDef *push_func =
- sqlFindFunction(sql_get(), "_sql_stat_push", 3, 0);
+ struct func *push_func =
+ sql_func_by_signature("_sql_stat_push", 3);
assert(push_func != NULL);
sqlVdbeAddOp4(v, OP_BuiltinFunction0, 1, stat4_reg, tmp_reg,
- (char *)push_func, P4_FUNCDEF);
+ (char *)push_func, P4_FUNC);
sqlVdbeChangeP5(v, 3);
sqlVdbeAddOp2(v, OP_Next, idx_cursor, next_row_addr);
/* Add the entry to the stat1 table. */
@@ -1746,14 +1746,3 @@ fail:
box_txn_rollback();
return -1;
}
-
-void
-sql_register_analyze_builtins(void)
-{
- static FuncDef funcs[] = {
- FUNCTION(_sql_stat_get, 2, 0, 0, statGet, FIELD_TYPE_ANY),
- FUNCTION(_sql_stat_push, 3, 0, 0, statPush, FIELD_TYPE_ANY),
- FUNCTION(_sql_stat_init, 3, 0, 0, statInit, FIELD_TYPE_ANY),
- };
- sqlInsertBuiltinFuncs(funcs, nelem(funcs));
-}
diff --git a/src/box/sql/callback.c b/src/box/sql/callback.c
index 737c24d98..b489f0c81 100644
--- a/src/box/sql/callback.c
+++ b/src/box/sql/callback.c
@@ -57,194 +57,3 @@ sql_get_coll_seq(Parse *parser, const char *name, uint32_t *coll_id)
return p->coll;
}
}
-
-/* During the search for the best function definition, this procedure
- * is called to test how well the function passed as the first argument
- * matches the request for a function with nArg arguments in a system
- * that uses encoding enc. The value returned indicates how well the
- * request is matched. A higher value indicates a better match.
- *
- * If nArg is -1 that means to only return a match (non-zero) if p->nArg
- * is also -1. In other words, we are searching for a function that
- * takes a variable number of arguments.
- *
- * If nArg is -2 that means that we are searching for any function
- * regardless of the number of arguments it uses, so return a positive
- * match score for any
- *
- * The returned value is always between 0 and 6, as follows:
- *
- * 0: Not a match.
- * 1: UTF8/16 conversion required and function takes any number of arguments.
- * 2: UTF16 byte order change required and function takes any number of args.
- * 3: encoding matches and function takes any number of arguments
- * 4: UTF8/16 conversion required - argument count matches exactly
- * 5: UTF16 byte order conversion required - argument count matches exactly
- * 6: Perfect match: encoding and argument count match exactly.
- *
- * If nArg==(-2) then any function with a non-null xSFunc is
- * a perfect match and any function with xSFunc NULL is
- * a non-match.
- */
-#define FUNC_PERFECT_MATCH 4 /* The score for a perfect match */
-static int
-matchQuality(FuncDef * p, /* The function we are evaluating for match quality */
- int nArg /* Desired number of arguments. (-1)==any */
- )
-{
- /* nArg of -2 is a special case */
- if (nArg == (-2))
- return FUNC_PERFECT_MATCH;
- /* Wrong number of arguments means "no match" */
- if (!column_mask_fieldno_is_set(p->signature_mask, (uint32_t)nArg))
- return 0;
- return p->signature_mask == ARGC_MASK(nArg) ? FUNC_PERFECT_MATCH : 1;
-}
-
-/*
- * Search a FuncDefHash for a function with the given name. Return
- * a pointer to the matching FuncDef if found, or 0 if there is no match.
- */
-static FuncDef *
-functionSearch(int h, /* Hash of the name */
- const char *zFunc /* Name of function */
- )
-{
- FuncDef *p;
- for (p = sqlBuiltinFunctions.a[h]; p; p = p->u.pHash) {
- if (sqlStrICmp(p->zName, zFunc) == 0) {
- return p;
- }
- }
- return 0;
-}
-
-/*
- * Insert a new FuncDef into a FuncDefHash hash table.
- */
-void
-sqlInsertBuiltinFuncs(FuncDef * aDef, /* List of global functions to be inserted */
- int nDef /* Length of the apDef[] list */
- )
-{
- int i;
- for (i = 0; i < nDef; i++) {
- FuncDef *pOther;
- const char *zName = aDef[i].zName;
- int nName = sqlStrlen30(zName);
- int h =
- (sqlUpperToLower[(u8) zName[0]] +
- nName) % SQL_FUNC_HASH_SZ;
- pOther = functionSearch(h, zName);
- if (pOther) {
- assert(pOther != &aDef[i] && pOther->pNext != &aDef[i]);
- aDef[i].pNext = pOther->pNext;
- pOther->pNext = &aDef[i];
- } else {
- aDef[i].pNext = 0;
- aDef[i].u.pHash = sqlBuiltinFunctions.a[h];
- sqlBuiltinFunctions.a[h] = &aDef[i];
- }
- }
-}
-
-/*
- * Locate a user function given a name, a number of arguments and a flag
- * indicating whether the function prefers UTF-16 over UTF-8. Return a
- * pointer to the FuncDef structure that defines that function, or return
- * NULL if the function does not exist.
- *
- * If the createFlag argument is true, then a new (blank) FuncDef
- * structure is created and liked into the "db" structure if a
- * no matching function previously existed.
- *
- * If nArg is -2, then the first valid function found is returned. A
- * function is valid if xSFunc is non-zero. The nArg==(-2)
- * case is used to see if zName is a valid function name for some number
- * of arguments. If nArg is -2, then createFlag must be 0.
- *
- * If createFlag is false, then a function with the required name and
- * number of arguments may be returned even if the eTextRep flag does not
- * match that requested.
- */
-FuncDef *
-sqlFindFunction(sql * db, /* An open database */
- const char *zName, /* Name of the function. zero-terminated */
- int nArg, /* Number of arguments. -1 means any number */
- u8 createFlag /* Create new entry if true and does not otherwise exist */
- )
-{
- FuncDef *p; /* Iterator variable */
- FuncDef *pBest = 0; /* Best match found so far */
- int bestScore = 0; /* Score of best match */
- int h; /* Hash value */
- int nName; /* Length of the name */
-
- assert(nArg >= (-2));
- assert(nArg >= (-1) || createFlag == 0);
- nName = sqlStrlen30(zName);
-
- /* First search for a match amongst the application-defined functions.
- */
- p = (FuncDef *) sqlHashFind(&db->aFunc, zName);
- while (p) {
- int score = matchQuality(p, nArg);
- if (score > bestScore) {
- pBest = p;
- bestScore = score;
- }
- p = p->pNext;
- }
-
- /* If no match is found, search the built-in functions.
- *
- * Except, if createFlag is true, that means that we are trying to
- * install a new function. Whatever FuncDef structure is returned it will
- * have fields overwritten with new information appropriate for the
- * new function. But the FuncDefs for built-in functions are read-only.
- * So we must not search for built-ins when creating a new function.
- */
- if (!createFlag && (pBest == NULL)) {
- bestScore = 0;
- h = (sqlUpperToLower[(u8) zName[0]] +
- nName) % SQL_FUNC_HASH_SZ;
- p = functionSearch(h, zName);
- while (p) {
- int score = matchQuality(p, nArg);
- if (score > bestScore) {
- pBest = p;
- bestScore = score;
- }
- p = p->pNext;
- }
- }
-
- /* If the createFlag parameter is true and the search did not reveal an
- * exact match for the name, number of arguments and encoding, then add a
- * new entry to the hash table and return it.
- */
- if (createFlag && bestScore < FUNC_PERFECT_MATCH &&
- (pBest =
- sqlDbMallocZero(db, sizeof(*pBest) + nName + 1)) != 0) {
- FuncDef *pOther;
- pBest->zName = (const char *)&pBest[1];
- pBest->signature_mask = ARGC_MASK(nArg);
- pBest->funcFlags = 0;
- memcpy((char *)&pBest[1], zName, nName + 1);
- pOther =
- (FuncDef *) sqlHashInsert(&db->aFunc, pBest->zName,
- pBest);
- if (pOther == pBest) {
- sqlDbFree(db, pBest);
- sqlOomFault(db);
- return 0;
- } else {
- pBest->pNext = pOther;
- }
- }
-
- if (pBest && (pBest->xSFunc || createFlag)) {
- return pBest;
- }
- return 0;
-}
diff --git a/src/box/sql/date.c b/src/box/sql/date.c
index 2e2a71ad2..dffc23616 100644
--- a/src/box/sql/date.c
+++ b/src/box/sql/date.c
@@ -1290,31 +1290,3 @@ currentTimeFunc(sql_context * context, int argc, sql_value ** argv)
}
}
#endif
-
-/*
- * This function registered all of the above C functions as SQL
- * functions. This should be the only routine in this file with
- * external linkage.
- */
-void
-sqlRegisterDateTimeFunctions(void)
-{
- static FuncDef aDateTimeFuncs[] = {
-#if 0
- DFUNCTION(julianday, -1, 0, 0, juliandayFunc, FIELD_TYPE_NUMBER),
- DFUNCTION(date, -1, 0, 0, dateFunc, FIELD_TYPE_STRING),
- DFUNCTION(time, -1, 0, 0, timeFunc, FIELD_TYPE_STRING),
- DFUNCTION(datetime, -1, 0, 0, datetimeFunc, FIELD_TYPE_STRING),
- DFUNCTION(strftime, -1, 0, 0, strftimeFunc, FIELD_TYPE_STRING),
- DFUNCTION(current_time, 0, 0, 0, ctimeFunc, FIELD_TYPE_STRING),
- DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc,
- FIELD_TYPE_STRING),
- DFUNCTION(current_date, 0, 0, 0, cdateFunc, FIELD_TYPE_STRING),
- STR_FUNCTION(current_time, 0, "%H:%M:%S", 0, currentTimeFunc),
- STR_FUNCTION(current_date, 0, "%Y-%m-%d", 0, currentTimeFunc),
- STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0,
- currentTimeFunc),
-#endif
- };
- sqlInsertBuiltinFuncs(aDateTimeFuncs, ArraySize(aDateTimeFuncs));
-}
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index 1f9d91705..64b3bc835 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -328,12 +328,11 @@ sql_expr_coll(Parse *parse, Expr *p, bool *is_explicit_coll, uint32_t *coll_id,
if (op == TK_FUNCTION) {
uint32_t arg_count = p->x.pList == NULL ? 0 :
p->x.pList->nExpr;
- struct FuncDef *func = sqlFindFunction(parse->db,
- p->u.zToken,
- arg_count, 0);
+ struct func *func =
+ sql_func_by_signature(p->u.zToken, arg_count);
if (func == NULL)
break;
- if ((func->funcFlags & SQL_FUNC_DERIVEDCOLL) != 0) {
+ if (sql_func_flag_test(func, SQL_FUNC_DERIVEDCOLL)) {
/*
* Now we use quite straightforward
* approach assuming that resulting
@@ -342,7 +341,7 @@ sql_expr_coll(Parse *parse, Expr *p, bool *is_explicit_coll, uint32_t *coll_id,
* built-in functions: trim, upper,
* lower, replace, substr.
*/
- assert(func->ret_type == FIELD_TYPE_STRING);
+ assert(func->def->returns == FIELD_TYPE_STRING);
p = p->x.pList->a->pExpr;
continue;
}
@@ -3975,11 +3974,9 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
case TK_FUNCTION:{
ExprList *pFarg; /* List of function arguments */
int nFarg; /* Number of function arguments */
- FuncDef *pDef; /* The function definition object */
const char *zId; /* The function name */
u32 constMask = 0; /* Mask of function arguments that are constant */
int i; /* Loop counter */
- sql *db = pParse->db; /* The database connection */
struct coll *coll = NULL;
assert(!ExprHasProperty(pExpr, EP_xIsSelect));
@@ -3991,8 +3988,9 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
nFarg = pFarg ? pFarg->nExpr : 0;
assert(!ExprHasProperty(pExpr, EP_IntValue));
zId = pExpr->u.zToken;
- pDef = sqlFindFunction(db, zId, nFarg, 0);
- if (pDef == 0 || pDef->xFinalize != 0) {
+ struct func *func = sql_func_by_signature(zId, nFarg);
+ if (func == NULL ||
+ func->def->aggregate == FUNC_AGGREGATE_GROUP) {
diag_set(ClientError, ER_NO_SUCH_FUNCTION,
zId);
pParse->is_aborted = true;
@@ -4002,7 +4000,7 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
* IFNULL() functions. This avoids unnecessary evaluation of
* arguments past the first non-NULL argument.
*/
- if (pDef->funcFlags & SQL_FUNC_COALESCE) {
+ if (sql_func_flag_test(func, SQL_FUNC_COALESCE)) {
int endCoalesce = sqlVdbeMakeLabel(v);
assert(nFarg >= 2);
sqlExprCode(pParse, pFarg->a[0].pExpr,
@@ -4026,7 +4024,7 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
/* The UNLIKELY() function is a no-op. The result is the value
* of the first argument.
*/
- if (pDef->funcFlags & SQL_FUNC_UNLIKELY) {
+ if (sql_func_flag_test(func, SQL_FUNC_UNLIKELY)) {
assert(nFarg >= 1);
return sqlExprCodeTarget(pParse,
pFarg->a[0].pExpr,
@@ -4049,7 +4047,7 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
* is done using ANSI rules from
* collations_check_compatibility().
*/
- if ((pDef->funcFlags & SQL_FUNC_NEEDCOLL) != 0) {
+ if (sql_func_flag_test(func, SQL_FUNC_NEEDCOLL)) {
struct coll *unused = NULL;
uint32_t curr_id = COLL_NONE;
bool is_curr_forced = false;
@@ -4096,9 +4094,8 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
* or OPFLAG_TYPEOFARG respectively, to avoid unnecessary data
* loading.
*/
- if ((pDef->
- funcFlags & (SQL_FUNC_LENGTH |
- SQL_FUNC_TYPEOF)) != 0) {
+ if (sql_func_flag_test(func, SQL_FUNC_LENGTH |
+ SQL_FUNC_TYPEOF)) {
u8 exprOp;
assert(nFarg == 1);
assert(pFarg->a[0].pExpr != 0);
@@ -4109,14 +4106,7 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
OPFLAG_LENGTHARG);
assert(SQL_FUNC_TYPEOF ==
OPFLAG_TYPEOFARG);
- testcase(pDef->
- funcFlags &
- OPFLAG_LENGTHARG);
- pFarg->a[0].pExpr->op2 =
- pDef->
- funcFlags &
- (OPFLAG_LENGTHARG |
- OPFLAG_TYPEOFARG);
+ pFarg->a[0].pExpr->op2 = true;
}
}
@@ -4128,12 +4118,15 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
} else {
r1 = 0;
}
- if (pDef->funcFlags & SQL_FUNC_NEEDCOLL) {
+ if (sql_func_flag_test(func, SQL_FUNC_NEEDCOLL)) {
sqlVdbeAddOp4(v, OP_CollSeq, 0, 0, 0,
(char *)coll, P4_COLLSEQ);
}
- sqlVdbeAddOp4(v, OP_BuiltinFunction0, constMask, r1,
- target, (char *)pDef, P4_FUNCDEF);
+ assert(func->def->language ==
+ FUNC_LANGUAGE_SQL_BUILTIN);
+ int op = OP_BuiltinFunction0;
+ sqlVdbeAddOp4(v, op, constMask, r1, target,
+ (char *)func, P4_FUNC);
sqlVdbeChangeP5(v, (u8) nFarg);
if (nFarg && constMask == 0) {
sqlReleaseTempRange(pParse, r1, nFarg);
@@ -5441,12 +5434,19 @@ analyzeAggregate(Walker * pWalker, Expr * pExpr)
pItem->iMem = ++pParse->nMem;
assert(!ExprHasProperty
(pExpr, EP_IntValue));
- pItem->pFunc = sqlFindFunction(
- pParse->db,
- pExpr->u.zToken,
- pExpr->x.pList ?
- pExpr->x.pList->nExpr : 0,
- 0);
+ uint32_t argc =
+ pExpr->x.pList != NULL ?
+ pExpr->x.pList->nExpr : 0;
+ pItem->func =
+ sql_func_by_signature(
+ pExpr->u.zToken,
+ argc);
+ assert(pItem->func->def->
+ language ==
+ FUNC_LANGUAGE_SQL_BUILTIN &&
+ pItem->func->def->
+ aggregate ==
+ FUNC_AGGREGATE_GROUP);
if (pExpr->flags & EP_Distinct) {
pItem->iDistinct =
pParse->nTab++;
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 8e07ce892..f07c52b95 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -1825,114 +1825,231 @@ groupConcatFinalize(sql_context * context)
}
int
-sql_is_like_func(struct sql *db, struct Expr *expr)
+sql_is_like_func(struct Expr *expr)
{
if (expr->op != TK_FUNCTION || !expr->x.pList ||
expr->x.pList->nExpr != 2)
return 0;
assert(!ExprHasProperty(expr, EP_xIsSelect));
- struct FuncDef *func = sqlFindFunction(db, expr->u.zToken, 2, 0);
+ struct func *func = sql_func_by_signature(expr->u.zToken, 2);
assert(func != NULL);
- if ((func->funcFlags & SQL_FUNC_LIKE) == 0)
+ if (!sql_func_flag_test(func, SQL_FUNC_LIKE))
return 0;
return 1;
}
-/*
- * All of the FuncDef structures in the aBuiltinFunc[] array above
- * to the global function hash table. This occurs at start-time (as
- * a consequence of calling sql_initialize()).
- *
- * After this routine runs
+static int
+sql_builtin_call_stub(struct func *func, struct port *args, struct port *ret)
+{
+ (void) func; (void) args; (void) ret;
+ diag_set(ClientError, ER_UNSUPPORTED,
+ "sql builtin function", "Lua frontend");
+ return -1;
+}
+
+static void
+sql_builtin_stub(sql_context *ctx, int argc, sql_value **argv)
+{
+ (void) argc; (void) argv;
+ diag_set(ClientError, ER_SQL_EXECUTE,
+ tt_sprintf("function '%s' is not implemented",
+ ctx->func->def->name));
+ ctx->is_aborted = true;
+}
+
+#define REG_FUNC(name, signature_mask, returns, flags, \
+ call, user_data, is_deterministic) \
+ {name, signature_mask, returns, flags, call, NULL, \
+ user_data, FUNC_AGGREGATE_NONE, is_deterministic}
+
+#define AGG_FUNC(name, signature_mask, returns, flags, \
+ call, finalize, user_data) \
+ {name, signature_mask, returns, flags, call, \
+ finalize, user_data, FUNC_AGGREGATE_GROUP, false}
+
+#define STUB_FUNC(name) \
+ {name, 0, FIELD_TYPE_ANY, 0, sql_builtin_stub, \
+ NULL, NULL, FUNC_AGGREGATE_NONE, false}
+
+/**
+ * A sequence of SQL builtins definitions in
+ * lexicographic order.
*/
-void
-sqlRegisterBuiltinFunctions(void)
+static struct {
+ const char *name;
+ uint64_t signature_mask;
+ enum field_type returns;
+ uint16_t flags;
+ void (*call)(sql_context *ctx, int argc, sql_value **argv);
+ void (*finalize)(sql_context *ctx);
+ void *user_data;
+ enum func_aggregate aggregate;
+ bool is_deterministic;
+} sql_builtins[] = {
+ REG_FUNC("ABS", ARGC_MASK(1), FIELD_TYPE_NUMBER, 0,
+ absFunc, NULL, true),
+ AGG_FUNC("AVG", ARGC_MASK(1), FIELD_TYPE_NUMBER, 0,
+ sum_step, avgFinalize, NULL),
+ STUB_FUNC("CEIL"), STUB_FUNC("CEILING"),
+ REG_FUNC("CHAR", ARGC_MASK_FULL, FIELD_TYPE_STRING, 0,
+ charFunc, NULL, true),
+ REG_FUNC("CHARACTER_LENGTH", ARGC_MASK(1), FIELD_TYPE_INTEGER, 0,
+ lengthFunc, NULL, true),
+ REG_FUNC("CHAR_LENGTH", ARGC_MASK(1), FIELD_TYPE_INTEGER, 0,
+ lengthFunc, NULL, true),
+ REG_FUNC("COALESCE", ARGC_MASK_FULL & ~ARGC_MASK2(0, 1),
+ FIELD_TYPE_SCALAR, SQL_FUNC_COALESCE,
+ sql_builtin_stub, NULL, true),
+ AGG_FUNC("COUNT", ARGC_MASK2(0, 1), FIELD_TYPE_INTEGER, 0,
+ countStep, countFinalize, NULL),
+ STUB_FUNC("CURRENT_DATE"), STUB_FUNC("CURRENT_TIME"),
+ STUB_FUNC("CURRENT_TIMESTAMP"), STUB_FUNC("DATE"),
+ STUB_FUNC("DATETIME"), STUB_FUNC("EVERY"),
+ STUB_FUNC("EXISTS"), STUB_FUNC("EXP"), STUB_FUNC("EXTRACT"),
+ STUB_FUNC("FLOOR"), STUB_FUNC("GREATER"),
+ REG_FUNC("GREATEST", ARGC_MASK_FULL, FIELD_TYPE_SCALAR,
+ SQL_FUNC_NEEDCOLL, minmaxFunc, SQL_INT_TO_PTR(1), true),
+ AGG_FUNC("GROUP_CONCAT", ARGC_MASK2(1, 2), FIELD_TYPE_STRING, 0,
+ groupConcatStep, groupConcatFinalize, NULL),
+ REG_FUNC("HEX", ARGC_MASK(1), FIELD_TYPE_STRING, 0,
+ hexFunc, NULL, true),
+ REG_FUNC("IFNULL", ARGC_MASK(2), FIELD_TYPE_INTEGER, SQL_FUNC_COALESCE,
+ sql_builtin_stub, NULL, true),
+ STUB_FUNC("JULIANDAY"),
+ REG_FUNC("LEAST", ARGC_MASK_FULL, FIELD_TYPE_SCALAR, SQL_FUNC_NEEDCOLL,
+ minmaxFunc, SQL_INT_TO_PTR(0), true),
+ REG_FUNC("LENGTH", ARGC_MASK(1), FIELD_TYPE_INTEGER, SQL_FUNC_LENGTH,
+ lengthFunc, NULL, true),
+ STUB_FUNC("LESSER"),
+ REG_FUNC("LIKE", ARGC_MASK2(2, 3), FIELD_TYPE_INTEGER,
+ SQL_FUNC_NEEDCOLL | SQL_FUNC_LIKE,
+ likeFunc, SQL_INT_TO_PTR(1), true),
+ REG_FUNC("LIKELIHOOD", ARGC_MASK(2), FIELD_TYPE_BOOLEAN,
+ SQL_FUNC_UNLIKELY, sql_builtin_stub, NULL, true),
+ REG_FUNC("LIKELY", ARGC_MASK(1), FIELD_TYPE_BOOLEAN, SQL_FUNC_UNLIKELY,
+ sql_builtin_stub, NULL, true),
+ STUB_FUNC("LN"),
+ REG_FUNC("LOWER", ARGC_MASK(1), FIELD_TYPE_STRING,
+ SQL_FUNC_DERIVEDCOLL | SQL_FUNC_NEEDCOLL,
+ LowerICUFunc, NULL, true),
+ AGG_FUNC("MAX", ARGC_MASK(1), FIELD_TYPE_SCALAR,
+ SQL_FUNC_NEEDCOLL | SQL_FUNC_MINMAX,
+ minmaxStep, minMaxFinalize, SQL_INT_TO_PTR(1)),
+ AGG_FUNC("MIN", ARGC_MASK(1), FIELD_TYPE_SCALAR,
+ SQL_FUNC_NEEDCOLL | SQL_FUNC_MINMAX,
+ minmaxStep, minMaxFinalize, SQL_INT_TO_PTR(0)),
+ STUB_FUNC("MOD"),
+ REG_FUNC("NULLIF", ARGC_MASK(2), FIELD_TYPE_SCALAR, SQL_FUNC_NEEDCOLL,
+ nullifFunc, NULL, true),
+ STUB_FUNC("OCTET_LENGTH"),
+ REG_FUNC("POSITION", ARGC_MASK(2), FIELD_TYPE_INTEGER,
+ SQL_FUNC_NEEDCOLL, position_func, NULL, true),
+ STUB_FUNC("POWER"),
+ REG_FUNC("PRINTF", ARGC_MASK_FULL, FIELD_TYPE_STRING, 0,
+ printfFunc, NULL, true),
+ REG_FUNC("QUOTE", ARGC_MASK(1), FIELD_TYPE_STRING, 0,
+ quoteFunc, NULL, true),
+ REG_FUNC("RANDOM", ARGC_MASK(0), FIELD_TYPE_INTEGER, 0,
+ randomFunc, NULL, false),
+ REG_FUNC("RANDOMBLOB", ARGC_MASK(1), FIELD_TYPE_VARBINARY, 0,
+ randomBlob, NULL, false),
+ REG_FUNC("REPLACE", ARGC_MASK(3), FIELD_TYPE_STRING,
+ SQL_FUNC_DERIVEDCOLL, replaceFunc, NULL, true),
+ REG_FUNC("ROUND", ARGC_MASK2(1, 2), FIELD_TYPE_INTEGER, 0,
+ roundFunc, NULL, true),
+ REG_FUNC("ROW_COUNT", ARGC_MASK(0), FIELD_TYPE_INTEGER, 0,
+ sql_row_count, NULL, true),
+ STUB_FUNC("SOME"),
+ REG_FUNC("SOUNDEX", ARGC_MASK(1), FIELD_TYPE_STRING, 0,
+ soundexFunc, NULL, true),
+ STUB_FUNC("SQRT"), STUB_FUNC("STRFTIME"),
+ REG_FUNC("SUBSTR", ARGC_MASK2(2, 3), FIELD_TYPE_STRING,
+ SQL_FUNC_DERIVEDCOLL, substrFunc, NULL, true),
+ AGG_FUNC("SUM", ARGC_MASK(1), FIELD_TYPE_NUMBER, 0, sum_step,
+ sumFinalize, NULL),
+ STUB_FUNC("TIME"),
+ AGG_FUNC("TOTAL", ARGC_MASK(1), FIELD_TYPE_NUMBER, 0, sum_step,
+ totalFinalize, NULL),
+ REG_FUNC("TRIM", ARGC_MASK3(1, 2, 3), FIELD_TYPE_STRING,
+ SQL_FUNC_DERIVEDCOLL, trim_func, NULL, true),
+ REG_FUNC("TYPEOF", ARGC_MASK(1), FIELD_TYPE_STRING,
+ SQL_FUNC_TYPEOF, typeofFunc, NULL, true),
+ REG_FUNC("UNICODE", ARGC_MASK(1), FIELD_TYPE_STRING, 0,
+ unicodeFunc, NULL, true),
+ REG_FUNC("UNLIKELY", ARGC_MASK(1), FIELD_TYPE_BOOLEAN,
+ SQL_FUNC_UNLIKELY, sql_builtin_stub, NULL, true),
+ REG_FUNC("UPPER", ARGC_MASK(1), FIELD_TYPE_STRING,
+ SQL_FUNC_DERIVEDCOLL | SQL_FUNC_NEEDCOLL,
+ UpperICUFunc, NULL, true),
+ REG_FUNC("VERSION", ARGC_MASK(0), FIELD_TYPE_STRING, 0,
+ sql_func_version, NULL, true),
+ REG_FUNC("ZEROBLOB", ARGC_MASK(1), FIELD_TYPE_VARBINARY, 0,
+ zeroblobFunc, NULL, true),
+ STUB_FUNC("_sql_stat_get"), STUB_FUNC("_sql_stat_init"),
+ STUB_FUNC("_sql_stat_push"),
+};
+
+static struct func_vtab func_sql_builtin_vtab;
+
+struct func *
+func_sql_builtin_new(struct func_def *def)
{
- /*
- * The following array holds FuncDef structures for all of the functions
- * defined in this file.
- *
- * The array cannot be constant since changes are made to the
- * FuncDef.pHash elements at start-time. The elements of this array
- * are read-only after initialization is complete.
- *
- * For peak efficiency, put the most frequently used function last.
- */
- static FuncDef aBuiltinFunc[] = {
- 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, ARGC_MASK(2), 0, 0, noopFunc, SQL_FUNC_UNLIKELY,
- FIELD_TYPE_BOOLEAN),
- FUNCTION2(likely, ARGC_MASK(1), 0, 0, noopFunc, SQL_FUNC_UNLIKELY,
- FIELD_TYPE_BOOLEAN),
- 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, 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, ARGC_MASK(1), 0, 0, typeofFunc, SQL_FUNC_TYPEOF,
- FIELD_TYPE_STRING),
- FUNCTION2(length, ARGC_MASK(1), 0, 0, lengthFunc, SQL_FUNC_LENGTH,
- FIELD_TYPE_INTEGER),
- 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, 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, 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, ARGC_MASK(1), 0, 0, sum_step, totalFinalize,
- FIELD_TYPE_NUMBER),
- AGGREGATE(avg, ARGC_MASK(1), 0, 0, sum_step, avgFinalize,
- FIELD_TYPE_NUMBER),
- AGGREGATE(count, ARGC_MASK2(0, 1), 0, 0, countStep, countFinalize,
- FIELD_TYPE_INTEGER),
- AGGREGATE(group_concat, ARGC_MASK2(1, 2), 0, 0, groupConcatStep,
- groupConcatFinalize, FIELD_TYPE_STRING),
- LIKEFUNC(like, ARGC_MASK2(2, 3), 1, SQL_FUNC_LIKE,
- FIELD_TYPE_INTEGER),
- FUNCTION2(coalesce, ARGC_MASK_FULL & ~ARGC_MASK2(0, 1), 0, 0, noopFunc, SQL_FUNC_COALESCE,
- FIELD_TYPE_SCALAR),
- };
- sql_register_analyze_builtins();
- sqlRegisterDateTimeFunctions();
- sqlInsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc));
-
-#if 0 /* Enable to print out how the built-in functions are hashed */
- {
- int i;
- FuncDef *p;
- for (i = 0; i < SQL_FUNC_HASH_SZ; i++) {
- printf("FUNC-HASH %02d:", i);
- for (p = sqlBuiltinFunctions.a[i]; p;
- p = p->u.pHash) {
- int n = sqlStrlen30(p->zName);
- int h = p->zName[0] + n;
- printf(" %s(%d)", p->zName, h);
- }
- printf("\n");
+ assert(def->language == FUNC_LANGUAGE_SQL_BUILTIN);
+ if (def->body != NULL || def->is_sandboxed) {
+ diag_set(ClientError, ER_CREATE_FUNCTION, def->name,
+ "body and is_sandboxed options are not compatible "
+ "with SQL language");
+ return NULL;
+ }
+ /** Binary search for corresponding builtin entry. */
+ int idx = -1, left = 0, right = nelem(sql_builtins) - 1;
+ while (left <= right) {
+ uint32_t mid = (left + right) / 2;
+ int rc = strcmp(def->name, sql_builtins[mid].name);
+ if (rc == 0) {
+ idx = mid;
+ break;
}
+ if (rc < 0)
+ right = mid - 1;
+ else
+ left = mid + 1;
}
-#endif
+ if (idx == -1) {
+ diag_set(ClientError, ER_CREATE_FUNCTION, def->name,
+ "unknown sql builtin name");
+ return NULL;
+ }
+ struct func_sql_builtin *func =
+ (struct func_sql_builtin *) malloc(sizeof(*func));
+ if (func == NULL) {
+ diag_set(OutOfMemory, sizeof(*func), "malloc", "func");
+ return NULL;
+ }
+ func->flags = sql_builtins[idx].flags;
+ func->user_data = sql_builtins[idx].user_data;
+ func->call = sql_builtins[idx].call;
+ func->finalize = sql_builtins[idx].finalize;
+ func->signature_mask = sql_builtins[idx].signature_mask;
+ func->base.vtab = &func_sql_builtin_vtab;
+ func->base.def = def;
+
+ def->is_deterministic = sql_builtins[idx].is_deterministic;
+ def->returns = sql_builtins[idx].returns;
+ def->aggregate = sql_builtins[idx].aggregate;
+ def->exports.sql = true;
+ return &func->base;
+}
+
+static void
+func_sql_builtin_destroy(struct func *func)
+{
+ assert(func->vtab == &func_sql_builtin_vtab);
+ assert(func->def->language == FUNC_LANGUAGE_SQL_BUILTIN);
+ free(func);
}
+
+static struct func_vtab func_sql_builtin_vtab = {
+ .call = sql_builtin_call_stub,
+ .destroy = func_sql_builtin_destroy,
+};
diff --git a/src/box/sql/global.c b/src/box/sql/global.c
index 6cadef809..c25b83de1 100644
--- a/src/box/sql/global.c
+++ b/src/box/sql/global.c
@@ -162,13 +162,6 @@ SQL_WSD struct sqlConfig sqlConfig = {
0x7ffffffe /* iOnceResetThreshold */
};
-/*
- * Hash table for global functions - functions common to all
- * database connections. After initialization, this table is
- * read-only.
- */
-FuncDefHash sqlBuiltinFunctions;
-
/*
* The value of the "pending" byte must be 0x40000000 (1 byte past the
* 1-gibabyte boundary) in a compatible database. sql never uses
diff --git a/src/box/sql/main.c b/src/box/sql/main.c
index eb6e4a7db..0b20f2132 100644
--- a/src/box/sql/main.c
+++ b/src/box/sql/main.c
@@ -131,9 +131,6 @@ sql_initialize(void)
if (sqlGlobalConfig.isInit == 0
&& sqlGlobalConfig.inProgress == 0) {
sqlGlobalConfig.inProgress = 1;
- memset(&sqlBuiltinFunctions, 0,
- sizeof(sqlBuiltinFunctions));
- sqlRegisterBuiltinFunctions();
sql_os_init();
sqlGlobalConfig.isInit = 1;
sqlGlobalConfig.inProgress = 0;
@@ -242,25 +239,6 @@ sqlCloseSavepoints(Vdbe * pVdbe)
pVdbe->anonymous_savepoint = NULL;
}
-/*
- * Invoke the destructor function associated with FuncDef p, if any. Except,
- * if this is not the last copy of the function, do not invoke it. Multiple
- * copies of a single function are created when create_function() is called
- * with SQL_ANY as the encoding.
- */
-static void
-functionDestroy(sql * db, FuncDef * p)
-{
- FuncDestructor *pDestructor = p->u.pDestructor;
- if (pDestructor) {
- pDestructor->nRef--;
- if (pDestructor->nRef == 0) {
- pDestructor->xDestroy(pDestructor->pUserData);
- sqlDbFree(db, pDestructor);
- }
- }
-}
-
/*
* Rollback all database files. If tripCode is not 0, then
* any write cursors are invalidated ("tripped" - as in "tripping a circuit
@@ -279,121 +257,6 @@ sqlRollbackAll(Vdbe * pVdbe)
}
}
-/*
- * This function is exactly the same as sql_create_function(), except
- * that it is designed to be called by internal code. The difference is
- * that if a malloc() fails in sql_create_function(), an error code
- * is returned and the mallocFailed flag cleared.
- */
-int
-sqlCreateFunc(sql * db,
- const char *zFunctionName,
- enum field_type type,
- int nArg,
- int flags,
- void *pUserData,
- void (*xSFunc) (sql_context *, int, sql_value **),
- void (*xStep) (sql_context *, int, sql_value **),
- void (*xFinal) (sql_context *),
- FuncDestructor * pDestructor)
-{
- FuncDef *p;
- int extraFlags;
-
- if (zFunctionName == 0 ||
- (xSFunc && (xFinal || xStep)) ||
- (!xSFunc && (xFinal && !xStep)) ||
- (!xSFunc && (!xFinal && xStep)) ||
- (nArg < -1 || nArg > SQL_MAX_FUNCTION_ARG) ||
- (255 < (sqlStrlen30(zFunctionName)))) {
- diag_set(ClientError, ER_CREATE_FUNCTION, zFunctionName,
- "wrong function definition");
- return -1;
- }
-
- assert(SQL_FUNC_CONSTANT == SQL_DETERMINISTIC);
- extraFlags = flags & SQL_DETERMINISTIC;
-
-
- /* Check if an existing function is being overridden or deleted. If so,
- * and there are active VMs, then return an error. If a function
- * is being overridden/deleted but there are no active VMs, allow the
- * operation to continue but invalidate all precompiled statements.
- */
- p = sqlFindFunction(db, zFunctionName, nArg, 0);
- 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 "\
- "statements");
- return -1;
- } else {
- sqlExpirePreparedStatements(db);
- }
- }
-
- p = sqlFindFunction(db, zFunctionName, nArg, 1);
- assert(p || db->mallocFailed);
- if (p == NULL)
- return -1;
-
- /* If an older version of the function with a configured destructor is
- * being replaced invoke the destructor function here.
- */
- functionDestroy(db, p);
-
- if (pDestructor) {
- pDestructor->nRef++;
- }
- p->u.pDestructor = pDestructor;
- p->funcFlags = extraFlags;
- testcase(p->funcFlags & SQL_DETERMINISTIC);
- p->xSFunc = xSFunc ? xSFunc : xStep;
- p->xFinalize = xFinal;
- p->pUserData = pUserData;
- p->signature_mask = ARGC_MASK(nArg);
- p->ret_type = type;
- return 0;
-}
-
-int
-sql_create_function_v2(sql * db,
- const char *zFunc,
- enum field_type type,
- int nArg,
- int flags,
- void *p,
- void (*xSFunc) (sql_context *, int,
- sql_value **),
- void (*xStep) (sql_context *, int,
- sql_value **),
- void (*xFinal) (sql_context *),
- void (*xDestroy) (void *))
-{
- FuncDestructor *pArg = 0;
-
- if (xDestroy) {
- pArg =
- (FuncDestructor *) sqlDbMallocZero(db,
- sizeof
- (FuncDestructor));
- if (!pArg) {
- xDestroy(p);
- return -1;
- }
- pArg->xDestroy = xDestroy;
- pArg->pUserData = p;
- }
- int rc = sqlCreateFunc(db, zFunc, type, nArg, flags, p, xSFunc, xStep,
- xFinal, pArg);
- if (pArg && pArg->nRef == 0) {
- assert(rc != 0);
- xDestroy(p);
- sqlDbFree(db, pArg);
- }
- return rc;
-}
-
/*
* This array defines hard upper bounds on limit values. The
* initializer must be kept in sync with the SQL_LIMIT_*
diff --git a/src/box/sql/resolve.c b/src/box/sql/resolve.c
index 0b90edd06..0c54afef6 100644
--- a/src/box/sql/resolve.c
+++ b/src/box/sql/resolve.c
@@ -38,6 +38,9 @@
#include "sqlInt.h"
#include <stdlib.h>
#include <string.h>
+#include "box/func.h"
+#include "box/func_def.h"
+#include "box/schema.h"
/*
* Walk the expression tree pExpr and increase the aggregate function
@@ -596,27 +599,30 @@ resolveExprStep(Walker * pWalker, Expr * pExpr)
int is_agg = 0; /* True if is an aggregate function */
int nId; /* Number of characters in function name */
const char *zId; /* The function name. */
- FuncDef *pDef; /* Information about the function */
assert(!ExprHasProperty(pExpr, EP_xIsSelect));
zId = pExpr->u.zToken;
nId = sqlStrlen30(zId);
- pDef = sqlFindFunction(pParse->db, zId, n, 0);
- if (pDef == 0) {
- pDef =
- sqlFindFunction(pParse->db, zId, -2,0);
- if (pDef == 0) {
+ struct func *func = sql_func_by_signature(zId, n);
+ if (func == NULL) {
+ func = func_by_name(zId, strlen(zId));
+ if (func == NULL || !func->def->exports.sql) {
+ func = NULL;
no_such_func = 1;
} else {
wrong_num_args = 1;
}
} else {
- is_agg = pDef->xFinalize != 0;
- pExpr->type = pDef->ret_type;
+ is_agg = func->def->language ==
+ FUNC_LANGUAGE_SQL_BUILTIN &&
+ func->def->aggregate ==
+ FUNC_AGGREGATE_GROUP;;
+ pExpr->type = func->def->returns;
const char *err =
"second argument to likelihood() must "\
"be a constant between 0.0 and 1.0";
- if (pDef->funcFlags & SQL_FUNC_UNLIKELY) {
+ if (sql_func_flag_test(func,
+ SQL_FUNC_UNLIKELY)) {
ExprSetProperty(pExpr,
EP_Unlikely | EP_Skip);
if (n == 2) {
@@ -643,21 +649,19 @@ resolveExprStep(Walker * pWalker, Expr * pExpr)
*/
/* TUNING: unlikely() probability is 0.0625. likely() is 0.9375 */
pExpr->iTable =
- pDef->zName[0] ==
- 'u' ? 8388608 : 125829120;
+ func->def->name[0] == 'u' ?
+ 8388608 : 125829120;
}
}
- if (pDef->
- funcFlags & (SQL_FUNC_CONSTANT |
- SQL_FUNC_SLOCHNG)) {
+ if (func->def->is_deterministic ||
+ sql_func_flag_test(func, SQL_FUNC_SLOCHNG)) {
/* For the purposes of the EP_ConstFunc flag, date and time
* functions and other functions that change slowly are considered
* constant because they are constant for the duration of one query
*/
ExprSetProperty(pExpr, EP_ConstFunc);
}
- if ((pDef->funcFlags & SQL_FUNC_CONSTANT) ==
- 0) {
+ if (!func->def->is_deterministic) {
/* Date/time functions that use 'now', and other functions
* that might change over time cannot be used
* in an index.
@@ -700,18 +704,14 @@ resolveExprStep(Walker * pWalker, Expr * pExpr)
pExpr->op2++;
pNC2 = pNC2->pNext;
}
- assert(pDef != 0);
+ assert(func != NULL);
if (pNC2) {
+ pNC2->ncFlags |= NC_HasAgg;
assert(SQL_FUNC_MINMAX ==
NC_MinMaxAgg);
- testcase((pDef->
- funcFlags &
- SQL_FUNC_MINMAX) != 0);
- pNC2->ncFlags |=
- NC_HasAgg | (pDef->
- funcFlags &
- SQL_FUNC_MINMAX);
-
+ if (sql_func_flag_test(func,
+ SQL_FUNC_MINMAX))
+ pNC2->ncFlags |= NC_MinMaxAgg;
}
pNC->ncFlags |= NC_AllowAgg;
}
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 921a52150..bce5cef3b 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -5277,7 +5277,7 @@ finalizeAggFunctions(Parse * pParse, AggInfo * pAggInfo)
assert(!ExprHasProperty(pF->pExpr, EP_xIsSelect));
sqlVdbeAddOp2(v, OP_AggFinal, pF->iMem,
pList ? pList->nExpr : 0);
- sqlVdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
+ sqlVdbeAppendP4(v, pF->func, P4_FUNC);
}
}
@@ -5318,7 +5318,7 @@ updateAccumulator(Parse * pParse, AggInfo * pAggInfo)
vdbe_insert_distinct(pParse, pF->iDistinct, pF->reg_eph,
addrNext, 1, regAgg);
}
- if (pF->pFunc->funcFlags & SQL_FUNC_NEEDCOLL) {
+ if (sql_func_flag_test(pF->func, SQL_FUNC_NEEDCOLL)) {
struct coll *coll = NULL;
struct ExprList_item *pItem;
int j;
@@ -5337,7 +5337,7 @@ updateAccumulator(Parse * pParse, AggInfo * pAggInfo)
(char *)coll, P4_COLLSEQ);
}
sqlVdbeAddOp3(v, OP_AggStep0, 0, regAgg, pF->iMem);
- sqlVdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
+ sqlVdbeAppendP4(v, pF->func, P4_FUNC);
sqlVdbeChangeP5(v, (u8) nArg);
sql_expr_type_cache_change(pParse, regAgg, nArg);
sqlReleaseTempRange(pParse, regAgg, nArg);
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 28552f64a..a66becc89 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -41,6 +41,8 @@
*/
#include "box/box.h"
#include "box/error.h"
+#include "box/func.h"
+#include "box/func_def.h"
#include "box/fk_constraint.h"
#include "box/txn.h"
#include "box/tuple.h"
@@ -1704,7 +1706,7 @@ case OP_BuiltinFunction0: {
int n;
sql_context *pCtx;
- assert(pOp->p4type==P4_FUNCDEF);
+ assert(pOp->p4type == P4_FUNC);
n = pOp->p5;
assert(pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor));
assert(n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1));
@@ -1712,7 +1714,7 @@ case OP_BuiltinFunction0: {
pCtx = sqlDbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sql_value*));
if (pCtx==0) goto no_mem;
pCtx->pOut = 0;
- pCtx->pFunc = pOp->p4.pFunc;
+ pCtx->func = pOp->p4.func;
pCtx->iOp = (int)(pOp - aOp);
pCtx->pVdbe = p;
pCtx->argc = n;
@@ -1747,7 +1749,9 @@ case OP_BuiltinFunction: {
}
#endif
pCtx->is_aborted = false;
- (*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */
+ assert(pCtx->func->def->language == FUNC_LANGUAGE_SQL_BUILTIN);
+ (*((struct func_sql_builtin *)pCtx->func)->call)(pCtx, pCtx->argc,
+ pCtx->argv);
/* If the function returned an error, throw an exception */
if (pCtx->is_aborted)
@@ -5005,7 +5009,7 @@ case OP_AggStep0: {
int n;
sql_context *pCtx;
- assert(pOp->p4type==P4_FUNCDEF);
+ assert(pOp->p4type == P4_FUNC);
n = pOp->p5;
assert(pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor));
assert(n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1));
@@ -5013,7 +5017,7 @@ case OP_AggStep0: {
pCtx = sqlDbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sql_value*));
if (pCtx==0) goto no_mem;
pCtx->pMem = 0;
- pCtx->pFunc = pOp->p4.pFunc;
+ pCtx->func = pOp->p4.func;
pCtx->iOp = (int)(pOp - aOp);
pCtx->pVdbe = p;
pCtx->argc = n;
@@ -5055,7 +5059,9 @@ case OP_AggStep: {
pCtx->pOut = &t;
pCtx->is_aborted = false;
pCtx->skipFlag = 0;
- (pCtx->pFunc->xSFunc)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */
+ assert(pCtx->func->def->language == FUNC_LANGUAGE_SQL_BUILTIN);
+ (*((struct func_sql_builtin *)pCtx->func)->call)(pCtx, pCtx->argc,
+ pCtx->argv);
if (pCtx->is_aborted) {
sqlVdbeMemRelease(&t);
goto abort_due_to_error;
@@ -5087,7 +5093,7 @@ case OP_AggFinal: {
assert(pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor));
pMem = &aMem[pOp->p1];
assert((pMem->flags & ~(MEM_Null|MEM_Agg))==0);
- if (sqlVdbeMemFinalize(pMem, pOp->p4.pFunc) != 0)
+ if (sql_vdbemem_finalize(pMem, pOp->p4.func) != 0)
goto abort_due_to_error;
UPDATE_MAX_BLOBSIZE(pMem);
if (sqlVdbeMemTooBig(pMem)) {
diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c
index 1aee3cf85..4ff8db621 100644
--- a/src/box/sql/vdbeapi.c
+++ b/src/box/sql/vdbeapi.c
@@ -484,8 +484,9 @@ sql_step(sql_stmt * pStmt)
void *
sql_user_data(sql_context * p)
{
- assert(p && p->pFunc);
- return p->pFunc->pUserData;
+ assert(p != NULL && p->func != NULL);
+ assert(p->func->def->language == FUNC_LANGUAGE_SQL_BUILTIN);
+ return ((struct func_sql_builtin *)p->func)->user_data;
}
/*
@@ -547,7 +548,7 @@ createAggContext(sql_context * p, int nByte)
} else {
sqlVdbeMemClearAndResize(pMem, nByte);
pMem->flags = MEM_Agg;
- pMem->u.pDef = p->pFunc;
+ pMem->u.func = p->func;
if (pMem->z) {
memset(pMem->z, 0, nByte);
}
@@ -563,7 +564,9 @@ createAggContext(sql_context * p, int nByte)
void *
sql_aggregate_context(sql_context * p, int nByte)
{
- assert(p && p->pFunc && p->pFunc->xFinalize);
+ assert(p != NULL && p->func != NULL &&
+ p->func->def->language == FUNC_LANGUAGE_SQL_BUILTIN &&
+ p->func->def->aggregate == FUNC_AGGREGATE_GROUP);
testcase(nByte < 0);
if ((p->pMem->flags & MEM_Agg) == 0) {
return createAggContext(p, nByte);
diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
index d32404580..a44540b1d 100644
--- a/src/box/sql/vdbeaux.c
+++ b/src/box/sql/vdbeaux.c
@@ -648,24 +648,11 @@ sqlVdbeJumpHere(Vdbe * p, int addr)
sqlVdbeChangeP2(p, addr, p->nOp);
}
-/*
- * If the input FuncDef structure is ephemeral, then free it. If
- * the FuncDef is not ephermal, then do nothing.
- */
-static void
-freeEphemeralFunction(sql * db, FuncDef * pDef)
-{
- if ((pDef->funcFlags & SQL_FUNC_EPHEM) != 0) {
- sqlDbFree(db, pDef);
- }
-}
-
static void vdbeFreeOpArray(sql *, Op *, int);
static SQL_NOINLINE void
freeP4FuncCtx(sql * db, sql_context * p)
{
- freeEphemeralFunction(db, p->pFunc);
sqlDbFree(db, p);
}
@@ -689,13 +676,11 @@ freeP4(sql * db, int p4type, void *p4)
case P4_KEYINFO:
sql_key_info_unref(p4);
break;
- case P4_FUNCDEF:{
- freeEphemeralFunction(db, (FuncDef *) p4);
- break;
- }
case P4_MEM:
sqlValueFree((sql_value *) p4);
break;
+ default:
+ break;
}
}
@@ -1149,17 +1134,17 @@ displayP4(Op * pOp, char *zTemp, int nTemp)
sqlXPrintf(&x, "(binary)");
break;
}
- case P4_FUNCDEF:{
- FuncDef *pDef = pOp->p4.pFunc;
- sqlXPrintf(&x, "%s(%d)", pDef->zName,
- pDef->signature_mask);
+ case P4_FUNC:{
+ struct func *func = pOp->p4.func;
+ sqlXPrintf(&x, "%s(%d)", func->def->name,
+ func->def->param_count);
break;
}
#if defined(SQL_DEBUG) || defined(VDBE_PROFILE)
case P4_FUNCCTX:{
- FuncDef *pDef = pOp->p4.pCtx->pFunc;
- sqlXPrintf(&x, "%s(%d)", pDef->zName,
- pDef->signature_mask);
+ struct func *func = pOp->p4.func;
+ sqlXPrintf(&x, "%s(%d)", func->def->name,
+ func->def->param_count);
break;
}
#endif
diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c
index b8c31ecec..8b2e816f2 100644
--- a/src/box/sql/vdbemem.c
+++ b/src/box/sql/vdbemem.c
@@ -312,33 +312,28 @@ sqlVdbeMemStringify(Mem * pMem)
return 0;
}
-/*
- * Memory cell pMem contains the context of an aggregate function.
- * This routine calls the finalize method for that function. The
- * result of the aggregate is stored back into pMem.
- *
- * Return -1 if the finalizer reports an error. 0 otherwise.
- */
int
-sqlVdbeMemFinalize(Mem * pMem, FuncDef * pFunc)
+sql_vdbemem_finalize(struct Mem *mem, struct func *func)
{
- if (ALWAYS(pFunc && pFunc->xFinalize)) {
+ if (ALWAYS(func != NULL &&
+ func->def->language == FUNC_LANGUAGE_SQL_BUILTIN &&
+ func->def->aggregate == FUNC_AGGREGATE_GROUP)) {
sql_context ctx;
Mem t;
- assert((pMem->flags & MEM_Null) != 0 || pFunc == pMem->u.pDef);
+ assert((mem->flags & MEM_Null) != 0 || func == mem->u.func);
memset(&ctx, 0, sizeof(ctx));
memset(&t, 0, sizeof(t));
t.flags = MEM_Null;
- t.db = pMem->db;
+ t.db = mem->db;
t.field_type = field_type_MAX;
ctx.pOut = &t;
- ctx.pMem = pMem;
- ctx.pFunc = pFunc;
- pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
- assert((pMem->flags & MEM_Dyn) == 0);
- if (pMem->szMalloc > 0)
- sqlDbFree(pMem->db, pMem->zMalloc);
- memcpy(pMem, &t, sizeof(t));
+ ctx.pMem = mem;
+ ctx.func = func;
+ ((struct func_sql_builtin *)func)->finalize(&ctx);
+ assert((mem->flags & MEM_Dyn) == 0);
+ if (mem->szMalloc > 0)
+ sqlDbFree(mem->db, mem->zMalloc);
+ memcpy(mem, &t, sizeof(t));
if (ctx.is_aborted)
return -1;
}
@@ -359,7 +354,7 @@ vdbeMemClearExternAndSetNull(Mem * p)
{
assert(VdbeMemDynamic(p));
if (p->flags & MEM_Agg) {
- sqlVdbeMemFinalize(p, p->u.pDef);
+ sql_vdbemem_finalize(p, p->u.func);
assert((p->flags & MEM_Agg) == 0);
testcase(p->flags & MEM_Dyn);
}
@@ -1289,7 +1284,6 @@ valueFromFunction(sql * db, /* The database connection */
sql_context ctx; /* Context object for function invocation */
sql_value **apVal = 0; /* Function arguments */
int nVal = 0; /* Size of apVal[] array */
- FuncDef *pFunc = 0; /* Function definition */
sql_value *pVal = 0; /* New value */
int rc = 0; /* Return code */
ExprList *pList = 0; /* Function arguments */
@@ -1300,13 +1294,13 @@ valueFromFunction(sql * db, /* The database connection */
pList = p->x.pList;
if (pList)
nVal = pList->nExpr;
- pFunc = sqlFindFunction(db, p->u.zToken, nVal, 0);
- assert(pFunc);
- if ((pFunc->funcFlags & (SQL_FUNC_CONSTANT | SQL_FUNC_SLOCHNG)) ==
- 0 || (pFunc->funcFlags & SQL_FUNC_NEEDCOLL)
- ) {
+ struct func *func = sql_func_by_signature(p->u.zToken, nVal);
+ assert(func != NULL);
+ if (func->def->language != FUNC_LANGUAGE_SQL_BUILTIN ||
+ (!func->def->is_deterministic &&
+ !sql_func_flag_test(func, SQL_FUNC_SLOCHNG)) ||
+ sql_func_flag_test(func, SQL_FUNC_NEEDCOLL))
return 0;
- }
if (pList) {
apVal =
@@ -1334,8 +1328,8 @@ valueFromFunction(sql * db, /* The database connection */
assert(!pCtx->pParse->is_aborted);
memset(&ctx, 0, sizeof(ctx));
ctx.pOut = pVal;
- ctx.pFunc = pFunc;
- pFunc->xSFunc(&ctx, nVal, apVal);
+ ctx.func = func;
+ ((struct func_sql_builtin *)func)->call(&ctx, nVal, apVal);
assert(!ctx.is_aborted);
sql_value_apply_type(pVal, type);
assert(rc == 0);
diff --git a/src/box/sql/whereexpr.c b/src/box/sql/whereexpr.c
index 8adf6a5f1..98615b118 100644
--- a/src/box/sql/whereexpr.c
+++ b/src/box/sql/whereexpr.c
@@ -273,7 +273,7 @@ like_optimization_is_valid(Parse *pParse, Expr *pExpr, Expr **ppPrefix,
/* Result code to return. */
int rc;
- if (!sql_is_like_func(db, pExpr)) {
+ if (!sql_is_like_func(pExpr)) {
return 0;
}
pList = pExpr->x.pList;
diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt
index 9bba37bcb..9d2fcea4b 100644
--- a/src/box/CMakeLists.txt
+++ b/src/box/CMakeLists.txt
@@ -130,7 +130,6 @@ add_library(box STATIC
${lua_sources}
lua/init.c
lua/call.c
- lua/lua_sql.c
lua/cfg.cc
lua/console.c
lua/tuple.c
diff --git a/test/sql-tap/where2.test.lua b/test/sql-tap/where2.test.lua
index 4116ca913..f267be8e6 100755
--- a/test/sql-tap/where2.test.lua
+++ b/test/sql-tap/where2.test.lua
@@ -231,7 +231,7 @@ test:do_execsql_test(
EXPLAIN SELECT * FROM x1, x2 WHERE x=1 ORDER BY random();
]], {
-- <where2-2.5>
- "/random/"
+ "/RANDOM/"
-- </where2-2.5>
})
@@ -254,7 +254,7 @@ test:do_execsql_test(
EXPLAIN SELECT * FROM x1, x2 WHERE x=1 ORDER BY abs(5);
]], {
-- <where2-2.6>
- "~/abs/"
+ "~/ABS/"
-- </where2-2.6>
})
--
2.22.0
More information about the Tarantool-patches
mailing list