From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: From: Kirill Shcherbatov Subject: [PATCH v5 1/3] box: introduce opts.is_multikey function option Date: Thu, 25 Jul 2019 21:39:43 +0300 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit To: tarantool-patches@freelists.org, kostja@tarantool.org Cc: vdavydov.dev@gmail.com, v.shpilevoy@tarantool.org, Kirill Shcherbatov List-ID: Needed for #1260 @TarantoolBot document Title: A new option is_multikey for function definition A new option is_multikey allows to specify wether new function returns multiple values packed in a table object. This is a native way to define multikey func_index. --- src/box/func_def.h | 22 ++++++++++++++++++++++ src/box/func_def.c | 19 ++++++++++++++++++- src/box/lua/call.c | 3 +++ src/box/alter.cc | 6 ++++++ src/box/lua/schema.lua | 3 ++- test/box/function1.result | 14 ++++++++++++++ test/box/function1.test.lua | 5 +++++ 7 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/box/func_def.h b/src/box/func_def.h index 2eed710e7..d99d89190 100644 --- a/src/box/func_def.h +++ b/src/box/func_def.h @@ -33,6 +33,7 @@ #include "trivia/util.h" #include "field_def.h" +#include "opt_def.h" #include #ifdef __cplusplus @@ -60,6 +61,25 @@ enum func_aggregate { extern const char *func_aggregate_strs[]; +/** Function options. */ +struct func_opts { + /** + * True when a function returns multiple values + * packed in array. + */ + bool is_multikey; +}; + +extern const struct func_opts func_opts_default; +extern const struct opt_def func_opts_reg[]; + +/** Create index options using default values. */ +static inline void +func_opts_create(struct func_opts *opts) +{ + *opts = func_opts_default; +} + /** * Definition of a function. Function body is not stored * or replicated (yet). @@ -109,6 +129,8 @@ struct func_def { }; uint8_t all; } exports; + /** The function options. */ + struct func_opts opts; /** Function name. */ char name[0]; }; diff --git a/src/box/func_def.c b/src/box/func_def.c index 41bef2ac7..11d2bdb84 100644 --- a/src/box/func_def.c +++ b/src/box/func_def.c @@ -29,6 +29,7 @@ * SUCH DAMAGE. */ #include "func_def.h" +#include "opt_def.h" #include "string.h" #include "diag.h" #include "error.h" @@ -37,6 +38,22 @@ const char *func_language_strs[] = {"LUA", "C", "SQL", "SQL_BUILTIN"}; const char *func_aggregate_strs[] = {"none", "group"}; +const struct func_opts func_opts_default = { + /* .is_multikey = */ false, +}; + +const struct opt_def func_opts_reg[] = { + OPT_DEF("is_multikey", OPT_BOOL, struct func_opts, is_multikey), +}; + +int +func_opts_cmp(struct func_opts *o1, struct func_opts *o2) +{ + if (o1->is_multikey != o2->is_multikey) + return o1->is_multikey - o2->is_multikey; + return 0; +} + int func_def_cmp(struct func_def *def1, struct func_def *def2) { @@ -70,7 +87,7 @@ func_def_cmp(struct func_def *def1, struct func_def *def2) return def1->comment - def2->comment; if (def1->comment != NULL && strcmp(def1->comment, def2->comment) != 0) return strcmp(def1->comment, def2->comment); - return 0; + return func_opts_cmp(&def1->opts, &def2->opts); } /** diff --git a/src/box/lua/call.c b/src/box/lua/call.c index 81f7f5bd9..0ac2eb7a6 100644 --- a/src/box/lua/call.c +++ b/src/box/lua/call.c @@ -900,6 +900,9 @@ lbox_func_new(struct lua_State *L, struct func *func) lua_pushstring(L, "is_deterministic"); lua_pushboolean(L, func->def->is_deterministic); lua_settable(L, top); + lua_pushstring(L, "is_multikey"); + lua_pushboolean(L, func->def->opts.is_multikey); + lua_settable(L, top); lua_pushstring(L, "is_sandboxed"); if (func->def->body != NULL) lua_pushboolean(L, func->def->is_sandboxed); diff --git a/src/box/alter.cc b/src/box/alter.cc index df699bb87..9b064286c 100644 --- a/src/box/alter.cc +++ b/src/box/alter.cc @@ -2652,6 +2652,7 @@ func_def_new_from_tuple(struct tuple *tuple) tnt_raise(ClientError, ER_CREATE_FUNCTION, tt_cstr(name, name_len), "function id is too big"); } + func_opts_create(&def->opts); memcpy(def->name, name, name_len); def->name[name_len] = '\0'; def->name_len = name_len; @@ -2750,6 +2751,11 @@ func_def_new_from_tuple(struct tuple *tuple) } } def->param_count = argc; + const char *opts = tuple_field(tuple, BOX_FUNC_FIELD_OPTS); + if (opts_decode(&def->opts, func_opts_reg, &opts, + ER_WRONG_SPACE_OPTIONS, BOX_FUNC_FIELD_OPTS, + NULL) != 0) + diag_raise(); } else { def->is_deterministic = false; def->is_sandboxed = false; diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index aadcd3fa9..334f49d51 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -2109,7 +2109,8 @@ box.schema.func.create = function(name, opts) if_not_exists = 'boolean', language = 'string', body = 'string', is_deterministic = 'boolean', - is_sandboxed = 'boolean', comment = 'string' }) + is_sandboxed = 'boolean', comment = 'string', + opts = 'table' }) local _func = box.space[box.schema.FUNC_ID] local _vfunc = box.space[box.schema.VFUNC_ID] local func = _vfunc.index.name:get{name} diff --git a/test/box/function1.result b/test/box/function1.result index 45db8ac7e..00e5880cd 100644 --- a/test/box/function1.result +++ b/test/box/function1.result @@ -99,6 +99,7 @@ box.func["function1.args"] sql: false id: 66 setuid: false + is_multikey: false is_deterministic: false name: function1.args language: C @@ -418,6 +419,7 @@ func sql: false id: 66 setuid: false + is_multikey: false is_deterministic: false comment: Divide two values name: divide @@ -489,6 +491,7 @@ func sql: false id: 66 setuid: false + is_multikey: false is_deterministic: false name: function1.divide language: C @@ -822,3 +825,14 @@ box.func.LUA:call({"return 1 + 1"}) --- - 2 ... +-- Introduce function options +box.schema.func.create('test', {body = "function(tuple) return tuple end", is_deterministic = true, opts = {is_multikey = true}}) +--- +... +box.func['test'].is_multikey == true +--- +- true +... +box.func['test']:drop() +--- +... diff --git a/test/box/function1.test.lua b/test/box/function1.test.lua index d22cffb46..5eb597d16 100644 --- a/test/box/function1.test.lua +++ b/test/box/function1.test.lua @@ -293,3 +293,8 @@ for _, v in pairs(sql_builtin_list) do ok = ok and (box.space._func.index.name:g ok == true box.func.LUA:call({"return 1 + 1"}) + +-- Introduce function options +box.schema.func.create('test', {body = "function(tuple) return tuple end", is_deterministic = true, opts = {is_multikey = true}}) +box.func['test'].is_multikey == true +box.func['test']:drop() -- 2.22.0