From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id 1FEC46C1AE; Fri, 21 May 2021 10:16:55 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 1FEC46C1AE DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1621581415; bh=w9DWdueMcRRX++RJVopvLXx8oNOUDm7BaxKO1x1LwMI=; h=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=TQtonm+KMluBdPXO6LSD7ijExoF4ooj03AAT6lP4Ad8IOa0EWch1NI6mnoCLpwoCv 0fjFZFeQFToTo7WL1k/VMRysDPJky5O2L/2bPjPLAY12YyX8hxL+BmdeloLNBfw47a 2qvsxKP8WjbIMq99gD1nA5yceNcW7b5A82zN+EhM= Received: from smtpng1.m.smailru.net (smtpng1.m.smailru.net [94.100.181.251]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id D0D8E6C1AE for ; Fri, 21 May 2021 10:16:51 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org D0D8E6C1AE Received: by smtpng1.m.smailru.net with esmtpa (envelope-from ) id 1ljzOs-0001NU-Po; Fri, 21 May 2021 10:16:51 +0300 Date: Fri, 21 May 2021 10:16:49 +0300 To: v.shpilevoy@tarantool.org, tarantool-patches@dev.tarantool.org Message-ID: <20210521071649.GA18987@tarantool.org> References: <9d53f29d460d7a4194cb3f95de4b5a4016453db3.1621503852.git.imeevma@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: <9d53f29d460d7a4194cb3f95de4b5a4016453db3.1621503852.git.imeevma@gmail.com> X-7564579A: 78E4E2B564C1792B X-77F55803: 4F1203BC0FB41BD91B019B01C53E51AFFAE5AC8370B8C7D84BE9C2CBFD04F41900894C459B0CD1B9CDA90A1E960FCAAB21ABDA58DB29472F795DE95FD173EE698B0D76B834BBB126 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE70D278D70F8433719EA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637C59BB75D821356298638F802B75D45FF914D58D5BE9E6BC1A93B80C6DEB9DEE97C6FB206A91F05B2150BEEA8B160CFBBC97D056EC71244DF1DC1F2ED7A42611AD2E47CDBA5A96583C09775C1D3CA48CFCA5A41EBD8A3A0199FA2833FD35BB23D2EF20D2F80756B5F868A13BD56FB6657A471835C12D1D977725E5C173C3A84C3CA5A41EBD8A3A0199FA2833FD35BB23DF004C906525384302BEBFE083D3B9BA71A620F70A64A45A98AA50765F79006372E808ACE2090B5E1725E5C173C3A84C3C5EA940A35A165FF2DBA43225CD8A89F83C798A30B85E16B57739F23D657EF2BB5C8C57E37DE458BEDA766A37F9254B7 X-C1DE0DAB: 0D63561A33F958A546EC88625B8C4DED3E793B824BBB7F3103B56FCA023603D6D59269BC5F550898D99A6476B3ADF6B47008B74DF8BB9EF7333BD3B22AA88B938A852937E12ACA752546FE575EB473F1410CA545F18667F91A7EA1CDA0B5A7A0 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D348F1757F8DFBC5C3376699D8C5B47B08084BFC48785C6F7DB58C694814A747C0014286554A15A20DB1D7E09C32AA3244CF4F1384865EF6F6397409683B9C40C59C3B3ADDA61883BB5729B2BEF169E0186 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2bioj02rlJ4F8e+1GfRz2v08/UA== X-Mailru-Sender: 689FA8AB762F73936BC43F508A0638224D5240C4B89B946DA2FBB3ACF7D50DA983D72C36FC87018B9F80AB2734326CD2FB559BB5D741EB96352A0ABBE4FDA4210A04DAD6CC59E33667EA787935ED9F1B X-Mras: Ok Subject: Re: [Tarantool-patches] [PATCH 1/1] sql: introduce UUID field type X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Mergen Imeev via Tarantool-patches Reply-To: Mergen Imeev Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" Hi! I found pissible memleak in my patch. Diff: diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c index 9288ef341..bf16f92ba 100644 --- a/src/box/sql/mem.c +++ b/src/box/sql/mem.c @@ -614,11 +614,10 @@ 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) + struct tt_uuid uuid; + if (tt_uuid_from_string(tt_cstr(mem->z, mem->n), &uuid) != 0) return -1; - mem->type = MEM_TYPE_UUID; - mem->flags = 0; - mem->field_type = FIELD_TYPE_UUID; + mem_set_uuid(mem, &uuid); return 0; } @@ -683,10 +682,8 @@ bin_to_uuid(struct Mem *mem) if (mem->n != UUID_LEN || tt_uuid_validate((struct tt_uuid *)mem->z) != 0) return -1; - mem->u.uuid = *(struct tt_uuid *)mem->z; - mem->type = MEM_TYPE_UUID; - mem->flags = 0; - mem->field_type = FIELD_TYPE_UUID; + struct tt_uuid uuid = *(struct tt_uuid *)mem->z; + mem_set_uuid(mem, &uuid); return 0; } On Thu, May 20, 2021 at 12:44:58PM +0300, Mergen Imeev via Tarantool-patches wrote: > 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. 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(). > --- > > https://github.com/tarantool/tarantool/issues/5886 > https://github.com/tarantool/tarantool/tree/imeevma/gh-5886-introduce-uuid-type-in-sql > > .../unreleased/introduce-uuid-to-sql.md | 3 + > extra/mkkeywordhash.c | 1 + > src/box/sql/func.c | 30 +- > src/box/sql/mem.c | 223 ++- > src/box/sql/mem.h | 38 +- > src/box/sql/parse.y | 1 + > src/box/sql/vdbe.c | 15 +- > test/sql-tap/CMakeLists.txt | 1 + > .../gh-5913-segfault-on-select-uuid.test.lua | 42 +- > .../sql-tap/gh-6024-funcs-return-bin.test.lua | 8 +- > test/sql-tap/sql_uuid.c | 57 + > test/sql-tap/uuid.test.lua | 1259 +++++++++++++++++ > 12 files changed, 1607 insertions(+), 71 deletions(-) > create mode 100644 changelogs/unreleased/introduce-uuid-to-sql.md > create mode 100644 test/sql-tap/sql_uuid.c > create mode 100755 test/sql-tap/uuid.test.lua > > diff --git a/changelogs/unreleased/introduce-uuid-to-sql.md b/changelogs/unreleased/introduce-uuid-to-sql.md > new file mode 100644 > index 000000000..120fb145a > --- /dev/null > +++ b/changelogs/unreleased/introduce-uuid-to-sql.md > @@ -0,0 +1,3 @@ > +## feature/core > + > + * Field type UUID is now available in SQL (gh-5886). > diff --git a/extra/mkkeywordhash.c b/extra/mkkeywordhash.c > index 7480c0211..0d998506c 100644 > --- a/extra/mkkeywordhash.c > +++ b/extra/mkkeywordhash.c > @@ -172,6 +172,7 @@ static Keyword aKeywordTable[] = { > { "UNSIGNED", "TK_UNSIGNED", true }, > { "UPDATE", "TK_UPDATE", true }, > { "USING", "TK_USING", true }, > + { "UUID" , "TK_UUID" , true }, > { "VALUES", "TK_VALUES", true }, > { "VARBINARY", "TK_VARBINARY", true }, > { "VIEW", "TK_VIEW", true }, > diff --git a/src/box/sql/func.c b/src/box/sql/func.c > index 90e8e152f..9c4480a92 100644 > --- a/src/box/sql/func.c > +++ b/src/box/sql/func.c > @@ -58,7 +58,8 @@ static const void * > mem_as_bin(struct Mem *mem) > { > const char *s; > - if (!mem_is_bytes(mem) && mem_to_str(mem) != 0) > + if (mem_cast_implicit(mem, FIELD_TYPE_VARBINARY) != 0 && > + mem_to_str(mem) != 0) > return NULL; > if (mem_get_bin(mem, &s) != 0) > return NULL; > @@ -142,26 +143,29 @@ typeofFunc(sql_context * context, int NotUsed, sql_value ** argv) > -1, SQL_STATIC); > return; > } > - switch (sql_value_type(argv[0])) { > - case MP_INT: > - case MP_UINT: > + switch (argv[0]->type) { > + case MEM_TYPE_INT: > + case MEM_TYPE_UINT: > z = "integer"; > break; > - case MP_STR: > + case MEM_TYPE_STR: > z = "string"; > break; > - case MP_DOUBLE: > + case MEM_TYPE_DOUBLE: > z = "double"; > break; > - case MP_BIN: > - case MP_ARRAY: > - case MP_MAP: > + case MEM_TYPE_BIN: > + case MEM_TYPE_ARRAY: > + case MEM_TYPE_MAP: > z = "varbinary"; > break; > - case MP_BOOL: > - case MP_NIL: > + case MEM_TYPE_BOOL: > + case MEM_TYPE_NULL: > z = "boolean"; > break; > + case MEM_TYPE_UUID: > + z = "uuid"; > + break; > default: > unreachable(); > break; > @@ -191,6 +195,7 @@ lengthFunc(sql_context * context, int argc, sql_value ** argv) > sql_result_uint(context, mem_len_unsafe(argv[0])); > break; > } > + case MP_EXT: > case MP_STR:{ > const unsigned char *z = mem_as_ustr(argv[0]); > if (z == 0) > @@ -235,6 +240,7 @@ absFunc(sql_context * context, int argc, sql_value ** argv) > } > case MP_BOOL: > case MP_BIN: > + case MP_EXT: > case MP_ARRAY: > case MP_MAP: { > diag_set(ClientError, ER_INCONSISTENT_TYPES, "number", > @@ -1461,8 +1467,8 @@ trim_func_one_arg(struct sql_context *context, sql_value *arg) > default_trim = (const unsigned char *) "\0"; > else > default_trim = (const unsigned char *) " "; > - int input_str_sz = mem_len_unsafe(arg); > const unsigned char *input_str = mem_as_ustr(arg); > + int input_str_sz = mem_len_unsafe(arg); > uint8_t trim_char_len[1] = { 1 }; > trim_procedure(context, TRIM_BOTH, default_trim, trim_char_len, 1, > input_str, input_str_sz); > 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) > +{ > + 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); > +} > + > const char * > mem_str(const struct Mem *mem) > { > - char buf[BUF_SIZE]; > + assert((int)UUID_STR_LEN > (int)BUF_SIZE); > + char buf[UUID_STR_LEN + 1]; > switch (mem->type) { > case MEM_TYPE_NULL: > return "NULL"; > @@ -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); > 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) > +{ > + mem_clear(mem); > + mem->field_type = FIELD_TYPE_UUID; > + mem->u.uuid = *uuid; > + mem->type = MEM_TYPE_UUID; > + mem->flags = 0; > +} > + > 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; > + mem->type = MEM_TYPE_UUID; > + mem->flags = 0; > + mem->field_type = FIELD_TYPE_UUID; > + return 0; > +} > + > static inline int > str_to_bool(struct Mem *mem) > { > @@ -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) > + 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; > +} > + > static inline int > bytes_to_int(struct Mem *mem) > { > @@ -810,6 +861,22 @@ map_to_str0(struct Mem *mem) > return mem_copy_str0(mem, str); > } > > +static inline int > +uuid_to_str0(struct Mem *mem) > +{ > + assert(mem->type == MEM_TYPE_UUID); > + char buf[UUID_STR_LEN + 1]; > + tt_uuid_to_string(&mem->u.uuid, &buf[0]); > + return mem_copy_str0(mem, &buf[0]); > +} > + > +static inline int > +uuid_to_bin(struct Mem *mem) > +{ > + assert(mem->type == MEM_TYPE_UUID); > + return mem_copy_bin(mem, (char *)&mem->u.uuid, UUID_LEN); > +} > + > int > mem_to_int(struct Mem *mem) > { > @@ -889,6 +956,8 @@ mem_to_str0(struct Mem *mem) > return map_to_str0(mem); > case MEM_TYPE_ARRAY: > return array_to_str0(mem); > + case MEM_TYPE_UUID: > + return uuid_to_str0(mem); > default: > return -1; > } > @@ -914,6 +983,8 @@ mem_to_str(struct Mem *mem) > return map_to_str0(mem); > case MEM_TYPE_ARRAY: > return array_to_str0(mem); > + case MEM_TYPE_UUID: > + return uuid_to_str0(mem); > default: > return -1; > } > @@ -966,9 +1037,19 @@ mem_cast_explicit(struct Mem *mem, enum field_type type) > return str_to_bin(mem); > if (mem_is_bytes(mem)) > return 0; > + if (mem->type == MEM_TYPE_UUID) > + return uuid_to_bin(mem); > return -1; > case FIELD_TYPE_NUMBER: > return mem_to_number(mem); > + case FIELD_TYPE_UUID: > + if (mem->type == MEM_TYPE_UUID) > + return 0; > + if (mem->type == MEM_TYPE_STR) > + return str_to_uuid(mem); > + if (mem->type == MEM_TYPE_BIN) > + return bin_to_uuid(mem); > + return -1; > case FIELD_TYPE_SCALAR: > if ((mem->type & (MEM_TYPE_MAP | MEM_TYPE_ARRAY)) != 0) > return -1; > @@ -996,6 +1077,8 @@ mem_cast_implicit(struct Mem *mem, enum field_type type) > case FIELD_TYPE_STRING: > if (mem->type == MEM_TYPE_STR) > return 0; > + if (mem->type == MEM_TYPE_UUID) > + return uuid_to_str0(mem); > return -1; > case FIELD_TYPE_DOUBLE: > if (mem->type == MEM_TYPE_DOUBLE) > @@ -1017,6 +1100,8 @@ mem_cast_implicit(struct Mem *mem, enum field_type type) > if ((mem->type & (MEM_TYPE_BIN | MEM_TYPE_MAP | > MEM_TYPE_ARRAY)) != 0) > return 0; > + if (mem->type == MEM_TYPE_UUID) > + return uuid_to_bin(mem); > return -1; > case FIELD_TYPE_NUMBER: > if (mem_is_num(mem)) > @@ -1034,6 +1119,14 @@ mem_cast_implicit(struct Mem *mem, enum field_type type) > if ((mem->type & (MEM_TYPE_MAP | MEM_TYPE_ARRAY)) != 0) > return -1; > return 0; > + case FIELD_TYPE_UUID: > + if (mem->type == MEM_TYPE_UUID) > + return 0; > + if (mem->type == MEM_TYPE_STR) > + return str_to_uuid(mem); > + if (mem->type == MEM_TYPE_BIN) > + return bin_to_uuid(mem); > + return -1; > case FIELD_TYPE_ANY: > return 0; > default: > @@ -1063,6 +1156,8 @@ mem_cast_implicit_old(struct Mem *mem, enum field_type type) > return int_to_str0(mem); > if (mem->type == MEM_TYPE_DOUBLE) > return double_to_str0(mem); > + if (mem->type == MEM_TYPE_UUID) > + return uuid_to_str0(mem); > return -1; > case FIELD_TYPE_DOUBLE: > if (mem->type == MEM_TYPE_DOUBLE) > @@ -1087,6 +1182,8 @@ mem_cast_implicit_old(struct Mem *mem, enum field_type type) > case FIELD_TYPE_VARBINARY: > if (mem->type == MEM_TYPE_BIN) > return 0; > + if (mem->type == MEM_TYPE_UUID) > + return uuid_to_bin(mem); > return -1; > case FIELD_TYPE_NUMBER: > if (mem_is_num(mem)) > @@ -1106,6 +1203,14 @@ mem_cast_implicit_old(struct Mem *mem, enum field_type type) > if ((mem->type & (MEM_TYPE_MAP | MEM_TYPE_ARRAY)) != 0) > return -1; > return 0; > + case FIELD_TYPE_UUID: > + if (mem->type == MEM_TYPE_UUID) > + return 0; > + if (mem->type == MEM_TYPE_STR) > + return str_to_uuid(mem); > + if (mem->type == MEM_TYPE_BIN) > + return bin_to_uuid(mem); > + return -1; > default: > break; > } > @@ -1238,6 +1343,24 @@ mem_len(const struct Mem *mem, uint32_t *len) > return 0; > } > > +int > +mem_get_uuid(const struct Mem *mem, struct tt_uuid *uuid) > +{ > + if ((mem->type & (MEM_TYPE_UUID | MEM_TYPE_STR | MEM_TYPE_BIN)) == 0) > + return -1; > + if (mem->type == MEM_TYPE_STR) > + return tt_uuid_from_string(tt_cstr(mem->z, mem->n), uuid); > + if (mem->type == MEM_TYPE_UUID) { > + *uuid = mem->u.uuid; > + return 0; > + } > + if (mem->n != UUID_LEN || > + tt_uuid_validate((struct tt_uuid *)mem->z) != 0) > + return -1; > + *uuid = *(struct tt_uuid *)mem->z; > + return 0; > +} > + > int > mem_get_agg(const struct Mem *mem, void **accum) > { > @@ -1898,6 +2021,15 @@ mem_cmp_str(const struct Mem *left, const struct Mem *right, int *result, > return 0; > } > > +int > +mem_cmp_uuid(const struct Mem *a, const struct Mem *b, int *result) > +{ > + if ((a->type & b->type & MEM_TYPE_UUID) == 0) > + return -1; > + *result = memcmp(&a->u.uuid, &b->u.uuid, UUID_LEN); > + return 0; > +} > + > /* > * Both *pMem1 and *pMem2 contain string values. Compare the two values > * using the collation sequence pColl. As usual, return a negative , zero > @@ -1950,13 +2082,15 @@ mem_type_to_str(const struct Mem *p) > return "varbinary"; > case MEM_TYPE_BOOL: > return "boolean"; > + case MEM_TYPE_UUID: > + return "uuid"; > default: > unreachable(); > } > } > > enum mp_type > -mem_mp_type(struct Mem *mem) > +mem_mp_type(const struct Mem *mem) > { > assert(mem->type < MEM_TYPE_INVALID); > switch (mem->type) { > @@ -1978,6 +2112,8 @@ mem_mp_type(struct Mem *mem) > return MP_BOOL; > case MEM_TYPE_DOUBLE: > return MP_DOUBLE; > + case MEM_TYPE_UUID: > + return MP_EXT; > default: > unreachable(); > } > @@ -2359,6 +2495,14 @@ sqlMemCompare(const Mem * pMem1, const Mem * pMem2, const struct coll * pColl) > return -1; > } > > + if (((type1 | type2) & MEM_TYPE_UUID) != 0) { > + if (mem_cmp_uuid(pMem1, pMem2, &res) == 0) > + return res; > + if (type1 != MEM_TYPE_UUID) > + return +1; > + return -1; > + } > + > /* At least one of the two values is a number > */ > if (((type1 | type2) & > @@ -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); > + buf = aKey1; > + mp_next(&aKey1); > + (void)len; > + if (type == MP_UUID) { > + assert(len == UUID_LEN); > + mem1.type = MEM_TYPE_UUID; > + if (mp_decode_uuid(&buf, &mem1.u.uuid) == NULL || > + mem_cmp_uuid(&mem1, pKey2, &rc) != 0) > + rc = 1; > + break; > } > + mem1.z = (char *)buf; > + mem1.n = aKey1 - buf; > + goto do_blob; > + } > } > *key1 = aKey1; > return rc; > @@ -2624,9 +2781,23 @@ mem_from_mp_ephemeral(struct Mem *mem, const char *buf, uint32_t *len) > break; > } > case MP_EXT: { > - mem->z = (char *)buf; > - mp_next(&buf); > - mem->n = buf - mem->z; > + int8_t type; > + const char *svp = buf; > + uint32_t len = mp_decode_extl(&buf, &type); > + (void)len; > + if (type == MP_UUID) { > + assert(len == UUID_LEN); > + buf = svp; > + if (mp_decode_uuid(&buf, &mem->u.uuid) == NULL) > + return -1; > + mem->type = MEM_TYPE_UUID; > + mem->flags = 0; > + mem->field_type = FIELD_TYPE_UUID; > + break; > + } > + mem->z = (char *)svp; > + mp_next(&svp); > + mem->n = svp - mem->z; > mem->type = MEM_TYPE_BIN; > mem->flags = MEM_Ephem; > mem->field_type = FIELD_TYPE_VARBINARY; > @@ -2763,6 +2934,9 @@ mpstream_encode_vdbe_mem(struct mpstream *stream, struct Mem *var) > case MEM_TYPE_BOOL: > mpstream_encode_bool(stream, var->u.b); > return; > + case MEM_TYPE_UUID: > + mpstream_encode_uuid(stream, &var->u.uuid); > + return; > default: > unreachable(); > } > @@ -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; > + break; > + } > default: > unreachable(); > } > @@ -2972,16 +3151,13 @@ port_lua_get_vdbemem(struct port *base, uint32_t *size) > char buf[BUF_SIZE]; > assert(field.ext_type == MP_UUID || > field.ext_type == MP_DECIMAL); > - uint32_t size; > if (field.ext_type == MP_UUID) { > - size = mp_sizeof_uuid(); > - assert(size < BUF_SIZE); > - mp_encode_uuid(&buf[0], field.uuidval); > - } else { > - size = mp_sizeof_decimal(field.decval); > - assert(size < BUF_SIZE); > - mp_encode_decimal(&buf[0], field.decval); > + mem_set_uuid(&val[i], field.uuidval); > + break; > } > + uint32_t size = mp_sizeof_decimal(field.decval); > + assert(size < BUF_SIZE); > + mp_encode_decimal(&buf[0], field.decval); > if (mem_copy_bin(&val[i], buf, size) != 0) > goto error; > break; > @@ -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; > diff --git a/src/box/sql/mem.h b/src/box/sql/mem.h > index 15d97da0e..564d48067 100644 > --- a/src/box/sql/mem.h > +++ b/src/box/sql/mem.h > @@ -30,6 +30,7 @@ > * SUCH DAMAGE. > */ > #include "box/field_def.h" > +#include "uuid/tt_uuid.h" > > struct sql; > struct Vdbe; > @@ -47,10 +48,11 @@ enum mem_type { > MEM_TYPE_MAP = 1 << 6, > MEM_TYPE_BOOL = 1 << 7, > MEM_TYPE_DOUBLE = 1 << 8, > - MEM_TYPE_INVALID = 1 << 9, > - MEM_TYPE_FRAME = 1 << 10, > - MEM_TYPE_PTR = 1 << 11, > - MEM_TYPE_AGG = 1 << 12, > + MEM_TYPE_UUID = 1 << 9, > + MEM_TYPE_INVALID = 1 << 10, > + MEM_TYPE_FRAME = 1 << 11, > + MEM_TYPE_PTR = 1 << 12, > + MEM_TYPE_AGG = 1 << 13, > }; > > /* > @@ -72,6 +74,7 @@ struct Mem { > */ > struct func *func; > struct VdbeFrame *pFrame; /* Used when flags==MEM_Frame */ > + struct tt_uuid uuid; > } u; > /** Type of the value this MEM contains. */ > enum mem_type type; > @@ -255,6 +258,11 @@ mem_is_any_null(const struct Mem *mem1, const struct Mem *mem2) > return ((mem1->type| mem2->type) & MEM_TYPE_NULL) != 0; > } > > +/** Check if MEM is compatible with field type. */ > +bool > +mem_is_field_compatible(const struct Mem *mem, enum field_type type, > + bool is_nullable); > + > /** > * Return a string that represent content of MEM. String is either allocated > * using static_alloc() of just a static variable. > @@ -290,6 +298,10 @@ mem_set_bool(struct Mem *mem, bool value); > void > mem_set_double(struct Mem *mem, double value); > > +/** Clear MEM and set it to UUID. */ > +void > +mem_set_uuid(struct Mem *mem, struct tt_uuid *uuid); > + > /** Clear MEM and set it to STRING. The string belongs to another object. */ > void > mem_set_str_ephemeral(struct Mem *mem, char *value, uint32_t len); > @@ -677,6 +689,14 @@ mem_cmp_str(const struct Mem *left, const struct Mem *right, int *result, > int > mem_cmp_num(const struct Mem *a, const struct Mem *b, int *result); > > +/** > + * Compare two MEMs and return the result of comparison. MEMs should be of > + * UUID type or their values are converted to UUID according to > + * implicit cast rules. Original MEMs are not changed. > + */ > +int > +mem_cmp_uuid(const struct Mem *left, const struct Mem *right, int *result); > + > /** > * Convert the given MEM to INTEGER. This function and the function below define > * the rules that are used to convert values of all other types to INTEGER. In > @@ -864,6 +884,14 @@ mem_get_bin(const struct Mem *mem, const char **s); > int > mem_len(const struct Mem *mem, uint32_t *len); > > +/** > + * Return value for MEM of UUID type. For MEM of all other types convert value > + * of the MEM to UUID if possible and return converted value. Original MEM is > + * not changed. > + */ > +int > +mem_get_uuid(const struct Mem *mem, struct tt_uuid *uuid); > + > /** > * Return length of value for MEM of STRING or VARBINARY type. This function is > * not safe since there is no proper processing in case mem_len() return an > @@ -898,7 +926,7 @@ mem_type_to_str(const struct Mem *p); > * transparent memory cell. > */ > enum mp_type > -mem_mp_type(struct Mem *mem); > +mem_mp_type(const struct Mem *mem); > > enum mp_type > sql_value_type(struct Mem *); > diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y > index abc363951..4c9cf475e 100644 > --- a/src/box/sql/parse.y > +++ b/src/box/sql/parse.y > @@ -1834,6 +1834,7 @@ typedef(A) ::= SCALAR . { A.type = FIELD_TYPE_SCALAR; } > typedef(A) ::= BOOL . { A.type = FIELD_TYPE_BOOLEAN; } > typedef(A) ::= BOOLEAN . { A.type = FIELD_TYPE_BOOLEAN; } > typedef(A) ::= VARBINARY . { A.type = FIELD_TYPE_VARBINARY; } > +typedef(A) ::= UUID . { A.type = FIELD_TYPE_UUID; } > > /** > * Time-like types are temporary disabled, until they are > diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c > index 12ec703a2..c78674882 100644 > --- a/src/box/sql/vdbe.c > +++ b/src/box/sql/vdbe.c > @@ -1322,10 +1322,10 @@ case OP_FunctionByName: { > region_truncate(region, region_svp); > if (mem == NULL) > goto abort_due_to_error; > - enum mp_type type = sql_value_type((sql_value *)pOut); > - if (!field_mp_plain_type_is_compatible(returns, type, true)) { > + if (!mem_is_field_compatible(pOut, returns, true)) { > diag_set(ClientError, ER_FUNC_INVALID_RETURN_TYPE, pOp->p4.z, > - field_type_strs[returns], mp_type_strs[type]); > + field_type_strs[returns], > + mp_type_strs[mem_mp_type(pOut)]); > goto abort_due_to_error; > } > > @@ -1634,6 +1634,15 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ > "boolean"); > goto abort_due_to_error; > } > + } else if (((pIn3->type | pIn1->type) & MEM_TYPE_UUID) != 0) { > + if (mem_cmp_uuid(pIn3, pIn1, &res) != 0) { > + char *str = pIn3->type != MEM_TYPE_UUID ? > + mem_type_to_str(pIn3) : > + mem_type_to_str(pIn1); > + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, str, > + "uuid"); > + goto abort_due_to_error; > + } > } else if (mem_is_bin(pIn3) || mem_is_bin(pIn1)) { > if (mem_cmp_bin(pIn3, pIn1, &res) != 0) { > char *str = !mem_is_bin(pIn3) ? > diff --git a/test/sql-tap/CMakeLists.txt b/test/sql-tap/CMakeLists.txt > index bf0c3a11d..bd2b9f33f 100644 > --- a/test/sql-tap/CMakeLists.txt > +++ b/test/sql-tap/CMakeLists.txt > @@ -1,3 +1,4 @@ > include_directories(${MSGPUCK_INCLUDE_DIRS}) > build_module(gh-5938-wrong-string-length gh-5938-wrong-string-length.c) > build_module(gh-6024-funcs-return-bin gh-6024-funcs-return-bin.c) > +build_module(sql_uuid sql_uuid.c) > diff --git a/test/sql-tap/gh-5913-segfault-on-select-uuid.test.lua b/test/sql-tap/gh-5913-segfault-on-select-uuid.test.lua > index 60978c2b5..34b22002a 100755 > --- a/test/sql-tap/gh-5913-segfault-on-select-uuid.test.lua > +++ b/test/sql-tap/gh-5913-segfault-on-select-uuid.test.lua > @@ -1,6 +1,6 @@ > #!/usr/bin/env tarantool > local test = require("sqltester") > -test:plan(6) > +test:plan(4) > > local uuid = require("uuid").fromstr("11111111-1111-1111-1111-111111111111") > local decimal = require("decimal").new(111.111) > @@ -13,16 +13,16 @@ box.space.T:insert({1, uuid, decimal}) > > -- > -- Make sure that there is no segmentation fault on select from field that > --- contains UUID or DECIMAL. Currently SQL does not support UUID and DECIMAL, > --- so they treated as VARBINARY. > +-- contains UUID or DECIMAL. Currently SQL does not support DECIMAL, so it is > +-- treated as VARBINARY. > -- > test:do_execsql_test( > "gh-5913-1", > [[ > SELECT i, u, d FROM t; > - SELECT i from t; > + SELECT i, u from t; > ]], { > - 1 > + 1, uuid > }) > > box.schema.create_space('T1') > @@ -32,19 +32,11 @@ box.space.T1:format({{name = "I", type = "integer"}, > box.space.T1:create_index("primary") > > -- > --- Since SQL does not support UUID and DECIMAL and they treated as VARBINARY, > --- they cannot be inserted from SQL. > +-- Since SQL does not support DECIMAL and it is treated as VARBINARY, it cannot > +-- be inserted from SQL. > -- > test:do_catchsql_test( > "gh-5913-2", > - [[ > - INSERT INTO t1 SELECT i, u, NULL FROM t; > - ]], { > - 1, "Type mismatch: can not convert varbinary to uuid" > - }) > - > -test:do_catchsql_test( > - "gh-5913-3", > [[ > INSERT INTO t1 SELECT i, NULL, d FROM t; > ]], { > @@ -52,11 +44,11 @@ test:do_catchsql_test( > }) > > -- > --- Still, if UUID or DECIMAL fields does not selected directly, insert is > --- working properly. > +-- Still, if DECIMAL fields does not selected directly, insert is working > +-- properly in case the space which receives these values is empty. > -- > test:do_execsql_test( > - "gh-5913-4", > + "gh-5913-3", > [[ > INSERT INTO t1 SELECT * FROM t; > SELECT count() FROM t1; > @@ -77,19 +69,11 @@ box.space.TD:create_index("primary") > box.space.TD:insert({1, decimal}) > > -- > --- Update of UUID or VARBINARY also does not lead to segfault, however throws an > --- error since after changing value cannot be inserted into the field from SQL. > +-- Update of VARBINARY also does not lead to segfault, however throws an error > +-- since after changing value cannot be inserted into the field from SQL. > -- > test:do_catchsql_test( > - "gh-5913-5", > - [[ > - UPDATE tu SET u = u; > - ]], { > - 1, "Type mismatch: can not convert varbinary to uuid" > - }) > - > -test:do_catchsql_test( > - "gh-5913-6", > + "gh-5913-4", > [[ > UPDATE td SET d = d; > ]], { > diff --git a/test/sql-tap/gh-6024-funcs-return-bin.test.lua b/test/sql-tap/gh-6024-funcs-return-bin.test.lua > index 9069379e1..c2954bba0 100755 > --- a/test/sql-tap/gh-6024-funcs-return-bin.test.lua > +++ b/test/sql-tap/gh-6024-funcs-return-bin.test.lua > @@ -23,7 +23,7 @@ test:do_execsql_test( > box.schema.func.create("gh-6024-funcs-return-bin.ret_uuid", { > language = "C", > param_list = {}, > - returns = "varbinary", > + returns = "uuid", > exports = {"SQL"}, > }) > > @@ -32,7 +32,7 @@ test:do_execsql_test( > [[ > SELECT typeof("gh-6024-funcs-return-bin.ret_uuid"()); > ]], { > - "varbinary" > + "uuid" > }) > > box.schema.func.create("gh-6024-funcs-return-bin.ret_decimal", { > @@ -53,7 +53,7 @@ test:do_execsql_test( > box.schema.func.create("get_uuid", { > language = "LUA", > param_list = {}, > - returns = "varbinary", > + returns = "uuid", > body = "function(x) return require('uuid').fromstr('11111111-1111-1111-1111-111111111111') end", > exports = {"SQL"}, > }) > @@ -63,7 +63,7 @@ test:do_execsql_test( > [[ > SELECT typeof("get_uuid"()), "get_uuid"() == "gh-6024-funcs-return-bin.ret_uuid"(); > ]], { > - "varbinary", true > + "uuid", true > }) > > box.schema.func.create("get_decimal", { > 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 > @@ -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); > +} > + > +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 @@ > +#!/usr/bin/env tarantool > +local build_path = os.getenv("BUILDDIR") > +package.cpath = build_path..'/test/sql-tap/?.so;'..build_path..'/test/sql-tap/?.dylib;'..package.cpath > + > +local test = require("sqltester") > +test:plan(137) > + > +local uuid = require("uuid") > +local uuid1 = uuid.fromstr("11111111-1111-1111-1111-111111111111") > +local uuid2 = uuid.fromstr("22222222-1111-1111-1111-111111111111") > +local uuid3 = uuid.fromstr("11111111-3333-1111-1111-111111111111") > + > +-- Check that it is possible to create spaces with UUID field. > +test:do_execsql_test( > + "uuid-1", > + [[ > + CREATE TABLE t1 (i INT PRIMARY KEY, u UUID); > + CREATE TABLE t2 (u UUID PRIMARY KEY); > + ]], { > + }) > + > +box.space.T1:insert({1, uuid1}) > +box.space.T1:insert({2, uuid2}) > +box.space.T1:insert({3, uuid3}) > +box.space.T1:insert({4, uuid1}) > +box.space.T1:insert({5, uuid1}) > +box.space.T1:insert({6, uuid2}) > +box.space.T2:insert({uuid1}) > +box.space.T2:insert({uuid2}) > +box.space.T2:insert({uuid3}) > + > +-- Check that SELECT can work with UUID. > +test:do_execsql_test( > + "uuid-2.1.1", > + [[ > + SELECT * FROM t1; > + ]], { > + 1, uuid1, 2, uuid2, 3, uuid3, 4, uuid1, 5, uuid1, 6, uuid2 > + }) > + > +test:do_execsql_test( > + "uuid-2.1.2", > + [[ > + SELECT * FROM t2; > + ]], { > + uuid1, uuid3, uuid2 > + }) > + > +-- Check that ORDER BY can work with UUID. > +test:do_execsql_test( > + "uuid-2.2.1", > + [[ > + SELECT * FROM t1 ORDER BY u; > + ]], { > + 1, uuid1, 4, uuid1, 5, uuid1, 3, uuid3, 2, uuid2, 6, uuid2 > + }) > + > +test:do_execsql_test( > + "uuid-2.2.2", > + [[ > + SELECT * FROM t1 ORDER BY u DESC; > + ]], { > + 2, uuid2, 6, uuid2, 3, uuid3, 1, uuid1, 4, uuid1, 5, uuid1 > + }) > + > +test:do_execsql_test( > + "uuid-2.2.3", > + [[ > + SELECT * FROM t2 ORDER BY u; > + ]], { > + uuid1, uuid3, uuid2 > + }) > + > +test:do_execsql_test( > + "uuid-2.2.4", > + [[ > + SELECT * FROM t2 ORDER BY u DESC; > + ]], { > + uuid2, uuid3, uuid1 > + }) > + > +-- Check that GROUP BY can work with UUID. > +test:do_execsql_test( > + "uuid-2.3.1", > + [[ > + SELECT count(*), u FROM t1 GROUP BY u; > + ]], { > + 3, uuid1, 1, uuid3, 2, uuid2 > + }) > + > +test:do_execsql_test( > + "uuid-2.3.2", > + [[ > + SELECT count(*), u FROM t2 GROUP BY u; > + ]], { > + 1, uuid1, 1, uuid3, 1, uuid2 > + }) > + > +-- Check that subselects can work with UUID. > +test:do_execsql_test( > + "uuid-2.4", > + [[ > + SELECT * FROM (SELECT * FROM (SELECT * FROM t2 LIMIT 2) LIMIT 2 OFFSET 1); > + ]], { > + uuid3 > + }) > + > +-- Check that DISTINCT can work with UUID. > +test:do_execsql_test( > + "uuid-2.5", > + [[ > + SELECT DISTINCT u FROM t1; > + ]], { > + uuid1, uuid2, uuid3 > + }) > + > +-- Check that VIEW can work with UUID. > +test:do_execsql_test( > + "uuid-2.6", > + [[ > + CREATE VIEW v AS SELECT u FROM t1; > + SELECT * FROM v; > + ]], { > + uuid1, uuid2, uuid3, uuid1, uuid1, uuid2 > + }) > + > +-- Check that LIMIT does not accept UUID as argument. > +test:do_catchsql_test( > + "uuid-3.1", > + [[ > + SELECT 1 LIMIT (SELECT u FROM t1 LIMIT 1); > + ]], { > + 1, "Failed to execute SQL statement: Only positive integers are allowed in the LIMIT clause" > + }) > + > +-- Check that OFFSET does not accept UUID as argument. > +test:do_catchsql_test( > + "uuid-3.2", > + [[ > + SELECT 1 LIMIT 1 OFFSET (SELECT u FROM t1 LIMIT 1); > + ]], { > + 1, "Failed to execute SQL statement: Only positive integers are allowed in the OFFSET clause" > + }) > + > +-- Check that ephemeral space can work with UUID. > +test:do_execsql_test( > + "uuid-4", > + [[ > + EXPLAIN SELECT * from (VALUES(1)), t2; > + ]], { > + "/OpenTEphemeral/" > + }) > + > +test:execsql([[ > + CREATE TABLE t5f (u UUID PRIMARY KEY, f UUID REFERENCES t5f(u)); > + CREATE TABLE t5c (i INT PRIMARY KEY, f UUID, CONSTRAINT ck CHECK(CAST(f AS STRING) != '11111111-1111-1111-1111-111111111111')); > + CREATE TABLE t5u (i INT PRIMARY KEY, f UUID UNIQUE); > +]]) > + > +-- Check that FOREIGN KEY constraint can work with UUID. > +test:do_catchsql_test( > + "uuid-5.1.1", > + [[ > + INSERT INTO t5f SELECT (SELECT u from t2 LIMIT 1 OFFSET 1), (SELECT u from t2 LIMIT 1); > + SELECT * from t5f; > + ]], { > + 1, "Failed to execute SQL statement: FOREIGN KEY constraint failed" > + }) > + > +test:do_execsql_test( > + "uuid-5.1.2", > + [[ > + INSERT INTO t5f SELECT u, u from t2 LIMIT 1; > + SELECT * from t5f; > + ]], { > + uuid1, uuid1 > + }) > + > +test:do_execsql_test( > + "uuid-5.1.3", > + [[ > + INSERT INTO t5f SELECT (SELECT u from t2 LIMIT 1 OFFSET 1), (SELECT u from t2 LIMIT 1); > + SELECT * from t5f; > + ]], { > + uuid1, uuid1, uuid3, uuid1 > + }) > + > +-- 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; > + ]], { > + 1, "Check constraint failed 'CK': CAST(f AS STRING) != '11111111-1111-1111-1111-111111111111'" > + }) > + > +test:do_execsql_test( > + "uuid-5.2.2", > + [[ > + INSERT INTO t5c SELECT 2, u FROM t2 LIMIT 1 OFFSET 1; > + SELECT * from t5c; > + ]], { > + 2, uuid3 > + }) > + > +-- Check that UNIQUE constraint can work with UUID. > +test:do_execsql_test( > + "uuid-5.3.1", > + [[ > + INSERT INTO t5u SELECT 1, u FROM t2 LIMIT 1; > + SELECT * from t5u; > + ]], { > + 1, uuid1 > + }) > + > +test:do_catchsql_test( > + "uuid-5.3.2", > + [[ > + INSERT INTO t5u SELECT 2, u FROM t2 LIMIT 1; > + SELECT * from t5u; > + ]], { > + 1, 'Duplicate key exists in unique index "unique_unnamed_T5U_2" '.. > + 'in space "T5U" with old tuple - '.. > + '[1, 11111111-1111-1111-1111-111111111111] and new tuple - '.. > + '[2, 11111111-1111-1111-1111-111111111111]' > + }) > + > +-- Check that built-in functions work with UUIDs as intended. > +test:do_catchsql_test( > + "uuid-6.1.1", > + [[ > + SELECT ABS(u) from t2; > + ]], { > + 1, "Inconsistent types: expected number got uuid" > + }) > + > +test:do_catchsql_test( > + "uuid-6.1.2", > + [[ > + SELECT AVG(u) from t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to number" > + }) > + > +test:do_execsql_test( > + "uuid-6.1.3", > + [[ > + SELECT CHAR(u) from t2; > + ]], { > + "\0", "\0", "\0" > + }) > + > +test:do_execsql_test( > + "uuid-6.1.4", > + [[ > + SELECT CHARACTER_LENGTH(u) from t2; > + ]], { > + 36, 36, 36 > + }) > + > +test:do_execsql_test( > + "uuid-6.1.5", > + [[ > + SELECT CHAR_LENGTH(u) from t2; > + ]], { > + 36, 36, 36 > + }) > + > +test:do_execsql_test( > + "uuid-6.1.6", > + [[ > + SELECT COALESCE(NULL, u, NULL, NULL) from t2; > + ]], { > + uuid1, uuid3, uuid2 > + }) > + > +test:do_execsql_test( > + "uuid-6.1.7", > + [[ > + SELECT COUNT(u) from t2; > + ]], { > + 3 > + }) > + > +test:do_execsql_test( > + "uuid-6.1.8", > + [[ > + SELECT GREATEST((SELECT u FROM t2 LIMIT 1), (SELECT u FROM t2 LIMIT 1 OFFSET 1)); > + ]], { > + uuid3 > + }) > + > +test:do_execsql_test( > + "uuid-6.1.9", > + [[ > + SELECT GROUP_CONCAT(u) from t2; > + ]], { > + "11111111-1111-1111-1111-111111111111,".. > + "11111111-3333-1111-1111-111111111111,".. > + "22222222-1111-1111-1111-111111111111" > + }) > + > +test:do_execsql_test( > + "uuid-6.1.10", > + [[ > + SELECT HEX(u) from t2; > + ]], { > + "11111111111111111111111111111111", > + "11111111333311111111111111111111", > + "22222222111111111111111111111111" > + }) > + > +test:do_execsql_test( > + "uuid-6.1.11", > + [[ > + SELECT IFNULL(u, NULL) from t2; > + ]], { > + uuid1, uuid3, uuid2 > + }) > + > +test:do_execsql_test( > + "uuid-6.1.12", > + [[ > + SELECT LEAST((SELECT u FROM t2 LIMIT 1), (SELECT u FROM t2 LIMIT 1 OFFSET 1)); > + ]], { > + uuid1 > + }) > + > +test:do_execsql_test( > + "uuid-6.1.13", > + [[ > + SELECT LENGTH(u) from t2; > + ]], { > + 36, 36, 36 > + }) > + > +test:do_catchsql_test( > + "uuid-6.1.14", > + [[ > + SELECT u LIKE 'a' from t2; > + ]], { > + 1, "Inconsistent types: expected text got uuid" > + }) > + > +test:do_execsql_test( > + "uuid-6.1.15", > + [[ > + SELECT LIKELIHOOD(u, 0.5) from t2; > + ]], { > + uuid1, uuid3, uuid2 > + }) > + > +test:do_execsql_test( > + "uuid-6.1.16", > + [[ > + SELECT LIKELY(u) from t2; > + ]], { > + uuid1, uuid3, uuid2 > + }) > + > +test:do_execsql_test( > + "uuid-6.1.17", > + [[ > + SELECT LOWER(u) from t2; > + ]], { > + "11111111-1111-1111-1111-111111111111", > + "11111111-3333-1111-1111-111111111111", > + "22222222-1111-1111-1111-111111111111" > + }) > + > +test:do_execsql_test( > + "uuid-6.1.18", > + [[ > + SELECT MAX(u) from t2; > + ]], { > + uuid2 > + }) > + > +test:do_execsql_test( > + "uuid-6.1.19", > + [[ > + SELECT MIN(u) from t2; > + ]], { > + uuid1 > + }) > + > +test:do_execsql_test( > + "uuid-6.1.20", > + [[ > + SELECT NULLIF(u, 1) from t2; > + ]], { > + uuid1, uuid3, uuid2 > + }) > + > +test:do_catchsql_test( > + "uuid-6.1.21", > + [[ > + SELECT POSITION(u, '1') from t2; > + ]], { > + 1, "Inconsistent types: expected text or varbinary got uuid" > + }) > + > +test:do_execsql_test( > + "uuid-6.1.22", > + [[ > + SELECT RANDOMBLOB(u) from t2; > + ]], { > + "", "", "" > + }) > + > +test:do_execsql_test( > + "uuid-6.1.23", > + [[ > + SELECT REPLACE(u, '1', '2') from t2; > + ]], { > + "22222222-2222-2222-2222-222222222222", > + "22222222-3333-2222-2222-222222222222", > + "22222222-2222-2222-2222-222222222222" > + }) > + > +test:do_catchsql_test( > + "uuid-6.1.24", > + [[ > + SELECT ROUND(u) from t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to numeric" > + }) > + > +test:do_execsql_test( > + "uuid-6.1.25", > + [[ > + SELECT SOUNDEX(u) from t2; > + ]], { > + "?000", "?000", "?000" > + }) > + > +test:do_execsql_test( > + "uuid-6.1.26", > + [[ > + SELECT SUBSTR(u, 3, 3) from t2; > + ]], { > + "111", "111", "222" > + }) > + > +test:do_catchsql_test( > + "uuid-6.1.27", > + [[ > + SELECT SUM(u) from t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to number" > + }) > + > +test:do_catchsql_test( > + "uuid-6.1.28", > + [[ > + SELECT TOTAL(u) from t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to number" > + }) > + > +test:do_execsql_test( > + "uuid-6.1.29", > + [[ > + SELECT TRIM(u) from t2; > + ]], { > + "11111111-1111-1111-1111-111111111111", > + "11111111-3333-1111-1111-111111111111", > + "22222222-1111-1111-1111-111111111111" > + }) > + > +test:do_execsql_test( > + "uuid-6.1.30", > + [[ > + SELECT TYPEOF(u) from t2; > + ]], { > + "uuid", "uuid", "uuid" > + }) > + > +test:do_execsql_test( > + "uuid-6.1.31", > + [[ > + SELECT UNICODE(u) from t2; > + ]], { > + 49, 49, 50 > + }) > + > +test:do_execsql_test( > + "uuid-6.1.32", > + [[ > + SELECT UNLIKELY(u) from t2; > + ]], { > + uuid1, uuid3, uuid2 > + }) > + > +test:do_execsql_test( > + "uuid-6.1.33", > + [[ > + SELECT UPPER(u) from t2; > + ]], { > + "11111111-1111-1111-1111-111111111111", > + "11111111-3333-1111-1111-111111111111", > + "22222222-1111-1111-1111-111111111111" > + }) > + > +test:do_catchsql_test( > + "uuid-6.1.33", > + [[ > + SELECT u || u from t2; > + ]], { > + 1, "Inconsistent types: expected text or varbinary got uuid" > + }) > + > +local func = {language = 'Lua', body = 'function(x) return type(x) end', > + returns = 'string', param_list = {'any'}, exports = {'SQL'}} > +box.schema.func.create('RETURN_TYPE', func); > + > +-- Check that Lua user-defined functions can accept UUID. > +test:do_execsql_test( > + "uuid-6.2", > + [[ > + SELECT RETURN_TYPE(u) FROM t2; > + ]], { > + "cdata", "cdata", "cdata" > + }) > + > +func = {language = 'Lua', returns = 'uuid', param_list = {}, exports = {'SQL'}, > + body = 'function(x) return require("uuid").fromstr("11111111-1111-1111-1111-111111111111") end'} > +box.schema.func.create('GET_UUID', func); > + > +-- Check that Lua user-defined functions can return UUID. > +test:do_execsql_test( > + "uuid-6.3", > + [[ > + SELECT GET_UUID(); > + ]], { > + uuid1 > + }) > + > +func = {language = 'C', returns = 'boolean', param_list = {'any'}, exports = {'SQL'}} > +box.schema.func.create("sql_uuid.is_uuid", func) > + > +-- Check that C user-defined functions can accept UUID. > +test:do_execsql_test( > + "uuid-6.4", > + [[ > + SELECT "sql_uuid.is_uuid"(i), "sql_uuid.is_uuid"(u) FROM t1 LIMIT 1; > + ]], { > + false, true > + }) > + > +func = {language = 'C', returns = 'uuid', param_list = {}, exports = {'SQL'}} > +box.schema.func.create("sql_uuid.ret_uuid", func) > + > +-- Check that C user-defined functions can return UUID. > +test:do_execsql_test( > + "uuid-6.5", > + [[ > + SELECT "sql_uuid.ret_uuid"(); > + ]], { > + uuid1 > + }) > + > +-- Check that explicit cast from UUID to another types works as intended. > +test:do_catchsql_test( > + "uuid-7.1.1", > + [[ > + SELECT cast(u AS UNSIGNED) FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to unsigned" > + }) > + > +test:do_execsql_test( > + "uuid-7.1.2", > + [[ > + SELECT cast(u AS STRING) FROM t2; > + ]], { > + "11111111-1111-1111-1111-111111111111", > + "11111111-3333-1111-1111-111111111111", > + "22222222-1111-1111-1111-111111111111" > + }) > + > +test:do_catchsql_test( > + "uuid-7.1.3", > + [[ > + SELECT cast(u AS NUMBER) FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to number" > + }) > + > +test:do_catchsql_test( > + "uuid-7.1.4", > + [[ > + SELECT cast(u AS DOUBLE) FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to double" > + }) > + > +test:do_catchsql_test( > + "uuid-7.1.5", > + [[ > + SELECT cast(u AS INTEGER) FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to integer" > + }) > + > +test:do_catchsql_test( > + "uuid-7.1.6", > + [[ > + SELECT cast(u AS BOOLEAN) FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to boolean" > + }) > + > +test:do_execsql_test( > + "uuid-7.1.7", > + [[ > + SELECT hex(cast(u AS VARBINARY)) FROM t2; > + ]], { > + "11111111111111111111111111111111", > + "11111111333311111111111111111111", > + "22222222111111111111111111111111" > + }) > + > +test:do_execsql_test( > + "uuid-7.1.8", > + [[ > + SELECT cast(u AS SCALAR) FROM t2; > + ]], { > + uuid1, uuid3, uuid2 > + }) > + > +test:do_execsql_test( > + "uuid-7.1.9", > + [[ > + SELECT cast(u AS UUID) FROM t2; > + ]], { > + uuid1, uuid3, uuid2 > + }) > + > +-- Check that explicit cast from another types to UUID works as intended. > +test:do_catchsql_test( > + "uuid-7.2.1", > + [[ > + SELECT cast(1 AS UUID); > + ]], { > + 1, "Type mismatch: can not convert 1 to uuid" > + }) > + > +test:do_execsql_test( > + "uuid-7.2.2", > + [[ > + SELECT cast('11111111-1111-1111-1111-111111111111' AS UUID); > + ]], { > + uuid1 > + }) > + > +test:do_catchsql_test( > + "uuid-7.2.3", > + [[ > + SELECT cast('1' AS UUID); > + ]], { > + 1, "Type mismatch: can not convert 1 to uuid" > + }) > + > +test:do_catchsql_test( > + "uuid-7.2.4", > + [[ > + SELECT cast(1.5 AS UUID); > + ]], { > + 1, "Type mismatch: can not convert 1.5 to uuid" > + }) > + > +test:do_catchsql_test( > + "uuid-7.2.5", > + [[ > + SELECT cast(-1 AS UUID); > + ]], { > + 1, "Type mismatch: can not convert -1 to uuid" > + }) > + > +test:do_catchsql_test( > + "uuid-7.2.6", > + [[ > + SELECT cast(true AS UUID); > + ]], { > + 1, "Type mismatch: can not convert TRUE to uuid" > + }) > + > +test:do_execsql_test( > + "uuid-7.2.7", > + [[ > + SELECT cast(x'11111111111111111111111111111111' AS UUID); > + ]], { > + uuid1 > + }) > + > +test:do_catchsql_test( > + "uuid-7.2.8", > + [[ > + SELECT cast(randomblob(10) as UUID) FROM t2 LIMIT 1; > + ]], { > + 1, "Type mismatch: can not convert varbinary to uuid" > + }) > + > +test:execsql([[ > + CREATE TABLE tu (id INT PRIMARY KEY AUTOINCREMENT, u UNSIGNED); > + CREATE TABLE ts (id INT PRIMARY KEY AUTOINCREMENT, s STRING); > + CREATE TABLE tn (id INT PRIMARY KEY AUTOINCREMENT, n NUMBER); > + CREATE TABLE td (id INT PRIMARY KEY AUTOINCREMENT, d DOUBLE); > + CREATE TABLE ti (id INT PRIMARY KEY AUTOINCREMENT, i INTEGER); > + CREATE TABLE tb (id INT PRIMARY KEY AUTOINCREMENT, b BOOLEAN); > + CREATE TABLE tv (id INT PRIMARY KEY AUTOINCREMENT, v VARBINARY); > + CREATE TABLE tsc (id INT PRIMARY KEY AUTOINCREMENT, sc SCALAR); > + CREATE TABLE tuu (id INT PRIMARY KEY AUTOINCREMENT, uu UUID); > + CREATE TABLE tsu (s STRING PRIMARY KEY, u UUID); > +]]) > + > +-- Check that implcit cast from UUID to another types works as intended. > +test:do_catchsql_test( > + "uuid-8.1.1", > + [[ > + INSERT INTO tu(u) SELECT u FROM t2; > + SELECT * FROM tu; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to unsigned" > + }) > + > +test:do_execsql_test( > + "uuid-8.1.2", > + [[ > + INSERT INTO ts(s) SELECT u FROM t2; > + SELECT * FROM ts; > + ]], { > + 1, "11111111-1111-1111-1111-111111111111", > + 2, "11111111-3333-1111-1111-111111111111", > + 3, "22222222-1111-1111-1111-111111111111" > + }) > + > +test:do_catchsql_test( > + "uuid-8.1.3", > + [[ > + INSERT INTO tn(n) SELECT u FROM t2; > + SELECT * FROM tn; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to number" > + }) > + > +test:do_catchsql_test( > + "uuid-8.1.4", > + [[ > + INSERT INTO td(d) SELECT u FROM t2; > + SELECT * FROM td; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to double" > + }) > + > +test:do_catchsql_test( > + "uuid-8.1.5", > + [[ > + INSERT INTO ti(i) SELECT u FROM t2; > + SELECT * FROM ti; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to integer" > + }) > + > +test:do_catchsql_test( > + "uuid-8.1.6", > + [[ > + INSERT INTO tb(b) SELECT u FROM t2; > + SELECT * FROM tb; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to boolean" > + }) > + > +test:do_execsql_test( > + "uuid-8.1.7", > + [[ > + INSERT INTO tv(v) SELECT u FROM t2; > + SELECT id, hex(v) FROM tv; > + ]], { > + 1, "11111111111111111111111111111111", > + 2, "11111111333311111111111111111111", > + 3, "22222222111111111111111111111111" > + }) > + > +test:do_execsql_test( > + "uuid-8.1.8", > + [[ > + INSERT INTO tsc(sc) SELECT u FROM t2; > + SELECT * FROM tsc; > + ]], { > + 1, uuid1, 2, uuid3, 3, uuid2 > + }) > + > +test:do_execsql_test( > + "uuid-8.1.9", > + [[ > + INSERT INTO tuu(uu) SELECT u FROM t2; > + SELECT * FROM tuu; > + ]], { > + 1, uuid1, 2, uuid3, 3, uuid2 > + }) > + > +-- Check that implicit cast from another types to UUID works as intended. > +test:do_catchsql_test( > + "uuid-8.2.1", > + [[ > + INSERT INTO tsu VALUES ('1_unsigned', 1); > + SELECT * FROM tsu ORDER BY s DESC LIMIT 1; > + ]], { > + 1, "Type mismatch: can not convert 1 to uuid" > + }) > + > +test:do_execsql_test( > + "uuid-8.2.2", > + [[ > + INSERT INTO tsu VALUES ('2_string_right', '11111111-1111-1111-1111-111111111111'); > + SELECT * FROM tsu ORDER BY s DESC LIMIT 1; > + ]], { > + '2_string_right', uuid1 > + }) > + > +test:do_catchsql_test( > + "uuid-8.2.3", > + [[ > + INSERT INTO tsu VALUES ('3_string_wrong', '1'); > + SELECT * FROM tsu ORDER BY s DESC LIMIT 1; > + ]], { > + 1, "Type mismatch: can not convert 1 to uuid" > + }) > + > +test:do_catchsql_test( > + "uuid-8.2.4", > + [[ > + INSERT INTO tsu VALUES ('4_double', 1.5); > + SELECT * FROM tsu ORDER BY s DESC LIMIT 1; > + ]], { > + 1, "Type mismatch: can not convert 1.5 to uuid" > + }) > + > +test:do_catchsql_test( > + "uuid-8.2.5", > + [[ > + INSERT INTO tsu VALUES ('5_integer', -1); > + SELECT * FROM tsu ORDER BY s DESC LIMIT 1; > + ]], { > + 1, "Type mismatch: can not convert -1 to uuid" > + }) > + > +test:do_catchsql_test( > + "uuid-8.2.6", > + [[ > + INSERT INTO tsu VALUES ('6_boolean', true); > + SELECT * FROM tsu ORDER BY s DESC LIMIT 1; > + ]], { > + 1, "Type mismatch: can not convert TRUE to uuid" > + }) > + > +test:do_execsql_test( > + "uuid-8.2.7", > + [[ > + INSERT INTO tsu SELECT '7_varbinary', x'11111111111111111111111111111111' FROM t2 LIMIT 1; > + SELECT * FROM tsu ORDER BY s DESC LIMIT 1; > + ]], { > + '7_varbinary', uuid1 > + }) > + > +test:do_catchsql_test( > + "uuid-8.2.8", > + [[ > + INSERT INTO tsu VALUES ('8_varbinary', randomblob(10)); > + SELECT * FROM tsu ORDER BY s DESC LIMIT 1; > + ]], { > + 1, "Type mismatch: can not convert varbinary to uuid" > + }) > + > +test:execsql([[ > + CREATE TABLE t9 (i INT PRIMARY KEY AUTOINCREMENT, u UUID); > + CREATE TABLE t9t (u UUID PRIMARY KEY); > + CREATE TRIGGER t AFTER INSERT ON t9 FOR EACH ROW BEGIN INSERT INTO t9t SELECT new.u; END; > +]]) > + > +-- Check that trigger can work with UUID. > +test:do_execsql_test( > + "uuid-9", > + [[ > + INSERT INTO t9(u) SELECT * FROM t2; > + SELECT * FROM t9t; > + ]], { > + uuid1, uuid3, uuid2 > + }) > + > +test:execsql([[ > + CREATE TABLE t10 (i INT PRIMARY KEY AUTOINCREMENT, u UUID DEFAULT '11111111-1111-1111-1111-111111111111'); > +]]) > + > +-- Check that INSERT into UUID field works. > +test:do_execsql_test( > + "uuid-10.1.1", > + [[ > + INSERT INTO t10 VALUES (1, '22222222-1111-1111-1111-111111111111'); > + SELECT * FROM t10 WHERE i = 1; > + ]], { > + 1, uuid2 > + }) > + > +test:do_execsql_test( > + "uuid-10.1.2", > + [[ > + INSERT INTO t10 VALUES (2, x'22222222111111111111111111111111'); > + SELECT * FROM t10 WHERE i = 2; > + ]], { > + 2, uuid2 > + }) > + > +test:do_execsql_test( > + "uuid-10.1.3", > + [[ > + INSERT INTO t10(i) VALUES (3); > + SELECT * FROM t10 WHERE i = 3; > + ]], { > + 3, uuid1 > + }) > + > +test:do_execsql_test( > + "uuid-10.1.4", > + [[ > + INSERT INTO t10 VALUES (4, NULL); > + SELECT * FROM t10 WHERE i = 4; > + ]], { > + 4, '' > + }) > + > +-- Check that UPDATE of UUID field works. > +test:do_execsql_test( > + "uuid-10.2.1", > + [[ > + UPDATE t10 SET u = '11111111-3333-1111-1111-111111111111' WHERE i = 1; > + SELECT * FROM t10 WHERE i = 1; > + ]], { > + 1, uuid3 > + }) > + > +test:do_execsql_test( > + "uuid-10.2.2", > + [[ > + UPDATE t10 SET u = x'11111111333311111111111111111111' WHERE i = 2; > + SELECT * FROM t10 WHERE i = 2; > + ]], { > + 2, uuid3 > + }) > + > +-- Check that JOIN by UUID field works. > +test:do_execsql_test( > + "uuid-11.1", > + [[ > + SELECT * FROM t1 JOIN t2 on t1.u = t2.u; > + ]], { > + 1, uuid1, uuid1, 2, uuid2, uuid2, 3, uuid3, uuid3, > + 4, uuid1, uuid1, 5, uuid1, uuid1, 6, uuid2, uuid2 > + }) > + > +test:do_execsql_test( > + "uuid-11.2", > + [[ > + SELECT * FROM t1 LEFT JOIN t2 on t1.u = t2.u; > + ]], { > + 1, uuid1, uuid1, 2, uuid2, uuid2, 3, uuid3, uuid3, > + 4, uuid1, uuid1, 5, uuid1, uuid1, 6, uuid2, uuid2 > + }) > + > +test:do_execsql_test( > + "uuid-11.3", > + [[ > + SELECT * FROM t1 INNER JOIN t2 on t1.u = t2.u; > + ]], { > + 1, uuid1, uuid1, 2, uuid2, uuid2, 3, uuid3, uuid3, > + 4, uuid1, uuid1, 5, uuid1, uuid1, 6, uuid2, uuid2 > + }) > + > +-- Check that arithmetic operations work with UUIDs as intended. > +test:do_catchsql_test( > + "uuid-12.1.1", > + [[ > + SELECT -u FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to numeric" > + }) > + > +test:do_catchsql_test( > + "uuid-12.1.2", > + [[ > + SELECT u + 1 FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to numeric" > + }) > + > +test:do_catchsql_test( > + "uuid-12.1.3", > + [[ > + SELECT u - 1 FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to numeric" > + }) > + > +test:do_catchsql_test( > + "uuid-12.1.4", > + [[ > + SELECT u * 1 FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to numeric" > + }) > + > +test:do_catchsql_test( > + "uuid-12.1.5", > + [[ > + SELECT u / 1 FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to numeric" > + }) > + > +test:do_catchsql_test( > + "uuid-12.1.6", > + [[ > + SELECT u % 1 FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to numeric" > + }) > + > +-- Check that bitwise operations work with UUIDs as intended. > +test:do_catchsql_test( > + "uuid-12.2.1", > + [[ > + SELECT ~u FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to integer" > + }) > + > +test:do_catchsql_test( > + "uuid-12.2.2", > + [[ > + SELECT u >> 1 FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to integer" > + }) > + > +test:do_catchsql_test( > + "uuid-12.2.3", > + [[ > + SELECT u << 1 FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to integer" > + }) > + > +test:do_catchsql_test( > + "uuid-12.2.4", > + [[ > + SELECT u | 1 FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to integer" > + }) > + > +test:do_catchsql_test( > + "uuid-12.2.5", > + [[ > + SELECT u & 1 FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to integer" > + }) > + > +-- Check that logical operations work with UUIDs as intended. > +test:do_catchsql_test( > + "uuid-12.3.1", > + [[ > + SELECT NOT u FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to boolean" > + }) > + > +test:do_catchsql_test( > + "uuid-12.3.2", > + [[ > + SELECT u AND true FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to boolean" > + }) > + > +test:do_catchsql_test( > + "uuid-12.3.3", > + [[ > + SELECT u OR true FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to boolean" > + }) > + > +test:do_catchsql_test( > + "uuid-12.3.4", > + [[ > + SELECT true AND u FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to boolean" > + }) > + > +test:do_catchsql_test( > + "uuid-12.3.5", > + [[ > + SELECT true OR u FROM t2; > + ]], { > + 1, "Type mismatch: can not convert 11111111-1111-1111-1111-111111111111 to boolean" > + }) > + > +-- Check that comparison with UUID works as intended. > +test:do_catchsql_test( > + "uuid-13.1.1", > + [[ > + SELECT u > 1 FROM t2; > + ]], { > + 1, "Type mismatch: can not convert unsigned to uuid" > + }) > + > +test:do_execsql_test( > + "uuid-13.1.2", > + [[ > + SELECT u > CAST('11111111-1111-1111-1111-111111111111' AS UUID) FROM t2; > + ]], { > + false, true, true > + }) > + > +test:do_catchsql_test( > + "uuid-13.1.3", > + [[ > + SELECT u > '1' FROM t2; > + ]], { > + 1, "Type mismatch: can not convert text to uuid" > + }) > + > +test:do_catchsql_test( > + "uuid-13.1.4", > + [[ > + SELECT u > 1.5 FROM t2; > + ]], { > + 1, "Type mismatch: can not convert real to uuid" > + }) > + > +test:do_catchsql_test( > + "uuid-13.1.5", > + [[ > + SELECT u > -1 FROM t2; > + ]], { > + 1, "Type mismatch: can not convert integer to uuid" > + }) > + > +test:do_catchsql_test( > + "uuid-13.1.6", > + [[ > + SELECT u > true FROM t2; > + ]], { > + 1, "Type mismatch: can not convert uuid to boolean" > + }) > + > +test:do_execsql_test( > + "uuid-13.1.7", > + [[ > + SELECT u > CAST(x'11111111111111111111111111111111' AS UUID) FROM t2; > + ]], { > + false, true, true > + }) > + > +test:do_catchsql_test( > + "uuid-13.1.8", > + [[ > + SELECT u > x'31' FROM t2; > + ]], { > + 1, "Type mismatch: can not convert varbinary to uuid" > + }) > + > +test:do_catchsql_test( > + "uuid-13.2.1", > + [[ > + SELECT u = 1 FROM t2; > + ]], { > + 1, "Type mismatch: can not convert unsigned to uuid" > + }) > + > +test:do_execsql_test( > + "uuid-13.2.2", > + [[ > + SELECT u = CAST('11111111-1111-1111-1111-111111111111' AS UUID) FROM t2; > + ]], { > + true, false, false > + }) > + > +test:do_catchsql_test( > + "uuid-13.2.3", > + [[ > + SELECT u = '1' FROM t2; > + ]], { > + 1, "Type mismatch: can not convert text to uuid" > + }) > + > +test:do_catchsql_test( > + "uuid-13.2.4", > + [[ > + SELECT u = 1.5 FROM t2; > + ]], { > + 1, "Type mismatch: can not convert real to uuid" > + }) > + > +test:do_catchsql_test( > + "uuid-13.2.5", > + [[ > + SELECT u = -1 FROM t2; > + ]], { > + 1, "Type mismatch: can not convert integer to uuid" > + }) > + > +test:do_catchsql_test( > + "uuid-13.2.6", > + [[ > + SELECT u = true FROM t2; > + ]], { > + 1, "Type mismatch: can not convert uuid to boolean" > + }) > + > +test:do_execsql_test( > + "uuid-13.2.7", > + [[ > + SELECT u = CAST(x'11111111111111111111111111111111' AS UUID) FROM t2; > + ]], { > + true, false, false > + }) > + > +test:do_catchsql_test( > + "uuid-13.2.8", > + [[ > + SELECT u = x'31' FROM t2; > + ]], { > + 1, "Type mismatch: can not convert varbinary to uuid" > + }) > + > +test:execsql([[ > + CREATE TABLE t14 (s SCALAR PRIMARY KEY); > +]]) > + > +-- Check that SCALAR field can contain UUID and use it in index. > +test:do_execsql_test( > + "uuid-14", > + [[ > + INSERT INTO t14 VALUES (1), (true), (1.5), (-1); > + INSERT INTO t14 VALUES (x'11111111111111111111111111111111'); > + INSERT INTO t14 VALUES (CAST(x'11111111111111111111111111111111' AS UUID)); > + INSERT INTO t14 VALUES ('11111111-1111-1111-1111-111111111111'); > + SELECT typeof(s) FROM t14; > + ]], { > + "boolean", "integer", "integer", "double", "string", "varbinary", "uuid" > + }) > + > +test:finish_test() > -- > 2.25.1 >