[Tarantool-patches] [PATCH v2 3/3] sql: updated implicit conversion table

Timur Safin tsafin at tarantool.org
Fri Jun 11 10:48:13 MSK 2021


* 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)
     ]], {
         -- <in4-2.6>
         "one", "two"
         -- </in4-2.6>
     })
 
+-- 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)
+    ]], {
+        -- <in4-2.6.1>
+        "one"
+        -- </in4-2.6.1>
+    })
+
 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(
         -- </4.2>
     })
 
-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
         -- </4.3>
     })
 
-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
         -- </4.4>
     })
 
@@ -279,23 +279,23 @@ test:do_execsql_test(
         -- </4.6>
     })
 
-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
         -- </4.7>
     })
 
-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
         -- </4.8>
     })
 
@@ -319,23 +319,23 @@ test:do_execsql_test(
         -- </5.2>
     })
 
-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"
+
         -- </5.3>
     })
 
-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"
+
         -- </5.4>
     })
 
@@ -349,13 +349,13 @@ test:do_execsql_test(
         -- </5.5>
     })
 
-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
         -- </5.6>
     })
 
@@ -379,23 +379,23 @@ test:do_execsql_test(
         -- </5.8>
     })
 
-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"
+
         -- </5.9>
     })
 
-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"
+
         -- </5.10>
     })
 
@@ -409,13 +409,13 @@ test:do_execsql_test(
         -- </5.11>
     })
 
-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
         -- </5.12>
     })
 
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



More information about the Tarantool-patches mailing list