[PATCH v2 3/3] netbox: define formats for tuple from netbox
imeevma at tarantool.org
imeevma at tarantool.org
Fri Jun 21 18:25:52 MSK 2019
This patch creates tuple_formats for the tuples obtained through
the netbox.
Closes #2978
@TarantoolBot document
Title: Field names for tuples received from net.box
It is possible now to access by field name for tuples received
from net.box. For example:
box.cfg{listen = 3302}
box.schema.user.grant('guest','read, write, execute', 'space')
box.schema.user.grant('guest', 'create', 'space')
box.schema.create_space("named", {format = {{name = "id"}}})
box.space.named:create_index('id', {parts = {{1, 'unsigned'}}})
box.space.named:insert({1})
require('net.box').connect('localhost', 3302).space.named:get(1).id
Result:
tarantool> require('net.box').connect('localhost', 3302).space.named:get(1).id
---
- 1
...
---
src/box/lua/net_box.c | 17 +++++---
src/box/lua/net_box.lua | 44 +++++++++++++--------
test/box/net.box.result | 98 +++++++++++++++++++++++++++++++++++++++++++++++
test/box/net.box.test.lua | 28 ++++++++++++++
4 files changed, 167 insertions(+), 20 deletions(-)
diff --git a/src/box/lua/net_box.c b/src/box/lua/net_box.c
index 7484a86..ad7bc6a 100644
--- a/src/box/lua/net_box.c
+++ b/src/box/lua/net_box.c
@@ -48,6 +48,7 @@
#include "box/errcode.h"
#include "lua/fiber.h"
#include "mpstream.h"
+#include "misc.h" /* lbox_check_tuple_format() */
#define cfg luaL_msgpack_default
@@ -590,12 +591,11 @@ netbox_encode_execute(lua_State *L)
* @param data MessagePack.
*/
static void
-netbox_decode_data(struct lua_State *L, const char **data)
+netbox_decode_data(struct lua_State *L, const char **data,
+ struct tuple_format *format)
{
uint32_t count = mp_decode_array(data);
lua_createtable(L, count, 0);
- struct tuple_format *format =
- box_tuple_format_default();
for (uint32_t j = 0; j < count; ++j) {
const char *begin = *data;
mp_next(data);
@@ -618,6 +618,13 @@ static int
netbox_decode_select(struct lua_State *L)
{
uint32_t ctypeid;
+ int top = lua_gettop(L);
+ assert(top == 1 || top == 2);
+ struct tuple_format *format;
+ if (top == 2 && lua_type(L, 2) == LUA_TCDATA)
+ format = lbox_check_tuple_format(L, 2);
+ else
+ format = tuple_format_runtime;
const char *data = *(const char **)luaL_checkcdata(L, 1, &ctypeid);
assert(mp_typeof(*data) == MP_MAP);
uint32_t map_size = mp_decode_map(&data);
@@ -627,7 +634,7 @@ netbox_decode_select(struct lua_State *L)
uint32_t key = mp_decode_uint(&data);
assert(key == IPROTO_DATA);
(void) key;
- netbox_decode_data(L, &data);
+ netbox_decode_data(L, &data, format);
*(const char **)luaL_pushcdata(L, ctypeid) = data;
return 2;
}
@@ -716,7 +723,7 @@ netbox_decode_execute(struct lua_State *L)
uint32_t key = mp_decode_uint(&data);
switch(key) {
case IPROTO_DATA:
- netbox_decode_data(L, &data);
+ netbox_decode_data(L, &data, tuple_format_runtime);
rows_index = i - map_size;
break;
case IPROTO_METADATA:
diff --git a/src/box/lua/net_box.lua b/src/box/lua/net_box.lua
index d9838f8..8f31712 100644
--- a/src/box/lua/net_box.lua
+++ b/src/box/lua/net_box.lua
@@ -63,12 +63,12 @@ local function decode_data(raw_data)
local response, raw_end = decode(raw_data)
return response[IPROTO_DATA_KEY], raw_end
end
-local function decode_tuple(raw_data)
- local response, raw_end = internal.decode_select(raw_data)
+local function decode_tuple(raw_data, raw_data_end, args)
+ local response, raw_end = internal.decode_select(raw_data, args.format)
return response[1], raw_end
end
-local function decode_get(raw_data)
- local body, raw_end = internal.decode_select(raw_data)
+local function decode_get(raw_data, raw_data_end, args)
+ local body, raw_end = internal.decode_select(raw_data, args.format)
if body[2] then
return nil, raw_end, box.error.MORE_THAN_ONE_TUPLE
end
@@ -82,6 +82,12 @@ local function decode_push(raw_data)
local response, raw_end = decode(raw_data)
return response[IPROTO_DATA_KEY][1], raw_end
end
+local function decode_call_16(raw_data)
+ return internal.decode_select(raw_data)
+end
+local function decode_select(raw_data, raw_data_end, args)
+ return internal.decode_select(raw_data, args.format)
+end
local function encode_call(send_buf, id, args)
return internal.encode_call(send_buf, id, args.func_name, args.args)
@@ -150,7 +156,7 @@ local method_encoder = {
local method_decoder = {
ping = decode_nil,
- call_16 = internal.decode_select,
+ call_16 = decode_call_16,
call_17 = decode_data,
eval = decode_data,
insert = decode_tuple,
@@ -158,7 +164,7 @@ local method_decoder = {
delete = decode_tuple,
update = decode_tuple,
upsert = decode_nil,
- select = internal.decode_select,
+ select = decode_select,
execute = internal.decode_execute,
get = decode_get,
min = decode_get,
@@ -623,7 +629,8 @@ local function create_transport(host, port, user, password, callback,
-- Decode xrow.body[DATA] to Lua objects
if status == IPROTO_OK_KEY then
request.response, real_end, request.errno =
- method_decoder[request.method](body_rpos, body_end)
+ method_decoder[request.method](body_rpos, body_end,
+ request.args)
assert(real_end == body_end, "invalid body length")
requests[id] = nil
request.id = nil
@@ -1267,6 +1274,7 @@ function remote_methods:_install_schema(schema_version, spaces, indices,
s.index = {}
s.temporary = false
s._format = format
+ s._format_cdata = box.internal.new_tuple_format(format)
s.connection = self
if #space > 5 then
local opts = space[6]
@@ -1384,13 +1392,15 @@ space_metatable = function(remote)
function methods:insert(tuple, opts)
check_space_arg(self, 'insert')
- local args = {space_id = self.id, tuple = tuple}
+ local args = {space_id = self.id, tuple = tuple,
+ format = self._format_cdata}
return remote:_request('insert', opts, args)
end
function methods:replace(tuple, opts)
check_space_arg(self, 'replace')
- local args = {space_id = self.id, tuple = tuple}
+ local args = {space_id = self.id, tuple = tuple,
+ format = self._format_cdata}
return remote:_request('replace', opts, args)
end
@@ -1443,7 +1453,7 @@ index_metatable = function(remote)
local limit = tonumber(opts and opts.limit) or 0xFFFFFFFF
local args = {space_id = self.space.id, index_id = self.id,
iterator = iterator, offset = offset, limit = limit,
- key = key}
+ key = key, format = self.space._format_cdata}
return (remote:_request('select', opts, args))
end
@@ -1453,7 +1463,8 @@ index_metatable = function(remote)
error("index:get() doesn't support `buffer` argument")
end
local args = {space_id = self.space.id, index_id = self.id,
- iterator = box.index.EQ, offset = 0, limit = 2, key = key}
+ iterator = box.index.EQ, offset = 0, limit = 2, key = key,
+ format = self.space._format_cdata}
return nothing_or_data(remote:_request('get', opts, args))
end
@@ -1463,7 +1474,8 @@ index_metatable = function(remote)
error("index:min() doesn't support `buffer` argument")
end
local args = {space_id = self.space.id, index_id = self.id,
- iterator = box.index.GE, offset = 0, limit = 1, key = key}
+ iterator = box.index.GE, offset = 0, limit = 1, key = key,
+ format = self.space._format_cdata}
return nothing_or_data(remote:_request('min', opts, args))
end
@@ -1473,7 +1485,8 @@ index_metatable = function(remote)
error("index:max() doesn't support `buffer` argument")
end
local args = {space_id = self.space.id, index_id = self.id,
- iterator = box.index.LE, offset = 0, limit = 1, key = key}
+ iterator = box.index.LE, offset = 0, limit = 1, key = key,
+ format = self.space._format_cdata}
return nothing_or_data(remote:_request('max', opts, args))
end
@@ -1490,14 +1503,15 @@ index_metatable = function(remote)
function methods:delete(key, opts)
check_index_arg(self, 'delete')
- local args = {space_id = self.space.id, index_id = self.id, key = key}
+ local args = {space_id = self.space.id, index_id = self.id, key = key,
+ format = self.space._format_cdata}
return nothing_or_data(remote:_request('delete', opts, args))
end
function methods:update(key, oplist, opts)
check_index_arg(self, 'update')
local args = {space_id = self.space.id, index_id = self.id, key = key,
- oplist = oplist}
+ oplist = oplist, format = self.space._format_cdata}
return nothing_or_data(remote:_request('update', opts, args))
end
diff --git a/test/box/net.box.result b/test/box/net.box.result
index 269df0d..1248c64 100644
--- a/test/box/net.box.result
+++ b/test/box/net.box.result
@@ -3572,6 +3572,104 @@ box.schema.func.drop('change_schema')
---
...
--
+-- gh-2978: field names for tuples received from netbox.
+--
+_ = box.schema.create_space("named", {format = {{name = "id"}, {name="abc"}}})
+---
+...
+_ = box.space.named:create_index('id', {parts = {{1, 'unsigned'}}})
+---
+...
+box.space.named:insert({1, 1})
+---
+- [1, 1]
+...
+box.schema.user.grant('guest', 'read, write, execute', 'space')
+---
+...
+cn = net.connect(box.cfg.listen)
+---
+...
+s = cn.space.named
+---
+...
+s:get{1}.id
+---
+- 1
+...
+s:get{1}:tomap()
+---
+- 1: 1
+ 2: 1
+ abc: 1
+ id: 1
+...
+s:insert{2,3}:tomap()
+---
+- 1: 2
+ 2: 3
+ abc: 3
+ id: 2
+...
+s:replace{2,14}:tomap()
+---
+- 1: 2
+ 2: 14
+ abc: 14
+ id: 2
+...
+s:update(1, {{'+', 2, 10}}):tomap()
+---
+- 1: 1
+ 2: 11
+ abc: 11
+ id: 1
+...
+s:select()[1]:tomap()
+---
+- 1: 1
+ 2: 11
+ abc: 11
+ id: 1
+...
+s:delete({2}):tomap()
+---
+- 1: 2
+ 2: 14
+ abc: 14
+ id: 2
+...
+-- Check that formats changes after reload.
+box.space.named:format({{name = "id2"}, {name="abc2"}})
+---
+...
+s:select()[1]:tomap()
+---
+- 1: 1
+ 2: 11
+ abc: 11
+ id: 1
+...
+cn:reload_schema()
+---
+...
+s:select()[1]:tomap()
+---
+- 1: 1
+ 2: 11
+ id2: 1
+ abc2: 11
+...
+cn:close()
+---
+...
+box.space.named:drop()
+---
+...
+box.schema.user.revoke('guest', 'read, write, execute', 'space')
+---
+...
+--
-- gh-3400: long-poll input discard must not touch event loop of
-- a closed connection.
--
diff --git a/test/box/net.box.test.lua b/test/box/net.box.test.lua
index 026f380..f222ad9 100644
--- a/test/box/net.box.test.lua
+++ b/test/box/net.box.test.lua
@@ -1433,6 +1433,34 @@ box.space.test3:drop()
box.schema.func.drop('change_schema')
--
+-- gh-2978: field names for tuples received from netbox.
+--
+_ = box.schema.create_space("named", {format = {{name = "id"}, {name="abc"}}})
+_ = box.space.named:create_index('id', {parts = {{1, 'unsigned'}}})
+box.space.named:insert({1, 1})
+box.schema.user.grant('guest', 'read, write, execute', 'space')
+cn = net.connect(box.cfg.listen)
+
+s = cn.space.named
+s:get{1}.id
+s:get{1}:tomap()
+s:insert{2,3}:tomap()
+s:replace{2,14}:tomap()
+s:update(1, {{'+', 2, 10}}):tomap()
+s:select()[1]:tomap()
+s:delete({2}):tomap()
+
+-- Check that formats changes after reload.
+box.space.named:format({{name = "id2"}, {name="abc2"}})
+s:select()[1]:tomap()
+cn:reload_schema()
+s:select()[1]:tomap()
+
+cn:close()
+box.space.named:drop()
+box.schema.user.revoke('guest', 'read, write, execute', 'space')
+
+--
-- gh-3400: long-poll input discard must not touch event loop of
-- a closed connection.
--
--
2.7.4
More information about the Tarantool-patches
mailing list