From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: From: Kirill Shcherbatov Subject: [PATCH v1 1/1] box: introduce VARBINARY field type Date: Wed, 26 Jun 2019 19:40:59 +0300 Message-Id: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit To: tarantool-patches@freelists.org, vdavydov.dev@gmail.com Cc: Kirill Shcherbatov List-ID: Introduced a new field type VARBINARY to represent mp_bin values. This field type would be useful for SQL type system. Closes #4201 Needed for #4206 --- http://github.com/tarantool/tarantool/tree/kshch/gh-4201-varbinary-type https://github.com/tarantool/tarantool/issues/4201 src/box/field_def.c | 23 +++-- src/box/field_def.h | 1 + src/box/lua/key_def.c | 1 + src/box/tuple_compare.cc | 17 ++++ test/box/varbinary_type.result | 152 +++++++++++++++++++++++++++++++ test/box/varbinary_type.test.lua | 51 +++++++++++ 6 files changed, 235 insertions(+), 10 deletions(-) create mode 100644 test/box/varbinary_type.result create mode 100644 test/box/varbinary_type.test.lua diff --git a/src/box/field_def.c b/src/box/field_def.c index 0ba3d3294..346042b98 100644 --- a/src/box/field_def.c +++ b/src/box/field_def.c @@ -55,6 +55,7 @@ const uint32_t field_mp_type[] = { (1U << MP_FLOAT) | (1U << MP_DOUBLE), /* [FIELD_TYPE_INTEGER] = */ (1U << MP_UINT) | (1U << MP_INT), /* [FIELD_TYPE_BOOLEAN] = */ 1U << MP_BOOL, + /* [FIELD_TYPE_VARBINARY] = */ 1U << MP_BIN, /* [FIELD_TYPE_SCALAR] = */ (1U << MP_UINT) | (1U << MP_INT) | (1U << MP_FLOAT) | (1U << MP_DOUBLE) | (1U << MP_STR) | (1U << MP_BIN) | (1U << MP_BOOL), @@ -69,6 +70,7 @@ const char *field_type_strs[] = { /* [FIELD_TYPE_NUMBER] = */ "number", /* [FIELD_TYPE_INTEGER] = */ "integer", /* [FIELD_TYPE_BOOLEAN] = */ "boolean", + /* [FIELD_TYPE_VARBINARY] = */"varbinary", /* [FIELD_TYPE_SCALAR] = */ "scalar", /* [FIELD_TYPE_ARRAY] = */ "array", /* [FIELD_TYPE_MAP] = */ "map", @@ -96,16 +98,17 @@ field_type_by_name_wrapper(const char *str, uint32_t len) * values can be stored in the j type. */ static const bool field_type_compatibility[] = { - /* ANY UNSIGNED STRING NUMBER INTEGER BOOLEAN SCALAR ARRAY MAP */ -/* ANY */ true, false, false, false, false, false, false, false, false, -/* UNSIGNED */ true, true, false, true, true, false, true, false, false, -/* STRING */ true, false, true, false, false, false, true, false, false, -/* NUMBER */ true, false, false, true, false, false, true, false, false, -/* INTEGER */ true, false, false, true, true, false, true, false, false, -/* BOOLEAN */ true, false, false, false, false, true, true, false, false, -/* SCALAR */ true, false, false, false, false, false, true, false, false, -/* ARRAY */ true, false, false, false, false, false, false, true, false, -/* MAP */ true, false, false, false, false, false, false, false, true, + /* ANY UNSIGNED STRING NUMBER INTEGER BOOLEAN VARBINARY SCALAR ARRAY MAP */ +/* ANY */ true, false, false, false, false, false, false, false, false, false, +/* UNSIGNED */ true, true, false, true, true, false, false, true, false, false, +/* STRING */ true, false, true, false, false, false, false, true, false, false, +/* NUMBER */ true, false, false, true, false, false, false, true, false, false, +/* INTEGER */ true, false, false, true, true, false, false, true, false, false, +/* BOOLEAN */ true, false, false, false, false, true, false, true, false, false, +/* VARBINARY*/ true, false, false, false, false, false, true, true, false, false, +/* SCALAR */ true, false, false, false, false, false, false, true, false, false, +/* ARRAY */ true, false, false, false, false, false, false, false, true, false, +/* MAP */ true, false, false, false, false, false, false, false, false, true, }; bool diff --git a/src/box/field_def.h b/src/box/field_def.h index f944de9d6..c1a7ec0a9 100644 --- a/src/box/field_def.h +++ b/src/box/field_def.h @@ -56,6 +56,7 @@ enum field_type { FIELD_TYPE_NUMBER, FIELD_TYPE_INTEGER, FIELD_TYPE_BOOLEAN, + FIELD_TYPE_VARBINARY, FIELD_TYPE_SCALAR, FIELD_TYPE_ARRAY, FIELD_TYPE_MAP, diff --git a/src/box/lua/key_def.c b/src/box/lua/key_def.c index dfcc89442..052a1c85d 100644 --- a/src/box/lua/key_def.c +++ b/src/box/lua/key_def.c @@ -111,6 +111,7 @@ luaT_key_def_set_part(struct lua_State *L, struct key_part_def *part, part->type = field_type_by_name(type_name, type_len); switch (part->type) { case FIELD_TYPE_ANY: + case FIELD_TYPE_VARBINARY: case FIELD_TYPE_ARRAY: case FIELD_TYPE_MAP: /* Tuple comparators don't support these types. */ diff --git a/src/box/tuple_compare.cc b/src/box/tuple_compare.cc index c1a70a087..95a0f58c9 100644 --- a/src/box/tuple_compare.cc +++ b/src/box/tuple_compare.cc @@ -404,6 +404,8 @@ tuple_compare_field(const char *field_a, const char *field_b, return mp_compare_number(field_a, field_b); case FIELD_TYPE_BOOLEAN: return mp_compare_bool(field_a, field_b); + case FIELD_TYPE_VARBINARY: + return mp_compare_bin(field_a, field_b); case FIELD_TYPE_SCALAR: return coll != NULL ? mp_compare_scalar_coll(field_a, field_b, coll) : @@ -434,6 +436,8 @@ tuple_compare_field_with_type(const char *field_a, enum mp_type a_type, field_b, b_type); case FIELD_TYPE_BOOLEAN: return mp_compare_bool(field_a, field_b); + case FIELD_TYPE_VARBINARY: + return mp_compare_bin(field_a, field_b); case FIELD_TYPE_SCALAR: return coll != NULL ? mp_compare_scalar_coll(field_a, field_b, coll) : @@ -1502,6 +1506,14 @@ field_hint_string(const char *field, struct coll *coll) hint_str_coll(field, len, coll); } +static inline hint_t +field_hint_varbinary(const char *field) +{ + assert(mp_typeof(*field) == MP_BIN); + uint32_t len = mp_decode_binl(&field); + return hint_bin(field, len); +} + static inline hint_t field_hint_scalar(const char *field, struct coll *coll) { @@ -1547,6 +1559,8 @@ field_hint(const char *field, struct coll *coll) return field_hint_number(field); case FIELD_TYPE_STRING: return field_hint_string(field, coll); + case FIELD_TYPE_VARBINARY: + return field_hint_varbinary(field); case FIELD_TYPE_SCALAR: return field_hint_scalar(field, coll); default: @@ -1648,6 +1662,9 @@ key_def_set_hint_func(struct key_def *def) case FIELD_TYPE_STRING: key_def_set_hint_func(def); break; + case FIELD_TYPE_VARBINARY: + key_def_set_hint_func(def); + break; case FIELD_TYPE_SCALAR: key_def_set_hint_func(def); break; diff --git a/test/box/varbinary_type.result b/test/box/varbinary_type.result new file mode 100644 index 000000000..c7cd5700c --- /dev/null +++ b/test/box/varbinary_type.result @@ -0,0 +1,152 @@ +env = require('test_run') +--- +... +test_run = env.new() +--- +... +-- +-- gh-4201: Introduce varbinary field type. +-- +s = box.schema.space.create('withdata') +--- +... +s:format({{"b", "integer"}}) +--- +... +_ = s:create_index('pk', {parts = {1, "varbinary"}}) +--- +- error: Field 1 has type 'integer' in space format, but type 'varbinary' in index + definition +... +s:format({{"b", "varbinary"}}) +--- +... +_ = s:create_index('pk', {parts = {1, "integer"}}) +--- +- error: Field 1 has type 'varbinary' in space format, but type 'integer' in index + definition +... +pk = s:create_index('pk', {parts = {1, "varbinary"}}) +--- +... +buffer = require('buffer') +--- +... +ffi = require('ffi') +--- +... +test_run:cmd("setopt delimiter ';'") +--- +- true +... +function bintuple_insert(space, bytes) + local tmpbuf = buffer.IBUF_SHARED + tmpbuf:reset() + local p = tmpbuf:alloc(3 + #bytes) + p[0] = 0x91 + p[1] = 0xC4 + p[2] = #bytes + for i, c in pairs(bytes) do p[i + 3 - 1] = c end + ffi.cdef[[int box_insert(uint32_t space_id, const char *tuple, const char *tuple_end, box_tuple_t **result);]] + ffi.C.box_insert(space.id, tmpbuf.rpos, tmpbuf.wpos, nil) +end +test_run:cmd("setopt delimiter ''"); +--- +... +bintuple_insert(s, {0xDE, 0xAD, 0xBE, 0xAF}) +--- +... +bintuple_insert(s, {0xFE, 0xED, 0xFA, 0xCE}) +--- +... +s:select() +--- +- - [!!binary 3q2+rw==] + - [!!binary /u36zg==] +... +box.execute("SELECT * FROM \"withdata\" WHERE \"b\" < x'FEEDFACE';") +--- +- metadata: + - name: b + type: varbinary + rows: + - [!!binary 3q2+rw==] +... +pk:alter({parts = {1, "scalar"}}) +--- +... +s:format({{"b", "scalar"}}) +--- +... +s:insert({11}) +--- +- [11] +... +s:insert({22}) +--- +- [22] +... +s:insert({"11"}) +--- +- ['11'] +... +s:insert({"22"}) +--- +- ['22'] +... +s:select() +--- +- - [11] + - [22] + - ['11'] + - ['22'] + - [!!binary 3q2+rw==] + - [!!binary /u36zg==] +... +box.execute("SELECT * FROM \"withdata\" WHERE \"b\" <= x'DEADBEAF';") +--- +- metadata: + - name: b + type: scalar + rows: + - [11] + - [22] + - ['11'] + - ['22'] + - [!!binary 3q2+rw==] +... +pk:alter({parts = {1, "varbinary"}}) +--- +- error: 'Tuple field 1 type does not match one required by operation: expected varbinary' +... +s:delete({11}) +--- +- [11] +... +s:delete({22}) +--- +- [22] +... +s:delete({"11"}) +--- +- ['11'] +... +s:delete({"22"}) +--- +- ['22'] +... +bintuple_insert(s, {0xFA, 0xDE, 0xDE, 0xAD}) +--- +... +pk:alter({parts = {1, "varbinary"}}) +--- +... +s:select() +--- +- - [!!binary 3q2+rw==] + - [!!binary +t7erQ==] + - [!!binary /u36zg==] +... +s:drop() +--- +... diff --git a/test/box/varbinary_type.test.lua b/test/box/varbinary_type.test.lua new file mode 100644 index 000000000..7895a1d22 --- /dev/null +++ b/test/box/varbinary_type.test.lua @@ -0,0 +1,51 @@ +env = require('test_run') +test_run = env.new() + +-- +-- gh-4201: Introduce varbinary field type. +-- +s = box.schema.space.create('withdata') +s:format({{"b", "integer"}}) +_ = s:create_index('pk', {parts = {1, "varbinary"}}) +s:format({{"b", "varbinary"}}) +_ = s:create_index('pk', {parts = {1, "integer"}}) +pk = s:create_index('pk', {parts = {1, "varbinary"}}) + +buffer = require('buffer') +ffi = require('ffi') + +test_run:cmd("setopt delimiter ';'") +function bintuple_insert(space, bytes) + local tmpbuf = buffer.IBUF_SHARED + tmpbuf:reset() + local p = tmpbuf:alloc(3 + #bytes) + p[0] = 0x91 + p[1] = 0xC4 + p[2] = #bytes + for i, c in pairs(bytes) do p[i + 3 - 1] = c end + ffi.cdef[[int box_insert(uint32_t space_id, const char *tuple, const char *tuple_end, box_tuple_t **result);]] + ffi.C.box_insert(space.id, tmpbuf.rpos, tmpbuf.wpos, nil) +end +test_run:cmd("setopt delimiter ''"); + +bintuple_insert(s, {0xDE, 0xAD, 0xBE, 0xAF}) +bintuple_insert(s, {0xFE, 0xED, 0xFA, 0xCE}) +s:select() +box.execute("SELECT * FROM \"withdata\" WHERE \"b\" < x'FEEDFACE';") +pk:alter({parts = {1, "scalar"}}) +s:format({{"b", "scalar"}}) +s:insert({11}) +s:insert({22}) +s:insert({"11"}) +s:insert({"22"}) +s:select() +box.execute("SELECT * FROM \"withdata\" WHERE \"b\" <= x'DEADBEAF';") +pk:alter({parts = {1, "varbinary"}}) +s:delete({11}) +s:delete({22}) +s:delete({"11"}) +s:delete({"22"}) +bintuple_insert(s, {0xFA, 0xDE, 0xDE, 0xAD}) +pk:alter({parts = {1, "varbinary"}}) +s:select() +s:drop() -- 2.21.0