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 6190C2AB08 for ; Mon, 17 Sep 2018 16:33:18 -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 e0W46aZGQ-fd for ; Mon, 17 Sep 2018 16:33:18 -0400 (EDT) Received: from smtp14.mail.ru (smtp14.mail.ru [94.100.181.95]) (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 807402AAA5 for ; Mon, 17 Sep 2018 16:33:15 -0400 (EDT) From: Nikita Pettik Subject: [tarantool-patches] [PATCH 2/6] sql: annotate SQL functions with return type Date: Mon, 17 Sep 2018 23:32:26 +0300 Message-Id: In-Reply-To: References: In-Reply-To: References: 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 Cc: Georgy Kirichenko From: Georgy Kirichenko Any SQL function should have declared type of returning value. Lets temporary add affinity to function definition as a type of returning value. --- src/box/lua/lua_sql.c | 207 +++++++++++++++++--------------- src/box/sql/analyze.c | 9 +- src/box/sql/date.c | 16 +-- src/box/sql/func.c | 142 ++++++++++++---------- src/box/sql/main.c | 7 +- src/box/sql/sqliteInt.h | 36 +++--- src/box/sql/vdbemem.c | 2 +- test/sql-tap/alias.test.lua | 2 +- test/sql-tap/analyze5.test.lua | 1 + test/sql-tap/analyze9.test.lua | 12 +- test/sql-tap/analyzeF.test.lua | 6 +- test/sql-tap/check.test.lua | 2 +- test/sql-tap/date.test.lua | 2 +- test/sql-tap/e_expr.test.lua | 26 ++-- test/sql-tap/func5.test.lua | 4 +- test/sql-tap/gh-3350-skip-scan.test.lua | 4 +- test/sql-tap/lua_sql.test.lua | 22 ++-- test/sql-tap/subquery.test.lua | 2 +- test/sql-tap/trigger9.test.lua | 2 +- 19 files changed, 271 insertions(+), 233 deletions(-) diff --git a/src/box/lua/lua_sql.c b/src/box/lua/lua_sql.c index 9d78679fb..e69e143db 100644 --- a/src/box/lua/lua_sql.c +++ b/src/box/lua/lua_sql.c @@ -6,13 +6,13 @@ * conditions are met: * * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. + * 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. + * 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 ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -33,27 +33,22 @@ #include "lua/utils.h" #include "box/lua/call.h" -#include -#include -#include +#include "box/sql/sqliteInt.h" +#include "box/sql/vdbeInt.h" -#define LUA_WRONG_TYPE_MESG "Unsupported type passed to lua" - -struct lua_sql_func_info{ +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). - * + * Lua func should be previously registered in sql + * (see lbox_sql_create_function). */ -static void lua_sql_call(sqlite3_context *pCtx, - int nVal, - sqlite3_value **apVal) { +static void +lua_sql_call(sqlite3_context *pCtx, int nVal, sqlite3_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 = sqlite3_user_data(pCtx); @@ -62,43 +57,33 @@ static void lua_sql_call(sqlite3_context *pCtx, for (int i = 0; i < nVal; i++) { sqlite3_value *param = apVal[i]; switch (sqlite3_value_type(param)) { - case SQLITE_INTEGER: { + case SQLITE_INTEGER: luaL_pushint64(L, sqlite3_value_int64(param)); break; - } - case SQLITE_FLOAT: { + case SQLITE_FLOAT: lua_pushnumber(L, sqlite3_value_double(param)); break; - } - case SQLITE_TEXT: { - lua_pushstring(L, - (const char *) sqlite3_value_text(param)); + case SQLITE_TEXT: + lua_pushstring(L, (const char *) sqlite3_value_text(param)); break; - } - case SQLITE_BLOB: { - const void *blob = sqlite3_value_blob(param); - lua_pushlstring(L, blob, - (size_t) sqlite3_value_bytes(param)); + case SQLITE_BLOB: + lua_pushlstring(L, sqlite3_value_blob(param), + (size_t) sqlite3_value_bytes(param)); break; - } - case SQLITE_NULL: { + case SQLITE_NULL: lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_nil_ref); break; - } - default: { - sqlite3_result_error(pCtx, - LUA_WRONG_TYPE_MESG, - -1); - goto lua_sql_call_exit_1; - } + default: + sqlite3_result_error(pCtx, "Unsupported type passed " + "to Lua", -1); + goto error; } } if (lua_pcall(L, lua_gettop(L) - 1, 1, 0) != 0){ sqlite3_result_error(pCtx, lua_tostring(L, -1), -1); - goto lua_sql_call_exit_1; + goto error; } - - switch(lua_type(L, -1)){ + switch(lua_type(L, -1)) { case LUA_TBOOLEAN: sqlite3_result_int(pCtx, lua_toboolean(L, -1)); break; @@ -106,26 +91,24 @@ static void lua_sql_call(sqlite3_context *pCtx, sqlite3_result_double(pCtx, lua_tonumber(L, -1)); break; case LUA_TSTRING: - sqlite3_result_text(pCtx, - lua_tostring(L, -1), - -1, - SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, lua_tostring(L, -1), -1, + SQLITE_TRANSIENT); break; case LUA_TNIL: sqlite3_result_null(pCtx); break; default: - sqlite3_result_error(pCtx, - "Unsupported type returned from lua", - -1); - goto lua_sql_call_exit_1; + sqlite3_result_error(pCtx, "Unsupported type returned from Lua", + -1); + goto error; } - lua_sql_call_exit_1: +error: luaL_unref(tarantool_L, LUA_REGISTRYINDEX, coro_ref); return; } -static void lua_sql_destroy(void * p) +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); @@ -134,65 +117,89 @@ static void lua_sql_destroy(void * p) } /** - * A helper to register lua function in sql in runtime + * A helper to register lua function in SQL during runtime. * It makes available queries like this: "SELECT lua_func(arg);" * - * sqlite3_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) + * sqlite3_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) +int +lbox_sql_create_function(struct lua_State *L) { - int argc = lua_gettop(L); - int func_arg_num = -1; // -1 is any arg num - int is_deterministic = 0; - const char *name; - size_t name_len; - char *normalized_name; - struct lua_sql_func_info *func_info; - int rc; - sqlite3 *db = sql_get(); - /** - * Check args. Three types are possible: - * sql_create_function("func_name", func) - * sql_create_function("func_name", func, func_arg_num) - * sql_create_function("func_name", func, func_arg_num, is_deterministic) - */ - if ( !(argc == 2 && lua_isstring(L, 1) && lua_isfunction(L, 2)) && - !(argc == 3 && lua_isstring(L, 1) && lua_isfunction(L, 2) && - lua_isnumber(L, 3)) && - !(argc == 4 && lua_isstring(L, 1) && lua_isfunction(L, 2) && - lua_isnumber(L, 3) && lua_isboolean(L, 4))) { - luaL_error(L, "Invalid arguments"); - return 0; - } + struct sqlite3 *db = sql_get(); if (db == NULL) { luaL_error(L, "Please call box.cfg{} first"); return 0; } - if (argc == 3) { - func_arg_num = (int) lua_tonumber(L, 3); - // func should be on top of the stack because of luaL_ref api + 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))) { + luaL_error(L, "Invalid arguments"); + return 0; + } + enum affinity_type type = AFFINITY_UNDEFINED; + const char *type_arg = lua_tostring(L, 2); + if (strcmp(type_arg, "INT") == 0 || strcmp(type_arg, "INTEGER") == 0) { + type = AFFINITY_INTEGER; + } else if (strcmp(type_arg, "TEXT") == 0) { + type = AFFINITY_TEXT; + } else if (strcmp(type_arg, "FLOAT") == 0) { + type = AFFINITY_REAL; + } else if (strcmp(type_arg, "NUM") == 0) { + type = AFFINITY_NUMERIC; + } else if (strcmp(type_arg, "BLOB") == 0) { + type = AFFINITY_BLOB; + } else { + 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 = (int) lua_tonumber(L, 4); lua_pop(L, 1); + } else if (argc == 5) { + is_deterministic = lua_toboolean(L, 5); + func_arg_num = (int) lua_tonumber(L, 4); + lua_pop(L, 2); } - if (argc == 4) { - if(lua_toboolean(L, 4)) - is_deterministic = SQLITE_DETERMINISTIC; - func_arg_num = (int) lua_tonumber(L, 3); - lua_pop(L, 2); - } - name = lua_tostring(L, 1); - name_len = strlen(name); - normalized_name = (char*) malloc(name_len+1); - memcpy(normalized_name, name, name_len+1); + const char *name = lua_tostring(L, 1); + size_t name_len = strlen(name); + char *normalized_name = (char *) region_alloc(&fiber()->gc, + name_len + 1); + if (normalized_name == NULL) { + luaL_error(L, "out of memory"); + return 0; + } + memcpy(normalized_name, name, name_len); + normalized_name[name_len] = '\0'; sqlite3NormalizeName(normalized_name); - func_info = (struct lua_sql_func_info*)malloc(sizeof(struct lua_sql_func_info)); + struct lua_sql_func_info *func_info = + (struct lua_sql_func_info *) malloc(sizeof(*func_info)); + if (func_info == NULL) { + luaL_error(L, "out of memory"); + return 0; + } func_info->func_ref = luaL_ref(L, LUA_REGISTRYINDEX); - rc = sqlite3_create_function_v2(db, normalized_name, func_arg_num, - is_deterministic, func_info, lua_sql_call, - NULL, NULL, lua_sql_destroy); - - free(normalized_name); - return rc; + sqlite3_create_function_v2(db, normalized_name, type, func_arg_num, + is_deterministic ? SQLITE_DETERMINISTIC : 0, + func_info, lua_sql_call, NULL, NULL, + lua_sql_destroy); + return 0; } - diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c index 76ae15386..f1aca5b78 100644 --- a/src/box/sql/analyze.c +++ b/src/box/sql/analyze.c @@ -375,7 +375,8 @@ static const FuncDef statInitFuncdef = { statInit, /* xSFunc */ 0, /* xFinalize */ "stat_init", /* zName */ - {0} + {0}, + 0 }; /* @@ -630,7 +631,8 @@ static const FuncDef statPushFuncdef = { statPush, /* xSFunc */ 0, /* xFinalize */ "stat_push", /* zName */ - {0} + {0}, + 0 }; #define STAT_GET_STAT1 0 /* "stat" column of stat1 table */ @@ -757,7 +759,8 @@ static const FuncDef statGetFuncdef = { statGet, /* xSFunc */ 0, /* xFinalize */ "stat_get", /* zName */ - {0} + {0}, + 0 }; static void diff --git a/src/box/sql/date.c b/src/box/sql/date.c index 9566cc386..8a3588355 100644 --- a/src/box/sql/date.c +++ b/src/box/sql/date.c @@ -1306,14 +1306,14 @@ sqlite3RegisterDateTimeFunctions(void) { static FuncDef aDateTimeFuncs[] = { #ifndef SQLITE_OMIT_DATETIME_FUNCS - DFUNCTION(julianday, -1, 0, 0, juliandayFunc), - DFUNCTION(date, -1, 0, 0, dateFunc), - DFUNCTION(time, -1, 0, 0, timeFunc), - DFUNCTION(datetime, -1, 0, 0, datetimeFunc), - DFUNCTION(strftime, -1, 0, 0, strftimeFunc), - DFUNCTION(current_time, 0, 0, 0, ctimeFunc), - DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc), - DFUNCTION(current_date, 0, 0, 0, cdateFunc), + DFUNCTION(julianday, -1, 0, 0, juliandayFunc, AFFINITY_REAL), + DFUNCTION(date, -1, 0, 0, dateFunc, AFFINITY_REAL), + DFUNCTION(time, -1, 0, 0, timeFunc, AFFINITY_REAL), + DFUNCTION(datetime, -1, 0, 0, datetimeFunc, AFFINITY_REAL), + DFUNCTION(strftime, -1, 0, 0, strftimeFunc, AFFINITY_REAL), + DFUNCTION(current_time, 0, 0, 0, ctimeFunc, AFFINITY_REAL), + DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc, AFFINITY_REAL), + DFUNCTION(current_date, 0, 0, 0, cdateFunc, AFFINITY_REAL), #else STR_FUNCTION(current_time, 0, "%H:%M:%S", 0, currentTimeFunc), STR_FUNCTION(current_date, 0, "%Y-%m-%d", 0, currentTimeFunc), diff --git a/src/box/sql/func.c b/src/box/sql/func.c index 45056a7da..8c34cbb3d 100644 --- a/src/box/sql/func.c +++ b/src/box/sql/func.c @@ -1678,7 +1678,8 @@ groupConcatFinalize(sqlite3_context * context) * a new one that always throws a run-time error. */ static inline int -sqlite3_overload_function(sqlite3 * db, const char *zName, int nArg) +sqlite3_overload_function(sqlite3 * db, const char *zName, + enum affinity_type type, int nArg) { int rc = SQLITE_OK; @@ -1688,7 +1689,8 @@ sqlite3_overload_function(sqlite3 * db, const char *zName, int nArg) } #endif if (sqlite3FindFunction(db, zName, nArg, 0) == 0) { - rc = sqlite3CreateFunc(db, zName, nArg, 0, 0, sqlite3InvalidFunction, 0, 0, 0); + rc = sqlite3CreateFunc(db, zName, type, nArg, 0, 0, + sqlite3InvalidFunction, 0, 0, 0); } rc = sqlite3ApiExit(db, rc); return rc; @@ -1702,7 +1704,7 @@ sqlite3_overload_function(sqlite3 * db, const char *zName, int nArg) void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 * db) { - int rc = sqlite3_overload_function(db, "MATCH", 2); + int rc = sqlite3_overload_function(db, "MATCH", AFFINITY_UNDEFINED, 2); assert(rc == SQLITE_NOMEM || rc == SQLITE_OK); if (rc == SQLITE_NOMEM) { sqlite3OomFault(db); @@ -1736,9 +1738,17 @@ sqlite3RegisterLikeFunctions(sqlite3 * db, int caseSensitive) } else { pInfo = (struct compareInfo *)&likeInfoNorm; } - sqlite3CreateFunc(db, "LIKE", 2, 0, pInfo, likeFunc, 0, 0, 0); - sqlite3CreateFunc(db, "LIKE", 3, 0, pInfo, likeFunc, 0, 0, 0); - sqlite3CreateFunc(db, "GLOB", 2, 0, (struct compareInfo *)&globInfo, likeFunc, 0, 0, 0); + /* + * FIXME: after introducing type LIKE must + * return that type: TRUE if the string matches the + * supplied pattern and FALSE otherwise. + */ + sqlite3CreateFunc(db, "LIKE", AFFINITY_INTEGER, 2, 0, pInfo, + likeFunc, 0, 0, 0); + sqlite3CreateFunc(db, "LIKE", AFFINITY_INTEGER, 3, 0, pInfo, + likeFunc, 0, 0, 0); + sqlite3CreateFunc(db, "GLOB", AFFINITY_INTEGER, 2, 0, + (struct compareInfo *) &globInfo, likeFunc, 0, 0, 0); setLikeOptFlag(db, "GLOB", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE); setLikeOptFlag(db, "LIKE", caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : @@ -1815,77 +1825,87 @@ sqlite3RegisterBuiltinFunctions(void) #ifdef SQLITE_SOUNDEX FUNCTION(soundex, 1, 0, 0, soundexFunc), #endif - FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), - FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), - FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), - FUNCTION(ltrim, 1, 1, 0, trimFunc), - FUNCTION(ltrim, 2, 1, 0, trimFunc), - FUNCTION(rtrim, 1, 2, 0, trimFunc), - FUNCTION(rtrim, 2, 2, 0, trimFunc), - FUNCTION(trim, 1, 3, 0, trimFunc), - FUNCTION(trim, 2, 3, 0, trimFunc), - FUNCTION(min, -1, 0, 1, minmaxFunc), - FUNCTION(min, 0, 0, 1, 0), + FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY, + AFFINITY_INTEGER), + FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY, + AFFINITY_INTEGER), + FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY, + AFFINITY_INTEGER), + FUNCTION(ltrim, 1, 1, 0, trimFunc, AFFINITY_TEXT), + FUNCTION(ltrim, 2, 1, 0, trimFunc, AFFINITY_TEXT), + FUNCTION(rtrim, 1, 2, 0, trimFunc, AFFINITY_TEXT), + FUNCTION(rtrim, 2, 2, 0, trimFunc, AFFINITY_TEXT), + FUNCTION(trim, 1, 3, 0, trimFunc, AFFINITY_TEXT), + FUNCTION(trim, 2, 3, 0, trimFunc, AFFINITY_TEXT), + FUNCTION(min, -1, 0, 1, minmaxFunc, 0), + FUNCTION(min, 0, 0, 1, 0, 0), AGGREGATE2(min, 1, 0, 1, minmaxStep, minMaxFinalize, - SQLITE_FUNC_MINMAX), - FUNCTION(max, -1, 1, 1, minmaxFunc), - FUNCTION(max, 0, 1, 1, 0), + SQLITE_FUNC_MINMAX, 0), + FUNCTION(max, -1, 1, 1, minmaxFunc, 0), + FUNCTION(max, 0, 1, 1, 0, 0), AGGREGATE2(max, 1, 1, 1, minmaxStep, minMaxFinalize, - SQLITE_FUNC_MINMAX), - FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), - FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH), - FUNCTION(instr, 2, 0, 0, instrFunc), - FUNCTION(printf, -1, 0, 0, printfFunc), - FUNCTION(unicode, 1, 0, 0, unicodeFunc), - FUNCTION(char, -1, 0, 0, charFunc), - FUNCTION(abs, 1, 0, 0, absFunc), + SQLITE_FUNC_MINMAX, 0), + FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF, + AFFINITY_TEXT), + FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH, + AFFINITY_INTEGER), + FUNCTION(instr, 2, 0, 0, instrFunc, AFFINITY_INTEGER), + FUNCTION(printf, -1, 0, 0, printfFunc, AFFINITY_TEXT), + FUNCTION(unicode, 1, 0, 0, unicodeFunc, AFFINITY_TEXT), + FUNCTION(char, -1, 0, 0, charFunc, AFFINITY_TEXT), + FUNCTION(abs, 1, 0, 0, absFunc, AFFINITY_REAL), #ifndef SQLITE_OMIT_FLOATING_POINT - FUNCTION(round, 1, 0, 0, roundFunc), - FUNCTION(round, 2, 0, 0, roundFunc), + FUNCTION(round, 1, 0, 0, roundFunc, AFFINITY_INTEGER), + FUNCTION(round, 2, 0, 0, roundFunc, AFFINITY_INTEGER), #endif - FUNCTION(upper, 1, 0, 1, UpperICUFunc), - FUNCTION(lower, 1, 0, 1, LowerICUFunc), - FUNCTION(hex, 1, 0, 0, hexFunc), - FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), - VFUNCTION(random, 0, 0, 0, randomFunc), - VFUNCTION(randomblob, 1, 0, 0, randomBlob), - FUNCTION(nullif, 2, 0, 1, nullifFunc), - FUNCTION(version, 0, 0, 0, sql_func_version), - FUNCTION(quote, 1, 0, 0, quoteFunc), - VFUNCTION(changes, 0, 0, 0, changes), - VFUNCTION(total_changes, 0, 0, 0, total_changes), - FUNCTION(replace, 3, 0, 0, replaceFunc), - FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc), - FUNCTION(substr, 2, 0, 0, substrFunc), - FUNCTION(substr, 3, 0, 0, substrFunc), - AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize), - AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize), - AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize), + FUNCTION(upper, 1, 0, 1, UpperICUFunc, AFFINITY_TEXT), + FUNCTION(lower, 1, 0, 1, LowerICUFunc, AFFINITY_TEXT), + FUNCTION(hex, 1, 0, 0, hexFunc, AFFINITY_TEXT), + FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE, + AFFINITY_INTEGER), + VFUNCTION(random, 0, 0, 0, randomFunc, AFFINITY_REAL), + VFUNCTION(randomblob, 1, 0, 0, randomBlob, AFFINITY_BLOB), + FUNCTION(nullif, 2, 0, 1, nullifFunc, 0), + FUNCTION(version, 0, 0, 0, sql_func_version, AFFINITY_TEXT), + FUNCTION(quote, 1, 0, 0, quoteFunc, AFFINITY_TEXT), + VFUNCTION(changes, 0, 0, 0, changes, AFFINITY_INTEGER), + VFUNCTION(total_changes, 0, 0, 0, total_changes, + AFFINITY_INTEGER), + FUNCTION(replace, 3, 0, 0, replaceFunc, AFFINITY_TEXT), + FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc, AFFINITY_BLOB), + FUNCTION(substr, 2, 0, 0, substrFunc, AFFINITY_TEXT), + FUNCTION(substr, 3, 0, 0, substrFunc, AFFINITY_TEXT), + AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize, 0), + AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize, 0), + AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize, 0), AGGREGATE2(count, 0, 0, 0, countStep, countFinalize, - SQLITE_FUNC_COUNT), - AGGREGATE(count, 1, 0, 0, countStep, countFinalize), + SQLITE_FUNC_COUNT, AFFINITY_INTEGER), + AGGREGATE(count, 1, 0, 0, countStep, countFinalize, + AFFINITY_INTEGER), AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, - groupConcatFinalize), + groupConcatFinalize, AFFINITY_TEXT), AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, - groupConcatFinalize), + groupConcatFinalize, AFFINITY_TEXT), LIKEFUNC(glob, 2, &globInfo, - SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE), + SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE, AFFINITY_INTEGER), #ifdef SQLITE_CASE_SENSITIVE_LIKE LIKEFUNC(like, 2, &likeInfoAlt, - SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE), + SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE, AFFINITY_INTEGER), LIKEFUNC(like, 3, &likeInfoAlt, - SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE), + SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE, AFFINITY_INTEGER), #else - LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE), - LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE), + LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE, + AFFINITY_INTEGER), + LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE, + AFFINITY_INTEGER), #endif #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION - FUNCTION(unknown, -1, 0, 0, unknownFunc), + FUNCTION(unknown, -1, 0, 0, unknownFunc, 0), #endif - FUNCTION(coalesce, 1, 0, 0, 0), - FUNCTION(coalesce, 0, 0, 0, 0), - FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), + FUNCTION(coalesce, 1, 0, 0, 0, 0), + FUNCTION(coalesce, 0, 0, 0, 0, 0), + FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE, 0), }; sqlite3AnalyzeFunctions(); sqlite3RegisterDateTimeFunctions(); diff --git a/src/box/sql/main.c b/src/box/sql/main.c index 69b2fec80..e2b55647d 100644 --- a/src/box/sql/main.c +++ b/src/box/sql/main.c @@ -1075,6 +1075,7 @@ sqlite3_interrupt(sqlite3 * db) int sqlite3CreateFunc(sqlite3 * db, const char *zFunctionName, + enum affinity_type type, int nArg, int flags, void *pUserData, @@ -1137,12 +1138,14 @@ sqlite3CreateFunc(sqlite3 * db, p->xFinalize = xFinal; p->pUserData = pUserData; p->nArg = (u16) nArg; + p->ret_type = type; return SQLITE_OK; } int sqlite3_create_function_v2(sqlite3 * db, const char *zFunc, + enum affinity_type type, int nArg, int flags, void *p, @@ -1173,8 +1176,8 @@ sqlite3_create_function_v2(sqlite3 * db, pArg->xDestroy = xDestroy; pArg->pUserData = p; } - rc = sqlite3CreateFunc(db, zFunc, nArg, flags, p, xSFunc, xStep, xFinal, - pArg); + rc = sqlite3CreateFunc(db, zFunc, type, nArg, flags, p, xSFunc, xStep, + xFinal, pArg); if (pArg && pArg->nRef == 0) { assert(rc != SQLITE_OK); xDestroy(p); diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index 5ca628aac..100777a28 100644 --- a/src/box/sql/sqliteInt.h +++ b/src/box/sql/sqliteInt.h @@ -737,6 +737,7 @@ sqlite3_memory_used(void); int sqlite3_create_function_v2(sqlite3 * db, const char *zFunctionName, + enum affinity_type type, int nArg, int flags, void *pApp, @@ -1659,6 +1660,8 @@ struct FuncDef { FuncDef *pHash; /* Next with a different name but the same hash */ FuncDestructor *pDestructor; /* Reference counted destructor function */ } u; + /* Return type. */ + enum affinity_type ret_type; }; /* @@ -1741,30 +1744,30 @@ struct FuncDestructor { * FuncDef.flags variable is set to the value passed as the flags * parameter. */ -#define FUNCTION(zName, nArg, iArg, bNC, xFunc) \ +#define FUNCTION(zName, nArg, iArg, bNC, xFunc, type) \ {nArg, SQLITE_FUNC_CONSTANT|(bNC*SQLITE_FUNC_NEEDCOLL), \ - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } -#define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \ + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0}, type } +#define VFUNCTION(zName, nArg, iArg, bNC, xFunc, type) \ {nArg, (bNC*SQLITE_FUNC_NEEDCOLL), \ - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } -#define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \ + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0}, type } +#define DFUNCTION(zName, nArg, iArg, bNC, xFunc, type) \ {nArg, SQLITE_FUNC_SLOCHNG|(bNC*SQLITE_FUNC_NEEDCOLL), \ - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } -#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \ + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0}, type } +#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags, type) \ {nArg,SQLITE_FUNC_CONSTANT|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\ - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0}, type } #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_SLOCHNG|(bNC*SQLITE_FUNC_NEEDCOLL), \ - pArg, 0, xFunc, 0, #zName, } -#define LIKEFUNC(zName, nArg, arg, flags) \ + pArg, 0, xFunc, 0, #zName, {SQLITE_AFF_STRING, {0}}} +#define LIKEFUNC(zName, nArg, arg, flags, type) \ {nArg, SQLITE_FUNC_CONSTANT|flags, \ - (void *)arg, 0, likeFunc, 0, #zName, {0} } -#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \ + (void *)arg, 0, likeFunc, 0, #zName, {0}, type } +#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal, type) \ {nArg, (nc*SQLITE_FUNC_NEEDCOLL), \ - SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}} -#define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \ + SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}, type} +#define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags, type) \ {nArg, (nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \ - SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}} + SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}, type} /* * All current savepoints are stored in a linked list starting at @@ -4530,7 +4533,8 @@ void sqlite3RegisterLikeFunctions(sqlite3 *, int); int sqlite3IsLikeFunction(sqlite3 *, Expr *, int *, char *); void sqlite3SchemaClear(sqlite3 *); Schema *sqlite3SchemaCreate(sqlite3 *); -int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, +int sqlite3CreateFunc(sqlite3 *, const char *, enum affinity_type, + int, int, void *, void (*)(sqlite3_context *, int, sqlite3_value **), void (*)(sqlite3_context *, int, sqlite3_value **), void (*)(sqlite3_context *), diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c index 65bb67d8f..27b83a0df 100644 --- a/src/box/sql/vdbemem.c +++ b/src/box/sql/vdbemem.c @@ -1422,7 +1422,7 @@ void sqlite3AnalyzeFunctions(void) { static FuncDef aAnalyzeTableFuncs[] = { - FUNCTION(sqlite_record, 1, 0, 0, recordFunc), + FUNCTION(sqlite_record, 1, 0, 0, recordFunc, 0), }; sqlite3InsertBuiltinFuncs(aAnalyzeTableFuncs, ArraySize(aAnalyzeTableFuncs)); diff --git a/test/sql-tap/alias.test.lua b/test/sql-tap/alias.test.lua index 4321413cb..df082b699 100755 --- a/test/sql-tap/alias.test.lua +++ b/test/sql-tap/alias.test.lua @@ -32,7 +32,7 @@ end -- Function is declared as deterministic deliberately. -- Otherwise it would be called as much as it occurs in a query. -box.internal.sql_create_function("sequence", sequence, 0, true) +box.internal.sql_create_function("sequence", "INT", sequence, 0, true) test:do_test( "alias-1.1", diff --git a/test/sql-tap/analyze5.test.lua b/test/sql-tap/analyze5.test.lua index d68bd3c5b..67229e78f 100755 --- a/test/sql-tap/analyze5.test.lua +++ b/test/sql-tap/analyze5.test.lua @@ -46,6 +46,7 @@ test:do_test( function() box.internal.sql_create_function( "msgpack_decode", + "BLOB", function(txt) -- MsgPack, must contain single-element array w/ string return require('msgpack').decode(txt)[1] diff --git a/test/sql-tap/analyze9.test.lua b/test/sql-tap/analyze9.test.lua index 1dbfe5d2b..9d60214cb 100755 --- a/test/sql-tap/analyze9.test.lua +++ b/test/sql-tap/analyze9.test.lua @@ -61,7 +61,7 @@ msgpack_decode_sample = function(txt) return decoded_str end -box.internal.sql_create_function("msgpack_decode_sample", msgpack_decode_sample) +box.internal.sql_create_function("msgpack_decode_sample", "TEXT", msgpack_decode_sample) test:do_execsql_test( 1.2, @@ -135,7 +135,7 @@ lindex = function(str, pos) return string.sub(str, pos+1, pos+1) end -box.internal.sql_create_function("lindex", lindex) +box.internal.sql_create_function("lindex", "TEXT", lindex) -- Analogue of function from tcl lrange = function(str, first, last) @@ -154,7 +154,7 @@ lrange = function(str, first, last) return res_tokens end -box.internal.sql_create_function("lrange", lrange) +box.internal.sql_create_function("lrange", "TEXT", lrange) generate_tens = function(n) tens = {} @@ -242,7 +242,7 @@ insert_filler_rows_n = function(iStart, nCopy, nVal) end end -box.internal.sql_create_function("insert_filler_rows_n", insert_filler_rows_n) +box.internal.sql_create_function("insert_filler_rows_n", "INT", insert_filler_rows_n) test:do_test( 4.1, @@ -1210,7 +1210,7 @@ r = function() return math.random(1, 15) end -box.internal.sql_create_function("r", r) +box.internal.sql_create_function("r", "NUM", r) test:do_test( 20.1, @@ -1346,7 +1346,7 @@ int_to_char = function(i) return ret end -box.internal.sql_create_function("int_to_char", int_to_char) +box.internal.sql_create_function("int_to_char", "TEXT", int_to_char) -- These tests are commented until query planer will be stable. --test:do_execsql_test( diff --git a/test/sql-tap/analyzeF.test.lua b/test/sql-tap/analyzeF.test.lua index 10cb574bd..0f67881af 100755 --- a/test/sql-tap/analyzeF.test.lua +++ b/test/sql-tap/analyzeF.test.lua @@ -22,7 +22,7 @@ local function isqrt(i) return math.floor(math.sqrt(i)) end -box.internal.sql_create_function("isqrt", isqrt) +box.internal.sql_create_function("isqrt", "FLOAT", isqrt) test:do_execsql_test( 1.0, @@ -109,9 +109,9 @@ local function det19() end -box.internal.sql_create_function("det4", det4) +box.internal.sql_create_function("det4", "NUM", det4) -box.internal.sql_create_function("det19", det19) +box.internal.sql_create_function("det19", "NUM", det19) where_clause_x = {"x = det4() AND y = det19()"} where_clauses_y = {"x = det19() AND y = det4()"} diff --git a/test/sql-tap/check.test.lua b/test/sql-tap/check.test.lua index ff36552de..cb5cfa32b 100755 --- a/test/sql-tap/check.test.lua +++ b/test/sql-tap/check.test.lua @@ -721,7 +721,7 @@ test:do_execsql_test( local function myfunc(x) return x < 10 end -box.internal.sql_create_function("myfunc", myfunc) +box.internal.sql_create_function("myfunc", "INT", myfunc) test:do_execsql_test( 7.1, diff --git a/test/sql-tap/date.test.lua b/test/sql-tap/date.test.lua index 5c22bf606..624437641 100755 --- a/test/sql-tap/date.test.lua +++ b/test/sql-tap/date.test.lua @@ -451,7 +451,7 @@ local function sleeper() -- after 100 ms os.execute("sleep 0.1") end -box.internal.sql_create_function("sleeper", sleeper) +box.internal.sql_create_function("sleeper", "INT", sleeper) -- db("func", "sleeper", "sleeper") test:do_test( "date-15.1", diff --git a/test/sql-tap/e_expr.test.lua b/test/sql-tap/e_expr.test.lua index e04431685..9a9a5faae 100755 --- a/test/sql-tap/e_expr.test.lua +++ b/test/sql-tap/e_expr.test.lua @@ -43,8 +43,8 @@ end local function regexfunc(a, b) return (a == b) end -box.internal.sql_create_function("MATCH", matchfunc) -box.internal.sql_create_function("REGEXP", regexfunc) +box.internal.sql_create_function("MATCH", "INT", matchfunc) +box.internal.sql_create_function("REGEXP", "INT", regexfunc) -- Set up three global variables: -- @@ -653,7 +653,7 @@ end local function reverse_collate(zLeft, zRight) return reverse_str(zLeft) > reverse_str(zRight) end -box.internal.sql_create_function("REVERSE", reverse_collate) +box.internal.sql_create_function("REVERSE", "INT", reverse_collate) --db("collate", "reverse", "reverse_collate") -- EVIDENCE-OF: R-59577-33471 The COLLATE operator is a unary postfix -- operator that assigns a collating sequence to an expression. @@ -1277,9 +1277,9 @@ local function glob(args) return 1 end -box.internal.sql_create_function("GLOB", glob) -box.internal.sql_create_function("MATCH", glob) -box.internal.sql_create_function("REGEXP", glob) +box.internal.sql_create_function("GLOB", "INT", glob) +box.internal.sql_create_function("MATCH", "INT", glob) +box.internal.sql_create_function("REGEXP", "INT", glob) local test_cases12 ={ {1, 123}, {2, 123.4e05}, @@ -1438,7 +1438,7 @@ local function func_x() xcount = xcount + 1 return x end -box.internal.sql_create_function("X", func_x) +box.internal.sql_create_function("X", "INT", func_x) local test_cases13 = { {1, 10, "x() >= 5 AND x() <= 15", 1, 2}, {2, 10, "x() BETWEEN 5 AND 15", 1, 1}, @@ -2126,7 +2126,7 @@ function likefunc(...) return 1 end -box.internal.sql_create_function("LIKE", likefunc) +box.internal.sql_create_function("LIKE", "INT", likefunc) --db("func", "like", "-argcount", 2, "likefunc") --db("func", "like", "-argcount", 3, "likefunc") test:do_execsql_test( @@ -2430,7 +2430,7 @@ local function globfunc(...) end return 1 end -box.internal.sql_create_function("GLOB", globfunc, 2) +box.internal.sql_create_function("GLOB", "INT", globfunc, 2) --db("func", "glob", "-argcount", 2, "globfunc") test:do_execsql_test( @@ -2498,7 +2498,7 @@ local function regexpfunc(...) end return 1 end -box.internal.sql_create_function("REGEXP", regexpfunc, 2) +box.internal.sql_create_function("REGEXP", "INT", regexpfunc, 2) --db("func", "regexp", "-argcount", 2, "regexpfunc") test:do_execsql_test( @@ -2581,7 +2581,7 @@ local function matchfunc(...) end return 1 end -box.internal.sql_create_function("MATCH", matchfunc, 2) +box.internal.sql_create_function("MATCH", "INT", matchfunc, 2) test:do_execsql_test( "e_expr-19.2.1", @@ -2659,7 +2659,7 @@ local function var(nm) local result = loadstring("return "..nm)() return result end -box.internal.sql_create_function("VAR", var) +box.internal.sql_create_function("VAR", "BLOB", var) --db("func", "var", "var") -- EVIDENCE-OF: R-30638-59954 In a CASE without a base expression, each -- WHEN expression is evaluated and the result treated as a boolean, @@ -3070,7 +3070,7 @@ local function ceval(x) evalcount = evalcount + 1 return x end -box.internal.sql_create_function("CEVAL", ceval) +box.internal.sql_create_function("CEVAL", "BLOB", ceval) evalcount = 0 test:do_execsql_test( "e_expr-26.1.1", diff --git a/test/sql-tap/func5.test.lua b/test/sql-tap/func5.test.lua index c8aa4f135..493b50552 100755 --- a/test/sql-tap/func5.test.lua +++ b/test/sql-tap/func5.test.lua @@ -76,8 +76,8 @@ counter = function(str) return global_counter end -box.internal.sql_create_function("counter1", counter, -1, false) -box.internal.sql_create_function("counter2", counter, -1, true) +box.internal.sql_create_function("counter1", "INT", counter, -1, false) +box.internal.sql_create_function("counter2", "INT", counter, -1, true) test:do_execsql_test( "func5-2.2", diff --git a/test/sql-tap/gh-3350-skip-scan.test.lua b/test/sql-tap/gh-3350-skip-scan.test.lua index 301b04a13..4cecfe081 100755 --- a/test/sql-tap/gh-3350-skip-scan.test.lua +++ b/test/sql-tap/gh-3350-skip-scan.test.lua @@ -19,8 +19,8 @@ local function int_to_char(i) return res end -box.internal.sql_create_function("lindex", lindex) -box.internal.sql_create_function("int_to_char", int_to_char) +box.internal.sql_create_function("lindex", "TEXT", lindex) +box.internal.sql_create_function("int_to_char", "TEXT", int_to_char) test:do_execsql_test( "skip-scan-1.1", diff --git a/test/sql-tap/lua_sql.test.lua b/test/sql-tap/lua_sql.test.lua index 394922a2f..68bb24ff2 100755 --- a/test/sql-tap/lua_sql.test.lua +++ b/test/sql-tap/lua_sql.test.lua @@ -13,7 +13,7 @@ end test:do_test( "lua_sql-1.0", function () - box.internal.sql_create_function("func1", allways_2) + box.internal.sql_create_function("func1", "INT", allways_2) return test:execsql("select func1(1)") end, {2}) @@ -22,7 +22,7 @@ test:do_test( test:do_test( "lua_sql-1.1", function () - box.internal.sql_create_function("func1", func1) + box.internal.sql_create_function("func1", "INT", func1) return test:execsql("select func1(1)") end, {1}) @@ -32,7 +32,7 @@ test:do_test( "lua_sql-1.2", function () for i = 1, 1000000, 1 do - box.internal.sql_create_function("func1", func1) + box.internal.sql_create_function("func1", "INT", func1) end return test:execsql("select func1(1)") end, @@ -42,10 +42,10 @@ test:do_test( test:do_test( "lua_sql-1.3", function () - box.internal.sql_create_function("allways_2", allways_2, 1) -- specify 1 arg - box.internal.sql_create_function("allways_2", func1) - box.internal.sql_create_function("allways_2", func1, 2) - box.internal.sql_create_function("allways_2", func1, 3) + box.internal.sql_create_function("allways_2", "INT", allways_2, 1) -- specify 1 arg + box.internal.sql_create_function("allways_2", "INT", func1) + box.internal.sql_create_function("allways_2", "INT", func1, 2) + box.internal.sql_create_function("allways_2", "INT", func1, 3) return test:execsql("select allways_2(1)") end, {2}) @@ -88,7 +88,7 @@ local function check_from_sql_to_lua(i, arg) end return 0 end -box.internal.sql_create_function("check_from_sql_to_lua", check_from_sql_to_lua) +box.internal.sql_create_function("check_from_sql_to_lua", "INT", check_from_sql_to_lua) -- check for different types for i = 1, #from_sql_to_lua, 1 do @@ -108,7 +108,7 @@ local from_lua_to_sql = { local function check_from_lua_to_sql(i) return from_lua_to_sql[i][2] end -box.internal.sql_create_function("check_from_lua_to_sql", check_from_lua_to_sql) +box.internal.sql_create_function("check_from_lua_to_sql", "BLOB", check_from_lua_to_sql) -- check for different types for i = 1, #from_lua_to_sql, 1 do @@ -125,7 +125,7 @@ local from_lua_to_sql_bad = { local function check_from_lua_to_sql_bad(i) return from_lua_to_sql_bad[i] end -box.internal.sql_create_function("check_from_lua_to_sql_bad", check_from_lua_to_sql_bad) +box.internal.sql_create_function("check_from_lua_to_sql_bad", "BLOB", check_from_lua_to_sql_bad) for i = 1, #from_lua_to_sql_bad, 1 do test:do_catchsql_test( @@ -138,7 +138,7 @@ local function allways_error() error("my_error123") return 1 end -box.internal.sql_create_function("allways_error", allways_error) +box.internal.sql_create_function("allways_error", "INT", allways_error) test:do_catchsql_test( "lua_sql-2.6", diff --git a/test/sql-tap/subquery.test.lua b/test/sql-tap/subquery.test.lua index 0e63f2e3e..fb1c23c0b 100755 --- a/test/sql-tap/subquery.test.lua +++ b/test/sql-tap/subquery.test.lua @@ -720,7 +720,7 @@ test:do_test( end callcnt = 0 - box.internal.sql_create_function("callcnt", callcntproc) + box.internal.sql_create_function("callcnt", "INT", callcntproc) return test:execsql [[ CREATE TABLE t4(x,y PRIMARY KEY); INSERT INTO t4 VALUES('one',1); diff --git a/test/sql-tap/trigger9.test.lua b/test/sql-tap/trigger9.test.lua index 30409582c..0dfd07ac3 100755 --- a/test/sql-tap/trigger9.test.lua +++ b/test/sql-tap/trigger9.test.lua @@ -46,7 +46,7 @@ local function has_rowdata(sql) -- X(41, "X!cmd", [=[["expr","[lsearch [execsql \"explain $sql\"] RowData]>=0"]]=]) end -box.internal.sql_create_function('randstr', test.randstr, 1) +box.internal.sql_create_function('randstr', 'TEXT', test.randstr, 1) -- MUST_WORK_TEST test:do_execsql_test( -- 2.15.1