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 A0A3F6EC55; Fri, 11 Jun 2021 10:49:59 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org A0A3F6EC55 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1623397799; bh=fLEiaGGKw7X/f6SEOc7pLT+59lpTuTec5WVy3WYPYms=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=RFRCnNvF67Mgby5K6LuuM9BpvphIPfP8gk4NK7/Q62EXLi+jc1NFPwpkupACZRRyn RaghxEFFOWpbltisXbY42fluv4W33bURdSJ3e+Gl48TUW3PvKhCxtDuVQIeYubApk9 VoLNNIFcQW3joE42ePJe5c/1vdAioa4JKkctiWDc= Received: from smtp58.i.mail.ru (smtp58.i.mail.ru [217.69.128.38]) (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 1AD076EC6E for ; Fri, 11 Jun 2021 10:48:30 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 1AD076EC6E Received: by smtp58.i.mail.ru with esmtpa (envelope-from ) id 1lrbu1-0001PD-1a; Fri, 11 Jun 2021 10:48:29 +0300 To: imeevma@tarantool.org Date: Fri, 11 Jun 2021 10:48:13 +0300 Message-Id: X-Mailer: git-send-email 2.29.2 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-7564579A: B8F34718100C35BD X-77F55803: 4F1203BC0FB41BD9D5B0DA836B685C549A9F97C297FFF2C725C7934AD8E7B4B9182A05F5380850408C2D6AA0346B973560E0C2D4D906DC235F1E78AB7B6C329E4A62FF2858136CC9 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7AED985C8E545F588EA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637FB2D77E6174520AE8638F802B75D45FF36EB9D2243A4F8B5A6FCA7DBDB1FC311F39EFFDF887939037866D6147AF826D8A209D73771337CF19096513B776774A3117882F4460429724CE54428C33FAD305F5C1EE8F4F765FC2EE5AD8F952D28FBA471835C12D1D9774AD6D5ED66289B52BA9C0B312567BB23117882F446042972877693876707352033AC447995A7AD18C26CFBAC0749D213D2E47CDBA5A96583BA9C0B312567BB2376E601842F6C81A19E625A9149C048EE3F735096452955E31AB2475877E8919AD8FC6C240DEA7642DBF02ECDB25306B2B78CF848AE20165D0A6AB1C7CE11FEE355C9F8201572E6EC6136E347CC761E07C4224003CC836476EA7A3FFF5B025636E2021AF6380DFAD1A18204E546F3947CB11811A4A51E3B096D1867E19FE1407959CC434672EE6371089D37D7C0E48F6C8AA50765F7900637BBEA499411984DA1EFF80C71ABB335746BA297DBC24807EABDAD6C7F3747799A X-B7AD71C0: AC4F5C86D027EB782CDD5689AFBDA7A24209795067102C07E8F7B195E1C97831784CCEFF0C784C6438E9427ECC4B679E X-C1DE0DAB: C20DE7B7AB408E4181F030C43753B8186998911F362727C414F749A5E30D975C8874A2D3FA5089FEE5E02E46A911F627AC328F0D317DDE499C2B6934AE262D3EE7EAB7254005DCED7532B743992DF240BDC6A1CF3F042BAD6DF99611D93F60EF31C0090ACECF247D699F904B3F4130E343918A1A30D5E7FCCB5012B2E24CD356 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D3433E9BC74ABA5769FAA1F7AD10869642351C3C8997FF17F319E4D3DE7D92421D7694D56247C699A8B1D7E09C32AA3244C4999DC95711B74B820CBA06E5F724DACE3D93501275E802FFACE5A9C96DEB163 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojCpYK6nkTlbEi1urangInYA== X-Mailru-Sender: 6CA451E36783D721CBEA96CEA26D325D022B9B16F44DDE47A9994187AC011AACB7CBEF92542CD7C82F97C478340294DCC77752E0C033A69E0F0C7111264B8915FF1320A92A5534336C18EFA0BB12DBB0 X-Mras: Ok Subject: [Tarantool-patches] [PATCH v2 3/3] sql: updated implicit conversion table 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: Timur Safin via Tarantool-patches Reply-To: Timur Safin Cc: tarantool-patches@dev.tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" * Changed implicit casts table according to consistent types RFC * fixed following directions for implicit conversions - string to double - double to integer - varbinary to string * got rid of mem_cast_implicit_old() as unnecessary, use always the updated mem_cast_implicit() * in addition to update of all relevant tests there is extended e_casts.test.lua used for checking of implicit conversion rules: * there is table information sanity check - e_casts.test.lua checks that implicit table content is sane, i.e. it's sort of symmetric for all defined combinations [from, to] * for the test we use inserts in specially crafted table as checks availability of implicit conversions between type values * Temporary TCASTS table used with sequence primary key * All fields of a form `{name = "unsigned", type = "unsigned", is_nullable = true}` used for all enabled types Relates to #5910, #6009 Closes #4470 * Additionally we have fixed unexpected results for sum of implicitly converted numbers Fixing unexpected results after implicit conversion to the signed or unsigned integer from well-formed string. ``` tarantool> box.execute([[select '1' + '2';]]) --- - metadata: - name: COLUMN_1 type: scalar rows: - [3] ... tarantool> box.execute([[select '1' + '-2';]]) --- - metadata: - name: COLUMN_1 type: scalar rows: - [18446744073709551615] ... tarantool> box.execute([[select '-1' + '-2';]]) --- - null - 'Failed to execute SQL statement: integer is overflowed' ... ``` Fixes #5756 --- src/box/sql/mem.c | 107 ++++----------------- src/box/sql/mem.h | 6 -- src/box/sql/util.c | 3 +- src/box/sql/vdbe.c | 8 +- src/box/sql/vdbeaux.c | 2 +- test/sql-tap/e_casts.test.lua | 136 ++++++++++++++++++++++++++- test/sql-tap/in4.test.lua | 17 +++- test/sql-tap/numcast.test.lua | 2 +- test/sql-tap/tkt-9a8b09f8e6.test.lua | 40 ++++---- test/sql/types.result | 104 ++++++++++---------- 10 files changed, 248 insertions(+), 177 deletions(-) diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c index 8bb6b672c..d6b114a81 100644 --- a/src/box/sql/mem.c +++ b/src/box/sql/mem.c @@ -1033,95 +1033,24 @@ mem_cast_implicit(struct Mem *mem, enum field_type type) } switch (type) { case FIELD_TYPE_UNSIGNED: - if (mem->type == MEM_TYPE_UINT) - return 0; - if (mem->type == MEM_TYPE_DOUBLE) - return double_to_uint(mem); - return -1; - 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) - return 0; - if ((mem->type & (MEM_TYPE_INT | MEM_TYPE_UINT)) != 0) - return int_to_double(mem); - return -1; - case FIELD_TYPE_INTEGER: if ((mem->type & (MEM_TYPE_INT | MEM_TYPE_UINT)) != 0) return 0; - if (mem->type == MEM_TYPE_DOUBLE) - return double_to_int(mem); - return -1; - case FIELD_TYPE_BOOLEAN: - if (mem->type == MEM_TYPE_BOOL) - return 0; - return -1; - case FIELD_TYPE_VARBINARY: - 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)) - return 0; - return -1; - case FIELD_TYPE_MAP: - if (mem->type == MEM_TYPE_MAP) - return 0; - return -1; - case FIELD_TYPE_ARRAY: - if (mem->type == MEM_TYPE_ARRAY) - return 0; - return -1; - case FIELD_TYPE_SCALAR: - 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: - break; - } - return -1; -} - -int -mem_cast_implicit_old(struct Mem *mem, enum field_type type) -{ - if (mem->type == MEM_TYPE_NULL) - return 0; - switch (type) { - case FIELD_TYPE_UNSIGNED: - if (mem->type == MEM_TYPE_UINT) - return 0; if (mem->type == MEM_TYPE_DOUBLE) return double_to_uint_precise(mem); if (mem->type == MEM_TYPE_STR) return bytes_to_uint(mem); return -1; case FIELD_TYPE_STRING: - if ((mem->type & (MEM_TYPE_STR | MEM_TYPE_BIN)) != 0) + if (mem->type == MEM_TYPE_STR) return 0; + if (mem->type == MEM_TYPE_UUID) + return uuid_to_str0(mem); if ((mem->type & (MEM_TYPE_INT | MEM_TYPE_UINT)) != 0) 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); + if (mem->type == MEM_TYPE_BIN) + return bin_to_str(mem); return -1; case FIELD_TYPE_DOUBLE: if (mem->type == MEM_TYPE_DOUBLE) @@ -1129,25 +1058,28 @@ mem_cast_implicit_old(struct Mem *mem, enum field_type type) if ((mem->type & (MEM_TYPE_INT | MEM_TYPE_UINT)) != 0) return int_to_double(mem); if (mem->type == MEM_TYPE_STR) - return bin_to_str(mem); + return bytes_to_double(mem); return -1; case FIELD_TYPE_INTEGER: if ((mem->type & (MEM_TYPE_INT | MEM_TYPE_UINT)) != 0) return 0; - if (mem->type == MEM_TYPE_STR) - return bytes_to_int(mem); if (mem->type == MEM_TYPE_DOUBLE) return double_to_int_precise(mem); + if (mem->type == MEM_TYPE_STR) + return bytes_to_int(mem); return -1; case FIELD_TYPE_BOOLEAN: if (mem->type == MEM_TYPE_BOOL) return 0; return -1; case FIELD_TYPE_VARBINARY: - if (mem->type == MEM_TYPE_BIN) + 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); + if (mem->type == MEM_TYPE_STR) + return str_to_bin(mem); return -1; case FIELD_TYPE_NUMBER: if (mem_is_num(mem)) @@ -1156,11 +1088,11 @@ mem_cast_implicit_old(struct Mem *mem, enum field_type type) return mem_to_number(mem); return -1; case FIELD_TYPE_MAP: - if (mem->type == MEM_TYPE_MAP) + if (mem_is_map(mem)) return 0; return -1; case FIELD_TYPE_ARRAY: - if (mem->type == MEM_TYPE_ARRAY) + if (mem_is_array(mem)) return 0; return -1; case FIELD_TYPE_SCALAR: @@ -1175,6 +1107,8 @@ mem_cast_implicit_old(struct Mem *mem, enum field_type type) if (mem->type == MEM_TYPE_BIN) return bin_to_uuid(mem); return -1; + case FIELD_TYPE_ANY: + return 0; default: break; } @@ -1460,7 +1394,7 @@ get_number(const struct Mem *mem, struct sql_num *number) if (mem->type == MEM_TYPE_INT) { number->i = mem->u.i; number->type = MEM_TYPE_INT; - number->is_neg = true; + number->is_neg = mem->u.i < 0; return 0; } if (mem->type == MEM_TYPE_UINT) { @@ -1473,13 +1407,6 @@ get_number(const struct Mem *mem, struct sql_num *number) return -1; if (sql_atoi64(mem->z, &number->i, &number->is_neg, mem->n) == 0) { number->type = number->is_neg ? MEM_TYPE_INT : MEM_TYPE_UINT; - /* - * The next line should be removed along with the is_neg field - * of struct sql_num. The integer type tells us about the sign. - * However, if it is removed, the behavior of arithmetic - * operations will change. - */ - number->is_neg = false; return 0; } if (sqlAtoF(mem->z, &number->d, mem->n) != 0) { diff --git a/src/box/sql/mem.h b/src/box/sql/mem.h index b3cd5c545..706cad43c 100644 --- a/src/box/sql/mem.h +++ b/src/box/sql/mem.h @@ -753,12 +753,6 @@ mem_cast_explicit(struct Mem *mem, enum field_type type); int mem_cast_implicit(struct Mem *mem, enum field_type type); -/** - * Convert the given MEM to given type according to legacy implicit cast rules. - */ -int -mem_cast_implicit_old(struct Mem *mem, enum field_type type); - /** * Return value for MEM of INTEGER type. For MEM of all other types convert * value of the MEM to INTEGER if possible and return converted value. Original diff --git a/src/box/sql/util.c b/src/box/sql/util.c index c556b9815..69b1a3937 100644 --- a/src/box/sql/util.c +++ b/src/box/sql/util.c @@ -958,9 +958,8 @@ sql_add_int(int64_t lhs, bool is_lhs_neg, int64_t rhs, bool is_rhs_neg, *res = lhs + rhs; return 0; } - *is_res_neg = is_rhs_neg ? (uint64_t)(-rhs) > (uint64_t) lhs : - (uint64_t)(-lhs) > (uint64_t) rhs; *res = lhs + rhs; + *is_res_neg = *res < 0; return 0; } diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 32d02d96e..0dc28e2d6 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -1660,7 +1660,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ } else if (type == FIELD_TYPE_STRING) { if (mem_cmp_str(pIn3, pIn1, &res, pOp->p4.pColl) != 0) { const char *str = - mem_cast_implicit_old(pIn3, type) != 0 ? + mem_cast_implicit(pIn3, type) != 0 ? mem_str(pIn3) : mem_str(pIn1); diag_set(ClientError, ER_SQL_TYPE_MISMATCH, str, "string"); @@ -1671,7 +1671,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ type = FIELD_TYPE_NUMBER; if (mem_cmp_num(pIn3, pIn1, &res) != 0) { const char *str = - mem_cast_implicit_old(pIn3, type) != 0 ? + mem_cast_implicit(pIn3, type) != 0 ? mem_str(pIn3) : mem_str(pIn1); diag_set(ClientError, ER_SQL_TYPE_MISMATCH, str, "numeric"); @@ -1682,7 +1682,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ assert(mem_is_str(pIn3) && mem_is_same_type(pIn3, pIn1)); if (mem_cmp_str(pIn3, pIn1, &res, pOp->p4.pColl) != 0) { const char *str = - mem_cast_implicit_old(pIn3, type) != 0 ? + mem_cast_implicit(pIn3, type) != 0 ? mem_str(pIn3) : mem_str(pIn1); diag_set(ClientError, ER_SQL_TYPE_MISMATCH, str, "string"); @@ -2218,7 +2218,7 @@ case OP_MakeRecord: { if (types != NULL) { pRec = pData0; do { - mem_cast_implicit_old(pRec++, *(types++)); + mem_cast_implicit(pRec++, *(types++)); } while(types[0] != field_type_MAX); } diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c index 4a1fdb637..c8e242c2f 100644 --- a/src/box/sql/vdbeaux.c +++ b/src/box/sql/vdbeaux.c @@ -2332,7 +2332,7 @@ sqlVdbeGetBoundValue(Vdbe * v, int iVar, u8 aff) sql_value *pRet = sqlValueNew(v->db); if (pRet) { mem_copy(pRet, pMem); - mem_cast_implicit_old(pRet, aff); + mem_cast_implicit(pRet, aff); } return pRet; } diff --git a/test/sql-tap/e_casts.test.lua b/test/sql-tap/e_casts.test.lua index 32d7e8e0c..952572921 100755 --- a/test/sql-tap/e_casts.test.lua +++ b/test/sql-tap/e_casts.test.lua @@ -2,7 +2,7 @@ local tap = require("tap") local test = tap.test("errno") -test:plan(1) +test:plan(3) local yaml = require("yaml") local ffi = require("ffi") @@ -137,6 +137,22 @@ local explicit_casts_table_spec = { [t_scalar] = {"Y", "S", "Y", "S", "S", "S", "S", "S", "S", "S", "" , "" , "Y"}, } +local implicit_casts_table_spec = { + [t_any] = {"Y", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S"}, + [t_unsigned]= {"Y", "Y", "Y", "Y", "Y", "" , "" , "Y", "Y", "" , "" , "" , "Y"}, + [t_string] = {"Y", "S", "Y", "S", "S", "" , "Y", "S", "S", "S", "" , "" , "Y"}, + [t_double] = {"Y", "S", "Y", "Y", "S", "" , "" , "Y", "Y", "" , "" , "" , "Y"}, + [t_integer] = {"Y", "S", "Y", "Y", "Y", "" , "" , "Y", "Y", "" , "" , "" , "Y"}, + [t_boolean] = {"Y", "" , "" , "" , "" , "Y", "" , "" , "" , "" , "" , "" , "Y"}, + [t_varbinary]={"Y", "" , "Y", "" , "" , "" , "Y", "" , "" , "S", "" , "" , "Y"}, + [t_number] = {"Y", "S", "Y", "Y", "S", "" , "" , "Y", "Y", "" , "" , "" , "Y"}, + [t_decimal] = {"Y", "S", "Y", "S", "S", "" , "" , "Y", "Y", "" , "" , "" , "Y"}, + [t_uuid] = {"Y", "" , "Y", "" , "" , "" , "Y", "" , "" , "Y", "" , "" , "Y"}, + [t_array] = {"Y", "" , "" , "" , "" , "" , "" , "" , "" , "" , "Y", "" , "" }, + [t_map] = {"Y", "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "Y", "" }, + [t_scalar] = {"Y", "S", "S", "S", "S", "S", "S", "S", "S", "S", "" , "" , "S"}, +} + local c_no = 0 local c_maybe = 1 local c_yes = 2 @@ -207,9 +223,31 @@ local function show_casts_table(table) end local explicit_casts = load_casts_spec(explicit_casts_table_spec, enabled_type, enabled_type_cast) +local implicit_casts = load_casts_spec(implicit_casts_table_spec, enabled_type, enabled_type) if verbose > 0 then show_casts_table(explicit_casts) + show_casts_table(implicit_casts) +end + +-- 0. check consistency of input conversion table + +-- implicit conversion table is considered consistent if +-- it's sort of symmetric against diagonal +-- (not necessary that always/sometimes are matching +-- but at least something should be presented) +local function test_check_table_consistency(test) + test:plan(169) + for _, from in ipairs(proper_order) do + for _, to in ipairs(proper_order) do + test:ok((normalize_cast(implicit_casts[from][to]) ~= c_no) == + (normalize_cast(implicit_casts[to][from]) ~= c_no), + label_for(from, to, + string.format("%s ~= %s", + implicit_casts[from][to], + implicit_casts[to][from]))) + end + end end local function merge_tables(...) @@ -334,7 +372,103 @@ local function test_check_explicit_casts(test) end end +local table_name = 'TCASTS' + +local function _created_formatted_space(name) + local space = box.schema.space.create(name) + space:create_index('pk', {sequence = true}) + local format = {{name = 'ID', type = 'unsigned', is_nullable = false}} + for _, type_id in ipairs(proper_order) do + if enabled_type[type_id] then + local type_name = type_names[type_id] + table.insert(format, {name = type_name, type = type_name, is_nullable = true}) + end + end + if #format > 0 then + space:format(format) + end + return space +end + +local function _cleanup_space(space) + space:drop() +end + +-- implicit +local function gen_implicit_insert_from_to(table_name, from, to) + local queries = {} + local from_exprs = gen_type_exprs(from) + for _, from_e in pairs(from_exprs) do + table.insert(queries, + string.format([[ insert into %s("%s") values(%s); ]], + table_name, type_names[to], from_e)) + end + return queries +end + + +-- 2. Check implicit casts table +local function test_check_implicit_casts(test) + test:plan(186) + local space = _created_formatted_space(table_name) + -- checking validity of all `from binop to` combinations + for _, from in ipairs(proper_order) do + for _, to in ipairs(proper_order) do + -- skip ANY, DECIMAL, UUID, etc. + if enabled_type[from] and enabled_type[to] then + local gen = gen_implicit_insert_from_to(table_name, from, to) + local failures = {} + local successes = {} + local castable = false + local expected = implicit_casts[from][to] + + if verbose > 0 then + print(expected, yaml.encode(gen)) + end + + for _, v in pairs(gen) do + local ok, result + ok, result = catch_query(v) + + if verbose > 0 then + print(string.format("V> ok = %s, result = %s, query = %s", + ok, result, v)) + end + + local title = string.format("%s => %s", v, human_cast(expected)) + if expected == c_yes then + test:ok(true == ok, label_for(from, to, title)) + elseif expected == c_no then + test:ok(false == ok, label_for(from, to, title)) + else + -- we can't report immediately for c_maybe because some + -- cases allowed to fail, so postpone decision + if ok then + castable = true + table.insert(successes, {result, v}) + else + table.insert(failures, {result, v}) + end + end + end + + -- ok, we aggregated stats for c_maybe mode - check it now + if expected == c_maybe then + local title = string.format("%s => %s", + #gen and gen[1]..'...' or '', + human_cast(expected)) + test:ok(castable, label_for(from, to, title), + failures) + end + end + end + end + _cleanup_space(space) +end + +test:test("e_casts - check consistency of implicit conversion table", test_check_table_consistency) test:test("e_casts - check explicit casts", test_check_explicit_casts) +test:test("e_casts - check implicit casts", test_check_implicit_casts) test:check() os.exit() diff --git a/test/sql-tap/in4.test.lua b/test/sql-tap/in4.test.lua index 588daefec..6aeaff5d5 100755 --- a/test/sql-tap/in4.test.lua +++ b/test/sql-tap/in4.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool local test = require("sqltester") -test:plan(52) +test:plan(53) --!./tcltestrunner.lua -- 2008 September 1 @@ -128,15 +128,26 @@ test:do_execsql_test( }) test:do_execsql_test( - "in4-2.6", + "in4-2.6.0", [[ - SELECT b FROM t2 WHERE a IN (1.0, 2.1) + SELECT b FROM t2 WHERE a IN (1.0, 2.0) ]], { -- "one", "two" -- }) +-- FIXME - IN [2.1] should convert to expected type of a +test:do_execsql_test( + "in4-2.6.1", + [[ + SELECT b FROM t2 WHERE a IN (1.0, 2.1) + ]], { + -- + "one" + -- + }) + test:do_execsql_test( "in4-2.7", [[ diff --git a/test/sql-tap/numcast.test.lua b/test/sql-tap/numcast.test.lua index 6ca1316d5..798b2dc77 100755 --- a/test/sql-tap/numcast.test.lua +++ b/test/sql-tap/numcast.test.lua @@ -139,7 +139,7 @@ test:do_catchsql_test( test:do_execsql_test( "cast-2.9", [[ - INSERT INTO t VALUES(2.1); + INSERT INTO t VALUES(2.0); SELECT * FROM t; ]], { 2, 9223372036854775808ULL, 18000000000000000000ULL diff --git a/test/sql-tap/tkt-9a8b09f8e6.test.lua b/test/sql-tap/tkt-9a8b09f8e6.test.lua index 67d6a1ccd..8ecf9f914 100755 --- a/test/sql-tap/tkt-9a8b09f8e6.test.lua +++ b/test/sql-tap/tkt-9a8b09f8e6.test.lua @@ -239,23 +239,23 @@ test:do_execsql_test( -- }) -test:do_catchsql_test( +test:do_execsql_test( 4.3, [[ SELECT x FROM t3 WHERE x IN ('1'); ]], { -- <4.3> - 1, "Type mismatch: can not convert 1 to number" + 1.0 -- }) -test:do_catchsql_test( +test:do_execsql_test( 4.4, [[ SELECT x FROM t3 WHERE x IN ('1.0'); ]], { -- <4.4> - 1, "Type mismatch: can not convert 1.0 to number" + 1.0 -- }) @@ -279,23 +279,23 @@ test:do_execsql_test( -- }) -test:do_catchsql_test( +test:do_execsql_test( 4.7, [[ SELECT x FROM t3 WHERE '1' IN (x); ]], { -- <4.7> - 1, "Type mismatch: can not convert 1 to number" + 1.0 -- }) -test:do_catchsql_test( +test:do_execsql_test( 4.8, [[ SELECT x FROM t3 WHERE '1.0' IN (x); ]], { -- <4.8> - 1, "Type mismatch: can not convert 1.0 to number" + 1.0 -- }) @@ -319,23 +319,23 @@ test:do_execsql_test( -- }) -test:do_catchsql_test( +test:do_execsql_test( 5.3, [[ SELECT x FROM t4 WHERE x IN ('1'); ]], { -- <5.3> - 1, "Type mismatch: can not convert 1 to number" + -- }) -test:do_catchsql_test( +test:do_execsql_test( 5.4, [[ SELECT x FROM t4 WHERE x IN ('1.0'); ]], { -- <5.4> - 1, "Type mismatch: can not convert 1.0 to number" + -- }) @@ -349,13 +349,13 @@ test:do_execsql_test( -- }) -test:do_catchsql_test( +test:do_execsql_test( 5.6, [[ SELECT x FROM t4 WHERE x IN ('1.11'); ]], { -- <5.6> - 1, "Type mismatch: can not convert 1.11 to number" + 1.11 -- }) @@ -379,23 +379,23 @@ test:do_execsql_test( -- }) -test:do_catchsql_test( +test:do_execsql_test( 5.9, [[ SELECT x FROM t4 WHERE '1' IN (x); ]], { -- <5.9> - 1, "Type mismatch: can not convert 1 to number" + -- }) -test:do_catchsql_test( +test:do_execsql_test( 5.10, [[ SELECT x FROM t4 WHERE '1.0' IN (x); ]], { -- <5.10> - 1, "Type mismatch: can not convert 1.0 to number" + -- }) @@ -409,13 +409,13 @@ test:do_execsql_test( -- }) -test:do_catchsql_test( +test:do_execsql_test( 5.12, [[ SELECT x FROM t4 WHERE '1.11' IN (x); ]], { -- <5.12> - 1, "Type mismatch: can not convert 1.11 to number" + 1.11 -- }) diff --git a/test/sql/types.result b/test/sql/types.result index 90a8bc5ec..20dbd2073 100644 --- a/test/sql/types.result +++ b/test/sql/types.result @@ -1059,7 +1059,8 @@ box.execute("INSERT INTO t1 VALUES (0), (1), (2);") box.execute("INSERT INTO t1 VALUES (-3);") --- - null -- 'Type mismatch: can not convert -3 to unsigned' +- 'Tuple field 1 (ID) type does not match one required by operation: expected unsigned, + got integer' ... box.execute("SELECT id FROM t1;") --- @@ -1224,12 +1225,13 @@ box.execute("INSERT INTO t VALUES(1, true);") ... box.execute("INSERT INTO t VALUES(1, 'asd');") --- -- null -- 'Type mismatch: can not convert asd to varbinary' +- row_count: 1 ... box.execute("INSERT INTO t VALUES(1, x'616263');") --- -- row_count: 1 +- null +- Duplicate key exists in unique index "pk_unnamed_T_1" in space "T" with old tuple + - [1, "asd"] and new tuple - [1, "abc"] ... box.execute("SELECT * FROM t WHERE v = 1") --- @@ -1253,8 +1255,7 @@ box.execute("SELECT * FROM t WHERE v = x'616263'") type: integer - name: V type: varbinary - rows: - - [1, 'abc'] + rows: [] ... box.execute("SELECT sum(v) FROM t;") --- @@ -1277,7 +1278,7 @@ box.execute("SELECT min(v) FROM t;") - name: COLUMN_1 type: scalar rows: - - ['abc'] + - ['asd'] ... box.execute("SELECT max(v) FROM t;") --- @@ -1285,7 +1286,7 @@ box.execute("SELECT max(v) FROM t;") - name: COLUMN_1 type: scalar rows: - - ['abc'] + - ['asd'] ... box.execute("SELECT count(v) FROM t;") --- @@ -1301,7 +1302,7 @@ box.execute("SELECT group_concat(v) FROM t;") - name: COLUMN_1 type: string rows: - - ['abc'] + - ['asd'] ... box.execute("SELECT lower(v) FROM t;") --- @@ -1332,7 +1333,7 @@ box.execute("SELECT quote(v) FROM t;") - name: COLUMN_1 type: string rows: - - ['X''616263'''] + - ['X''617364'''] ... box.execute("SELECT LEAST(v, x'') FROM t;") --- @@ -1351,8 +1352,7 @@ box.execute("SELECT v FROM t WHERE v = x'616263';") - metadata: - name: V type: varbinary - rows: - - ['abc'] + rows: [] ... box.execute("SELECT v FROM t ORDER BY v;") --- @@ -1360,11 +1360,11 @@ box.execute("SELECT v FROM t ORDER BY v;") - name: V type: varbinary rows: - - ['abc'] + - ['asd'] ... box.execute("UPDATE t SET v = x'636261' WHERE v = x'616263';") --- -- row_count: 1 +- row_count: 0 ... box.execute("SELECT v FROM t;") --- @@ -1372,7 +1372,7 @@ box.execute("SELECT v FROM t;") - name: V type: varbinary rows: - - ['cba'] + - ['asd'] ... box.execute("CREATE TABLE parent (id INT PRIMARY KEY, a VARBINARY UNIQUE);") --- @@ -2206,8 +2206,9 @@ box.execute([[INSERT INTO ti(i) VALUES (true);]]) ... box.execute([[INSERT INTO ti(i) VALUES ('33');]]) --- -- null -- 'Type mismatch: can not convert 33 to integer' +- autoincrement_ids: + - 4 + row_count: 1 ... box.execute([[INSERT INTO ti(i) VALUES (X'3434');]]) --- @@ -2225,6 +2226,7 @@ box.execute([[SELECT * FROM ti;]]) - [1, null] - [2, 11] - [3, 33] + - [4, 33] ... box.execute([[INSERT INTO td(d) VALUES (NULL);]]) --- @@ -2256,8 +2258,9 @@ box.execute([[INSERT INTO td(d) VALUES (true);]]) ... box.execute([[INSERT INTO td(d) VALUES ('33');]]) --- -- null -- 'Type mismatch: can not convert 33 to double' +- autoincrement_ids: + - 4 + row_count: 1 ... box.execute([[INSERT INTO td(d) VALUES (X'3434');]]) --- @@ -2275,6 +2278,7 @@ box.execute([[SELECT * FROM td;]]) - [1, null] - [2, 11] - [3, 22.2] + - [4, 33] ... box.execute([[INSERT INTO tb(b) VALUES (NULL);]]) --- @@ -2327,13 +2331,15 @@ box.execute([[INSERT INTO tt(t) VALUES (NULL);]]) ... box.execute([[INSERT INTO tt(t) VALUES (11);]]) --- -- null -- 'Type mismatch: can not convert 11 to string' +- autoincrement_ids: + - 2 + row_count: 1 ... box.execute([[INSERT INTO tt(t) VALUES (22.2);]]) --- -- null -- 'Type mismatch: can not convert 22.2 to string' +- autoincrement_ids: + - 3 + row_count: 1 ... box.execute([[INSERT INTO tt(t) VALUES (true);]]) --- @@ -2343,13 +2349,14 @@ box.execute([[INSERT INTO tt(t) VALUES (true);]]) box.execute([[INSERT INTO tt(t) VALUES ('33');]]) --- - autoincrement_ids: - - 2 + - 4 row_count: 1 ... box.execute([[INSERT INTO tt(t) VALUES (X'3434');]]) --- -- null -- 'Type mismatch: can not convert varbinary to string' +- autoincrement_ids: + - 5 + row_count: 1 ... box.execute([[SELECT * FROM tt;]]) --- @@ -2360,7 +2367,10 @@ box.execute([[SELECT * FROM tt;]]) type: string rows: - [1, null] - - [2, '33'] + - [2, '11'] + - [3, '22.2'] + - [4, '33'] + - [5, '44'] ... box.execute([[INSERT INTO tv(v) VALUES (NULL);]]) --- @@ -2385,13 +2395,14 @@ box.execute([[INSERT INTO tv(v) VALUES (true);]]) ... box.execute([[INSERT INTO tv(v) VALUES ('33');]]) --- -- null -- 'Type mismatch: can not convert 33 to varbinary' +- autoincrement_ids: + - 2 + row_count: 1 ... box.execute([[INSERT INTO tv(v) VALUES (X'3434');]]) --- - autoincrement_ids: - - 2 + - 3 row_count: 1 ... box.execute([[SELECT * FROM tv;]]) @@ -2403,7 +2414,8 @@ box.execute([[SELECT * FROM tv;]]) type: varbinary rows: - [1, null] - - [2, '44'] + - [2, '33'] + - [3, '44'] ... box.execute([[INSERT INTO ts(s) VALUES (NULL);]]) --- @@ -2459,11 +2471,11 @@ box.execute([[SELECT * FROM ts;]]) -- Check for UPDATE. box.execute([[DELETE FROM ti;]]) --- -- row_count: 3 +- row_count: 4 ... box.execute([[DELETE FROM td;]]) --- -- row_count: 3 +- row_count: 4 ... box.execute([[DELETE FROM tb;]]) --- @@ -2471,11 +2483,11 @@ box.execute([[DELETE FROM tb;]]) ... box.execute([[DELETE FROM tt;]]) --- -- row_count: 2 +- row_count: 5 ... box.execute([[DELETE FROM tv;]]) --- -- row_count: 2 +- row_count: 3 ... box.execute([[DELETE FROM ts;]]) --- @@ -2559,8 +2571,7 @@ box.execute([[UPDATE ti SET i = true WHERE a = 1;]]) ... box.execute([[UPDATE ti SET i = '33' WHERE a = 1;]]) --- -- null -- 'Type mismatch: can not convert 33 to integer' +- row_count: 1 ... box.execute([[UPDATE ti SET i = X'3434' WHERE a = 1;]]) --- @@ -2600,8 +2611,7 @@ box.execute([[UPDATE td SET d = true WHERE a = 1;]]) ... box.execute([[UPDATE td SET d = '33' WHERE a = 1;]]) --- -- null -- 'Type mismatch: can not convert 33 to double' +- row_count: 1 ... box.execute([[UPDATE td SET d = X'3434' WHERE a = 1;]]) --- @@ -2616,7 +2626,7 @@ box.execute([[SELECT * FROM td;]]) - name: D type: double rows: - - [1, 22.2] + - [1, 33] ... box.execute([[UPDATE tb SET b = NULL WHERE a = 1;]]) --- @@ -2662,13 +2672,11 @@ box.execute([[UPDATE tt SET t = NULL WHERE a = 1;]]) ... box.execute([[UPDATE tt SET t = 11 WHERE a = 1;]]) --- -- null -- 'Type mismatch: can not convert 11 to string' +- row_count: 1 ... box.execute([[UPDATE tt SET t = 22.2 WHERE a = 1;]]) --- -- null -- 'Type mismatch: can not convert 22.2 to string' +- row_count: 1 ... box.execute([[UPDATE tt SET t = true WHERE a = 1;]]) --- @@ -2681,8 +2689,7 @@ box.execute([[UPDATE tt SET t = '33' WHERE a = 1;]]) ... box.execute([[UPDATE tt SET t = X'3434' WHERE a = 1;]]) --- -- null -- 'Type mismatch: can not convert varbinary to string' +- row_count: 1 ... box.execute([[SELECT * FROM tt;]]) --- @@ -2692,7 +2699,7 @@ box.execute([[SELECT * FROM tt;]]) - name: T type: string rows: - - [1, '33'] + - [1, '44'] ... box.execute([[UPDATE tv SET v = NULL WHERE a = 1;]]) --- @@ -2715,8 +2722,7 @@ box.execute([[UPDATE tv SET v = true WHERE a = 1;]]) ... box.execute([[UPDATE tv SET v = '33' WHERE a = 1;]]) --- -- null -- 'Type mismatch: can not convert 33 to varbinary' +- row_count: 1 ... box.execute([[UPDATE tv SET v = X'3434' WHERE a = 1;]]) --- -- 2.29.2