Skip to content

Commit

Permalink
lua/key_def: add key validation and comparison functions
Browse files Browse the repository at this point in the history
Closes #9863

@TarantoolBot document
Title: Document key validation and comparison `key_def` module functions

The following new functions were introduced to the `key_def` Lua module:

 - `key_def:validate_key(key)`: validates a key against a key definition
   object. Raises an exception if the key doesn't match. Returns nothing
   on success. See also `box_key_def_validate_key` C API function.

 - `key_def:validate_full_key(key)`: validates a full key against a key
   definition object. Raises an exception if the key doesn't match.
   Returns nothing on success. See also `box_key_def_validate_full_key`
   C API function.

 - `key_def:validate_tuple(tuple)`: validates a tuple against a key
   definition object. Raises an exception if the tuple doesn't match.
   Returns nothing on success. See also `box_key_def_validate_tuple`
   C API function.

 - `key_def:compare_keys(key_a, key_b)`: compares two keys according to
   a key definition object. Raises an exception if any of the given key
   doesn't match the key definition. On success, returns a value <0 if
   `key_a` parts are less than `key_b` parts, 0 if equal, >0 if greater.
  • Loading branch information
locker committed Mar 27, 2024
1 parent f0b3a7b commit 7e5881e
Show file tree
Hide file tree
Showing 7 changed files with 719 additions and 4 deletions.
4 changes: 4 additions & 0 deletions changelogs/unreleased/gh-9863-new-key-def-functions.md
@@ -0,0 +1,4 @@
## feature/lua

* Added key validation and comparison functions to the `key_def` module
(gh-9863).
138 changes: 138 additions & 0 deletions src/box/lua/key_def.c
Expand Up @@ -344,6 +344,58 @@ luaT_key_def_extract_key(struct lua_State *L, int idx)
return 1;
}

int
luaT_key_def_validate_key(struct lua_State *L, int idx)
{
struct key_def *key_def = luaT_is_key_def(L, idx);
assert(key_def != NULL);

struct region *region = &fiber()->gc;
size_t region_svp = region_used(region);
const char *key = luaT_tuple_encode(L, -1, NULL);
if (key == NULL ||
box_key_def_validate_key(key_def, key, NULL) != 0) {
region_truncate(region, region_svp);
return luaT_error(L);
}
region_truncate(region, region_svp);
return 0;
}

int
luaT_key_def_validate_full_key(struct lua_State *L, int idx)
{
struct key_def *key_def = luaT_is_key_def(L, idx);
assert(key_def != NULL);

struct region *region = &fiber()->gc;
size_t region_svp = region_used(region);
const char *key = luaT_tuple_encode(L, -1, NULL);
if (key == NULL ||
box_key_def_validate_full_key(key_def, key, NULL) != 0) {
region_truncate(region, region_svp);
return luaT_error(L);
}
region_truncate(region, region_svp);
return 0;
}

int
luaT_key_def_validate_tuple(struct lua_State *L, int idx)
{
struct key_def *key_def = luaT_is_key_def(L, idx);
assert(key_def != NULL);

struct tuple *tuple = luaT_key_def_check_tuple(L, key_def, -1);
if (tuple == NULL)
return luaT_error(L);
int rc = box_key_def_validate_tuple(key_def, tuple);
tuple_unref(tuple);
if (rc != 0)
return luaT_error(L);
return 0;
}

int
luaT_key_def_compare(struct lua_State *L, int idx)
{
Expand Down Expand Up @@ -412,6 +464,38 @@ luaT_key_def_compare_with_key(struct lua_State *L, int idx)
return 1;
}

int
luaT_key_def_compare_keys(struct lua_State *L, int idx)
{
struct key_def *key_def = luaT_is_key_def(L, idx);
assert(key_def != NULL);

struct region *region = &fiber()->gc;
size_t region_svp = region_used(region);

const char *key_a = luaT_tuple_encode(L, -2, NULL);
if (key_a == NULL ||
box_key_def_validate_key(key_def, key_a, NULL) != 0) {
region_truncate(region, region_svp);
return luaT_error(L);
}
uint32_t part_count_a = mp_decode_array(&key_a);

const char *key_b = luaT_tuple_encode(L, -1, NULL);
if (key_b == NULL ||
box_key_def_validate_key(key_def, key_b, NULL) != 0) {
region_truncate(region, region_svp);
return luaT_error(L);
}
uint32_t part_count_b = mp_decode_array(&key_b);

int rc = key_compare(key_a, part_count_a, HINT_NONE,
key_b, part_count_b, HINT_NONE, key_def);
region_truncate(region, region_svp);
lua_pushinteger(L, rc);
return 1;
}

int
luaT_key_def_merge(struct lua_State *L, int idx_a, int idx_b)
{
Expand Down Expand Up @@ -443,6 +527,42 @@ lbox_key_def_extract_key(struct lua_State *L)
return luaT_key_def_extract_key(L, 1);
}

/**
* key_def:validate_key(key)
* Stack: [1] key_def; [2] key.
*/
static int
lbox_key_def_validate_key(struct lua_State *L)
{
if (lua_gettop(L) != 2 || luaT_is_key_def(L, 1) == NULL)
return luaL_error(L, "Usage: key_def:validate_key(key)");
return luaT_key_def_validate_key(L, 1);
}

/**
* key_def:validate_full_key(key)
* Stack: [1] key_def; [2] key.
*/
static int
lbox_key_def_validate_full_key(struct lua_State *L)
{
if (lua_gettop(L) != 2 || luaT_is_key_def(L, 1) == NULL)
return luaL_error(L, "Usage: key_def:validate_full_key(key)");
return luaT_key_def_validate_full_key(L, 1);
}

/**
* key_def:validate_tuple(key)
* Stack: [1] key_def; [2] tuple.
*/
static int
lbox_key_def_validate_tuple(struct lua_State *L)
{
if (lua_gettop(L) != 2 || luaT_is_key_def(L, 1) == NULL)
return luaL_error(L, "Usage: key_def:validate_tuple(tuple)");
return luaT_key_def_validate_tuple(L, 1);
}

/**
* key_def:compare(tuple_a, tuple_b)
* Stack: [1] key_def; [2] tuple_a; [3] tuple_b.
Expand Down Expand Up @@ -471,6 +591,20 @@ lbox_key_def_compare_with_key(struct lua_State *L)
return luaT_key_def_compare_with_key(L, 1);
}

/**
* key_def:compare_keys(key_a, key_b)
* Stack: [1] key_def; [2] key_a; [3] key_b.
*/
static int
lbox_key_def_compare_keys(struct lua_State *L)
{
if (lua_gettop(L) != 3 || luaT_is_key_def(L, 1) == NULL) {
return luaL_error(L, "Usage: key_def:compare_keys("
"key_a, key_b)");
}
return luaT_key_def_compare_keys(L, 1);
}

/**
* key_def:merge(second_key_def)
* Stack: [1] key_def; [2] second_key_def.
Expand Down Expand Up @@ -562,8 +696,12 @@ luaopen_key_def(struct lua_State *L)
static const struct luaL_Reg meta[] = {
{"new", lbox_key_def_new},
{"extract_key", lbox_key_def_extract_key},
{"validate_key", lbox_key_def_validate_key},
{"validate_full_key", lbox_key_def_validate_full_key},
{"validate_tuple", lbox_key_def_validate_tuple},
{"compare", lbox_key_def_compare},
{"compare_with_key", lbox_key_def_compare_with_key},
{"compare_keys", lbox_key_def_compare_keys},
{"merge", lbox_key_def_merge},
{"totable", lbox_key_def_to_table},
{NULL, NULL}
Expand Down
30 changes: 30 additions & 0 deletions src/box/lua/key_def.h
Expand Up @@ -72,6 +72,27 @@ luaT_is_key_def(struct lua_State *L, int idx);
int
luaT_key_def_extract_key(struct lua_State *L, int idx);

/**
* Check that key matches given key definition.
* Raise error if not.
*/
int
luaT_key_def_validate_key(struct lua_State *L, int idx);

/**
* Check that full key matches given key definition.
* Raise error if not.
*/
int
luaT_key_def_validate_full_key(struct lua_State *L, int idx);

/**
* Check that tuple matches given key definition.
* Raise error if not.
*/
int
luaT_key_def_validate_tuple(struct lua_State *L, int idx);

/**
* Compare tuples using the key definition.
* Push 0 if key_fields(tuple_a) == key_fields(tuple_b)
Expand All @@ -94,6 +115,15 @@ luaT_key_def_compare(struct lua_State *L, int idx);
int
luaT_key_def_compare_with_key(struct lua_State *L, int idx);

/**
* Compare keys using the key definition.
* Push 0 if parts(key_a) == parts(key_b)
* <0 if parts(key_a) < parts(key_b)
* >0 if parts(key_a) > parts(key_b)
*/
int
luaT_key_def_compare_keys(struct lua_State *L, int idx);

/**
* Construct and export to LUA a new key definition with a set
* union of key parts from first and second key defs. Parts of
Expand Down
4 changes: 4 additions & 0 deletions src/box/lua/key_def.lua
Expand Up @@ -4,8 +4,12 @@ local key_def_t = ffi.typeof('struct key_def')

local methods = {
['extract_key'] = key_def.extract_key,
['validate_key'] = key_def.validate_key,
['validate_full_key'] = key_def.validate_full_key,
['validate_tuple'] = key_def.validate_tuple,
['compare'] = key_def.compare,
['compare_with_key'] = key_def.compare_with_key,
['compare_keys'] = key_def.compare_keys,
['merge'] = key_def.merge,
['totable'] = key_def.totable,
['__serialize'] = key_def.totable,
Expand Down
82 changes: 78 additions & 4 deletions src/box/lua/space.cc
Expand Up @@ -239,6 +239,47 @@ lbox_index_parts_extract_key(struct lua_State *L)
return luaT_key_def_extract_key(L, lua_upvalueindex(1));
}

/**
* index.parts:validate_key(key)
* Stack: [1] unused; [2] key.
* key_def is passed in the upvalue.
*/
static int
lbox_index_parts_validate_key(struct lua_State *L)
{
if (lua_gettop(L) != 2)
return luaL_error(L, "Usage: index.parts:validate_key(key)");
return luaT_key_def_validate_key(L, lua_upvalueindex(1));
}

/**
* index.parts:validate_full_key(key)
* Stack: [1] unused; [2] key.
* key_def is passed in the upvalue.
*/
static int
lbox_index_parts_validate_full_key(struct lua_State *L)
{
if (lua_gettop(L) != 2)
return luaL_error(L, "Usage: index.parts:validate_full_key("
"key)");
return luaT_key_def_validate_full_key(L, lua_upvalueindex(1));
}

/**
* index.parts:validate_tuple(key)
* Stack: [1] unused; [2] tuple.
* key_def is passed in the upvalue.
*/
static int
lbox_index_parts_validate_tuple(struct lua_State *L)
{
if (lua_gettop(L) != 2)
return luaL_error(L, "Usage: index.parts:validate_tuple("
"tuple)");
return luaT_key_def_validate_tuple(L, lua_upvalueindex(1));
}

/**
* index.parts:compare(tuple_a, tuple_b)
* Stack: [1] unused; [2] tuple_a; [3] tuple_b.
Expand Down Expand Up @@ -269,6 +310,21 @@ lbox_index_parts_compare_with_key(struct lua_State *L)
return luaT_key_def_compare_with_key(L, lua_upvalueindex(1));
}

/**
* index.parts:compare_keys(key_a, key_b)
* Stack: [1] unused; [2] key_a; [3] key_b.
* key_def is passed in the upvalue.
*/
static int
lbox_index_parts_compare_keys(struct lua_State *L)
{
if (lua_gettop(L) != 3) {
return luaL_error(L, "Usage: index.parts:compare_keys("
"key_a, key_b)");
}
return luaT_key_def_compare_keys(L, lua_upvalueindex(1));
}

/**
* index.parts:merge(second_index_parts)
* Stack: [1] unused; [2] second_index_parts.
Expand Down Expand Up @@ -321,24 +377,42 @@ luaT_add_index_parts_methods(struct lua_State *L, const struct key_def *key_def)
lua_newtable(L);
int idx_index = lua_gettop(L);

/* Push 4 references to cdata onto the stack, one for each closure. */
luaT_push_key_def(L, key_def);
lua_pushvalue(L, -1);
lua_pushvalue(L, -1);
lua_pushvalue(L, -1);
int idx_key_def = lua_gettop(L);

lua_pushvalue(L, idx_key_def);
lua_pushcclosure(L, &lbox_index_parts_extract_key, 1);
lua_setfield(L, idx_index, "extract_key");

lua_pushvalue(L, idx_key_def);
lua_pushcclosure(L, &lbox_index_parts_validate_key, 1);
lua_setfield(L, idx_index, "validate_key");

lua_pushvalue(L, idx_key_def);
lua_pushcclosure(L, &lbox_index_parts_validate_full_key, 1);
lua_setfield(L, idx_index, "validate_full_key");

lua_pushvalue(L, idx_key_def);
lua_pushcclosure(L, &lbox_index_parts_validate_tuple, 1);
lua_setfield(L, idx_index, "validate_tuple");

lua_pushvalue(L, idx_key_def);
lua_pushcclosure(L, &lbox_index_parts_compare, 1);
lua_setfield(L, idx_index, "compare");

lua_pushvalue(L, idx_key_def);
lua_pushcclosure(L, &lbox_index_parts_compare_with_key, 1);
lua_setfield(L, idx_index, "compare_with_key");

lua_pushvalue(L, idx_key_def);
lua_pushcclosure(L, &lbox_index_parts_compare_keys, 1);
lua_setfield(L, idx_index, "compare_keys");

lua_pushvalue(L, idx_key_def);
lua_pushcclosure(L, &lbox_index_parts_merge, 1);
lua_setfield(L, idx_index, "merge");

lua_pop(L, 1); /* key_def */
lua_setfield(L, -2, "__index");
lua_setmetatable(L, -2);
}
Expand Down

0 comments on commit 7e5881e

Please sign in to comment.