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 987662A4D4 for ; Mon, 25 Mar 2019 08:27:45 -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 Ohnu86Y3Xaun for ; Mon, 25 Mar 2019 08:27:45 -0400 (EDT) Received: from smtp54.i.mail.ru (smtp54.i.mail.ru [217.69.128.34]) (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 D13352A380 for ; Mon, 25 Mar 2019 08:27:44 -0400 (EDT) From: Kirill Shcherbatov Subject: [tarantool-patches] [PATCH v1 1/1] lua: export key_def methods for LUA key_def object Date: Mon, 25 Mar 2019 15:27:41 +0300 Message-Id: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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, alexander.turenko@tarantool.org Cc: Kirill Shcherbatov Functions extract_key, compare, compare_with_key, merge defined for key_def introduced for LUA key_def object. Close #4025 @TarantoolBot document Title: Built-in methods for key_def object Now it is possible to work with index base object - key definition in LUA. Available methods: key = key_def:extract_key(tuple) key_def:compare(tuple_a, tuple_b) key_def:compare_with_key(tuple, key), where key is tuple or table new_key_def = key_def:merge(second_key_def) Example: -- Removal values for secondary non-unique index key_def = require('key_def') s = box.schema.space.create('test') pk = s:create_index('pk') idx = s:create_index('test', {unique=false, parts = {{2, 'number', path = 'a'}, {2, 'number', path = 'b'}}}) s:insert{1, {a = 1, b = 1}} s:insert{2, {a = 1, b = 2}} pk_def = key_def.new(pk.parts) for _, tuple in pairs(idx:select({1, nil})) do local key = pk_def:extract_key(tuple) pk:delete(key) end --- src/box/CMakeLists.txt | 1 + src/box/lua/init.c | 2 + src/box/lua/key_def.c | 134 ++++++++++++++++++++++++++++++++++++++++ src/box/lua/key_def.h | 8 +++ src/box/lua/key_def.lua | 19 ++++++ src/box/lua/space.cc | 28 +-------- test/box/tuple.result | 133 +++++++++++++++++++++++++++++++++++++++ test/box/tuple.test.lua | 39 ++++++++++++ 8 files changed, 338 insertions(+), 26 deletions(-) create mode 100644 src/box/lua/key_def.lua diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt index f25c21045..906ce22e6 100644 --- a/src/box/CMakeLists.txt +++ b/src/box/CMakeLists.txt @@ -12,6 +12,7 @@ lua_source(lua_sources lua/net_box.lua) lua_source(lua_sources lua/upgrade.lua) lua_source(lua_sources lua/console.lua) lua_source(lua_sources lua/xlog.lua) +lua_source(lua_sources lua/key_def.lua) set(bin_sources) bin_source(bin_sources bootstrap.snap bootstrap.h) diff --git a/src/box/lua/init.c b/src/box/lua/init.c index 69f346414..68ef58909 100644 --- a/src/box/lua/init.c +++ b/src/box/lua/init.c @@ -63,6 +63,7 @@ extern char session_lua[], tuple_lua[], + key_def_lua[], schema_lua[], load_cfg_lua[], xlog_lua[], @@ -81,6 +82,7 @@ static const char *lua_sources[] = { "box/console", console_lua, "box/load_cfg", load_cfg_lua, "box/xlog", xlog_lua, + "box/key_def", key_def_lua, NULL }; diff --git a/src/box/lua/key_def.c b/src/box/lua/key_def.c index 813582913..6d2c06afb 100644 --- a/src/box/lua/key_def.c +++ b/src/box/lua/key_def.c @@ -34,8 +34,10 @@ #include #include #include "diag.h" +#include "tuple.h" #include "box/key_def.h" #include "box/box.h" +#include "box/tuple.h" #include "box/coll_id_cache.h" #include "lua/utils.h" #include "box/tuple_format.h" /* TUPLE_INDEX_BASE */ @@ -149,6 +151,28 @@ luaT_key_def_set_part(struct lua_State *L, struct key_part_def *part) return 0; } +void +lbox_fill_key_part(struct lua_State *L, const struct key_part *part) +{ + lua_newtable(L); + lua_pushstring(L, field_type_strs[part->type]); + lua_setfield(L, -2, "type"); + lua_pushnumber(L, part->fieldno + TUPLE_INDEX_BASE); + lua_setfield(L, -2, "fieldno"); + if (part->path != NULL) { + lua_pushlstring(L, part->path, part->path_len); + lua_setfield(L, -2, "path"); + } + lua_pushboolean(L, key_part_is_nullable(part)); + lua_setfield(L, -2, "is_nullable"); + if (part->coll_id != COLL_NONE) { + struct coll_id *coll_id = coll_by_id(part->coll_id); + assert(coll_id != NULL); + lua_pushstring(L, coll_id->name); + lua_setfield(L, -2, "collation"); + } +} + struct key_def * check_key_def(struct lua_State *L, int idx) { @@ -175,6 +199,103 @@ lbox_key_def_gc(struct lua_State *L) return 0; } +static int +lbox_key_def_extract_key(lua_State *L) +{ + struct key_def *key_def; + struct tuple *tuple; + if (lua_gettop(L) != 2 || (key_def = check_key_def(L, 1)) == NULL || + (tuple = luaT_istuple(L, 2)) == NULL) + return luaL_error(L, "Usage key_def:extract_key(tuple)"); + + uint32_t key_size; + char *key = tuple_extract_key(tuple, key_def, &key_size); + if (key == NULL) + return luaT_error(L); + + struct tuple *ret = + box_tuple_new(box_tuple_format_default(), key, key + key_size); + if (ret == NULL) + return luaT_error(L); + luaT_pushtuple(L, ret); + return 1; +} + +static int +lbox_key_def_compare(lua_State *L) +{ + struct key_def *key_def; + struct tuple *tuple_a, *tuple_b; + if (lua_gettop(L) != 3 || (key_def = check_key_def(L, 1)) == NULL || + (tuple_a = luaT_istuple(L, 2)) == NULL || + (tuple_b = luaT_istuple(L, 3)) == NULL) + return luaL_error(L, "Usage key_def:compare(tuple_a, tuple_b)"); + + int rc = tuple_compare(tuple_a, tuple_b, key_def); + lua_pushinteger(L, rc); + return 1; +} + +static int +lbox_key_def_compare_with_key(lua_State *L) +{ + struct key_def *key_def; + struct tuple *tuple, *key_tuple; + if (lua_gettop(L) != 3 || (key_def = check_key_def(L, 1)) == NULL || + (tuple = luaT_istuple(L, 2)) == NULL) + goto usage_error; + + lua_remove(L, 1); + lua_remove(L, 1); + if (luaT_tuple_new(L, box_tuple_format_default()) != 1 || + (key_tuple = luaT_istuple(L, -1)) == NULL) + goto usage_error; + + const char *key = tuple_data(key_tuple); + assert(mp_typeof(*key) == MP_ARRAY); + uint32_t part_count = mp_decode_array(&key); + + int rc = tuple_compare_with_key(tuple, key, part_count, key_def); + lua_pushinteger(L, rc); + return 1; +usage_error: + return luaL_error(L, "Usage key_def:compare_with_key(tuple, key)"); +} + +static int +lbox_key_def_merge(lua_State *L) +{ + struct key_def *key_def_a, *key_def_b; + if (lua_gettop(L) != 2 || (key_def_a = check_key_def(L, 1)) == NULL || + (key_def_b = check_key_def(L, 2)) == NULL) + return luaL_error(L, "Usage key_def:merge(second_key_def)"); + + struct key_def *new_key_def = key_def_merge(key_def_a, key_def_b); + if (new_key_def == NULL) + return luaT_error(L); + + *(struct key_def **)luaL_pushcdata(L, key_def_type_id) = new_key_def; + lua_pushcfunction(L, lbox_key_def_gc); + luaL_setcdatagc(L, -2); + return 1; +} + +static int +lbox_key_def_to_map(struct lua_State *L) +{ + struct key_def *key_def; + if (lua_gettop(L) != 1 || (key_def = check_key_def(L, 1)) == NULL) + return luaL_error(L, "Usage key_def:tomap()"); + + lua_createtable(L, key_def->part_count, 0); + for (uint32_t i = 0; i < key_def->part_count; ++i) { + lua_pushnumber(L, i + 1); + lbox_fill_key_part(L, &key_def->parts[i]); + lua_settable(L, -3); + } + return 1; +} + /** * Create a new key_def from a Lua table. * @@ -236,5 +357,18 @@ luaopen_key_def(struct lua_State *L) }; luaL_register_module(L, "key_def", meta); + lua_newtable(L); /* key_def.internal */ + lua_pushcfunction(L, lbox_key_def_extract_key); + lua_setfield(L, -2, "extract_key"); + lua_pushcfunction(L, lbox_key_def_compare); + lua_setfield(L, -2, "compare"); + lua_pushcfunction(L, lbox_key_def_compare_with_key); + lua_setfield(L, -2, "compare_with_key"); + lua_pushcfunction(L, lbox_key_def_merge); + lua_setfield(L, -2, "merge"); + lua_pushcfunction(L, lbox_key_def_to_map); + lua_setfield(L, -2, "tomap"); + lua_setfield(L, -2, "internal"); + return 1; } diff --git a/src/box/lua/key_def.h b/src/box/lua/key_def.h index 61894d452..02217d3a3 100644 --- a/src/box/lua/key_def.h +++ b/src/box/lua/key_def.h @@ -36,6 +36,14 @@ extern "C" { #endif /* defined(__cplusplus) */ struct lua_State; +struct key_part; + +/** + * Prepare a new table representing a key_part on top of the Lua + * stack. + */ +void +lbox_fill_key_part(struct lua_State *L, const struct key_part *part); /** * Extract a key_def object from a Lua stack. diff --git a/src/box/lua/key_def.lua b/src/box/lua/key_def.lua new file mode 100644 index 000000000..5dc8d9357 --- /dev/null +++ b/src/box/lua/key_def.lua @@ -0,0 +1,19 @@ +local ffi = require('ffi') +local key_def = require('key_def') +local key_def_t = ffi.typeof('struct key_def') + +local methods = { + ['extract_key'] = key_def.internal.extract_key, + ['compare'] = key_def.internal.compare, + ['compare_with_key'] = key_def.internal.compare_with_key, + ['merge'] = key_def.internal.merge, + ['tomap'] = key_def.internal.tomap, + ['__serialize'] = key_def.internal.tomap, +} + +ffi.metatype(key_def_t, { + __index = function(self, key) + return methods[key] + end, + __tostring = function(key_def) return "" end, +}) diff --git a/src/box/lua/space.cc b/src/box/lua/space.cc index 9dfc97b6a..9be27959c 100644 --- a/src/box/lua/space.cc +++ b/src/box/lua/space.cc @@ -30,6 +30,7 @@ */ #include "box/lua/space.h" #include "box/lua/tuple.h" +#include "box/lua/key_def.h" #include "box/sql/sqlLimit.h" #include "lua/utils.h" #include "lua/trigger.h" @@ -286,32 +287,7 @@ lbox_fillspace(struct lua_State *L, struct space *space, int i) for (uint32_t j = 0; j < index_def->key_def->part_count; j++) { lua_pushnumber(L, j + 1); - lua_newtable(L); - const struct key_part *part = - &index_def->key_def->parts[j]; - - lua_pushstring(L, field_type_strs[part->type]); - lua_setfield(L, -2, "type"); - - lua_pushnumber(L, part->fieldno + TUPLE_INDEX_BASE); - lua_setfield(L, -2, "fieldno"); - - if (part->path != NULL) { - lua_pushlstring(L, part->path, part->path_len); - lua_setfield(L, -2, "path"); - } - - lua_pushboolean(L, key_part_is_nullable(part)); - lua_setfield(L, -2, "is_nullable"); - - if (part->coll_id != COLL_NONE) { - struct coll_id *coll_id = - coll_by_id(part->coll_id); - assert(coll_id != NULL); - lua_pushstring(L, coll_id->name); - lua_setfield(L, -2, "collation"); - } - + lbox_fill_key_part(L, &index_def->key_def->parts[j]); lua_settable(L, -3); /* index[k].parts[j] */ } diff --git a/test/box/tuple.result b/test/box/tuple.result index 82ad8404d..a0209ca4a 100644 --- a/test/box/tuple.result +++ b/test/box/tuple.result @@ -1231,3 +1231,136 @@ s2:frommap({a="1", k="11"}):tomap({names_only = true}) s2:drop() --- ... +-- +-- gh-4025: Introduce built-in function to get index key +-- from tuple. +-- +key_def = require('key_def') +--- +... +s = box.schema.space.create('test', {engine='vinyl'}) +--- +... +pk = s:create_index('pk') +--- +... +sk = s:create_index('sk', {unique=false, parts = {{2, 'number'}, {3, 'number'}}}) +--- +... +tuple_a = box.tuple.new({1, 1, 22}) +--- +... +tuple_b = box.tuple.new({2, 1, 11}) +--- +... +tuple_c = box.tuple.new({3, 1, 22}) +--- +... +pk_def = key_def.new(pk.parts) +--- +... +pk_def:extract_key(tuple_a) +--- +- [1] +... +sk_def = key_def.new(sk.parts) +--- +... +sk_def:extract_key(tuple_a) +--- +- [1, 22] +... +s:insert(tuple_a) +--- +- [1, 1, 22] +... +s:insert(tuple_b) +--- +- [2, 1, 11] +... +for _, tuple in pairs(sk:select({1, nil})) do pk:delete(pk_def:extract_key(tuple)) end +--- +... +s:select() +--- +- [] +... +pk_def:compare(tuple_b, tuple_a) +--- +- 1 +... +pk_def:compare(tuple_b, tuple_c) +--- +- -1 +... +sk_def:compare(tuple_b, tuple_a) +--- +- -1 +... +sk_def:compare(tuple_a, tuple_c) +--- +- 0 +... +pk_sk_def = pk_def:merge(sk_def) +--- +... +pk_sk_def:extract_key(tuple_a) +--- +- [1, 1, 22] +... +pk_sk_def:compare(tuple_a, tuple_b) +--- +- -1 +... +sk_pk_def = sk_def:merge(pk_def) +--- +... +sk_pk_def:extract_key(tuple_a) +--- +- [1, 22, 1] +... +sk_pk_def:compare(tuple_a, tuple_b) +--- +- 1 +... +key = sk_def:extract_key(tuple_a) +--- +... +sk_def:compare_with_key(tuple_a, key) +--- +- 0 +... +sk_def:compare_with_key(tuple_a, {1, 20}) +--- +- 1 +... +sk_def:tomap() +--- +- - type: number + is_nullable: false + fieldno: 2 + - type: number + is_nullable: false + fieldno: 3 +... +sk_def +--- +- - type: number + is_nullable: false + fieldno: 2 + - type: number + is_nullable: false + fieldno: 3 +... +print(sk_def) +--- +... +key_def.new(sk_def:tomap()) +--- +- - type: number + is_nullable: false + fieldno: 2 + - type: number + is_nullable: false + fieldno: 3 +... diff --git a/test/box/tuple.test.lua b/test/box/tuple.test.lua index 8030b0884..0a626b36a 100644 --- a/test/box/tuple.test.lua +++ b/test/box/tuple.test.lua @@ -416,3 +416,42 @@ s2:frommap({a="1", k="11"}) s2:frommap({a="1", k="11"}):tomap({names_only = true}) s2:drop() + +-- +-- gh-4025: Introduce built-in function to get index key +-- from tuple. +-- +key_def = require('key_def') +s = box.schema.space.create('test', {engine='vinyl'}) +pk = s:create_index('pk') +sk = s:create_index('sk', {unique=false, parts = {{2, 'number'}, {3, 'number'}}}) +tuple_a = box.tuple.new({1, 1, 22}) +tuple_b = box.tuple.new({2, 1, 11}) +tuple_c = box.tuple.new({3, 1, 22}) +pk_def = key_def.new(pk.parts) +pk_def:extract_key(tuple_a) +sk_def = key_def.new(sk.parts) +sk_def:extract_key(tuple_a) +s:insert(tuple_a) +s:insert(tuple_b) +for _, tuple in pairs(sk:select({1, nil})) do pk:delete(pk_def:extract_key(tuple)) end +s:select() +pk_def:compare(tuple_b, tuple_a) +pk_def:compare(tuple_b, tuple_c) +sk_def:compare(tuple_b, tuple_a) +sk_def:compare(tuple_a, tuple_c) + +pk_sk_def = pk_def:merge(sk_def) +pk_sk_def:extract_key(tuple_a) +pk_sk_def:compare(tuple_a, tuple_b) +sk_pk_def = sk_def:merge(pk_def) +sk_pk_def:extract_key(tuple_a) +sk_pk_def:compare(tuple_a, tuple_b) + +key = sk_def:extract_key(tuple_a) +sk_def:compare_with_key(tuple_a, key) +sk_def:compare_with_key(tuple_a, {1, 20}) +sk_def:tomap() +sk_def +print(sk_def) +key_def.new(sk_def:tomap()) -- 2.21.0