From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id CC588225C2 for ; Wed, 24 Jul 2019 04:12:03 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id WU7mVLlRvIkp for ; Wed, 24 Jul 2019 04:12:03 -0400 (EDT) Received: from smtpng3.m.smailru.net (smtpng3.m.smailru.net [94.100.177.149]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id 8A61222662 for ; Wed, 24 Jul 2019 04:12:03 -0400 (EDT) From: imeevma@tarantool.org Subject: [tarantool-patches] [PATCH v2 1/2] sql: add ARRAY, MAP and ANY types to mem_apply_type() Date: Wed, 24 Jul 2019 11:12:01 +0300 Message-Id: In-Reply-To: References: Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-Help: List-Unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-Subscribe: List-Owner: List-post: List-Archive: To: korablev@tarantool.org Cc: tarantool-patches@freelists.org Function mem_apply_type() implements implicit type conversion. As a rule, tuple to be inserted to the space is exposed to this conversion which is invoked during execution of OP_MakeRecord opcode (which in turn forms tuple). This function was not adjusted to operate on ARRAY, MAP and ANY field types since they are poorly supported in current SQL implementation. Hence, when tuple to be inserted in space having mentioned field types reaches this function, it results in error. Note that we can't set ARRAY or MAP types in SQL, but such situation may appear during UPDATE operation on space created via Lua interface. This problem is solved by extending implicit type conversions with obvious casts: array field can be casted to array, map to map and any to any. Closes #4189 --- src/box/sql/vdbe.c | 35 ++++++++++++++++++++++++++++++++++- test/sql/types.result | 40 ++++++++++++++++++++++++++++++++++++++++ test/sql/types.test.lua | 15 +++++++++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 6a4a303..1200ff4 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -292,7 +292,19 @@ mem_apply_numeric_type(struct Mem *record) * Convert mem to a string representation. * * SCALAR: - * Mem is unchanged, but flag is set to BLOB. + * Mem is unchanged, but flag is set to BLOB in case of + * scalar-like type. Otherwise, (MAP, ARRAY) conversion + * is impossible. + * + * BOOLEAN: + * If memory holds BOOLEAN no actions take place. + * + * ANY: + * Mem is unchanged, no actions take place. + * + * MAP/ARRAY: + * These types can't be casted to scalar ones, or to each + * other. So the only valid conversion is to type itself. * * @param record The value to apply type to. * @param type The type to be applied. @@ -338,6 +350,27 @@ mem_apply_type(struct Mem *record, enum field_type type) record->flags &= ~(MEM_Real | MEM_Int); return 0; case FIELD_TYPE_SCALAR: + /* Can't cast MAP and ARRAY to scalar types. */ + if ((record->flags & MEM_Subtype) != 0 && + record->subtype == SQL_SUBTYPE_MSGPACK) { + assert(mp_typeof(*record->z) == MP_MAP || + mp_typeof(*record->z) == MP_ARRAY); + return -1; + } + return 0; + case FIELD_TYPE_MAP: + if ((record->flags & MEM_Subtype) != 0 && + record->subtype == SQL_SUBTYPE_MSGPACK && + mp_typeof(*record->z) == MP_MAP) + return 0; + return -1; + case FIELD_TYPE_ARRAY: + if ((record->flags & MEM_Subtype) != 0 && + record->subtype == SQL_SUBTYPE_MSGPACK && + mp_typeof(*record->z) == MP_ARRAY) + return 0; + return -1; + case FIELD_TYPE_ANY: return 0; default: return -1; diff --git a/test/sql/types.result b/test/sql/types.result index 5abe6e0..0dba69f 100644 --- a/test/sql/types.result +++ b/test/sql/types.result @@ -1110,6 +1110,46 @@ box.execute("SELECT a FROM t1 WHERE a IN (1.1, 2.1);") type: unsigned rows: [] ... +-- +-- gh-4189: make sure that update doesn't throw an error if format +-- of table features map/array field types. +-- +format = {} +--- +... +format[1] = {type = 'integer', name = 'I'} +--- +... +format[2] = {type = 'boolean', name = 'B'} +--- +... +format[3] = {type = 'array', name = 'F1'} +--- +... +format[4] = {type = 'map', name = 'F2'} +--- +... +format[5] = {type = 'any', name = 'F3'} +--- +... +s = box.schema.space.create('T', {format = format}) +--- +... +ii = s:create_index('ii') +--- +... +s:insert({1, true, {1, 2}, {a = 3}, 'asd'}) +--- +- [1, true, [1, 2], {'a': 3}, 'asd'] +... +box.execute('UPDATE t SET b = false WHERE i = 1;') +--- +- row_count: 1 +... +s:select() +--- +- - [1, false, [1, 2], {'a': 3}, 'asd'] +... s:drop() --- ... diff --git a/test/sql/types.test.lua b/test/sql/types.test.lua index 410864a..22cb105 100644 --- a/test/sql/types.test.lua +++ b/test/sql/types.test.lua @@ -275,4 +275,19 @@ _ = s:create_index('sk', { parts = { 'A' } }) s:insert({ 1, 1 }) box.execute("SELECT a FROM t1 WHERE a IN (1.1, 2.1);") +-- +-- gh-4189: make sure that update doesn't throw an error if format +-- of table features map/array field types. +-- +format = {} +format[1] = {type = 'integer', name = 'I'} +format[2] = {type = 'boolean', name = 'B'} +format[3] = {type = 'array', name = 'F1'} +format[4] = {type = 'map', name = 'F2'} +format[5] = {type = 'any', name = 'F3'} +s = box.schema.space.create('T', {format = format}) +ii = s:create_index('ii') +s:insert({1, true, {1, 2}, {a = 3}, 'asd'}) +box.execute('UPDATE t SET b = false WHERE i = 1;') +s:select() s:drop() -- 2.7.4