diff --git a/src/box/alter.cc b/src/box/alter.cc index ff6f5c4b843befe7ba30a740986aa77eba509b96..33f9b0a719ba78c5890411a7945c4bf7fcf52d2b 100644 --- a/src/box/alter.cc +++ b/src/box/alter.cc @@ -2537,83 +2537,31 @@ 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 field_count = tuple_field_count(tuple); - uint32_t name_len, body_len, comment_len; - const char *name, *body, *comment; - name = tuple_field_str_xc(tuple, BOX_FUNC_FIELD_NAME, &name_len); - if (name_len > BOX_NAME_MAX) { + uint32_t len; + const char *name = tuple_field_str_xc(tuple, BOX_FUNC_FIELD_NAME, + &len); + if (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, name_len); - if (field_count > BOX_FUNC_FIELD_BODY) { - body = tuple_field_str_xc(tuple, BOX_FUNC_FIELD_BODY, - &body_len); - comment = tuple_field_str_xc(tuple, BOX_FUNC_FIELD_COMMENT, - &comment_len); - uint32_t len; - const char *routine_type = tuple_field_str_xc(tuple, - BOX_FUNC_FIELD_ROUTINE_TYPE, &len); - if (len != strlen("function") || - strncasecmp(routine_type, "function", len) != 0) { - tnt_raise(ClientError, ER_CREATE_FUNCTION, name, - "unsupported routine_type value"); - } - const char *sql_data_access = tuple_field_str_xc(tuple, - BOX_FUNC_FIELD_SQL_DATA_ACCESS, &len); - if (len != strlen("none") || - strncasecmp(sql_data_access, "none", len) != 0) { - tnt_raise(ClientError, ER_CREATE_FUNCTION, name, - "unsupported sql_data_access value"); - } - bool is_null_call = tuple_field_bool_xc(tuple, - BOX_FUNC_FIELD_IS_NULL_CALL); - if (is_null_call != true) { - tnt_raise(ClientError, ER_CREATE_FUNCTION, name, - "unsupported is_null_call value"); - } - } else { - body = NULL; - body_len = 0; - comment = NULL; - comment_len = 0; - } - uint32_t body_offset, comment_offset; - uint32_t def_sz = func_def_sizeof(name_len, body_len, comment_len, - &body_offset, &comment_offset); - struct func_def *def = - (struct func_def *) malloc(def_sz); + identifier_check_xc(name, len); + struct func_def *def = (struct func_def *) malloc(func_def_sizeof(len)); if (def == NULL) - tnt_raise(OutOfMemory, def_sz, "malloc", "def"); + tnt_raise(OutOfMemory, func_def_sizeof(len), "malloc", "def"); auto def_guard = make_scoped_guard([=] { free(def); }); func_def_get_ids_from_tuple(tuple, &def->fid, &def->uid); if (def->fid > BOX_FUNCTION_MAX) { tnt_raise(ClientError, ER_CREATE_FUNCTION, - tt_cstr(name, name_len), "function id is too big"); + tt_cstr(name, len), "function id is too big"); } - memcpy(def->name, name, name_len); - def->name[name_len] = 0; - def->name_len = name_len; - if (body_len > 0) { - def->body = (char *)def + body_offset; - memcpy(def->body, body, body_len); - def->body[body_len] = 0; - } else { - def->body = NULL; - } - if (comment_len > 0) { - def->comment = (char *)def + comment_offset; - memcpy(def->comment, comment, comment_len); - def->comment[comment_len] = 0; - } else { - def->comment = NULL; - } - if (field_count > BOX_FUNC_FIELD_SETUID) + memcpy(def->name, name, len); + def->name[len] = 0; + def->name_len = len; + if (tuple_field_count(tuple) > BOX_FUNC_FIELD_SETUID) def->setuid = tuple_field_u32_xc(tuple, BOX_FUNC_FIELD_SETUID); else def->setuid = false; - if (field_count > BOX_FUNC_FIELD_LANGUAGE) { + if (tuple_field_count(tuple) > BOX_FUNC_FIELD_LANGUAGE) { const char *language = tuple_field_cstr_xc(tuple, BOX_FUNC_FIELD_LANGUAGE); def->language = STR2ENUM(func_language, language); @@ -2625,17 +2573,6 @@ func_def_new_from_tuple(struct tuple *tuple) /* Lua is the default. */ def->language = FUNC_LANGUAGE_LUA; } - if (field_count > BOX_FUNC_FIELD_BODY) { - def->is_deterministic = - tuple_field_bool_xc(tuple, - BOX_FUNC_FIELD_IS_DETERMINISTIC); - def->is_sandboxed = - tuple_field_bool_xc(tuple, - BOX_FUNC_FIELD_IS_SANDBOXED); - } else { - def->is_deterministic = false; - def->is_sandboxed = false; - } def_guard.is_active = false; return def; } diff --git a/src/box/bootstrap.snap b/src/box/bootstrap.snap index 33d110c700b9e67d07af54a3164728733ba2100d..56943ef7e7d0fe0e3dbb5d346544e2c78c3dc154 100644 Binary files a/src/box/bootstrap.snap and b/src/box/bootstrap.snap differ diff --git a/src/box/func.c b/src/box/func.c index 88cf8cdc9638954001c41f7d753531c3542ab9e3..8227527ec6bc294529108aa672cdbd7eca6e17e6 100644 --- a/src/box/func.c +++ b/src/box/func.c @@ -416,13 +416,8 @@ static struct func_vtab func_c_vtab; static struct func * func_c_new(struct func_def *def) { + (void) def; assert(def->language == FUNC_LANGUAGE_C); - if (def->body != NULL || def->is_sandboxed) { - diag_set(ClientError, ER_CREATE_FUNCTION, def->name, - "body and is_sandboxed options are not compatible " - "with C language"); - return NULL; - } struct func_c *func = (struct func_c *) malloc(sizeof(struct func_c)); if (func == NULL) { diag_set(OutOfMemory, sizeof(*func), "malloc", "func"); diff --git a/src/box/func_def.c b/src/box/func_def.c index 17eafb559e01e2453fa9bc463484000acb03f965..2b135e2d770efabe5f919d0abe28138d9cbe68ed 100644 --- a/src/box/func_def.c +++ b/src/box/func_def.c @@ -14,19 +14,7 @@ func_def_cmp(struct func_def *def1, struct func_def *def2) return def1->setuid - def2->setuid; if (def1->language != def2->language) return def1->language - def2->language; - if (def1->is_deterministic != def2->is_deterministic) - return def1->is_deterministic - def2->is_deterministic; - if (def1->is_sandboxed != def2->is_sandboxed) - return def1->is_sandboxed - def2->is_sandboxed; if (strcmp(def1->name, def2->name) != 0) return strcmp(def1->name, def2->name); - if ((def1->body != NULL) != (def2->body != NULL)) - return def1->body - def2->body; - if (def1->body != NULL && strcmp(def1->body, def2->body) != 0) - return strcmp(def1->body, def2->body); - if ((def1->comment != NULL) != (def2->comment != NULL)) - return def1->comment - def2->comment; - if (def1->comment != NULL && strcmp(def1->comment, def2->comment) != 0) - return strcmp(def1->comment, def2->comment); return 0; } diff --git a/src/box/func_def.h b/src/box/func_def.h index 170aef53690054b79ba6763ab084227fd09a6fe9..866d425a1cc24ba5ef5800048d660532b14ecb31 100644 --- a/src/box/func_def.h +++ b/src/box/func_def.h @@ -58,26 +58,11 @@ struct func_def { uint32_t fid; /** Owner of the function. */ uint32_t uid; - /** Definition of the persistent function. */ - char *body; - /** User-defined comment for a function. */ - char *comment; /** * True if the function requires change of user id before * invocation. */ bool setuid; - /** - * Whether this function is deterministic (can produce - * only one result for a given list of parameters). - */ - bool is_deterministic; - /** - * Whether the routine must be initialized with isolated - * sandbox where only a limited number if functions is - * available. - */ - bool is_sandboxed; /** * The language of the stored function. */ @@ -91,22 +76,13 @@ struct func_def { /** * @param name_len length of func_def->name * @returns size in bytes needed to allocate for struct func_def - * for a function of length @a a name_len, body @a body_len and - * with comment @a comment_len. + * for a function of length @a a name_len. */ static inline size_t -func_def_sizeof(uint32_t name_len, uint32_t body_len, uint32_t comment_len, - uint32_t *body_offset, uint32_t *comment_offset) +func_def_sizeof(uint32_t name_len) { /* +1 for '\0' name terminating. */ - size_t sz = sizeof(struct func_def) + name_len + 1; - *body_offset = sz; - if (body_len > 0) - sz += body_len + 1; - *comment_offset = sz; - if (comment_len > 0) - sz += comment_len + 1; - return sz; + return sizeof(struct func_def) + name_len + 1; } /** Compare two given function definitions. */ diff --git a/src/box/lua/call.c b/src/box/lua/call.c index 88110c4356c7d7d80ef2118b9bdf54001d5c348d..a236325b6753a16d1722644ce980b9a68f9a284d 100644 --- a/src/box/lua/call.c +++ b/src/box/lua/call.c @@ -294,7 +294,6 @@ port_lua_create(struct port *port, struct lua_State *L) } struct execute_lua_ctx { - int lua_ref; const char *name; uint32_t name_len; struct port *args; @@ -324,24 +323,6 @@ execute_lua_call(lua_State *L) return lua_gettop(L); } -static int -execute_lua_call_by_ref(lua_State *L) -{ - struct execute_lua_ctx *ctx = - (struct execute_lua_ctx *) lua_topointer(L, 1); - lua_settop(L, 0); /* clear the stack to simplify the logic below */ - - lua_rawgeti(L, LUA_REGISTRYINDEX, ctx->lua_ref); - - /* Push the rest of args (a tuple). */ - int top = lua_gettop(L); - port_dump_lua(ctx->args, L, true); - int arg_count = lua_gettop(L) - top; - - lua_call(L, arg_count, LUA_MULTRET); - return lua_gettop(L); -} - static int execute_lua_eval(lua_State *L) { @@ -553,168 +534,22 @@ box_lua_eval(const char *expr, uint32_t expr_len, struct func_lua { /** Function object base class. */ struct func base; - /** - * For a persistent function: a reference to the - * function body. Otherwise LUA_REFNIL. - */ - int lua_ref; }; static struct func_vtab func_lua_vtab; -static struct func_vtab func_persistent_lua_vtab; - -static const char *default_sandbox_exports[] = { - "assert", "error", "ipairs", "math", "next", "pairs", "pcall", "print", - "select", "string", "table", "tonumber", "tostring", "type", "unpack", - "xpcall", "utf8", -}; - -/** - * Assemble a new sandbox with given exports table on the top of - * a given Lua stack. All modules in exports list are copied - * deeply to ensure the immutability of this system object. - */ -static int -prepare_lua_sandbox(struct lua_State *L, const char *exports[], - int export_count) -{ - lua_createtable(L, export_count, 0); - if (export_count == 0) - return 0; - int rc = -1; - const char *deepcopy = "table.deepcopy"; - int luaL_deepcopy_func_ref = LUA_REFNIL; - int ret = box_lua_find(L, deepcopy, deepcopy + strlen(deepcopy)); - if (ret < 0) - goto end; - luaL_deepcopy_func_ref = luaL_ref(L, LUA_REGISTRYINDEX); - assert(luaL_deepcopy_func_ref != LUA_REFNIL); - for (int i = 0; i < export_count; i++) { - uint32_t name_len = strlen(exports[i]); - ret = box_lua_find(L, exports[i], exports[i] + name_len); - if (ret < 0) - goto end; - switch (lua_type(L, -1)) { - case LUA_TTABLE: - lua_rawgeti(L, LUA_REGISTRYINDEX, - luaL_deepcopy_func_ref); - lua_insert(L, -2); - lua_call(L, 1, 1); - break; - case LUA_TFUNCTION: - break; - default: - unreachable(); - } - lua_setfield(L, -2, exports[i]); - } - rc = 0; -end: - luaL_unref(tarantool_L, LUA_REGISTRYINDEX, luaL_deepcopy_func_ref); - return rc; -} - -/** - * Assemble a Lua function object by user-defined function body. - */ -static int -func_persistent_lua_load(struct func_lua *func) -{ - int rc = -1; - int top = lua_gettop(tarantool_L); - struct region *region = &fiber()->gc; - size_t region_svp = region_used(region); - const char *load_pref = "return "; - uint32_t load_str_sz = - strlen(load_pref) + strlen(func->base.def->body) + 1; - char *load_str = region_alloc(region, load_str_sz); - if (load_str == NULL) { - diag_set(OutOfMemory, load_str_sz, "region", "load_str"); - return -1; - } - sprintf(load_str, "%s%s", load_pref, func->base.def->body); - - /* - * Perform loading of the persistent Lua function - * in a new sandboxed Lua thread. The sandbox is - * required to guarantee the safety of executing - * an arbitrary user-defined code - * (e.g. body = 'fiber.yield()'). - */ - struct lua_State *coro_L = lua_newthread(tarantool_L); - if (!func->base.def->is_sandboxed) { - /* - * Keep an original env to apply for non-sandboxed - * persistent function. It is required because - * built object inherits parent env. - */ - lua_getfenv(tarantool_L, -1); - lua_insert(tarantool_L, -2); - } - if (prepare_lua_sandbox(tarantool_L, NULL, 0) != 0) - unreachable(); - lua_setfenv(tarantool_L, -2); - int coro_ref = luaL_ref(tarantool_L, LUA_REGISTRYINDEX); - if (luaL_loadstring(coro_L, load_str) != 0 || - lua_pcall(coro_L, 0, 1, 0) != 0) { - diag_set(ClientError, ER_LOAD_FUNCTION, func->base.def->name, - luaT_tolstring(coro_L, -1, NULL)); - goto end; - } - if (!lua_isfunction(coro_L, -1)) { - diag_set(ClientError, ER_LOAD_FUNCTION, func->base.def->name, - "given body doesn't define a function"); - goto end; - } - lua_xmove(coro_L, tarantool_L, 1); - if (func->base.def->is_sandboxed) { - if (prepare_lua_sandbox(tarantool_L, default_sandbox_exports, - nelem(default_sandbox_exports)) != 0) { - diag_set(ClientError, ER_LOAD_FUNCTION, - func->base.def->name, - diag_last_error(diag_get())->errmsg); - goto end; - } - } else { - lua_insert(tarantool_L, -2); - } - lua_setfenv(tarantool_L, -2); - func->lua_ref = luaL_ref(tarantool_L, LUA_REGISTRYINDEX); - rc = 0; -end: - lua_settop(tarantool_L, top); - region_truncate(region, region_svp); - luaL_unref(tarantool_L, LUA_REGISTRYINDEX, coro_ref); - return rc; -} struct func * func_lua_new(struct func_def *def) { + (void) def; assert(def->language == FUNC_LANGUAGE_LUA); - if (def->is_sandboxed && def->body == NULL) { - diag_set(ClientError, ER_CREATE_FUNCTION, def->name, - "is_sandboxed option may be set only for persistent " - "Lua function (when body option is set)"); - return NULL; - } struct func_lua *func = (struct func_lua *) malloc(sizeof(struct func_lua)); if (func == NULL) { diag_set(OutOfMemory, sizeof(*func), "malloc", "func"); return NULL; } - if (def->body != NULL) { - func->base.def = def; - func->base.vtab = &func_persistent_lua_vtab; - if (func_persistent_lua_load(func) != 0) { - free(func); - return NULL; - } - } else { - func->lua_ref = LUA_REFNIL; - func->base.vtab = &func_lua_vtab; - } + func->base.vtab = &func_lua_vtab; return &func->base; } @@ -739,42 +574,6 @@ static struct func_vtab func_lua_vtab = { .destroy = func_lua_destroy, }; -static void -func_persistent_lua_unload(struct func_lua *func) -{ - luaL_unref(tarantool_L, LUA_REGISTRYINDEX, func->lua_ref); -} - -static void -func_persistent_lua_destroy(struct func *base) -{ - assert(base != NULL && base->def->language == FUNC_LANGUAGE_LUA && - base->def->body != NULL); - assert(base->vtab == &func_persistent_lua_vtab); - struct func_lua *func = (struct func_lua *) base; - func_persistent_lua_unload(func); - free(func); -} - -static inline int -func_persistent_lua_call(struct func *base, struct port *args, struct port *ret) -{ - assert(base != NULL && base->def->language == FUNC_LANGUAGE_LUA && - base->def->body != NULL); - assert(base->vtab == &func_persistent_lua_vtab); - struct func_lua *func = (struct func_lua *)base; - struct execute_lua_ctx ctx; - ctx.lua_ref = func->lua_ref; - ctx.args = args; - return box_process_lua(execute_lua_call_by_ref, &ctx, ret); - -} - -static struct func_vtab func_persistent_lua_vtab = { - .call = func_persistent_lua_call, - .destroy = func_persistent_lua_destroy, -}; - static int lbox_module_reload(lua_State *L) { @@ -868,27 +667,6 @@ lbox_func_new(struct lua_State *L, struct func *func) lua_pushstring(L, "language"); lua_pushstring(L, func_language_strs[func->def->language]); lua_settable(L, top); - lua_pushstring(L, "body"); - if (func->def->body != NULL) - lua_pushstring(L, func->def->body); - else - lua_pushnil(L); - lua_settable(L, top); - lua_pushstring(L, "comment"); - if (func->def->comment != NULL) - lua_pushstring(L, func->def->comment); - else - lua_pushnil(L); - lua_settable(L, top); - lua_pushstring(L, "is_deterministic"); - lua_pushboolean(L, func->def->is_deterministic); - lua_settable(L, top); - lua_pushstring(L, "is_sandboxed"); - if (func->def->body != NULL) - lua_pushboolean(L, func->def->is_sandboxed); - else - lua_pushnil(L); - lua_settable(L, top); /* Bless func object. */ lua_getfield(L, LUA_GLOBALSINDEX, "box"); diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index 1ab97440c426b73fb9e4a14ad5c04684cbbfc5cb..9c3ee063cc9da6c520252c750c78f3f39e64920c 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -2138,10 +2138,7 @@ box.schema.func.create = function(name, opts) opts = opts or {} check_param_table(opts, { setuid = 'boolean', if_not_exists = 'boolean', - language = 'string', body = 'string', - is_deterministic = 'boolean', - is_sandboxed = 'boolean', - comment = 'string' }) + language = 'string'}) local _func = box.space[box.schema.FUNC_ID] local _vfunc = box.space[box.schema.VFUNC_ID] local func = _vfunc.index.name:get{name} @@ -2151,19 +2148,10 @@ box.schema.func.create = function(name, opts) end return end - local datetime = os.date("%Y-%m-%d %H:%M:%S") - opts = update_param_table(opts, { setuid = false, language = 'lua', - body = '', routine_type = 'function', data_type = setmap{}, - sql_data_access = 'none', is_deterministic = false, - is_sandboxed = false, is_null_call = true, opts = setmap{}, - comment = '', created = datetime, last_altered = datetime}) + opts = update_param_table(opts, { setuid = false, language = 'lua'}) opts.language = string.upper(opts.language) opts.setuid = opts.setuid and 1 or 0 - _func:auto_increment{session.euid(), name, opts.setuid, opts.language, - opts.body, opts.routine_type, opts.data_type, - opts.sql_data_access, opts.is_deterministic, - opts.is_sandboxed, opts.is_null_call, opts.opts, - opts.comment, opts.created, opts.last_altered} + _func:auto_increment{session.euid(), name, opts.setuid, opts.language} end box.schema.func.drop = function(name, opts) diff --git a/src/box/lua/upgrade.lua b/src/box/lua/upgrade.lua index 5a8875c1033c03e59be95e3f7b579c0ac539db88..3385b8e17f8f7e769d6aff769eea100f95bf9c88 100644 --- a/src/box/lua/upgrade.lua +++ b/src/box/lua/upgrade.lua @@ -152,7 +152,6 @@ local function initial_1_7_5() local _cluster = box.space[box.schema.CLUSTER_ID] local _truncate = box.space[box.schema.TRUNCATE_ID] local MAP = setmap({}) - local datetime = os.date("%Y-%m-%d %H:%M:%S") -- -- _schema @@ -327,8 +326,7 @@ 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', '', 'function', - MAP, 'none', false, false, true, MAP, '', datetime, datetime} + _func:replace{1, ADMIN, 'box.schema.user.info', 1, 'LUA'} -- grant 'public' role access to 'box.schema.user.info' function log.info('grant execute on function "box.schema.user.info" to public') @@ -822,41 +820,10 @@ local function create_vcollation_space() box.space[box.schema.VCOLLATION_ID]: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='routine_type', type='string'} - format[8] = {name='data_type', type='map'} - format[9] = {name='sql_data_access', type='string'} - format[10] = {name='is_deterministic', type='boolean'} - format[11] = {name='is_sandboxed', type='boolean'} - format[12] = {name='is_null_call', type='boolean'} - format[13] = {name='opts', type='map'} - format[14] = {name='comment', type='string'} - format[15] = {name='created', type='string'} - format[16] = {name='last_altered', type='string'} - local datetime = os.date("%Y-%m-%d %H:%M:%S") - for _, v in box.space._func:pairs() do - _ = box.space._func:replace({v.id, v.owner, v.name, v.setuid, - v[5] or 'LUA', '', 'function', setmap({}), - 'none', false, false, true, setmap({}), - '', datetime, datetime}) - end - _func:format(format) -end - local function upgrade_to_2_2_1() upgrade_sequence_to_2_2_1() upgrade_ck_constraint_to_2_2_1() create_vcollation_space() - upgrade_func_to_2_2_1() end -------------------------------------------------------------------------------- diff --git a/src/box/schema_def.h b/src/box/schema_def.h index 8543a3a77c3f92d8228acc6c9841b7597e976e95..88b5502b8c93ed54428a7f0df956fa0e4c4b3082 100644 --- a/src/box/schema_def.h +++ b/src/box/schema_def.h @@ -167,17 +167,6 @@ enum { BOX_FUNC_FIELD_NAME = 2, BOX_FUNC_FIELD_SETUID = 3, BOX_FUNC_FIELD_LANGUAGE = 4, - BOX_FUNC_FIELD_BODY = 5, - BOX_FUNC_FIELD_ROUTINE_TYPE = 6, - BOX_FUNC_FIELD_DATA_TYPE = 7, - BOX_FUNC_FIELD_SQL_DATA_ACCESS = 8, - BOX_FUNC_FIELD_IS_DETERMINISTIC = 9, - BOX_FUNC_FIELD_IS_SANDBOXED = 10, - BOX_FUNC_FIELD_IS_NULL_CALL = 11, - BOX_FUNC_FIELD_OPTS = 12, - BOX_FUNC_FIELD_COMMENT = 13, - BOX_FUNC_FIELD_CREATED = 14, - BOX_FUNC_FIELD_LAST_ALTERED = 15 }; /** _collation fields. */ diff --git a/test/box-py/bootstrap.result b/test/box-py/bootstrap.result index 4e17fbfea2a7521f0d4ff45950dd6fd49969f06b..b20dc41e5f5f8012142a5455f39c5a78a94b9fc1 100644 --- a/test/box-py/bootstrap.result +++ b/test/box-py/bootstrap.result @@ -53,12 +53,7 @@ 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'}, {'name': 'language', 'type': 'string'}, {'name': 'body', - 'type': 'string'}, {'name': 'routine_type', 'type': 'string'}, {'name': 'data_type', - 'type': 'map'}, {'name': 'sql_data_access', 'type': 'string'}, {'name': 'is_deterministic', - 'type': 'boolean'}, {'name': 'is_sandboxed', 'type': 'boolean'}, {'name': 'is_null_call', - 'type': 'boolean'}, {'name': 'opts', 'type': 'map'}, {'name': 'comment', 'type': 'string'}, - {'name': 'created', 'type': 'string'}, {'name': 'last_altered', 'type': 'string'}]] + 'type': 'unsigned'}]] - [297, 1, '_vfunc', 'sysview', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'owner', 'type': 'unsigned'}, {'name': 'name', 'type': 'string'}, {'name': 'setuid', 'type': 'unsigned'}]] @@ -155,10 +150,9 @@ box.space._user:select{} - [3, 1, 'replication', 'role', {}] - [31, 1, 'super', 'role', {}] ... -for _, v in box.space._func:pairs{} do r = {} table.insert(r, v:update({{"=", 15, ""}, {"=", 16, ""}})) return r end +box.space._func:select{} --- -- - [1, 1, 'box.schema.user.info', 1, 'LUA', '', 'function', {}, 'none', false, false, - true, {}, '', '', ''] +- - [1, 1, 'box.schema.user.info', 1, 'LUA'] ... box.space._priv:select{} --- diff --git a/test/box-py/bootstrap.test.py b/test/box-py/bootstrap.test.py index ba0689ae90fd4b7d1c68cec87eaec8c245922816..4f2f55a7c952213b50fd47eb4c345e1b1ff0842e 100644 --- a/test/box-py/bootstrap.test.py +++ b/test/box-py/bootstrap.test.py @@ -4,7 +4,7 @@ server.admin('box.space._cluster:select{}') server.admin('box.space._space:select{}') server.admin('box.space._index:select{}') server.admin('box.space._user:select{}') -server.admin('for _, v in box.space._func:pairs{} do r = {} table.insert(r, v:update({{"=", 15, ""}, {"=", 16, ""}})) return r end') +server.admin('box.space._func:select{}') server.admin('box.space._priv:select{}') # Cleanup diff --git a/test/box/access_misc.result b/test/box/access_misc.result index c3ed3a65d7a33787be850350c53116e49ab49e2e..53d3661067e60c17cfcc3a1436362c8ecfe7f1e6 100644 --- a/test/box/access_misc.result +++ b/test/box/access_misc.result @@ -793,12 +793,7 @@ 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'}, {'name': 'language', 'type': 'string'}, {'name': 'body', - 'type': 'string'}, {'name': 'routine_type', 'type': 'string'}, {'name': 'data_type', - 'type': 'map'}, {'name': 'sql_data_access', 'type': 'string'}, {'name': 'is_deterministic', - 'type': 'boolean'}, {'name': 'is_sandboxed', 'type': 'boolean'}, {'name': 'is_null_call', - 'type': 'boolean'}, {'name': 'opts', 'type': 'map'}, {'name': 'comment', 'type': 'string'}, - {'name': 'created', 'type': 'string'}, {'name': 'last_altered', 'type': 'string'}]] + 'type': 'unsigned'}]] - [297, 1, '_vfunc', 'sysview', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'owner', 'type': 'unsigned'}, {'name': 'name', 'type': 'string'}, {'name': 'setuid', 'type': 'unsigned'}]] @@ -834,8 +829,7 @@ box.space._space:select() ... box.space._func:select() --- -- - [1, 1, 'box.schema.user.info', 1, 'LUA', '', 'function', {}, 'none', false, false, - true, {}, '', '2019-06-23 18:11:31', '2019-06-23 18:11:31'] +- - [1, 1, 'box.schema.user.info', 1, 'LUA'] ... session = nil --- diff --git a/test/box/function1.result b/test/box/function1.result index 7bea2d64ddb6e925c7725d71ea822a364735265b..99006926e5ec245eabd768598592c7c3c5a0c5af 100644 --- a/test/box/function1.result +++ b/test/box/function1.result @@ -16,25 +16,7 @@ c = net.connect(os.getenv("LISTEN")) box.schema.func.create('function1', {language = "C"}) --- ... -function setmap(tab) return setmetatable(tab, { __serialize = 'map' }) end ---- -... -datetime = os.date("%Y-%m-%d %H:%M:%S") ---- -... -box.space._func:replace{2, 1, 'function1', 0, 'LUA', '', 'procedure', setmap({}), 'none', false, false, true, setmap({}), '', datetime, datetime} ---- -- error: 'Failed to create function ''function1'': unsupported routine_type value' -... -box.space._func:replace{2, 1, 'function1', 0, 'LUA', '', 'function', setmap({}), 'reads', false, false, true, setmap({}), '', datetime, datetime} ---- -- error: 'Failed to create function ''function1'': unsupported sql_data_access value' -... -box.space._func:replace{2, 1, 'function1', 0, 'LUA', '', 'function', setmap({}), 'none', false, false, false, setmap({}), '', datetime, datetime} ---- -- error: 'Failed to create function ''function1'': unsupported is_null_call value' -... -box.space._func:replace{2, 1, 'function1', 0, 'LUA', '', 'function', setmap({}), 'none', false, false, true, setmap({}), '', datetime, datetime} +box.space._func:replace{2, 1, 'function1', 0, 'LUA'} --- - error: function does not support alter ... @@ -77,11 +59,10 @@ c:call('function1.args', { 15 }) ... box.func["function1.args"] --- -- is_deterministic: false - id: 2 +- language: C setuid: false name: function1.args - language: C + id: 2 ... box.func["function1.args"]:call() --- @@ -345,7 +326,7 @@ c:close() function divide(a, b) return a / b end --- ... -box.schema.func.create("divide", {comment = 'Divide two values'}) +box.schema.func.create("divide") --- ... func = box.func.divide @@ -387,12 +368,10 @@ func:drop() ... func --- -- is_deterministic: false - id: 2 +- language: LUA setuid: false - comment: Divide two values name: divide - language: LUA + id: 2 ... func.drop() --- @@ -445,11 +424,10 @@ func:drop() ... func --- -- is_deterministic: false - id: 2 +- language: C setuid: false name: function1.divide - language: C + id: 2 ... func:drop() --- @@ -532,177 +510,6 @@ box.schema.func.drop('secret_leak') box.schema.func.drop('secret') --- ... --- --- gh-4182: Introduce persistent Lua functions. --- -test_run:cmd("setopt delimiter ';'") ---- -- true -... -body = [[function(tuple) - if type(tuple.address) ~= 'string' then - return nil, 'Invalid field type' - end - local t = tuple.address:upper():split() - for k,v in pairs(t) do t[k] = v end - return t - end -]] -test_run:cmd("setopt delimiter ''"); ---- -... -box.schema.func.create('addrsplit', {body = body, language = "C"}) ---- -- error: 'Failed to create function ''addrsplit'': body and is_sandboxed options are - not compatible with C language' -... -box.schema.func.create('addrsplit', {is_sandboxed = true, language = "C"}) ---- -- error: 'Failed to create function ''addrsplit'': body and is_sandboxed options are - not compatible with C language' -... -box.schema.func.create('addrsplit', {is_sandboxed = true}) ---- -- error: 'Failed to create function ''addrsplit'': is_sandboxed option may be set - only for persistent Lua function (when body option is set)' -... -box.schema.func.create('invalid', {body = "function(tuple) ret tuple"}) ---- -- error: 'Failed to dynamically load function ''invalid'': [string "return function(tuple) - ret tuple"]:1: ''='' expected near ''tuple''' -... -box.schema.func.create('addrsplit', {body = body, is_deterministic = true}) ---- -... -box.schema.user.grant('guest', 'execute', 'function', 'addrsplit') ---- -... -conn = net.connect(box.cfg.listen) ---- -... -conn:call('addrsplit', {{address = "Moscow Dolgoprudny"}}) ---- -- ['MOSCOW', 'DOLGOPRUDNY'] -... -box.func.addrsplit:call({{address = "Moscow Dolgoprudny"}}) ---- -- - MOSCOW - - DOLGOPRUDNY -... -conn:close() ---- -... -box.snapshot() ---- -- ok -... -test_run:cmd("restart server default") -test_run = require('test_run').new() ---- -... -test_run:cmd("push filter '(.builtin/.*.lua):[0-9]+' to '\\1'") ---- -- true -... -net = require('net.box') ---- -... -conn = net.connect(box.cfg.listen) ---- -... -conn:call('addrsplit', {{address = "Moscow Dolgoprudny"}}) ---- -- ['MOSCOW', 'DOLGOPRUDNY'] -... -box.func.addrsplit:call({{address = "Moscow Dolgoprudny"}}) ---- -- - MOSCOW - - DOLGOPRUDNY -... -conn:close() ---- -... -box.schema.user.revoke('guest', 'execute', 'function', 'addrsplit') ---- -... -box.func.addrsplit:drop() ---- -... --- Test sandboxed functions. -test_run:cmd("setopt delimiter ';'") ---- -- true -... -body = [[function(number) - math.abs = math.log - return math.abs(number) - end]] -test_run:cmd("setopt delimiter ''"); ---- -... -box.schema.func.create('monkey', {body = body, is_sandboxed = true}) ---- -... -box.func.monkey:call({1}) ---- -- 0 -... -math.abs(1) ---- -- 1 -... -box.func.monkey:drop() ---- -... -sum = 0 ---- -... -function inc_g(val) sum = sum + val end ---- -... -box.schema.func.create('call_inc_g', {body = "function(val) inc_g(val) end"}) ---- -... -box.func.call_inc_g:call({1}) ---- -... -assert(sum == 1) ---- -- true -... -box.schema.func.create('call_inc_g_safe', {body = "function(val) inc_g(val) end", is_sandboxed = true}) ---- -... -box.func.call_inc_g_safe:call({1}) ---- -- error: '[string "return function(val) inc_g(val) end"]:1: attempt to call global - ''inc_g'' (a nil value)' -... -assert(sum == 1) ---- -- true -... -box.func.call_inc_g:drop() ---- -... -box.func.call_inc_g_safe:drop() ---- -... --- Test persistent function assemble corner cases -box.schema.func.create('compiletime_tablef', {body = "{}"}) ---- -- error: 'Failed to dynamically load function ''compiletime_tablef'': given body doesn''t - define a function' -... -box.schema.func.create('compiletime_call_inc_g', {body = "inc_g()"}) ---- -- error: 'Failed to dynamically load function ''compiletime_call_inc_g'': [string - "return inc_g()"]:1: attempt to call global ''inc_g'' (a nil value)' -... -assert(sum == 1) ---- -- true -... test_run:cmd("clear filter") --- - true diff --git a/test/box/function1.test.lua b/test/box/function1.test.lua index 243f78eb148405140d669bb5c9b9cc4aab898c0d..25966b91582a9385c1d013d16af9d5610bf72bd1 100644 --- a/test/box/function1.test.lua +++ b/test/box/function1.test.lua @@ -7,12 +7,7 @@ net = require('net.box') c = net.connect(os.getenv("LISTEN")) box.schema.func.create('function1', {language = "C"}) -function setmap(tab) return setmetatable(tab, { __serialize = 'map' }) end -datetime = os.date("%Y-%m-%d %H:%M:%S") -box.space._func:replace{2, 1, 'function1', 0, 'LUA', '', 'procedure', setmap({}), 'none', false, false, true, setmap({}), '', datetime, datetime} -box.space._func:replace{2, 1, 'function1', 0, 'LUA', '', 'function', setmap({}), 'reads', false, false, true, setmap({}), '', datetime, datetime} -box.space._func:replace{2, 1, 'function1', 0, 'LUA', '', 'function', setmap({}), 'none', false, false, false, setmap({}), '', datetime, datetime} -box.space._func:replace{2, 1, 'function1', 0, 'LUA', '', 'function', setmap({}), 'none', false, false, true, setmap({}), '', datetime, datetime} +box.space._func:replace{2, 1, 'function1', 0, 'LUA'} box.schema.user.grant('guest', 'execute', 'function', 'function1') _ = box.schema.space.create('test') _ = box.space.test:create_index('primary') @@ -125,7 +120,7 @@ c:close() -- Test registered functions interface. function divide(a, b) return a / b end -box.schema.func.create("divide", {comment = 'Divide two values'}) +box.schema.func.create("divide") func = box.func.divide func.call({4, 2}) func:call(4, 2) @@ -185,68 +180,4 @@ box.schema.user.revoke('guest', 'execute', 'function', 'secret_leak') box.schema.func.drop('secret_leak') box.schema.func.drop('secret') --- --- gh-4182: Introduce persistent Lua functions. --- -test_run:cmd("setopt delimiter ';'") -body = [[function(tuple) - if type(tuple.address) ~= 'string' then - return nil, 'Invalid field type' - end - local t = tuple.address:upper():split() - for k,v in pairs(t) do t[k] = v end - return t - end -]] -test_run:cmd("setopt delimiter ''"); -box.schema.func.create('addrsplit', {body = body, language = "C"}) -box.schema.func.create('addrsplit', {is_sandboxed = true, language = "C"}) -box.schema.func.create('addrsplit', {is_sandboxed = true}) -box.schema.func.create('invalid', {body = "function(tuple) ret tuple"}) -box.schema.func.create('addrsplit', {body = body, is_deterministic = true}) -box.schema.user.grant('guest', 'execute', 'function', 'addrsplit') -conn = net.connect(box.cfg.listen) -conn:call('addrsplit', {{address = "Moscow Dolgoprudny"}}) -box.func.addrsplit:call({{address = "Moscow Dolgoprudny"}}) -conn:close() -box.snapshot() -test_run:cmd("restart server default") -test_run = require('test_run').new() -test_run:cmd("push filter '(.builtin/.*.lua):[0-9]+' to '\\1'") -net = require('net.box') -conn = net.connect(box.cfg.listen) -conn:call('addrsplit', {{address = "Moscow Dolgoprudny"}}) -box.func.addrsplit:call({{address = "Moscow Dolgoprudny"}}) -conn:close() -box.schema.user.revoke('guest', 'execute', 'function', 'addrsplit') -box.func.addrsplit:drop() - --- Test sandboxed functions. -test_run:cmd("setopt delimiter ';'") -body = [[function(number) - math.abs = math.log - return math.abs(number) - end]] -test_run:cmd("setopt delimiter ''"); -box.schema.func.create('monkey', {body = body, is_sandboxed = true}) -box.func.monkey:call({1}) -math.abs(1) -box.func.monkey:drop() - -sum = 0 -function inc_g(val) sum = sum + val end -box.schema.func.create('call_inc_g', {body = "function(val) inc_g(val) end"}) -box.func.call_inc_g:call({1}) -assert(sum == 1) -box.schema.func.create('call_inc_g_safe', {body = "function(val) inc_g(val) end", is_sandboxed = true}) -box.func.call_inc_g_safe:call({1}) -assert(sum == 1) -box.func.call_inc_g:drop() -box.func.call_inc_g_safe:drop() - --- Test persistent function assemble corner cases -box.schema.func.create('compiletime_tablef', {body = "{}"}) -box.schema.func.create('compiletime_call_inc_g', {body = "inc_g()"}) -assert(sum == 1) - test_run:cmd("clear filter")