From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: From: Kirill Shcherbatov Subject: [PATCH v2 5/9] schema: rework _func system space format Date: Thu, 6 Jun 2019 15:04:01 +0300 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit To: tarantool-patches@freelists.org, vdavydov.dev@gmail.com Cc: Kirill Shcherbatov List-ID: This patch updates a _func system space to prepare it for working with persistent functions. The format of the _func system space is [ UINT, UINT, STR, UINT, STR, STR, STR, BOOL, MAP] It is preparational step to introduce persistent Lua function in Tarantool. The new field is a string that represents the function body, returns is the type of value that it returns, and the is_deterministic flag is responsible whether this routine deterministic or not (can produce only one result for a given list of parameters). Updated function definition structure, decode operation and migration script correspondingly. Part of #4182 Needed for #1260 --- src/box/alter.cc | 61 ++++++++++++++++++++++++++++------- src/box/bootstrap.snap | Bin 4393 -> 4449 bytes src/box/func_def.h | 14 ++++++-- src/box/lua/schema.lua | 13 ++++++-- src/box/lua/upgrade.lua | 25 +++++++++++++- src/box/schema_def.h | 4 +++ test/box-py/bootstrap.result | 6 ++-- test/box/access_misc.result | 6 ++-- 8 files changed, 108 insertions(+), 21 deletions(-) diff --git a/src/box/alter.cc b/src/box/alter.cc index 3b57a7d82..11cad77c3 100644 --- a/src/box/alter.cc +++ b/src/box/alter.cc @@ -2426,26 +2426,45 @@ func_def_get_ids_from_tuple(struct tuple *tuple, uint32_t *fid, uint32_t *uid) static struct func_def * func_def_new_from_tuple(struct tuple *tuple) { - uint32_t len; - const char *name = tuple_field_str_xc(tuple, BOX_FUNC_FIELD_NAME, - &len); - if (len > BOX_NAME_MAX) + uint32_t field_count = tuple_field_count(tuple); + uint32_t name_len, body_len; + const char *name, *body; + name = tuple_field_str_xc(tuple, BOX_FUNC_FIELD_NAME, &name_len); + if (name_len > BOX_NAME_MAX) { tnt_raise(ClientError, ER_CREATE_FUNCTION, tt_cstr(name, BOX_INVALID_NAME_MAX), "function name is too long"); - identifier_check_xc(name, len); - struct func_def *def = (struct func_def *) malloc(func_def_sizeof(len)); + } + identifier_check_xc(name, name_len); + if (field_count > BOX_FUNC_FIELD_BODY) { + body = tuple_field_str_xc(tuple, BOX_FUNC_FIELD_BODY, + &body_len); + } else { + body = NULL; + body_len = 0; + } + + uint32_t def_sz = func_def_sizeof(name_len, body_len); + struct func_def *def = (struct func_def *) malloc(def_sz); if (def == NULL) - tnt_raise(OutOfMemory, func_def_sizeof(len), "malloc", "def"); + tnt_raise(OutOfMemory, def_sz, "malloc", "def"); auto def_guard = make_scoped_guard([=] { free(def); }); func_def_get_ids_from_tuple(tuple, &def->fid, &def->uid); - memcpy(def->name, name, len); - def->name[len] = 0; - if (tuple_field_count(tuple) > BOX_FUNC_FIELD_SETUID) + memcpy(def->name, name, name_len); + def->name[name_len] = 0; + if (body_len > 0) { + def->body = def->name + name_len + 1; + memcpy(def->body, body, body_len); + def->body[body_len] = 0; + } else { + def->body = NULL; + } + + if (field_count > BOX_FUNC_FIELD_SETUID) def->setuid = tuple_field_u32_xc(tuple, BOX_FUNC_FIELD_SETUID); else def->setuid = false; - if (tuple_field_count(tuple) > BOX_FUNC_FIELD_LANGUAGE) { + if (field_count > BOX_FUNC_FIELD_LANGUAGE) { const char *language = tuple_field_cstr_xc(tuple, BOX_FUNC_FIELD_LANGUAGE); def->language = STR2ENUM(func_language, language); @@ -2457,6 +2476,26 @@ func_def_new_from_tuple(struct tuple *tuple) /* Lua is the default. */ def->language = FUNC_LANGUAGE_LUA; } + if (def->language != FUNC_LANGUAGE_LUA && body_len > 0) { + tnt_raise(ClientError, ER_CREATE_FUNCTION, name, + "function body may be specified only for " + "Lua language"); + } + if (field_count > BOX_FUNC_FIELD_BODY) { + assert(field_count > BOX_FUNC_FIELD_OPTS); + const char *type = + tuple_field_cstr_xc(tuple, BOX_FUNC_FIELD_RETURNS); + def->returns = STR2ENUM(field_type, type); + if (def->returns == field_type_MAX) { + tnt_raise(ClientError, ER_CREATE_FUNCTION, name, + "function return value has unknown field type"); + } + def->is_deterministic = + tuple_field_bool_xc(tuple, BOX_FUNC_FIELD_IS_DETERMINISTIC); + } else { + def->returns = FIELD_TYPE_ANY; + def->is_deterministic = false; + } def_guard.is_active = false; return def; } diff --git a/src/box/bootstrap.snap b/src/box/bootstrap.snap index bb8fbeba114b1e72a5585548fb7f22796931d90f..440495684401541854e9d9180f55cc9a4bc45b25 100644 diff --git a/src/box/func_def.h b/src/box/func_def.h index 5b52ab498..7a920f65e 100644 --- a/src/box/func_def.h +++ b/src/box/func_def.h @@ -32,6 +32,7 @@ */ #include "trivia/util.h" +#include "field_def.h" #include /** @@ -54,11 +55,17 @@ struct func_def { uint32_t fid; /** Owner of the function. */ uint32_t uid; + /** Definition of the persistent function. */ + char *body; /** * True if the function requires change of user id before * invocation. */ bool setuid; + /** The type of the returned value. */ + enum field_type returns; + /** Whether this function is deterministic. */ + bool is_deterministic; /** * The language of the stored function. */ @@ -73,10 +80,13 @@ struct func_def { * for a function of length @a a name_len. */ static inline size_t -func_def_sizeof(uint32_t name_len) +func_def_sizeof(uint32_t name_len, uint32_t body_len) { /* +1 for '\0' name terminating. */ - return sizeof(struct func_def) + name_len + 1; + size_t sz = sizeof(struct func_def) + name_len + 1; + if (body_len > 0) + sz += body_len + 1; + return sz; } /** diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index 39bd8da6d..b5393e19a 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -2105,7 +2105,9 @@ box.schema.func.create = function(name, opts) opts = opts or {} check_param_table(opts, { setuid = 'boolean', if_not_exists = 'boolean', - language = 'string'}) + language = 'string', body = 'string', + returns = 'string', is_deterministic = 'boolean', + 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} @@ -2115,10 +2117,15 @@ box.schema.func.create = function(name, opts) end return end - opts = update_param_table(opts, { setuid = false, language = 'lua'}) + opts = update_param_table(opts, { setuid = false, language = 'lua', + body = '', returns = 'any', + is_deterministic = false, + opts = setmap{}}) opts.language = string.upper(opts.language) opts.setuid = opts.setuid and 1 or 0 - _func:auto_increment{session.euid(), name, opts.setuid, opts.language} + _func:auto_increment{session.euid(), name, opts.setuid, opts.language, + opts.body, opts.returns, opts.is_deterministic, + opts.opts} end box.schema.func.drop = function(name, opts) diff --git a/src/box/lua/upgrade.lua b/src/box/lua/upgrade.lua index 070662698..6f35e0b5a 100644 --- a/src/box/lua/upgrade.lua +++ b/src/box/lua/upgrade.lua @@ -324,7 +324,8 @@ local function initial_1_7_5() -- create "box.schema.user.info" function log.info('create function "box.schema.user.info" with setuid') - _func:replace{1, ADMIN, 'box.schema.user.info', 1, 'LUA'} + _func:replace{1, ADMIN, 'box.schema.user.info', 1, 'LUA', '', 'any', + false, MAP} -- grant 'public' role access to 'box.schema.user.info' function log.info('grant execute on function "box.schema.user.info" to public') @@ -774,8 +775,30 @@ local function upgrade_sequence_to_2_2_1() _space_sequence:format(format) end +local function upgrade_func_to_2_2_1() + log.info("Update _func format") + local _func = box.space[box.schema.FUNC_ID] + local format = {} + format[1] = {name='id', type='unsigned'} + format[2] = {name='owner', type='unsigned'} + format[3] = {name='name', type='string'} + format[4] = {name='setuid', type='unsigned'} + format[5] = {name='language', type='string'} + format[6] = {name='body', type='string'} + format[7] = {name='returns', type='string'} + format[8] = {name='is_deterministic', type='boolean'} + format[9] = {name='opts', type='map'} + for _, v in box.space._func:pairs() do + _ = box.space._func:replace({v.id, v.owner, v.name, v.setuid, + v[5] or 'LUA', '', 'any', false, + setmap({})}) + end + _func:format(format) +end + local function upgrade_to_2_2_1() upgrade_sequence_to_2_2_1() + upgrade_func_to_2_2_1() end -------------------------------------------------------------------------------- diff --git a/src/box/schema_def.h b/src/box/schema_def.h index b817b49f6..b8cbdb12e 100644 --- a/src/box/schema_def.h +++ b/src/box/schema_def.h @@ -163,6 +163,10 @@ enum { BOX_FUNC_FIELD_NAME = 2, BOX_FUNC_FIELD_SETUID = 3, BOX_FUNC_FIELD_LANGUAGE = 4, + BOX_FUNC_FIELD_BODY = 5, + BOX_FUNC_FIELD_RETURNS = 6, + BOX_FUNC_FIELD_IS_DETERMINISTIC = 7, + BOX_FUNC_FIELD_OPTS = 8, }; /** _collation fields. */ diff --git a/test/box-py/bootstrap.result b/test/box-py/bootstrap.result index 0684914c0..305bb9276 100644 --- a/test/box-py/bootstrap.result +++ b/test/box-py/bootstrap.result @@ -49,7 +49,9 @@ box.space._space:select{} 'type': 'string'}, {'name': 'opts', 'type': 'map'}, {'name': 'parts', 'type': 'array'}]] - [296, 1, '_func', 'memtx', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'owner', 'type': 'unsigned'}, {'name': 'name', 'type': 'string'}, {'name': 'setuid', - 'type': 'unsigned'}]] + 'type': 'unsigned'}, {'name': 'language', 'type': 'string'}, {'name': 'body', + 'type': 'string'}, {'name': 'returns', 'type': 'string'}, {'name': 'is_deterministic', + 'type': 'boolean'}, {'name': 'opts', 'type': 'map'}]] - [297, 1, '_vfunc', 'sysview', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'owner', 'type': 'unsigned'}, {'name': 'name', 'type': 'string'}, {'name': 'setuid', 'type': 'unsigned'}]] @@ -142,7 +144,7 @@ box.space._user:select{} ... box.space._func:select{} --- -- - [1, 1, 'box.schema.user.info', 1, 'LUA'] +- - [1, 1, 'box.schema.user.info', 1, 'LUA', '', 'any', false, {}] ... box.space._priv:select{} --- diff --git a/test/box/access_misc.result b/test/box/access_misc.result index 24bdd9d63..6e4558a19 100644 --- a/test/box/access_misc.result +++ b/test/box/access_misc.result @@ -789,7 +789,9 @@ box.space._space:select() 'type': 'string'}, {'name': 'opts', 'type': 'map'}, {'name': 'parts', 'type': 'array'}]] - [296, 1, '_func', 'memtx', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'owner', 'type': 'unsigned'}, {'name': 'name', 'type': 'string'}, {'name': 'setuid', - 'type': 'unsigned'}]] + 'type': 'unsigned'}, {'name': 'language', 'type': 'string'}, {'name': 'body', + 'type': 'string'}, {'name': 'returns', 'type': 'string'}, {'name': 'is_deterministic', + 'type': 'boolean'}, {'name': 'opts', 'type': 'map'}]] - [297, 1, '_vfunc', 'sysview', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'owner', 'type': 'unsigned'}, {'name': 'name', 'type': 'string'}, {'name': 'setuid', 'type': 'unsigned'}]] @@ -822,7 +824,7 @@ box.space._space:select() ... box.space._func:select() --- -- - [1, 1, 'box.schema.user.info', 1, 'LUA'] +- - [1, 1, 'box.schema.user.info', 1, 'LUA', '', 'any', false, {}] ... session = nil --- -- 2.21.0