From: Vladislav Shpilevoy via Tarantool-patches <tarantool-patches@dev.tarantool.org> To: imeevma@tarantool.org Cc: tarantool-patches@dev.tarantool.org Subject: Re: [Tarantool-patches] [PATCH 1/1] sql: introduce UUID field type Date: Sat, 22 May 2021 18:04:15 +0200 [thread overview] Message-ID: <2cf25c21-9522-446d-3cf9-d36e0523d24b@tarantool.org> (raw) In-Reply-To: <9d53f29d460d7a4194cb3f95de4b5a4016453db3.1621503852.git.imeevma@gmail.com> Hi! Thanks for the patch! See 15 comments below. > sql: introduce UUID field type > > This patch introduces UUID to SQL. UUID is now available as a new field > type. > > Closes #5886 > > @TarantoolBot document > Title: Field type UUID is now available in SQL > > The UUID field type is now available in SQL. This means that we can > create spaces and indexes with UUID, use it in SELECT, UPDATE and > DELETE. UUID can be accepted and returned by built-in functions and > user-defined functions. > > During comparison, UUID cannot be implicitly converted to any other > types, but in any other case, UUID can be implicitly converted to STRING > or VARBINARY. 1. I couldn't parse this - can it be implicitly converted to STRING/VARBINARY or not? What is this "any other case"? In the RFC I see that UUID should be ok to be implicitly converted to STRING and VARBINARY. > UUID can be explicitly converted to STRING or VARBINARY > using CAST(). STRING and VARBINARY can be implicitly converted to UUID, > except for comparison. STRING and VARBINARY can be explicitly converted > to UUID using CAST(). > > diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c > index 47845599e..9288ef341 100644 > --- a/src/box/sql/mem.c > +++ b/src/box/sql/mem.c > @@ -58,10 +58,22 @@ enum { > BUF_SIZE = 32, > }; > > +bool > +mem_is_field_compatible(const struct Mem *mem, enum field_type type, > + bool is_nullable) 2. Nullable flag is passed as true in the only usage place of this function. I propose to inline it here to true and drop the argument. > +{ > + if (mem->type == MEM_TYPE_UUID) > + return (field_ext_type[type] & (1U << MP_UUID)) != 0; > + enum mp_type mp_type = mem_mp_type(mem); > + assert(mp_type != MP_EXT); > + return field_mp_plain_type_is_compatible(type, mp_type, is_nullable); > +} > @@ -81,6 +93,9 @@ mem_str(const struct Mem *mem) > case MEM_TYPE_MAP: > case MEM_TYPE_ARRAY: > return mp_str(mem->z); > + case MEM_TYPE_UUID: > + tt_uuid_to_string(&mem->u.uuid, &buf[0]); > + return tt_sprintf("%s", buf); 3. You don't need to change buf size. Use tt_uuid_str(). > case MEM_TYPE_BOOL: > return mem->u.b ? "TRUE" : "FALSE"; > default: > @@ -190,6 +205,16 @@ mem_set_double(struct Mem *mem, double value) > mem->type = MEM_TYPE_DOUBLE; > } > > +void > +mem_set_uuid(struct Mem *mem, struct tt_uuid *uuid) 4. You can make uuid argument const. > +{ > + mem_clear(mem); > + mem->field_type = FIELD_TYPE_UUID; > + mem->u.uuid = *uuid; > + mem->type = MEM_TYPE_UUID; > + mem->flags = 0; 5. Flags should be already 0 after clear(). > +} > + > static inline void > set_str_const(struct Mem *mem, char *value, uint32_t len, int alloc_type) > { > @@ -585,6 +610,18 @@ str_to_bin(struct Mem *mem) > return 0; > } > > +static inline int > +str_to_uuid(struct Mem *mem) > +{ > + assert(mem->type == MEM_TYPE_STR); > + if (tt_uuid_from_string(tt_cstr(mem->z, mem->n), &mem->u.uuid) != 0) > + return -1; 6. This is going to crash if mem->n is more than the static buffer size. I would suggest to introduce some way to extract UUID from a non-terminated string, and add a test maybe. The same in mem_get_uuid(). Which is not used anywhere btw. Perhaps you can drop it. > @@ -639,6 +676,20 @@ bin_to_str0(struct Mem *mem) > return 0; > } > > +static inline int > +bin_to_uuid(struct Mem *mem) > +{ > + assert(mem->type == MEM_TYPE_BIN); > + if (mem->n != UUID_LEN || > + tt_uuid_validate((struct tt_uuid *)mem->z) != 0) 7. What if this is MEM_Zero and z is not allocated yet? > + return -1; > + mem->u.uuid = *(struct tt_uuid *)mem->z; > + mem->type = MEM_TYPE_UUID; > + mem->flags = 0; > + mem->field_type = FIELD_TYPE_UUID; > + return 0; > +} > @@ -2566,11 +2710,24 @@ sqlVdbeCompareMsgpack(const char **key1, > case MP_ARRAY: > case MP_MAP: > case MP_EXT:{ > - mem1.z = (char *)aKey1; > - mp_next(&aKey1); > - mem1.n = aKey1 - (char *)mem1.z; > - goto do_blob; > + int8_t type; > + const char *buf = aKey1; > + uint32_t len = mp_decode_extl(&buf, &type); 8. This is going to crash when type is MP_ARRAY or MP_MAP. Is it possible to add a test? > + buf = aKey1; > + mp_next(&aKey1); 9. You can skip faster, using buf + len which you already decoded. The same in mem_from_mp_ephemeral(). > @@ -2849,6 +3023,11 @@ port_vdbemem_dump_lua(struct port *base, struct lua_State *L, bool is_flat) > case MEM_TYPE_BOOL: > lua_pushboolean(L, mem->u.b); > break; > + case MEM_TYPE_UUID: { > + struct tt_uuid *uuid = luaL_pushuuid(L); > + *uuid = mem->u.uuid; 10. You could do *luaL_pushuuid(L) = mem->u.uuid right away, without the temporary variable. Up to you. > @@ -3073,7 +3249,18 @@ port_c_get_vdbemem(struct port *base, uint32_t *size) > break; > case MP_EXT: > str = data; > - mp_next(&data); > + int8_t type; > + len = mp_decode_extl(&data, &type); > + if (type == MP_UUID) { > + assert(len == UUID_LEN); > + struct tt_uuid *uuid = &val[i].u.uuid; > + data = str; > + if (mp_decode_uuid(&data, uuid) == NULL) > + goto error; > + val[i].type = MEM_TYPE_UUID; > + break; > + } > + data += len; > if (mem_copy_bin(&val[i], str, data - str) != 0) > goto error; > break; 11. You need to patch memTracePrint() as well. > diff --git a/test/sql-tap/sql_uuid.c b/test/sql-tap/sql_uuid.c > new file mode 100644 > index 000000000..592b9e48f > --- /dev/null > +++ b/test/sql-tap/sql_uuid.c 12. It is already in sql* folder, no need to prefix the file name with 'sql_'. > @@ -0,0 +1,57 @@ > +#include "msgpuck.h" > +#include "module.h" > +#include "uuid/mp_uuid.h" > +#include "mp_extension_types.h" > + > +enum { > + BUF_SIZE = 512, > +}; > + > +int > +is_uuid(box_function_ctx_t *ctx, const char *args, const char *args_end) > +{ > + uint32_t arg_count = mp_decode_array(&args); > + if (arg_count != 1) { > + return box_error_set(__FILE__, __LINE__, ER_PROC_C, > + "invalid argument count"); > + } > + bool is_uuid; > + if (mp_typeof(*args) == MP_EXT) { > + const char *str = args; > + int8_t type; > + mp_decode_extl(&str, &type); > + is_uuid = type == MP_UUID; > + } else { > + is_uuid = false; > + } > + > + char tuple_buf[BUF_SIZE]; > + assert(mp_sizeof_array(1) + mp_sizeof_bool(is_uuid) < BUF_SIZE); > + char *d = tuple_buf; > + d = mp_encode_array(d, 1); > + d = mp_encode_bool(d, is_uuid); > + > + box_tuple_format_t *fmt = box_tuple_format_default(); > + box_tuple_t *tuple = box_tuple_new(fmt, tuple_buf, d); > + if (tuple == NULL) > + return -1; > + return box_return_tuple(ctx, tuple); 13. Use box_return_mp() instead of all that. The same below. > +} > + > +int > +ret_uuid(box_function_ctx_t *ctx, const char *args, const char *args_end) > +{ > + struct tt_uuid uuid; > + memset(&uuid, 0x11, sizeof(uuid)); > + char tuple_buf[BUF_SIZE]; > + assert(mp_sizeof_array(1) + mp_sizeof_uuid() < BUF_SIZE); > + char *d = tuple_buf; > + d = mp_encode_array(d, 1); > + d = mp_encode_uuid(d, &uuid); > + > + box_tuple_format_t *fmt = box_tuple_format_default(); > + box_tuple_t *tuple = box_tuple_new(fmt, tuple_buf, d); > + if (tuple == NULL) > + return -1; > + return box_return_tuple(ctx, tuple); > +} > diff --git a/test/sql-tap/uuid.test.lua b/test/sql-tap/uuid.test.lua > new file mode 100755 > index 000000000..9210d05db > --- /dev/null > +++ b/test/sql-tap/uuid.test.lua > @@ -0,0 +1,1259 @@ <...> > + > +-- Check that CHECK constraint can work with UUID. > +test:do_catchsql_test( > + "uuid-5.2.1", > + [[ > + INSERT INTO t5c SELECT 1, u FROM t2 LIMIT 1; > + SELECT * from t5c; 14. This SELECT is unreachable. The same in 5.3.2, 8.1.3, 8.1.4, 8.1.5, 8.1.6, 8.2.1, 8.2.3, 8.2.4, 8.2.5, 8.2.6, 8.2.8. > + ]], { > + 1, "Check constraint failed 'CK': CAST(f AS STRING) != '11111111-1111-1111-1111-111111111111'" > + }) 15. It might worth dropping the created spaces in order to clear the test artifacts.
next prev parent reply other threads:[~2021-05-22 16:04 UTC|newest] Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-05-20 9:44 Mergen Imeev via Tarantool-patches 2021-05-21 7:16 ` Mergen Imeev via Tarantool-patches 2021-05-22 16:04 ` Vladislav Shpilevoy via Tarantool-patches [this message] 2021-05-25 14:13 ` Mergen Imeev via Tarantool-patches 2021-05-25 21:50 ` Vladislav Shpilevoy via Tarantool-patches 2021-05-27 16:40 ` Mergen Imeev via Tarantool-patches 2021-05-25 22:58 ` Timur Safin via Tarantool-patches 2021-05-27 15:33 ` Mergen Imeev via Tarantool-patches
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=2cf25c21-9522-446d-3cf9-d36e0523d24b@tarantool.org \ --to=tarantool-patches@dev.tarantool.org \ --cc=imeevma@tarantool.org \ --cc=v.shpilevoy@tarantool.org \ --subject='Re: [Tarantool-patches] [PATCH 1/1] sql: introduce UUID field type' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox