[PATCH v2 2/3] lua: internal function to parse space format
imeevma at tarantool.org
imeevma at tarantool.org
Fri Jun 21 18:25:51 MSK 2019
This patch defines a new function that parses space format and
returns it to Lua as cdata. For this cdata destructor is included.
Needed for #2978
---
src/box/lua/misc.cc | 120 +++++++++++++++++++++++++++++++++++++++++++++++++
src/box/lua/misc.h | 3 ++
test/box/misc.result | 88 ++++++++++++++++++++++++++++++++++++
test/box/misc.test.lua | 50 +++++++++++++++++++++
4 files changed, 261 insertions(+)
diff --git a/src/box/lua/misc.cc b/src/box/lua/misc.cc
index 8de7401..a835d3d 100644
--- a/src/box/lua/misc.cc
+++ b/src/box/lua/misc.cc
@@ -37,9 +37,13 @@
#include "box/box.h"
#include "box/port.h"
+#include "box/tuple.h"
+#include "box/tuple_format.h"
#include "box/lua/tuple.h"
#include "mpstream.h"
+static uint32_t CTID_STRUCT_TUPLE_FORMAT_PTR;
+
/** {{{ Miscellaneous utils **/
char *
@@ -116,14 +120,130 @@ lbox_select(lua_State *L)
/* }}} */
+/** {{{ Utils to work with tuple_format. **/
+
+struct tuple_format *
+lbox_check_tuple_format(struct lua_State *L, int narg)
+{
+ uint32_t ctypeid;
+ struct tuple_format *format =
+ *(struct tuple_format **)luaL_checkcdata(L, narg, &ctypeid);
+ if (ctypeid != CTID_STRUCT_TUPLE_FORMAT_PTR) {
+ luaL_error(L, "Invalid argument: 'struct tuple_format *' "
+ "expected, got %s)",
+ lua_typename(L, lua_type(L, narg)));
+ }
+ return format;
+}
+
+static int
+lbox_tuple_format_gc(struct lua_State *L)
+{
+ struct tuple_format *format = lbox_check_tuple_format(L, 1);
+ tuple_format_unref(format);
+ return 0;
+}
+
+static int
+lbox_push_tuple_format(struct lua_State *L, struct tuple_format *format)
+{
+ struct tuple_format **ptr = (struct tuple_format **)
+ luaL_pushcdata(L, CTID_STRUCT_TUPLE_FORMAT_PTR);
+ *ptr = format;
+ tuple_format_ref(format);
+ lua_pushcfunction(L, lbox_tuple_format_gc);
+ luaL_setcdatagc(L, -2);
+ return 1;
+}
+
+static int
+lbox_tuple_format_new(struct lua_State *L)
+{
+ assert(CTID_STRUCT_TUPLE_FORMAT_PTR != 0);
+ if (lua_gettop(L) == 0)
+ return lbox_push_tuple_format(L, tuple_format_runtime);
+ if (lua_gettop(L) > 1 || ! lua_istable(L, 1))
+ return luaL_error(L, "Usage: box.internal.format_new(format)");
+ uint32_t count = lua_objlen(L, 1);
+ if (count == 0)
+ return lbox_push_tuple_format(L, tuple_format_runtime);
+ size_t size = count * sizeof(struct field_def);
+ struct region *region = &fiber()->gc;
+ size_t region_svp = region_used(region);
+ struct field_def *fields =
+ (struct field_def *)region_alloc(region, size);
+ if (fields == NULL) {
+ diag_set(OutOfMemory, size, "region_alloc", "fields");
+ return luaT_error(L);
+ }
+ for (uint32_t i = 0; i < count; ++i) {
+ size_t len;
+
+ fields[i] = field_def_default;
+
+ lua_pushinteger(L, i + 1);
+ lua_gettable(L, 1);
+
+ lua_pushstring(L, "type");
+ lua_gettable(L, -2);
+ if (! lua_isnil(L, -1)) {
+ const char *type_name = lua_tolstring(L, -1, &len);
+ fields[i].type = field_type_by_name(type_name, len);
+ if (fields[i].type == field_type_MAX) {
+ const char *err =
+ "field %d has unknown field type";
+ return luaL_error(L, tt_sprintf(err, i + 1));
+ }
+ }
+ lua_pop(L, 1);
+
+ lua_pushstring(L, "name");
+ lua_gettable(L, -2);
+ if (lua_isnil(L, -1)) {
+ return luaL_error(L, tt_sprintf("field %d name is not "
+ "specified", i + 1));
+ }
+ const char *name = lua_tolstring(L, -1, &len);
+ fields[i].name = (char *)region_alloc(region, len + 1);
+ if (fields == NULL) {
+ diag_set(OutOfMemory, size, "region_alloc",
+ "fields[i].name");
+ return luaT_error(L);
+ }
+ memcpy(fields[i].name, name, len);
+ fields[i].name[len] = '\0';
+ lua_pop(L, 1);
+ lua_pop(L, 1);
+ }
+ struct tuple_dictionary *dict = tuple_dictionary_new(fields, count);
+ region_truncate(region, region_svp);
+ if (dict == NULL)
+ return luaT_error(L);
+ struct tuple_format *format =
+ tuple_format_new(&tuple_format_runtime->vtab, NULL, NULL, 0,
+ NULL, 0, 0, dict, false, false);
+ if (format == NULL)
+ return luaT_error(L);
+ return lbox_push_tuple_format(L, format);
+}
+
+/* }}} */
+
void
box_lua_misc_init(struct lua_State *L)
{
static const struct luaL_Reg boxlib_internal[] = {
{"select", lbox_select},
+ {"new_tuple_format", lbox_tuple_format_new},
{NULL, NULL}
};
luaL_register(L, "box.internal", boxlib_internal);
lua_pop(L, 1);
+
+ int rc = luaL_cdef(L, "struct tuple_format;");
+ assert(rc == 0);
+ (void) rc;
+ CTID_STRUCT_TUPLE_FORMAT_PTR = luaL_ctypeid(L, "struct tuple_format *");
+ assert(CTID_STRUCT_TUPLE_FORMAT_PTR != 0);
}
diff --git a/src/box/lua/misc.h b/src/box/lua/misc.h
index dfedfe3..1c6f1f6 100644
--- a/src/box/lua/misc.h
+++ b/src/box/lua/misc.h
@@ -45,6 +45,9 @@ lbox_encode_tuple_on_gc(struct lua_State *L, int idx, size_t *p_len);
void
box_lua_misc_init(struct lua_State *L);
+struct tuple_format *
+lbox_check_tuple_format(struct lua_State *L, int narg);
+
#if defined(__cplusplus)
} /* extern "C" */
#endif /* defined(__cplusplus) */
diff --git a/test/box/misc.result b/test/box/misc.result
index 43b5a4a..5c42e33 100644
--- a/test/box/misc.result
+++ b/test/box/misc.result
@@ -1271,3 +1271,91 @@ box.cfg{too_long_threshold = too_long_threshold}
s:drop()
---
...
+--
+-- gh-2978: Function to parse space format.
+--
+-- Error: no field name:
+format = {}
+---
+...
+format[1] = {}
+---
+...
+format[1].type = 'unsigned'
+---
+...
+box.internal.new_tuple_format(format)
+---
+- error: field 1 name is not specified
+...
+-- Error: duplicate field name:
+format[1].name = 'aaa'
+---
+...
+format[2] = {}
+---
+...
+format[2].name = 'aaa'
+---
+...
+format[2].type = 'any'
+---
+...
+box.internal.new_tuple_format(format)
+---
+- error: Space field 'aaa' is duplicate
+...
+-- Error: wrong field type:
+format[2].name = 'bbb'
+---
+...
+format[3] = {}
+---
+...
+format[3].name = 'ccc'
+---
+...
+format[3].type = 'something'
+---
+...
+box.internal.new_tuple_format(format)
+---
+- error: field 3 has unknown field type
+...
+-- Error: too many arguments:
+box.internal.new_tuple_format(format, format)
+---
+- error: 'Usage: box.internal.format_new(format)'
+...
+-- Error: wrong argument:
+box.internal.new_tuple_format(1)
+---
+- error: 'Usage: box.internal.format_new(format)'
+...
+--
+-- In next tests we should receive cdata("struct tuple_format *").
+-- We do not have a way to check cdata in Lua, but there should be
+-- no errors.
+--
+-- Without argument it is equivalent to new_tuple_format({})
+tuple_format = box.internal.new_tuple_format()
+---
+...
+-- If no type that type == "any":
+format[3].type = nil
+---
+...
+tuple_format = box.internal.new_tuple_format(format)
+---
+...
+-- Function space:format() without arguments returns valid format:
+tuple_format = box.internal.new_tuple_format(box.space._space:format())
+---
+...
+-- Check is_nullable option fo field
+format[2].is_nullable = true
+---
+...
+tuple_format = box.internal.new_tuple_format(format)
+---
+...
diff --git a/test/box/misc.test.lua b/test/box/misc.test.lua
index 75d937e..94a6450 100644
--- a/test/box/misc.test.lua
+++ b/test/box/misc.test.lua
@@ -353,3 +353,53 @@ lsn == expected_lsn
box.cfg{too_long_threshold = too_long_threshold}
s:drop()
+
+--
+-- gh-2978: Function to parse space format.
+--
+
+-- Error: no field name:
+format = {}
+format[1] = {}
+format[1].type = 'unsigned'
+box.internal.new_tuple_format(format)
+
+-- Error: duplicate field name:
+format[1].name = 'aaa'
+format[2] = {}
+format[2].name = 'aaa'
+format[2].type = 'any'
+box.internal.new_tuple_format(format)
+
+-- Error: wrong field type:
+format[2].name = 'bbb'
+format[3] = {}
+format[3].name = 'ccc'
+format[3].type = 'something'
+box.internal.new_tuple_format(format)
+
+-- Error: too many arguments:
+box.internal.new_tuple_format(format, format)
+
+-- Error: wrong argument:
+box.internal.new_tuple_format(1)
+
+--
+-- In next tests we should receive cdata("struct tuple_format *").
+-- We do not have a way to check cdata in Lua, but there should be
+-- no errors.
+--
+
+-- Without argument it is equivalent to new_tuple_format({})
+tuple_format = box.internal.new_tuple_format()
+
+-- If no type that type == "any":
+format[3].type = nil
+tuple_format = box.internal.new_tuple_format(format)
+
+-- Function space:format() without arguments returns valid format:
+tuple_format = box.internal.new_tuple_format(box.space._space:format())
+
+-- Check is_nullable option fo field
+format[2].is_nullable = true
+tuple_format = box.internal.new_tuple_format(format)
--
2.7.4
More information about the Tarantool-patches
mailing list