Tarantool development patches archive
 help / color / mirror / Atom feed
* [Tarantool-patches] [PATCH 0/6] Remove implicit cast
@ 2020-05-28 14:17 Mergen Imeev
  2020-05-28 14:17 ` [Tarantool-patches] [PATCH 1/6] sql: remove implicit cast for assignment Mergen Imeev
                   ` (6 more replies)
  0 siblings, 7 replies; 21+ messages in thread
From: Mergen Imeev @ 2020-05-28 14:17 UTC (permalink / raw)
  To: v.shpilevoy, tsafin, tarantool-patches

This patch-set removes implicit cast between string and numbers
for assignment and for comparison.

https://github.com/tarantool/tarantool/issues/3809
https://github.com/tarantool/tarantool/issues/4230
https://github.com/tarantool/tarantool/tree/imeevma/gh-3809-disallow-imlicit-cast-from-string-to-nums

Mergen Imeev (6):
  sql: remove implicit cast for assignment
  sql: remove mem_apply_type() from OP_MakeRecord
  sql: replace ApplyType by CheckType for IN operator
  sql: remove mem_apply_type() from OP_MustBeInt
  sql: remove implicit cast from string for comparison
  sql: remove OP_ApplyType

 src/box/sql/analyze.c                         |   7 +-
 src/box/sql/delete.c                          |   8 +-
 src/box/sql/expr.c                            |  40 +-
 src/box/sql/fk_constraint.c                   |   9 +-
 src/box/sql/insert.c                          |   2 +-
 src/box/sql/select.c                          |  25 +-
 src/box/sql/sqlInt.h                          |  13 -
 src/box/sql/update.c                          |  14 +-
 src/box/sql/vdbe.c                            | 222 ++++--
 src/box/sql/wherecode.c                       | 205 +-----
 test/sql-tap/autoinc.test.lua                 |   4 +-
 test/sql-tap/default.test.lua                 |   6 +-
 test/sql-tap/e_select1.test.lua               |  27 +-
 .../gh-3809-implicit-cast-assignment.test.lua | 633 ++++++++++++++++++
 .../gh-4230-del-impl-cast-str-to-num.test.lua |  78 +++
 test/sql-tap/identifier_case.test.lua         |   6 +-
 test/sql-tap/in1.test.lua                     |   4 +-
 test/sql-tap/in3.test.lua                     |  18 +-
 test/sql-tap/in4.test.lua                     | 100 +--
 test/sql-tap/index1.test.lua                  |  24 +-
 test/sql-tap/insert3.test.lua                 |  12 +-
 test/sql-tap/intpkey.test.lua                 |  37 +-
 test/sql-tap/join.test.lua                    |   8 +-
 test/sql-tap/limit.test.lua                   |   2 +-
 test/sql-tap/minmax2.test.lua                 |   6 +-
 test/sql-tap/misc1.test.lua                   |  66 +-
 test/sql-tap/numcast.test.lua                 |   4 +-
 test/sql-tap/select1.test.lua                 |  12 +-
 test/sql-tap/select4.test.lua                 |  12 +-
 test/sql-tap/select7.test.lua                 |   4 +-
 test/sql-tap/sort.test.lua                    |   8 +-
 test/sql-tap/subquery.test.lua                |  73 +-
 test/sql-tap/tkt-3998683a16.test.lua          |  36 +-
 test/sql-tap/tkt-54844eea3f.test.lua          |   8 +-
 test/sql-tap/tkt-7bbfb7d442.test.lua          |   4 +-
 test/sql-tap/tkt-80e031a00f.test.lua          |   4 +-
 test/sql-tap/tkt-9a8b09f8e6.test.lua          |  88 +--
 test/sql-tap/tkt-f973c7ac31.test.lua          |  32 +-
 test/sql-tap/tkt-fc7bd6358f.test.lua          |   8 +-
 test/sql-tap/tkt1444.test.lua                 |   4 +-
 test/sql-tap/tkt3493.test.lua                 |  46 +-
 test/sql-tap/tkt3841.test.lua                 |  12 +-
 test/sql-tap/transitive1.test.lua             |  16 +-
 test/sql-tap/triggerA.test.lua                |   4 +-
 test/sql-tap/unique.test.lua                  |   8 +-
 test/sql-tap/view.test.lua                    |   2 +-
 test/sql-tap/where2.test.lua                  | 183 +----
 test/sql-tap/where5.test.lua                  |  22 +-
 test/sql-tap/whereB.test.lua                  | 254 +++----
 test/sql-tap/whereC.test.lua                  |   8 +-
 test/sql/boolean.result                       |  14 +-
 test/sql/persistency.result                   |   2 +-
 test/sql/types.result                         |  37 +-
 test/sql/types.test.lua                       |   1 -
 54 files changed, 1316 insertions(+), 1166 deletions(-)
 create mode 100755 test/sql-tap/gh-3809-implicit-cast-assignment.test.lua
 create mode 100755 test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua

-- 
2.25.1

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [Tarantool-patches] [PATCH 1/6] sql: remove implicit cast for assignment
  2020-05-28 14:17 [Tarantool-patches] [PATCH 0/6] Remove implicit cast Mergen Imeev
@ 2020-05-28 14:17 ` Mergen Imeev
  2020-06-01 17:03   ` Vladislav Shpilevoy
  2020-05-28 14:17 ` [Tarantool-patches] [PATCH 2/6] sql: remove mem_apply_type() from OP_MakeRecord Mergen Imeev
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 21+ messages in thread
From: Mergen Imeev @ 2020-05-28 14:17 UTC (permalink / raw)
  To: v.shpilevoy, tsafin, tarantool-patches

This patch removes implicit cast for assignment, however,
it is allowed to implicitly cast DOUBLE to INTEGER and
vice versa.

Closes #3809
---
 src/box/sql/insert.c                          |   2 +-
 src/box/sql/vdbe.c                            | 113 ++++
 test/sql-tap/autoinc.test.lua                 |   4 +-
 test/sql-tap/default.test.lua                 |   6 +-
 test/sql-tap/e_select1.test.lua               |  10 +-
 .../gh-3809-implicit-cast-assignment.test.lua | 633 ++++++++++++++++++
 test/sql-tap/index1.test.lua                  |  24 +-
 test/sql-tap/insert3.test.lua                 |  10 +-
 test/sql-tap/intpkey.test.lua                 |  13 +-
 test/sql-tap/minmax2.test.lua                 |   6 +-
 test/sql-tap/misc1.test.lua                   |  34 +-
 test/sql-tap/numcast.test.lua                 |   4 +-
 test/sql-tap/select1.test.lua                 |   8 +-
 test/sql-tap/select4.test.lua                 |  12 +-
 test/sql-tap/select7.test.lua                 |   2 +-
 test/sql-tap/sort.test.lua                    |   8 +-
 test/sql-tap/tkt-3998683a16.test.lua          |  36 +-
 test/sql-tap/tkt-54844eea3f.test.lua          |   8 +-
 test/sql-tap/tkt-7bbfb7d442.test.lua          |   4 +-
 test/sql-tap/tkt1444.test.lua                 |   4 +-
 test/sql-tap/tkt3493.test.lua                 |   6 +-
 test/sql-tap/tkt3841.test.lua                 |  12 +-
 test/sql-tap/triggerA.test.lua                |   4 +-
 test/sql-tap/unique.test.lua                  |   8 +-
 test/sql-tap/view.test.lua                    |   2 +-
 test/sql-tap/where5.test.lua                  |  10 +-
 test/sql-tap/whereB.test.lua                  |  14 +-
 test/sql/boolean.result                       |   2 +-
 test/sql/persistency.result                   |   2 +-
 test/sql/types.result                         |  25 +-
 30 files changed, 870 insertions(+), 156 deletions(-)
 create mode 100755 test/sql-tap/gh-3809-implicit-cast-assignment.test.lua

diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index 588e142d2..253304ba3 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -69,7 +69,7 @@ sql_emit_table_types(struct Vdbe *v, struct space_def *def, int reg)
 	for (uint32_t i = 0; i < field_count; ++i)
 		colls_type[i] = def->fields[i].type;
 	colls_type[field_count] = field_type_MAX;
-	sqlVdbeAddOp4(v, OP_ApplyType, reg, field_count, 0,
+	sqlVdbeAddOp4(v, OP_CheckType, reg, field_count, 0,
 			  (char *)colls_type, P4_DYNAMIC);
 }
 
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 724bc188b..2a941025c 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -414,6 +414,94 @@ sql_value_apply_type(
 	mem_apply_type((Mem *) pVal, type);
 }
 
+/**
+ * Check that mem_type of the mem compatible with given type. In
+ * case of numeric values this fuction tries to comvert mem to
+ * given type and returns -1 if it is impossible.
+ *
+ * @param mem The value to check.
+ * @param type The type to check.
+ */
+static int
+mem_check_types(struct Mem *mem, enum field_type type)
+{
+	if ((mem->flags & MEM_Null) != 0)
+		return 0;
+	assert(type < field_type_MAX);
+	uint32_t flags = mem->flags;
+	switch (type) {
+	case FIELD_TYPE_UNSIGNED:
+		if ((flags & MEM_Int) != 0)
+			return -1;
+		if ((flags & MEM_Real) != 0 && mem->u.r < 0)
+			return -1;
+		FALLTHROUGH;
+	case FIELD_TYPE_INTEGER:
+		if ((flags & (MEM_Int | MEM_UInt)) != 0)
+			return 0;
+		if ((flags & MEM_Real) != 0) {
+			double d = mem->u.r;
+			int64_t i = (int64_t) d;
+			uint64_t u = (uint64_t) d;
+			if (i == d) {
+				mem_set_int(mem, i, i <= -1);
+				return 0;
+			}
+			if (u == d) {
+				mem_set_u64(mem, u);
+				return 0;
+			}
+		}
+		return -1;
+	case FIELD_TYPE_BOOLEAN:
+		if ((flags & MEM_Bool) != 0)
+			return 0;
+		return -1;
+	case FIELD_TYPE_NUMBER:
+		if ((flags & (MEM_Real | MEM_Int | MEM_UInt)) != 0)
+			return 0;
+		return -1;
+	case FIELD_TYPE_DOUBLE:
+		if ((flags & MEM_Real) != 0)
+			return 0;
+		if ((flags & (MEM_Int | MEM_UInt)) != 0)
+			return sqlVdbeMemRealify(mem);
+		return -1;
+	case FIELD_TYPE_STRING:
+		if ((flags & MEM_Str) != 0)
+			return 0;
+		return -1;
+	case FIELD_TYPE_VARBINARY:
+		if ((flags & MEM_Blob) != 0)
+			return 0;
+		return -1;
+	case FIELD_TYPE_SCALAR:
+		/* Can't cast MAP and ARRAY to scalar types. */
+		if ((flags & MEM_Subtype) == 0 ||
+		    mem->subtype != SQL_SUBTYPE_MSGPACK)
+			return 0;
+		assert(mp_typeof(*mem->z) == MP_MAP ||
+		       mp_typeof(*mem->z) == MP_ARRAY);
+		return -1;
+	case FIELD_TYPE_MAP:
+		if ((flags & MEM_Subtype) != 0 &&
+		    mem->subtype == SQL_SUBTYPE_MSGPACK &&
+		    mp_typeof(*mem->z) == MP_MAP)
+			return 0;
+		return -1;
+	case FIELD_TYPE_ARRAY:
+		if ((flags & MEM_Subtype) != 0 &&
+		    mem->subtype == SQL_SUBTYPE_MSGPACK &&
+		    mp_typeof(*mem->z) == MP_ARRAY)
+			return 0;
+		return -1;
+	case FIELD_TYPE_ANY:
+		return 0;
+	default:
+		return -1;
+	}
+}
+
 /*
  * pMem currently only holds a string type (or maybe a BLOB that we can
  * interpret as a string if we want to).  Compute its corresponding
@@ -2772,6 +2860,31 @@ case OP_ApplyType: {
 	break;
 }
 
+/* Opcode: CheckType P1 P2 * P4 *
+ * Synopsis: type(r[P1@P2])
+ *
+ * Check that types of P2 registers starting from register
+ * P1 are compatible with given field_types.
+ */
+case OP_CheckType: {
+	enum field_type *types = pOp->p4.types;
+	assert(types != NULL);
+	assert(types[pOp->p2] == field_type_MAX);
+	pIn1 = &aMem[pOp->p1];
+	enum field_type type;
+	while((type = *(types++)) != field_type_MAX) {
+		assert(pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)]);
+		assert(memIsValid(pIn1));
+		if (mem_check_types(pIn1, type) != 0) {
+			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+				 mem_type_to_str(pIn1), field_type_strs[type]);
+			goto abort_due_to_error;
+		}
+		pIn1++;
+	}
+	break;
+}
+
 /* Opcode: MakeRecord P1 P2 P3 P4 P5
  * Synopsis: r[P3]=mkrec(r[P1@P2])
  *
diff --git a/test/sql-tap/autoinc.test.lua b/test/sql-tap/autoinc.test.lua
index 37e65e541..ec8dfeab1 100755
--- a/test/sql-tap/autoinc.test.lua
+++ b/test/sql-tap/autoinc.test.lua
@@ -618,7 +618,7 @@ test:do_catchsql_test(
             INSERT INTO t2 VALUES('asd'); 
     ]], {
         -- <autoinc-10.2>
-        1, "Type mismatch: can not convert asd to integer"
+        1, "Type mismatch: can not convert text to integer"
         -- </autoinc-10.2>
     })
 
@@ -694,7 +694,7 @@ test:do_test(
                  INSERT INTO t3928(b) VALUES('after-int-' || CAST(new.b AS TEXT));
             END;
             DELETE FROM t3928 WHERE a!=1;
-            UPDATE t3928 SET b=456 WHERE a=1;
+            UPDATE t3928 SET b='456' WHERE a=1;
             SELECT * FROM t3928 ORDER BY a;
         ]])
     end, {
diff --git a/test/sql-tap/default.test.lua b/test/sql-tap/default.test.lua
index d3e35c71c..f1def2b10 100755
--- a/test/sql-tap/default.test.lua
+++ b/test/sql-tap/default.test.lua
@@ -109,16 +109,12 @@ test:do_execsql_test(
 	f VARCHAR(15), --COLLATE RTRIM,
 	g INTEGER DEFAULT( 3600*12 )
 	);
-	INSERT INTO t3 VALUES(null, 5, 'row1', 5.25, 8.67, 321, 432);
+	INSERT INTO t3 VALUES(null, 5, 'row1', 5.25, 8.67, '321', 432);
 	SELECT a, typeof(a), b, typeof(b), c, typeof(c), 
 	d, typeof(d), e, typeof(e), f, typeof(f),
 	g, typeof(g) FROM t3;
 	]], {
 	-- <default-3.1>
-	-- TODO: In original test "321" is not a string, its a value.
-	-- In current situation I don't know what to do, need Kirill's
-	-- advice.
-	-- Bulat
 	1, "integer", 5, "integer", "row1", "string", 5.25, "number", 8.67, "number", "321", "string", 432, "integer"
 	-- </default-3.1>
 })
diff --git a/test/sql-tap/e_select1.test.lua b/test/sql-tap/e_select1.test.lua
index 1d3b964b9..7673426f4 100755
--- a/test/sql-tap/e_select1.test.lua
+++ b/test/sql-tap/e_select1.test.lua
@@ -753,11 +753,11 @@ test:do_execsql_test(
         CREATE TABLE z3(id  INT primary key, a NUMBER, b NUMBER);
 
         INSERT INTO z1 VALUES(1, 51.65, -59.58, 'belfries');
-        INSERT INTO z1 VALUES(2, -5, NULL, 75);
+        INSERT INTO z1 VALUES(2, -5, NULL, '75');
         INSERT INTO z1 VALUES(3, -2.2, -23.18, 'suiters');
         INSERT INTO z1 VALUES(4, NULL, 67, 'quartets');
         INSERT INTO z1 VALUES(5, -1.04, -32.3, 'aspen');
-        INSERT INTO z1 VALUES(6, 63, '0', -26);
+        INSERT INTO z1 VALUES(6, 63, 0, '-26');
 
         INSERT INTO z2 VALUES(1, NULL, 21);
         INSERT INTO z2 VALUES(2, 36.0, 6.0);
@@ -1457,13 +1457,13 @@ test:do_execsql_test(
         CREATE TABLE q2(id  INT primary key, d TEXT, e NUMBER);
         CREATE TABLE q3(id  INT primary key, f TEXT, g INT);
 
-        INSERT INTO q1 VALUES(1, 16, -87.66, NULL);
+        INSERT INTO q1 VALUES(1, '16', -87.66, NULL);
         INSERT INTO q1 VALUES(2, 'legible', 94, -42.47);
         INSERT INTO q1 VALUES(3, 'beauty', 36, NULL);
 
         INSERT INTO q2 VALUES(1, 'legible', 1);
         INSERT INTO q2 VALUES(2, 'beauty', 2);
-        INSERT INTO q2 VALUES(3, -65, 4);
+        INSERT INTO q2 VALUES(3, '-65', 4);
         INSERT INTO q2 VALUES(4, 'emanating', -16.56);
 
         INSERT INTO q3 VALUES(1, 'beauty', 2);
@@ -1603,7 +1603,7 @@ test:do_execsql_test(
         CREATE TABLE w2(a  INT PRIMARY KEY, b TEXT);
 
         INSERT INTO w1 VALUES('1', 4.1);
-        INSERT INTO w2 VALUES(1, 4.1);
+        INSERT INTO w2 VALUES(1, '4.1');
     ]], {
         -- <e_select-7.10.0>
 
diff --git a/test/sql-tap/gh-3809-implicit-cast-assignment.test.lua b/test/sql-tap/gh-3809-implicit-cast-assignment.test.lua
new file mode 100755
index 000000000..9df90bf72
--- /dev/null
+++ b/test/sql-tap/gh-3809-implicit-cast-assignment.test.lua
@@ -0,0 +1,633 @@
+#!/usr/bin/env tarantool
+test = require("sqltester")
+test:plan(75)
+
+--
+-- Make sure that duting assignment there is no impolicit casts
+-- with exception of implicit cast between numeric values.
+--
+test:execsql([[
+    CREATE TABLE ti (a INT PRIMARY KEY AUTOINCREMENT, i INTEGER);
+    CREATE TABLE td (a INT PRIMARY KEY AUTOINCREMENT, d DOUBLE);
+    CREATE TABLE tb (a INT PRIMARY KEY AUTOINCREMENT, b BOOLEAN);
+    CREATE TABLE tt (a INT PRIMARY KEY AUTOINCREMENT, t TEXT);
+    CREATE TABLE tv (a INT PRIMARY KEY AUTOINCREMENT, v VARBINARY);
+    CREATE TABLE ts (a INT PRIMARY KEY AUTOINCREMENT, s SCALAR);
+]])
+
+test:do_catchsql_test(
+    "gh-3809-1",
+    [[
+        INSERT INTO ti(i) VALUES (11)
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-2",
+    [[
+        INSERT INTO ti(i) VALUES (22.2)
+    ]], {
+        1, "Type mismatch: can not convert real to integer"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-3",
+    [[
+        INSERT INTO ti(i) VALUES (33.0)
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-4",
+    [[
+        INSERT INTO ti(i) VALUES (true)
+    ]], {
+        1, "Type mismatch: can not convert boolean to integer"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-5",
+    [[
+        INSERT INTO ti(i) VALUES ('33')
+    ]], {
+        1, "Type mismatch: can not convert text to integer"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-6",
+    [[
+        INSERT INTO ti(i) VALUES (X'3434')
+    ]], {
+        1, "Type mismatch: can not convert varbinary to integer"
+    })
+
+test:do_execsql_test(
+    "gh-3809-7",
+    [[
+        SELECT * FROM ti;
+    ]], {
+        1, 11, 2, 33
+    })
+
+test:do_catchsql_test(
+    "gh-3809-8",
+    [[
+        INSERT INTO td(d) VALUES (11)
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-9",
+    [[
+        INSERT INTO td(d) VALUES (22.2)
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-10",
+    [[
+        INSERT INTO td(d) VALUES (true)
+    ]], {
+        1, "Type mismatch: can not convert boolean to double"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-11",
+    [[
+        INSERT INTO td(d) VALUES ('33')
+    ]], {
+        1, "Type mismatch: can not convert text to double"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-12",
+    [[
+        INSERT INTO td(d) VALUES (X'3434')
+    ]], {
+        1, "Type mismatch: can not convert varbinary to double"
+    })
+
+test:do_execsql_test(
+    "gh-3809-13",
+    [[
+        SELECT * FROM td;
+    ]], {
+        1, 11, 2, 22.2
+    })
+
+test:do_catchsql_test(
+    "gh-3809-14",
+    [[
+        INSERT INTO tb(b) VALUES (11)
+    ]], {
+        1, "Type mismatch: can not convert unsigned to boolean"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-15",
+    [[
+        INSERT INTO tb(b) VALUES (22.2)
+    ]], {
+        1, "Type mismatch: can not convert real to boolean"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-16",
+    [[
+        INSERT INTO tb(b) VALUES (true)
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-17",
+    [[
+        INSERT INTO tb(b) VALUES ('33')
+    ]], {
+        1, "Type mismatch: can not convert text to boolean"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-18",
+    [[
+        INSERT INTO tb(b) VALUES (X'3434')
+    ]], {
+        1, "Type mismatch: can not convert varbinary to boolean"
+    })
+
+test:do_execsql_test(
+    "gh-3809-19",
+    [[
+        SELECT * FROM tb;
+    ]], {
+        1, true
+    })
+
+test:do_catchsql_test(
+    "gh-3809-20",
+    [[
+        INSERT INTO tt(t) VALUES (11)
+    ]], {
+        1, "Type mismatch: can not convert unsigned to string"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-21",
+    [[
+        INSERT INTO tt(t) VALUES (22.2)
+    ]], {
+        1, "Type mismatch: can not convert real to string"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-22",
+    [[
+        INSERT INTO tt(t) VALUES (true)
+    ]], {
+        1, "Type mismatch: can not convert boolean to string"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-23",
+    [[
+        INSERT INTO tt(t) VALUES ('33')
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-24",
+    [[
+        INSERT INTO tt(t) VALUES (X'3434')
+    ]], {
+        1, "Type mismatch: can not convert varbinary to string"
+    })
+
+test:do_execsql_test(
+    "gh-3809-25",
+    [[
+        SELECT * FROM tt;
+    ]], {
+        1, "33"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-26",
+    [[
+        INSERT INTO tv(v) VALUES (11)
+    ]], {
+        1, "Type mismatch: can not convert unsigned to varbinary"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-27",
+    [[
+        INSERT INTO tv(v) VALUES (22.2)
+    ]], {
+        1, "Type mismatch: can not convert real to varbinary"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-28",
+    [[
+        INSERT INTO tv(v) VALUES (true)
+    ]], {
+        1, "Type mismatch: can not convert boolean to varbinary"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-29",
+    [[
+        INSERT INTO tv(v) VALUES ('33')
+    ]], {
+        1, "Type mismatch: can not convert text to varbinary"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-30",
+    [[
+        INSERT INTO tv(v) VALUES (X'3434')
+    ]], {
+        0
+    })
+
+test:do_execsql_test(
+    "gh-3809-31",
+    [[
+        SELECT * FROM tv;
+    ]], {
+        1, "44"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-32",
+    [[
+        INSERT INTO ts(s) VALUES (11)
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-33",
+    [[
+        INSERT INTO ts(s) VALUES (22.2)
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-34",
+    [[
+        INSERT INTO ts(s) VALUES (true)
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-35",
+    [[
+        INSERT INTO ts(s) VALUES ('33')
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-36",
+    [[
+        INSERT INTO ts(s) VALUES (X'3434')
+    ]], {
+        0
+    })
+
+test:do_execsql_test(
+    "gh-3809-37",
+    [[
+        SELECT * FROM ts;
+    ]], {
+        1, 11, 2, 22.2, 3, true, 4, "33", 5, "44"
+    })
+
+test:execsql([[
+    DELETE FROM ti;
+    DELETE FROM td;
+    DELETE FROM tb;
+    DELETE FROM tt;
+    DELETE FROM tv;
+    DELETE FROM ts;
+    INSERT INTO ti(a) VALUES(1);
+    INSERT INTO td(a) VALUES(1);
+    INSERT INTO tb(a) VALUES(1);
+    INSERT INTO tt(a) VALUES(1);
+    INSERT INTO tv(a) VALUES(1);
+    INSERT INTO ts(a) VALUES(1);
+]])
+
+test:do_execsql_test(
+    "gh-3809-38",
+    [[
+        SELECT * FROM ti, td, tb, tt, tv, ts;
+    ]], {
+        1, "", 1, "", 1, "", 1, "", 1, "", 1, ""
+    })
+
+test:do_catchsql_test(
+    "gh-3809-39",
+    [[
+        UPDATE ti SET i = 11 WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-40",
+    [[
+        UPDATE ti SET i = 22.2 WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert real to integer"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-41",
+    [[
+        UPDATE ti SET i = 33.0 WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-42",
+    [[
+        UPDATE ti SET i = true WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert boolean to integer"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-43",
+    [[
+        UPDATE ti SET i = '33' WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert text to integer"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-44",
+    [[
+        UPDATE ti SET i = X'3434' WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert varbinary to integer"
+    })
+
+test:do_execsql_test(
+    "gh-3809-45",
+    [[
+        SELECT * FROM ti;
+    ]], {
+        1, 33
+    })
+
+test:do_catchsql_test(
+    "gh-3809-46",
+    [[
+        UPDATE td SET d = 11 WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-47",
+    [[
+        UPDATE td SET d = 22.2 WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-48",
+    [[
+        UPDATE td SET d = true WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert boolean to double"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-49",
+    [[
+        UPDATE td SET d = '33' WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert text to double"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-50",
+    [[
+        UPDATE td SET d = X'3434' WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert varbinary to double"
+    })
+
+test:do_execsql_test(
+    "gh-3809-51",
+    [[
+        SELECT * FROM td;
+    ]], {
+        1, 22.2
+    })
+
+test:do_catchsql_test(
+    "gh-3809-52",
+    [[
+        UPDATE tb SET b = 11 WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert unsigned to boolean"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-53",
+    [[
+        UPDATE tb SET b = 22.2 WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert real to boolean"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-54",
+    [[
+        UPDATE tb SET b = true WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-55",
+    [[
+        UPDATE tb SET b = '33' WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert text to boolean"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-56",
+    [[
+        UPDATE tb SET b = X'3434' WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert varbinary to boolean"
+    })
+
+test:do_execsql_test(
+    "gh-3809-57",
+    [[
+        SELECT * FROM tb;
+    ]], {
+        1, true
+    })
+
+test:do_catchsql_test(
+    "gh-3809-58",
+    [[
+        UPDATE tt SET t = 11 WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert unsigned to string"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-59",
+    [[
+        UPDATE tt SET t = 22.2 WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert real to string"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-60",
+    [[
+        UPDATE tt SET t = true WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert boolean to string"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-61",
+    [[
+        UPDATE tt SET t = '33' WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-62",
+    [[
+        UPDATE tt SET t = X'3434' WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert varbinary to string"
+    })
+
+test:do_execsql_test(
+    "gh-3809-63",
+    [[
+        SELECT * FROM tt;
+    ]], {
+        1, "33"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-64",
+    [[
+        UPDATE tv SET v = 11 WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert unsigned to varbinary"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-65",
+    [[
+        UPDATE tv SET v = 22.2 WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert real to varbinary"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-66",
+    [[
+        UPDATE tv SET v = true WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert boolean to varbinary"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-67",
+    [[
+        UPDATE tv SET v = '33' WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert text to varbinary"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-68",
+    [[
+        UPDATE tv SET v = X'3434' WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_execsql_test(
+    "gh-3809-69",
+    [[
+        SELECT * FROM tv;
+    ]], {
+        1, "44"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-70",
+    [[
+        UPDATE ts SET s = 11 WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-71",
+    [[
+        UPDATE ts SET s = 22.2 WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-72",
+    [[
+        UPDATE ts SET s = true WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-73",
+    [[
+        UPDATE ts SET s = '33' WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-74",
+    [[
+        UPDATE ts SET s = X'3434' WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_execsql_test(
+    "gh-3809-75",
+    [[
+        SELECT * FROM ts;
+    ]], {
+        1, "44"
+    })
+
+test:finish_test()
diff --git a/test/sql-tap/index1.test.lua b/test/sql-tap/index1.test.lua
index e173e685c..ce66b7c1e 100755
--- a/test/sql-tap/index1.test.lua
+++ b/test/sql-tap/index1.test.lua
@@ -593,25 +593,17 @@ test:do_test(
         -- </index-11.1>
     })
 end
--- integrity_check index-11.2
--- Numeric strings should compare as if they were numbers.  So even if the
--- strings are not character-by-character the same, if they represent the
--- same number they should compare equal to one another.  Verify that this
--- is true in indices.
---
--- Updated for sql v3: sql will now store these values as numbers
--- (because the affinity of column a is NUMERIC) so the quirky
--- representations are not retained. i.e. '+1.0' becomes '1'.
+
 test:do_execsql_test(
     "index-12.1",
     [[
         CREATE TABLE t4(id  INT primary key, a NUMBER,b INT );
-        INSERT INTO t4 VALUES(1, '0.0',1);
-        INSERT INTO t4 VALUES(2, '0.00',2);
-        INSERT INTO t4 VALUES(4, '-1.0',4);
-        INSERT INTO t4 VALUES(5, '+1.0',5);
-        INSERT INTO t4 VALUES(6, '0',6);
-        INSERT INTO t4 VALUES(7, '00000',7);
+        INSERT INTO t4 VALUES(1, 0.0, 1);
+        INSERT INTO t4 VALUES(2, 0.00, 2);
+        INSERT INTO t4 VALUES(4, -1.0, 4);
+        INSERT INTO t4 VALUES(5, +1.0, 5);
+        INSERT INTO t4 VALUES(6, 0, 6);
+        INSERT INTO t4 VALUES(7, 00000, 7);
         SELECT a FROM t4 ORDER BY b;
     ]], {
         -- <index-12.1>
@@ -692,7 +684,7 @@ test:do_execsql_test(
            c  TEXT,
            UNIQUE(a,c)
         );
-        INSERT INTO t5 VALUES(1,2,3);
+        INSERT INTO t5 VALUES(1,2,'3');
         SELECT * FROM t5;
     ]], {
         -- <index-13.1>
diff --git a/test/sql-tap/insert3.test.lua b/test/sql-tap/insert3.test.lua
index 43bb06630..b92bc508e 100755
--- a/test/sql-tap/insert3.test.lua
+++ b/test/sql-tap/insert3.test.lua
@@ -60,7 +60,7 @@ test:do_execsql_test(
             CREATE TABLE log2(rowid INTEGER PRIMARY KEY AUTOINCREMENT, x TEXT UNIQUE,y INT );
             CREATE TRIGGER r2 BEFORE INSERT ON t1 FOR EACH ROW BEGIN
               UPDATE log2 SET y=y+1 WHERE x=new.b;
-              INSERT OR IGNORE INTO log2(x, y) VALUES(new.b,1);
+              INSERT OR IGNORE INTO log2(x, y) VALUES(CAST(new.b AS STRING),1);
             END;
             INSERT INTO t1(a, b) VALUES('hi', 453);
             SELECT x,y FROM log ORDER BY x;
@@ -129,8 +129,8 @@ test:do_execsql_test(
               INSERT INTO t2dup(a,b,c) VALUES(new.a,new.b,new.c);
             END;
             INSERT INTO t2(a) VALUES(123);
-            INSERT INTO t2(b) VALUES(234);
-            INSERT INTO t2(c) VALUES(345);
+            INSERT INTO t2(b) VALUES('234');
+            INSERT INTO t2(c) VALUES('345');
             SELECT * FROM t2dup;
     ]], {
         -- <insert3-2.1>
@@ -143,8 +143,8 @@ test:do_execsql_test(
     [[
             DELETE FROM t2dup;
             INSERT INTO t2(a) SELECT 1 FROM t1 LIMIT 1;
-            INSERT INTO t2(b) SELECT 987 FROM t1 LIMIT 1;
-            INSERT INTO t2(c) SELECT 876 FROM t1 LIMIT 1;
+            INSERT INTO t2(b) SELECT '987' FROM t1 LIMIT 1;
+            INSERT INTO t2(c) SELECT '876' FROM t1 LIMIT 1;
             SELECT * FROM t2dup;
     ]], {
         -- <insert3-2.2>
diff --git a/test/sql-tap/intpkey.test.lua b/test/sql-tap/intpkey.test.lua
index b6b186632..0db18ba91 100755
--- a/test/sql-tap/intpkey.test.lua
+++ b/test/sql-tap/intpkey.test.lua
@@ -770,11 +770,6 @@ test:do_execsql_test(
         -- </intpkey-11.1>
     })
 
--- integrity_check intpkey-12.1
--- Try to use a string that looks like a floating point number as
--- an integer primary key.  This should actually work when the floating
--- point value can be rounded to an integer without loss of data.
---
 test:do_execsql_test(
     "intpkey-13.1",
     [[
@@ -788,7 +783,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "intpkey-13.2",
     [[
-        INSERT INTO t1 VALUES('1',2,3);
+        INSERT INTO t1 VALUES(1,'2','3');
         SELECT * FROM t1 WHERE a=1;
     ]], {
         -- <intpkey-13.2>
@@ -825,7 +820,7 @@ end
 test:do_catchsql_test(
     "intpkey-13.5",
     [[
-        INSERT INTO t1 VALUES('+1234567890',3,4);
+        INSERT INTO t1 VALUES(1234567890,'3','4');
     ]], {
         -- <intpkey-13.5>
         0
@@ -842,7 +837,7 @@ test:do_execsql_test(
         CREATE TABLE t3(a INTEGER PRIMARY KEY, b INTEGER, c TEXT);
         INSERT INTO t3 VALUES(1, 1, 'one');
         INSERT INTO t3 VALUES(2, 2, '2');
-        INSERT INTO t3 VALUES(3, 3, 3);
+        INSERT INTO t3 VALUES(3, 3, '3');
     ]], {
         -- <intpkey-14.1>
         
@@ -905,7 +900,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "intpkey-15.1",
     [[
-        INSERT INTO t1 VALUES(2147483647, 'big-1', 123);
+        INSERT INTO t1 VALUES(2147483647, 'big-1', '123');
         SELECT * FROM t1 WHERE a>2147483648;
     ]], {
         -- <intpkey-15.1>
diff --git a/test/sql-tap/minmax2.test.lua b/test/sql-tap/minmax2.test.lua
index 0e0f0d08e..707d1c4da 100755
--- a/test/sql-tap/minmax2.test.lua
+++ b/test/sql-tap/minmax2.test.lua
@@ -441,9 +441,9 @@ test:do_execsql_test(
     "minmax2-8.2",
     [[
         CREATE TABLE t5(a INTEGER PRIMARY KEY);
-        INSERT INTO t5 VALUES('1234');
-        INSERT INTO t5 VALUES('234');
-        INSERT INTO t5 VALUES('34');
+        INSERT INTO t5 VALUES(1234);
+        INSERT INTO t5 VALUES(234);
+        INSERT INTO t5 VALUES(34);
         SELECT min(a), max(a) FROM t5;
     ]], {
         -- <minmax2-8.2>
diff --git a/test/sql-tap/misc1.test.lua b/test/sql-tap/misc1.test.lua
index 32f38cc97..e0fe50bbe 100755
--- a/test/sql-tap/misc1.test.lua
+++ b/test/sql-tap/misc1.test.lua
@@ -34,9 +34,9 @@ test:do_test(
         end
         cmd = cmd .. ")"
         test:execsql(cmd)
-        cmd = "INSERT INTO manycol VALUES(1, 0"
+        cmd = "INSERT INTO manycol VALUES(1, '0'"
         for i = 1, 99, 1 do
-            cmd = cmd .. ","..i..""
+            cmd = cmd .. ",'"..i.."'"
         end
         cmd = cmd .. ")"
         test:execsql(cmd)
@@ -61,9 +61,9 @@ test:do_test(
     "misc1-1.3.1",
     function()
         for j = 100, 1000, 100 do
-            local cmd = string.format("INSERT INTO manycol VALUES(%s, %s", j, j)
+            local cmd = string.format("INSERT INTO manycol VALUES(%s, '%s'", j, j)
             for i = 1, 99, 1 do
-                cmd = cmd .. ","..(i + j)..""
+                cmd = cmd .. ",'"..(i + j).."'"
             end
             cmd = cmd .. ")"
             test:execsql(cmd)
@@ -178,12 +178,12 @@ test:do_test(
         test:execsql([[
             CREATE TABLE agger(one text primary key, two text, three text, four text);
             START TRANSACTION;
-            INSERT INTO agger VALUES(1, 'one', 'hello', 'yes');
-            INSERT INTO agger VALUES(2, 'two', 'howdy', 'no');
-            INSERT INTO agger VALUES(3, 'thr', 'howareya', 'yes');
-            INSERT INTO agger VALUES(4, 'two', 'lothere', 'yes');
-            INSERT INTO agger VALUES(5, 'one', 'atcha', 'yes');
-            INSERT INTO agger VALUES(6, 'two', 'hello', 'no');
+            INSERT INTO agger VALUES('1', 'one', 'hello', 'yes');
+            INSERT INTO agger VALUES('2', 'two', 'howdy', 'no');
+            INSERT INTO agger VALUES('3', 'thr', 'howareya', 'yes');
+            INSERT INTO agger VALUES('4', 'two', 'lothere', 'yes');
+            INSERT INTO agger VALUES('5', 'one', 'atcha', 'yes');
+            INSERT INTO agger VALUES('6', 'two', 'hello', 'no');
             COMMIT
         ]])
         return test:execsql("SELECT count(*) FROM agger")
@@ -531,7 +531,7 @@ test:do_test(
     "misc1-10.7",
     function()
         where = string.gsub(where, "x0=0", "x0=100")
-        return test:catchsql("UPDATE manycol SET x1=x1+1 "..where.."")
+        return test:catchsql("UPDATE manycol SET x1=CAST(x1+1 AS STRING) "..where.."")
     end, {
         -- <misc1-10.7>
         0
@@ -553,7 +553,7 @@ test:do_execsql_test(
 -- } {0 {}}
 test:do_execsql_test(
     "misc1-10.9",
-    "UPDATE manycol SET x1=x1+1 "..where
+    "UPDATE manycol SET x1=CAST(x1+1 AS STRING) "..where
         --"UPDATE manycol SET x1=x1+1 $::where AND rowid>0"
     , {})
 
@@ -665,7 +665,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-12.6",
     [[
-        INSERT OR IGNORE INTO t6 VALUES('y',0);
+        INSERT OR IGNORE INTO t6 VALUES('y','0');
         SELECT * FROM t6;
     ]], {
         -- <misc1-12.6>
@@ -679,10 +679,10 @@ test:do_execsql_test(
     "misc1-12.7",
     [[
         CREATE TABLE t7(x INTEGER, y TEXT, z  INT primary key);
-        INSERT INTO t7 VALUES(0,0,1);
-        INSERT INTO t7 VALUES(0.0,0,2);
-        INSERT INTO t7 VALUES(0,0.0,3);
-        INSERT INTO t7 VALUES(0.0,0.0,4);
+        INSERT INTO t7 VALUES(0,'0',1);
+        INSERT INTO t7 VALUES(0.0,'0',2);
+        INSERT INTO t7 VALUES(0,'0.0',3);
+        INSERT INTO t7 VALUES(0.0,'0.0',4);
         SELECT DISTINCT x, y FROM t7 ORDER BY z;
     ]], {
         -- <misc1-12.7>
diff --git a/test/sql-tap/numcast.test.lua b/test/sql-tap/numcast.test.lua
index eeac5353a..9bbae5ca4 100755
--- a/test/sql-tap/numcast.test.lua
+++ b/test/sql-tap/numcast.test.lua
@@ -135,7 +135,7 @@ test:do_catchsql_test(
         INSERT INTO t VALUES(20000000000000000000.01);
         SELECT * FROM t;
     ]], {
-        1,"Tuple field 1 type does not match one required by operation: expected integer"
+        1,"Type mismatch: can not convert real to integer"
     })
 
 test:do_catchsql_test(
@@ -144,7 +144,7 @@ test:do_catchsql_test(
         INSERT INTO t VALUES(2.1);
         SELECT * FROM t;
     ]], {
-        1,"Tuple field 1 type does not match one required by operation: expected integer"
+        1,"Type mismatch: can not convert real to integer"
     })
 
 --
diff --git a/test/sql-tap/select1.test.lua b/test/sql-tap/select1.test.lua
index fbebfab37..9a969bf3c 100755
--- a/test/sql-tap/select1.test.lua
+++ b/test/sql-tap/select1.test.lua
@@ -231,7 +231,7 @@ string.format([[
         CREATE TABLE t3(id INT, a TEXT, b TEXT, PRIMARY KEY(id));
         INSERT INTO t3 VALUES(1, 'abc',NULL);
         INSERT INTO t3 VALUES(2, NULL,'xyz');
-        INSERT INTO t3 SELECT f1, * FROM test1;
+        INSERT INTO t3 SELECT f1, CAST(f1 AS STRING), CAST(f2 AS STRING) FROM test1;
         DROP TABLE IF EXISTS t4;
         CREATE TABLE t4(id INT, a INT , b TEXT , PRIMARY KEY(id));
         INSERT INTO t4 VALUES(1, NULL,'%s');
@@ -1671,8 +1671,8 @@ test:do_execsql_test(
     [[
         DELETE FROM t3;
         DELETE FROM t4;
-        INSERT INTO t3 VALUES(0,1,2);
-        INSERT INTO t4 VALUES(0,3,4);
+        INSERT INTO t3 VALUES(0,'1','2');
+        INSERT INTO t4 VALUES(0,3,'4');
         SELECT * FROM t3, t4;
     ]], {
         -- <select1-11.1>
@@ -1878,7 +1878,7 @@ test:do_execsql_test(
     "select1-12.4",
     [[
         DELETE FROM t3;
-        INSERT INTO t3 VALUES(0,1,2);
+        INSERT INTO t3 VALUES(0,'1','2');
     ]], {
         -- <select1-12.4>
         
diff --git a/test/sql-tap/select4.test.lua b/test/sql-tap/select4.test.lua
index 23cf1bf1b..f7a320438 100755
--- a/test/sql-tap/select4.test.lua
+++ b/test/sql-tap/select4.test.lua
@@ -761,12 +761,12 @@ test:do_test(
         test:execsql [[
             CREATE TABLE t3(a text primary key, b NUMBER, c text);
             START TRANSACTION;
-            INSERT INTO t3 VALUES(1, 1.1, '1.1');
-            INSERT INTO t3 VALUES(2, 1.10, '1.10');
-            INSERT INTO t3 VALUES(3, 1.10, '1.1');
-            INSERT INTO t3 VALUES(4, 1.1, '1.10');
-            INSERT INTO t3 VALUES(5, 1.2, '1.2');
-            INSERT INTO t3 VALUES(6, 1.3, '1.3');
+            INSERT INTO t3 VALUES('1', 1.1, '1.1');
+            INSERT INTO t3 VALUES('2', 1.10, '1.10');
+            INSERT INTO t3 VALUES('3', 1.10, '1.1');
+            INSERT INTO t3 VALUES('4', 1.1, '1.10');
+            INSERT INTO t3 VALUES('5', 1.2, '1.2');
+            INSERT INTO t3 VALUES('6', 1.3, '1.3');
             COMMIT;
         ]]
         return test:execsql [[
diff --git a/test/sql-tap/select7.test.lua b/test/sql-tap/select7.test.lua
index fec5d7a41..e1e43c557 100755
--- a/test/sql-tap/select7.test.lua
+++ b/test/sql-tap/select7.test.lua
@@ -255,7 +255,7 @@ test:do_execsql_test(
     [[
         DROP TABLE IF EXISTS t5;
         CREATE TABLE t5(a TEXT primary key, b INT);
-        INSERT INTO t5 VALUES(123, 456);
+        INSERT INTO t5 VALUES('123', 456);
         SELECT typeof(a), a FROM t5 GROUP BY a HAVING a<b;
     ]], {
         -- <select7-7.7>
diff --git a/test/sql-tap/sort.test.lua b/test/sql-tap/sort.test.lua
index 36074d6ef..18bfd443d 100755
--- a/test/sql-tap/sort.test.lua
+++ b/test/sql-tap/sort.test.lua
@@ -505,10 +505,10 @@ test:do_execsql_test(
           a INTEGER PRIMARY KEY,
           b VARCHAR(30)
         );
-        INSERT INTO t4 VALUES(1,1);
-        INSERT INTO t4 VALUES(2,2);
-        INSERT INTO t4 VALUES(11,11);
-        INSERT INTO t4 VALUES(12,12);
+        INSERT INTO t4 VALUES(1,'1');
+        INSERT INTO t4 VALUES(2,'2');
+        INSERT INTO t4 VALUES(11,'11');
+        INSERT INTO t4 VALUES(12,'12');
         SELECT a FROM t4 ORDER BY 1;
     ]], {
         -- <sort-7.1>
diff --git a/test/sql-tap/tkt-3998683a16.test.lua b/test/sql-tap/tkt-3998683a16.test.lua
index 885dcf5cd..c91960c2c 100755
--- a/test/sql-tap/tkt-3998683a16.test.lua
+++ b/test/sql-tap/tkt-3998683a16.test.lua
@@ -26,24 +26,24 @@ test:do_test(
     function()
         return test:execsql [[
             CREATE TABLE t1(x  INT primary key, y NUMBER);
-            INSERT INTO t1 VALUES(1, '1.0');
-            INSERT INTO t1 VALUES(2, '.125');
-            INSERT INTO t1 VALUES(3, '123.');
-            INSERT INTO t1 VALUES(4, '123.e+2');
-            INSERT INTO t1 VALUES(5, '.125e+3');
-            INSERT INTO t1 VALUES(6, '123e4');
-            INSERT INTO t1 VALUES(11, '  1.0');
-            INSERT INTO t1 VALUES(12, '  .125');
-            INSERT INTO t1 VALUES(13, '  123.');
-            INSERT INTO t1 VALUES(14, '  123.e+2');
-            INSERT INTO t1 VALUES(15, '  .125e+3');
-            INSERT INTO t1 VALUES(16, '  123e4');
-            INSERT INTO t1 VALUES(21, '1.0  ');
-            INSERT INTO t1 VALUES(22, '.125  ');
-            INSERT INTO t1 VALUES(23, '123.  ');
-            INSERT INTO t1 VALUES(24, '123.e+2  ');
-            INSERT INTO t1 VALUES(25, '.125e+3  ');
-            INSERT INTO t1 VALUES(26, '123e4  ');
+            INSERT INTO t1 VALUES(1, 1.0);
+            INSERT INTO t1 VALUES(2, .125);
+            INSERT INTO t1 VALUES(3, 123.);
+            INSERT INTO t1 VALUES(4, 123.e+2);
+            INSERT INTO t1 VALUES(5, .125e+3);
+            INSERT INTO t1 VALUES(6, 123e4);
+            INSERT INTO t1 VALUES(11, 1.0);
+            INSERT INTO t1 VALUES(12, .125);
+            INSERT INTO t1 VALUES(13, 123.);
+            INSERT INTO t1 VALUES(14, 123.e+2);
+            INSERT INTO t1 VALUES(15, .125e+3);
+            INSERT INTO t1 VALUES(16, 123e4);
+            INSERT INTO t1 VALUES(21, 1.0);
+            INSERT INTO t1 VALUES(22, .125);
+            INSERT INTO t1 VALUES(23, 123.);
+            INSERT INTO t1 VALUES(24, 123.e+2);
+            INSERT INTO t1 VALUES(25, .125e+3);
+            INSERT INTO t1 VALUES(26, 123e4);
             SELECT x FROM t1 WHERE typeof(y)=='number' ORDER BY x;
         ]]
     end, {
diff --git a/test/sql-tap/tkt-54844eea3f.test.lua b/test/sql-tap/tkt-54844eea3f.test.lua
index d6cd56e52..89d0d1218 100755
--- a/test/sql-tap/tkt-54844eea3f.test.lua
+++ b/test/sql-tap/tkt-54844eea3f.test.lua
@@ -62,10 +62,10 @@ test:do_execsql_test(
     "1.2",
     [[
         CREATE TABLE t4(id INT primary key, a TEXT, b TEXT, c TEXT);
-        INSERT INTO t4 VALUES(1, 'a', 1, 'one');
-        INSERT INTO t4 VALUES(2, 'a', 2, 'two');
-        INSERT INTO t4 VALUES(3, 'b', 1, 'three');
-        INSERT INTO t4 VALUES(4, 'b', 2, 'four');
+        INSERT INTO t4 VALUES(1, 'a', '1', 'one');
+        INSERT INTO t4 VALUES(2, 'a', '2', 'two');
+        INSERT INTO t4 VALUES(3, 'b', '1', 'three');
+        INSERT INTO t4 VALUES(4, 'b', '2', 'four');
         SELECT ( 
           SELECT c FROM (
             SELECT a,b,c FROM t4 WHERE a=output.a ORDER BY b LIMIT 10 OFFSET 1
diff --git a/test/sql-tap/tkt-7bbfb7d442.test.lua b/test/sql-tap/tkt-7bbfb7d442.test.lua
index 535303771..bfddcd920 100755
--- a/test/sql-tap/tkt-7bbfb7d442.test.lua
+++ b/test/sql-tap/tkt-7bbfb7d442.test.lua
@@ -109,13 +109,13 @@ if (1 > 0)
                     T1.Variant AS Variant,
                     T1.ControlDate AS ControlDate,
                     1 AS ControlState,
-                    COALESCE(T2.DeliveredQty,0) AS DeliveredQty
+                    CAST(COALESCE(T2.DeliveredQty,0) AS STRING) AS DeliveredQty
                 FROM (
                     SELECT
                         NEW.InventoryControlId AS InventoryControlId,
                         II.SKU AS SKU,
                         II.Variant AS Variant,
-                        COALESCE(LastClosedIC.ControlDate,NEW.ControlDate) AS ControlDate
+                        CAST(COALESCE(LastClosedIC.ControlDate,NEW.ControlDate) AS STRING) AS ControlDate
                     FROM
                         InventoryItem II
                     LEFT JOIN
diff --git a/test/sql-tap/tkt1444.test.lua b/test/sql-tap/tkt1444.test.lua
index 82a5ded25..fb148bc5f 100755
--- a/test/sql-tap/tkt1444.test.lua
+++ b/test/sql-tap/tkt1444.test.lua
@@ -30,8 +30,8 @@ test:do_execsql_test(
     [[
         CREATE TABLE DemoTable (id  INT primary key, x INTEGER, TextKey TEXT, DKey NUMBER);
         CREATE INDEX DemoTableIdx ON DemoTable (TextKey);
-        INSERT INTO DemoTable VALUES(1, 9,8,7);
-        INSERT INTO DemoTable VALUES(2, 1,2,3);
+        INSERT INTO DemoTable VALUES(1, 9,'8',7);
+        INSERT INTO DemoTable VALUES(2, 1,'2',3);
         CREATE VIEW DemoView AS SELECT x, TextKey, DKey FROM DemoTable ORDER BY TextKey;
         SELECT x,TextKey,DKey FROM DemoTable UNION ALL SELECT * FROM DemoView ORDER BY 1;
     ]], {
diff --git a/test/sql-tap/tkt3493.test.lua b/test/sql-tap/tkt3493.test.lua
index 7ceec4702..de77e61e9 100755
--- a/test/sql-tap/tkt3493.test.lua
+++ b/test/sql-tap/tkt3493.test.lua
@@ -29,8 +29,8 @@ test:do_execsql_test(
         START TRANSACTION;
         INSERT INTO A VALUES(1,'123');
         INSERT INTO A VALUES(2,'456');
-        INSERT INTO B VALUES(1,1);
-        INSERT INTO B VALUES(2,2);
+        INSERT INTO B VALUES(1,'1');
+        INSERT INTO B VALUES(2,'2');
         INSERT INTO A_B VALUES(1,1);
         INSERT INTO A_B VALUES(2,2);
         COMMIT;
@@ -116,7 +116,7 @@ test:do_execsql_test(
     "tkt3493-2.1",
     [[
         CREATE TABLE t1(a TEXT PRIMARY KEY, b INT);
-        INSERT INTO t1 VALUES(123, 456);
+        INSERT INTO t1 VALUES('123', 456);
     ]], {
         -- <tkt3493-2.1>
         
diff --git a/test/sql-tap/tkt3841.test.lua b/test/sql-tap/tkt3841.test.lua
index 5203d0cd4..56668f6a3 100755
--- a/test/sql-tap/tkt3841.test.lua
+++ b/test/sql-tap/tkt3841.test.lua
@@ -31,12 +31,12 @@ test:do_execsql_test(
 
         INSERT INTO table2 VALUES ('a', 'alist');
         INSERT INTO table2 VALUES ('b', 'blist');
-        INSERT INTO list VALUES ('a', 1);
-        INSERT INTO list VALUES ('a', 2);
-        INSERT INTO list VALUES ('a', 3);
-        INSERT INTO list VALUES ('b', 4);
-        INSERT INTO list VALUES ('b', 5);
-        INSERT INTO list VALUES ('b', 6);
+        INSERT INTO list VALUES ('a', '1');
+        INSERT INTO list VALUES ('a', '2');
+        INSERT INTO list VALUES ('a', '3');
+        INSERT INTO list VALUES ('b', '4');
+        INSERT INTO list VALUES ('b', '5');
+        INSERT INTO list VALUES ('b', '6');
 
         SELECT
           table2.x,
diff --git a/test/sql-tap/triggerA.test.lua b/test/sql-tap/triggerA.test.lua
index fac51ca14..fc8ecfe17 100755
--- a/test/sql-tap/triggerA.test.lua
+++ b/test/sql-tap/triggerA.test.lua
@@ -283,7 +283,7 @@ test:do_test(
             CREATE TABLE result2(id INTEGER PRIMARY KEY, a TEXT,b INT);
             CREATE TRIGGER r5d INSTEAD OF DELETE ON v5 FOR EACH ROW BEGIN
               INSERT INTO result2(id, a,b) VALUES((SELECT coalesce(max(id),0) + 1 FROM result2),
-                                                  old.x, old.b);
+                                                  CAST(old.x AS STRING), old.b);
             END;
             DELETE FROM v5 WHERE x=5;
             SELECT a, b FROM result2;
@@ -301,7 +301,7 @@ test:do_test(
             DELETE FROM result4;
             CREATE TRIGGER r5u INSTEAD OF UPDATE ON v5 FOR EACH ROW BEGIN
               INSERT INTO result4(id, a,b,c,d) VALUES((SELECT coalesce(max(id),0) + 1 FROM result4),
-                                                      old.x, old.b, new.x, new.b);
+                                                      CAST(old.x AS STRING), old.b, CAST(new.x AS STRING), new.b);
             END;
             UPDATE v5 SET b = b+9900000 WHERE x BETWEEN 3 AND 5;
             SELECT a,b,c,d FROM result4 ORDER BY a;
diff --git a/test/sql-tap/unique.test.lua b/test/sql-tap/unique.test.lua
index 9818f90a8..6b0a7e20d 100755
--- a/test/sql-tap/unique.test.lua
+++ b/test/sql-tap/unique.test.lua
@@ -52,7 +52,7 @@ test:do_catchsql_test(
 test:do_catchsql_test(
     "unique-1.2",
     [[
-        INSERT INTO t1(a,b,c) VALUES(1,2,3)
+        INSERT INTO t1(a,b,c) VALUES(1,2,'3')
     ]], {
         -- <unique-1.2>
         0
@@ -62,7 +62,7 @@ test:do_catchsql_test(
 test:do_catchsql_test(
     "unique-1.3",
     [[
-        INSERT INTO t1(a,b,c) VALUES(1,3,4)
+        INSERT INTO t1(a,b,c) VALUES(1,3,'4')
     ]], {
         -- <unique-1.3>
         1, "Duplicate key exists in unique index 'pk_unnamed_T1_1' in space 'T1'"
@@ -83,7 +83,7 @@ test:do_execsql_test(
 test:do_catchsql_test(
     "unique-1.5",
     [[
-        INSERT INTO t1(a,b,c) VALUES(3,2,4)
+        INSERT INTO t1(a,b,c) VALUES(3,2,'4')
     ]], {
         -- <unique-1.5>
         1, "Duplicate key exists in unique index 'unique_unnamed_T1_2' in space 'T1'"
@@ -104,7 +104,7 @@ test:do_execsql_test(
 test:do_catchsql_test(
     "unique-1.7",
     [[
-        INSERT INTO t1(a,b,c) VALUES(3,4,5)
+        INSERT INTO t1(a,b,c) VALUES(3,4,'5')
     ]], {
         -- <unique-1.7>
         0
diff --git a/test/sql-tap/view.test.lua b/test/sql-tap/view.test.lua
index e553b91c7..ab14c5edb 100755
--- a/test/sql-tap/view.test.lua
+++ b/test/sql-tap/view.test.lua
@@ -757,7 +757,7 @@ test:do_execsql_test(
     "view-10.1",
     [=[
         CREATE TABLE t3("9" integer primary key, "4" text);
-        INSERT INTO t3 VALUES(1,2);
+        INSERT INTO t3 VALUES(1,'2');
         CREATE VIEW v_t3_a AS SELECT a."9" FROM t3 AS a;
         CREATE VIEW v_t3_b AS SELECT "4" FROM t3;
         SELECT * FROM v_t3_a;
diff --git a/test/sql-tap/where5.test.lua b/test/sql-tap/where5.test.lua
index 749201564..3aefcaca5 100755
--- a/test/sql-tap/where5.test.lua
+++ b/test/sql-tap/where5.test.lua
@@ -27,11 +27,11 @@ test:do_test("where5-1.0", function()
         CREATE TABLE t1(x TEXT primary key);
         CREATE TABLE t2(x integer primary key);
         CREATE TABLE t3(x integer PRIMARY KEY);
-        INSERT INTO t1 VALUES(-1);
-        INSERT INTO t1 VALUES(0);
-        INSERT INTO t1 VALUES(1);
-        INSERT INTO t2 SELECT * FROM t1;
-        INSERT INTO t3 SELECT * FROM t1;
+        INSERT INTO t1 VALUES('-1');
+        INSERT INTO t1 VALUES('0');
+        INSERT INTO t1 VALUES('1');
+        INSERT INTO t2 SELECT CAST(x AS INTEGER) FROM t1;
+        INSERT INTO t3 SELECT CAST(x AS INTEGER) FROM t1;
     ]]
     return test:execsql [[
         SELECT * FROM t1 WHERE x<0
diff --git a/test/sql-tap/whereB.test.lua b/test/sql-tap/whereB.test.lua
index d98645fdc..fe5e28c70 100755
--- a/test/sql-tap/whereB.test.lua
+++ b/test/sql-tap/whereB.test.lua
@@ -112,24 +112,16 @@ test:do_execsql_test(
     -- </whereB-1.102>
     })
 
--- For this set of tests:
---
---  *   t1.y holds a text value with affinity TEXT
---  *   t2.b holds an integer value with affinity NONE
---
--- These values are not equal and because neither affinity is NUMERIC
--- no type conversion occurs.
---
 test:do_execsql_test(
     "whereB-2.1",
     [[
         DROP TABLE t1;
         DROP TABLE t2;
 
-        CREATE TABLE t1(x  INT primary key, y TEXT);    -- affinity of t1.y is TEXT
-        INSERT INTO t1 VALUES(1,99);
+        CREATE TABLE t1(x  INT primary key, y TEXT);
+        INSERT INTO t1 VALUES(1,'99');
 
-        CREATE TABLE t2(a  INT primary key, b SCALAR);  -- affinity of t2.b is NONE
+        CREATE TABLE t2(a  INT primary key, b SCALAR);
         CREATE INDEX t2b ON t2(b);
         INSERT INTO t2 VALUES(2, 99);
 
diff --git a/test/sql/boolean.result b/test/sql/boolean.result
index 112e41a12..e88183854 100644
--- a/test/sql/boolean.result
+++ b/test/sql/boolean.result
@@ -161,7 +161,7 @@ SELECT s FROM ts WHERE s IN (true, 1, 'abcd');
 INSERT INTO ts VALUES (true, 12345);
  | ---
  | - null
- | - 'Type mismatch: can not convert TRUE to integer'
+ | - 'Type mismatch: can not convert boolean to integer'
  | ...
 
 -- Check that we can create index on field of type BOOLEAN.
diff --git a/test/sql/persistency.result b/test/sql/persistency.result
index 6d14d4c4e..6ec2f06fc 100644
--- a/test/sql/persistency.result
+++ b/test/sql/persistency.result
@@ -370,7 +370,7 @@ box.execute("SELECT \"name\", \"opts\" FROM \"_trigger\"");
 box.execute("INSERT INTO foobar VALUES ('foobar trigger test', 8888)")
 ---
 - null
-- 'Type mismatch: can not convert foobar trigger test to integer'
+- 'Type mismatch: can not convert text to integer'
 ...
 box.execute("SELECT * FROM barfoo WHERE foo = 9999");
 ---
diff --git a/test/sql/types.result b/test/sql/types.result
index 54aff460e..6b0f7a651 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -1062,7 +1062,7 @@ 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'
+- 'Type mismatch: can not convert integer to unsigned'
 ...
 box.execute("SELECT id FROM t1;")
 ---
@@ -1220,22 +1220,22 @@ box.execute("CREATE TABLE t (id INT PRIMARY KEY, v VARBINARY);")
 box.execute("INSERT INTO t VALUES(1, 1);")
 ---
 - null
-- 'Type mismatch: can not convert 1 to varbinary'
+- 'Type mismatch: can not convert unsigned to varbinary'
 ...
 box.execute("INSERT INTO t VALUES(1, 1.123);")
 ---
 - null
-- 'Type mismatch: can not convert 1.123 to varbinary'
+- 'Type mismatch: can not convert real to varbinary'
 ...
 box.execute("INSERT INTO t VALUES(1, true);")
 ---
 - null
-- 'Type mismatch: can not convert TRUE to varbinary'
+- 'Type mismatch: can not convert boolean to varbinary'
 ...
 box.execute("INSERT INTO t VALUES(1, 'asd');")
 ---
 - null
-- 'Type mismatch: can not convert asd to varbinary'
+- 'Type mismatch: can not convert text to varbinary'
 ...
 box.execute("INSERT INTO t VALUES(1, x'616263');")
 ---
@@ -1617,7 +1617,7 @@ s:insert({1, {1,2,3}})
 box.execute('INSERT INTO t1(a) SELECT a FROM t2;')
 ---
 - null
-- 'Type mismatch: can not convert [1, 2, 3] to scalar'
+- 'Type mismatch: can not convert varbinary to scalar'
 ...
 s:replace({1, {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30}})
 ---
@@ -1627,8 +1627,7 @@ s:replace({1, {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25
 box.execute('INSERT INTO t1(a) SELECT a FROM t2;')
 ---
 - null
-- 'Type mismatch: can not convert [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
-  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30] to scalar'
+- 'Type mismatch: can not convert varbinary to scalar'
 ...
 --
 -- Make sure that the error will be displayed correctly even if
@@ -1653,13 +1652,7 @@ s:replace({1, long_array})
 box.execute('INSERT INTO t1(a) SELECT a FROM t2;')
 ---
 - null
-- 'Type mismatch: can not convert [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
-  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
-  35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
-  55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
-  75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
-  95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
-  112, 113, 114, 115, 116, 117, 11'
+- 'Type mismatch: can not convert varbinary to scalar'
 ...
 s:drop()
 ---
@@ -1680,7 +1673,7 @@ s:insert({1, {b = 1}})
 box.execute('INSERT INTO t1(a) SELECT a FROM t2;')
 ---
 - null
-- 'Type mismatch: can not convert {"b": 1} to scalar'
+- 'Type mismatch: can not convert varbinary to scalar'
 ...
 s:drop()
 ---
-- 
2.25.1

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [Tarantool-patches] [PATCH 2/6] sql: remove mem_apply_type() from OP_MakeRecord
  2020-05-28 14:17 [Tarantool-patches] [PATCH 0/6] Remove implicit cast Mergen Imeev
  2020-05-28 14:17 ` [Tarantool-patches] [PATCH 1/6] sql: remove implicit cast for assignment Mergen Imeev
@ 2020-05-28 14:17 ` Mergen Imeev
  2020-06-01 17:03   ` Vladislav Shpilevoy
  2020-05-28 14:17 ` [Tarantool-patches] [PATCH 3/6] sql: replace ApplyType by CheckType for IN operator Mergen Imeev
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 21+ messages in thread
From: Mergen Imeev @ 2020-05-28 14:17 UTC (permalink / raw)
  To: v.shpilevoy, tsafin, tarantool-patches

This patch removes type changing from OP_MakeRecord.

Part of #4230
---
 src/box/sql/analyze.c       |  7 +------
 src/box/sql/delete.c        |  8 ++------
 src/box/sql/expr.c          |  8 +-------
 src/box/sql/fk_constraint.c |  9 ++-------
 src/box/sql/select.c        | 25 ++++++-------------------
 src/box/sql/update.c        | 14 +++-----------
 src/box/sql/vdbe.c          | 11 -----------
 test/sql-tap/in3.test.lua   |  4 ++--
 8 files changed, 17 insertions(+), 69 deletions(-)

diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
index f74f9b358..23fbb15de 100644
--- a/src/box/sql/analyze.c
+++ b/src/box/sql/analyze.c
@@ -965,12 +965,7 @@ vdbe_emit_analyze_space(struct Parse *parse, struct space *space)
 		sqlVdbeAddOp2(v, OP_Next, idx_cursor, next_row_addr);
 		/* Add the entry to the stat1 table. */
 		callStatGet(v, stat4_reg, STAT_GET_STAT1, stat1_reg);
-		enum field_type types[4] = { FIELD_TYPE_STRING,
-					     FIELD_TYPE_STRING,
-					     FIELD_TYPE_STRING,
-					     field_type_MAX };
-		sqlVdbeAddOp4(v, OP_MakeRecord, tab_name_reg, 4, tmp_reg,
-				  (char *)types, sizeof(types));
+		sqlVdbeAddOp3(v, OP_MakeRecord, tab_name_reg, 4, tmp_reg);
 		sqlVdbeAddOp4(v, OP_IdxInsert, tmp_reg, 0, 0,
 				  (char *)stat1, P4_SPACEPTR);
 		/* Add the entries to the stat4 table. */
diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
index 68abd1f58..0b6f0bd62 100644
--- a/src/box/sql/delete.c
+++ b/src/box/sql/delete.c
@@ -328,12 +328,8 @@ sql_table_delete_from(struct Parse *parse, struct SrcList *tab_list,
 			 * key.
 			 */
 			key_len = 0;
-			struct index *pk = space_index(space, 0);
-			enum field_type *types = is_view ? NULL :
-						 sql_index_type_str(parse->db,
-								    pk->def);
-			sqlVdbeAddOp4(v, OP_MakeRecord, reg_pk, pk_len,
-					  reg_key, (char *)types, P4_DYNAMIC);
+			sqlVdbeAddOp3(v, OP_MakeRecord, reg_pk, pk_len,
+				      reg_key);
 			/* Set flag to save memory allocating one
 			 * by malloc.
 			 */
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index bc2182446..019628a26 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -2859,8 +2859,6 @@ sqlCodeSubselect(Parse * pParse,	/* Parsing context */
 				struct ExprList_item *pItem;
 				int r1, r2, r3;
 
-				enum field_type lhs_type =
-					sql_expr_type(pLeft);
 				bool unused;
 				struct coll *unused_coll;
 				if (sql_expr_coll(pParse, pExpr->pLeft, &unused,
@@ -2886,11 +2884,7 @@ sqlCodeSubselect(Parse * pParse,	/* Parsing context */
 						jmpIfDynamic = -1;
 					}
 					r3 = sqlExprCodeTarget(pParse, pE2, r1);
-					enum field_type types[2] =
-						{ lhs_type, field_type_MAX };
-	 				sqlVdbeAddOp4(v, OP_MakeRecord, r3,
-							  1, r2, (char *)types,
-							  sizeof(types));
+					sqlVdbeAddOp3(v, OP_MakeRecord, r3, 1, r2);
 					sql_expr_type_cache_change(pParse,
 								   r3, 1);
 					sqlVdbeAddOp2(v, OP_IdxInsert, r2,
diff --git a/src/box/sql/fk_constraint.c b/src/box/sql/fk_constraint.c
index 482220a95..43471d51a 100644
--- a/src/box/sql/fk_constraint.c
+++ b/src/box/sql/fk_constraint.c
@@ -262,13 +262,8 @@ fk_constraint_lookup_parent(struct Parse *parse_context, struct space *parent,
 					  link->child_field + 1 + reg_data,
 					  temp_regs + i);
 		}
-		struct index *idx = space_index(parent, referenced_idx);
-		assert(idx != NULL);
-		sqlVdbeAddOp4(v, OP_MakeRecord, temp_regs, field_count,
-				  rec_reg,
-				  (char *) sql_index_type_str(parse_context->db,
-							      idx->def),
-				  P4_DYNAMIC);
+		sqlVdbeAddOp3(v, OP_MakeRecord, temp_regs, field_count,
+			      rec_reg);
 		sqlVdbeAddOp4Int(v, OP_Found, cursor, ok_label, rec_reg, 0);
 		sqlReleaseTempReg(parse_context, rec_reg);
 		sqlReleaseTempRange(parse_context, temp_regs, field_count);
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index f39484013..64ef9f0b5 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -1270,13 +1270,8 @@ selectInnerLoop(Parse * pParse,		/* The parser context */
 					       regOrig, nResultCol, nPrefixReg);
 			} else {
 				int r1 = sqlGetTempReg(pParse);
-				enum field_type *types =
-					field_type_sequence_dup(pParse,
-								pDest->dest_type,
-								nResultCol);
-				sqlVdbeAddOp4(v, OP_MakeRecord, regResult,
-						  nResultCol, r1, (char *)types,
-						  P4_DYNAMIC);
+				sqlVdbeAddOp3(v, OP_MakeRecord, regResult,
+					      nResultCol, r1);
 				sql_expr_type_cache_change(pParse,
 							   regResult,
 							   nResultCol);
@@ -1693,12 +1688,8 @@ generateSortTail(Parse * pParse,	/* Parsing context */
 			break;
 		}
 	case SRT_Set:{
-			enum field_type *types =
-				field_type_sequence_dup(pParse, pDest->dest_type,
-							nColumn);
-			sqlVdbeAddOp4(v, OP_MakeRecord, regRow, nColumn,
-					  regTupleid, (char *)types,
-					  P4_DYNAMIC);
+			sqlVdbeAddOp3(v, OP_MakeRecord, regRow, nColumn,
+				      regTupleid);
 			sql_expr_type_cache_change(pParse, regRow, nColumn);
 			sqlVdbeAddOp2(v, OP_IdxInsert, regTupleid, pDest->reg_eph);
 			break;
@@ -3134,12 +3125,8 @@ generateOutputSubroutine(struct Parse *parse, struct Select *p,
 			int r1;
 			testcase(in->nSdst > 1);
 			r1 = sqlGetTempReg(parse);
-			enum field_type *types =
-				field_type_sequence_dup(parse, dest->dest_type,
-							in->nSdst);
-			sqlVdbeAddOp4(v, OP_MakeRecord, in->iSdst,
-					  in->nSdst, r1, (char *)types,
-					  P4_DYNAMIC);
+			sqlVdbeAddOp3(v, OP_MakeRecord, in->iSdst, in->nSdst,
+				      r1);
 			sql_expr_type_cache_change(parse, in->iSdst,
 						   in->nSdst);
 			sqlVdbeAddOp2(v, OP_IdxInsert, r1, dest->reg_eph);
diff --git a/src/box/sql/update.c b/src/box/sql/update.c
index d25262c21..cb10ed3a1 100644
--- a/src/box/sql/update.c
+++ b/src/box/sql/update.c
@@ -251,11 +251,7 @@ sqlUpdate(Parse * pParse,		/* The parser context */
 		nKey = pk_part_count;
 		regKey = iPk;
 	} else {
-		enum field_type *types = is_view ? NULL :
-					 sql_index_type_str(pParse->db,
-							    pPk->def);
-		sqlVdbeAddOp4(v, OP_MakeRecord, iPk, pk_part_count,
-				  regKey, (char *) types, P4_DYNAMIC);
+		sqlVdbeAddOp3(v, OP_MakeRecord, iPk, pk_part_count, regKey);
 		/*
 		 * Set flag to save memory allocating one by
 		 * malloc.
@@ -420,12 +416,8 @@ sqlUpdate(Parse * pParse,		/* The parser context */
 			int key_reg;
 			if (okOnePass) {
 				key_reg = sqlGetTempReg(pParse);
-				enum field_type *types =
-					sql_index_type_str(pParse->db,
-							   pPk->def);
-				sqlVdbeAddOp4(v, OP_MakeRecord, iPk,
-						  pk_part_count, key_reg,
-						  (char *) types, P4_DYNAMIC);
+				sqlVdbeAddOp3(v, OP_MakeRecord, iPk,
+					      pk_part_count, key_reg);
 			} else {
 				assert(nKey == 0);
 				key_reg = regKey;
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 2a941025c..fc41ee0d6 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -2902,7 +2902,6 @@ case OP_CheckType: {
  * into ephemeral space. Thus, sort of memory optimization can be performed.
  */
 case OP_MakeRecord: {
-	Mem *pRec;             /* The new record */
 	Mem *pData0;           /* First field to be combined into the record */
 	Mem MAYBE_UNUSED *pLast;  /* Last field of the record */
 	int nField;            /* Number of fields in the record */
@@ -2924,7 +2923,6 @@ case OP_MakeRecord: {
 	 * of the record to data0.
 	 */
 	nField = pOp->p1;
-	enum field_type *types = pOp->p4.types;
 	bIsEphemeral = pOp->p5;
 	assert(nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem+1 - p->nCursor)+1);
 	pData0 = &aMem[nField];
@@ -2935,15 +2933,6 @@ case OP_MakeRecord: {
 	assert(pOp->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2);
 	pOut = vdbe_prepare_null_out(p, pOp->p3);
 
-	/* Apply the requested types to all inputs */
-	assert(pData0<=pLast);
-	if (types != NULL) {
-		pRec = pData0;
-		do {
-			mem_apply_type(pRec++, *(types++));
-		} while(types[0] != field_type_MAX);
-	}
-
 	struct region *region = &fiber()->gc;
 	size_t used = region_used(region);
 	uint32_t tuple_size;
diff --git a/test/sql-tap/in3.test.lua b/test/sql-tap/in3.test.lua
index e29db9d93..f7681640e 100755
--- a/test/sql-tap/in3.test.lua
+++ b/test/sql-tap/in3.test.lua
@@ -354,7 +354,7 @@ test:do_test(
         return exec_neph(" SELECT y IN (SELECT a FROM t1) FROM t2 ")
     end, {
         -- <in3-3.5>
-        1, true
+        1, false
         -- </in3-3.5>
     })
 
@@ -378,7 +378,7 @@ test:do_test(
         return exec_neph(" SELECT y IN (SELECT c FROM t1) FROM t2 ")
     end, {
         -- <in3-3.7>
-        1, true
+        1, false
         -- </in3-3.7>
     })
 
-- 
2.25.1

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [Tarantool-patches] [PATCH 3/6] sql: replace ApplyType by CheckType for IN operator
  2020-05-28 14:17 [Tarantool-patches] [PATCH 0/6] Remove implicit cast Mergen Imeev
  2020-05-28 14:17 ` [Tarantool-patches] [PATCH 1/6] sql: remove implicit cast for assignment Mergen Imeev
  2020-05-28 14:17 ` [Tarantool-patches] [PATCH 2/6] sql: remove mem_apply_type() from OP_MakeRecord Mergen Imeev
@ 2020-05-28 14:17 ` Mergen Imeev
  2020-05-28 14:17 ` [Tarantool-patches] [PATCH 4/6] sql: remove mem_apply_type() from OP_MustBeInt Mergen Imeev
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 21+ messages in thread
From: Mergen Imeev @ 2020-05-28 14:17 UTC (permalink / raw)
  To: v.shpilevoy, tsafin, tarantool-patches

This patch removes implicit cast from STRING to numeric
and vice versa of left operand of IN operator.

Part of #4230
Part of #4692
---
 src/box/sql/expr.c                   |  2 +-
 test/sql-tap/in3.test.lua            | 14 +-----
 test/sql-tap/subquery.test.lua       | 69 +---------------------------
 test/sql-tap/tkt-80e031a00f.test.lua |  4 +-
 test/sql/boolean.result              | 12 ++---
 5 files changed, 11 insertions(+), 90 deletions(-)

diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index 019628a26..8ec685cd9 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -3179,7 +3179,7 @@ sqlExprCodeIN(Parse * pParse,	/* Parsing and code generating context */
 	 * true.
 	 */
 	zAff[nVector] = field_type_MAX;
-	sqlVdbeAddOp4(v, OP_ApplyType, rLhs, nVector, 0, (char*)zAff,
+	sqlVdbeAddOp4(v, OP_CheckType, rLhs, nVector, 0, (char*)zAff,
 			  P4_DYNAMIC);
 	/*
 	 * zAff will be freed at the end of VDBE execution, since
diff --git a/test/sql-tap/in3.test.lua b/test/sql-tap/in3.test.lua
index f7681640e..a2147b0e8 100755
--- a/test/sql-tap/in3.test.lua
+++ b/test/sql-tap/in3.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(29)
+test:plan(28)
 
 --!./tcltestrunner.lua
 -- 2007 November 29
@@ -322,18 +322,6 @@ test:do_test(
         -- </in3-3.2>
     })
 
-test:do_test(
-    "in3-3.3",
-    function()
-        -- Logically, numeric affinity is applied to both sides before
-        -- the comparison, but index can't be used.
-        return exec_neph(" SELECT x IN (SELECT b FROM t1) FROM t2 ")
-    end, {
-        -- <in3-3.3>
-        1, true
-        -- </in3-3.3>
-    })
-
 test:do_test(
     "in3-3.4",
     function()
diff --git a/test/sql-tap/subquery.test.lua b/test/sql-tap/subquery.test.lua
index 15c4c8276..e0771825e 100755
--- a/test/sql-tap/subquery.test.lua
+++ b/test/sql-tap/subquery.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(73)
+test:plan(69)
 
 --!./tcltestrunner.lua
 -- 2005 January 19
@@ -335,73 +335,6 @@ test:do_execsql_test(
         -- </subquery-2.4.3>
     })
 
-test:do_execsql_test(
-    "subquery-2.5.1",
-    [[
-        CREATE TABLE t3(a INTEGER PRIMARY KEY);
-        INSERT INTO t3 VALUES(10);
-
-        CREATE TABLE t4(x TEXT PRIMARY KEY);
-        INSERT INTO t4 VALUES('10');
-    ]], {
-        -- <subquery-2.5.1>
-        
-        -- </subquery-2.5.1>
-    })
-
-test:do_test(
-    "subquery-2.5.2",
-    function()
-        -- In the expr "x IN (SELECT a FROM t3)" the RHS of the IN operator
-        -- has text affinity and the LHS has integer affinity.  The rule is
-        -- that we try to convert both sides to an integer before doing the
-        -- comparision. Hence, the integer value 10 in t3 will compare equal
-        -- to the string value '10.0' in t4 because the t4 value will be
-        -- converted into an integer.
-        return test:execsql [[
-            SELECT * FROM t4 WHERE x IN (SELECT a FROM t3);
-        ]]
-    end, {
-        -- <subquery-2.5.2>
-        "10"
-        -- </subquery-2.5.2>
-    })
-
-test:do_test(
-    "subquery-2.5.3.1",
-    function()
-        -- The t4i index cannot be used to resolve the "x IN (...)" constraint
-        -- because the constraint has integer affinity but t4i has text affinity.
-        return test:execsql [[
-            CREATE INDEX t4i ON t4(x);
-            SELECT * FROM t4 WHERE x IN (SELECT a FROM t3);
-        ]]
-    end, {
-        -- <subquery-2.5.3.1>
-        "10"
-        -- </subquery-2.5.3.1>
-    })
-
--- Tarantool: no-rowid is implied for the table, so query plan contains
--- scan over t4i. Verified w/ vanilla sql. Comment this case
---do_test subquery-2.5.3.2 {
--- Verify that the t4i index was not used in the previous query
---  execsql {
---    EXPLAIN QUERY PLAN
---    SELECT * FROM t4 WHERE x IN (SELECT a FROM t3);
---  }
---} {~/t4i/}
-test:do_execsql_test(
-    "subquery-2.5.4",
-    [[
-        DROP TABLE t3;
-        DROP TABLE t4;
-    ]], {
-        -- <subquery-2.5.4>
-        
-        -- </subquery-2.5.4>
-    })
-
 --------------------------------------------------------------------
 -- The following test cases - subquery-3.* - test tickets that
 -- were raised during development of correlated subqueries.
diff --git a/test/sql-tap/tkt-80e031a00f.test.lua b/test/sql-tap/tkt-80e031a00f.test.lua
index a0e6539e0..c883937ca 100755
--- a/test/sql-tap/tkt-80e031a00f.test.lua
+++ b/test/sql-tap/tkt-80e031a00f.test.lua
@@ -346,7 +346,7 @@ test:do_catchsql_test(
         SELECT 'hello' IN t1
     ]], {
         -- <tkt-80e031a00f.27>
-        1, 'Type mismatch: can not convert hello to integer'
+        1, 'Type mismatch: can not convert text to integer'
         -- </tkt-80e031a00f.27>
     })
 
@@ -356,7 +356,7 @@ test:do_catchsql_test(
         SELECT 'hello' NOT IN t1
     ]], {
         -- <tkt-80e031a00f.28>
-        1, 'Type mismatch: can not convert hello to integer'
+        1, 'Type mismatch: can not convert text to integer'
         -- </tkt-80e031a00f.28>
     })
 
diff --git a/test/sql/boolean.result b/test/sql/boolean.result
index e88183854..c74713c34 100644
--- a/test/sql/boolean.result
+++ b/test/sql/boolean.result
@@ -3877,12 +3877,12 @@ SELECT false IN (0, 1, 2, 3);
 SELECT true IN (SELECT b FROM t7);
  | ---
  | - null
- | - 'Type mismatch: can not convert TRUE to integer'
+ | - 'Type mismatch: can not convert boolean to integer'
  | ...
 SELECT false IN (SELECT b FROM t7);
  | ---
  | - null
- | - 'Type mismatch: can not convert FALSE to integer'
+ | - 'Type mismatch: can not convert boolean to integer'
  | ...
 SELECT a1, a1 IN (0, 1, 2, 3) FROM t6
  | ---
@@ -5038,22 +5038,22 @@ SELECT a2 IN (0.1, 1.2, 2.3, 3.4) FROM t6 LIMIT 1;
 SELECT true IN (SELECT c FROM t8);
  | ---
  | - null
- | - 'Type mismatch: can not convert TRUE to number'
+ | - 'Type mismatch: can not convert boolean to number'
  | ...
 SELECT false IN (SELECT c FROM t8);
  | ---
  | - null
- | - 'Type mismatch: can not convert FALSE to number'
+ | - 'Type mismatch: can not convert boolean to number'
  | ...
 SELECT a1 IN (SELECT c FROM t8) FROM t6 LIMIT 1;
  | ---
  | - null
- | - 'Type mismatch: can not convert FALSE to number'
+ | - 'Type mismatch: can not convert boolean to number'
  | ...
 SELECT a2 IN (SELECT c FROM t8) FROM t6 LIMIT 1;
  | ---
  | - null
- | - 'Type mismatch: can not convert TRUE to number'
+ | - 'Type mismatch: can not convert boolean to number'
  | ...
 
 SELECT true BETWEEN 0.1 and 9.9;
-- 
2.25.1

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [Tarantool-patches] [PATCH 4/6] sql: remove mem_apply_type() from OP_MustBeInt
  2020-05-28 14:17 [Tarantool-patches] [PATCH 0/6] Remove implicit cast Mergen Imeev
                   ` (2 preceding siblings ...)
  2020-05-28 14:17 ` [Tarantool-patches] [PATCH 3/6] sql: replace ApplyType by CheckType for IN operator Mergen Imeev
@ 2020-05-28 14:17 ` Mergen Imeev
  2020-06-01 17:04   ` Vladislav Shpilevoy
  2020-05-28 14:17 ` [Tarantool-patches] [PATCH 5/6] sql: remove implicit cast from string for comparison Mergen Imeev
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 21+ messages in thread
From: Mergen Imeev @ 2020-05-28 14:17 UTC (permalink / raw)
  To: v.shpilevoy, tsafin, tarantool-patches

This patch replaces mem_apply_type() by mem_check_types() in
OP_MustBeInt, which allows to remove implicit case in some places,
for example in IN operator.

Part of #4230
---
 src/box/sql/vdbe.c                   |  2 +-
 test/sql-tap/e_select1.test.lua      | 17 +++--
 test/sql-tap/in4.test.lua            | 97 +---------------------------
 test/sql-tap/join.test.lua           |  1 -
 test/sql-tap/limit.test.lua          |  2 +-
 test/sql-tap/tkt-9a8b09f8e6.test.lua |  4 --
 test/sql-tap/tkt-fc7bd6358f.test.lua |  2 -
 test/sql-tap/transitive1.test.lua    |  4 +-
 test/sql-tap/whereB.test.lua         |  2 -
 test/sql-tap/whereC.test.lua         |  8 +--
 10 files changed, 18 insertions(+), 121 deletions(-)

diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index fc41ee0d6..7add67ae7 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -2073,7 +2073,7 @@ case OP_AddImm: {            /* in1 */
 case OP_MustBeInt: {            /* jump, in1 */
 	pIn1 = &aMem[pOp->p1];
 	if ((pIn1->flags & (MEM_Int | MEM_UInt)) == 0) {
-		mem_apply_type(pIn1, FIELD_TYPE_INTEGER);
+		mem_check_types(pIn1, FIELD_TYPE_INTEGER);
 		if ((pIn1->flags & (MEM_Int | MEM_UInt)) == 0) {
 			if (pOp->p2==0) {
 				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
diff --git a/test/sql-tap/e_select1.test.lua b/test/sql-tap/e_select1.test.lua
index 7673426f4..578620fca 100755
--- a/test/sql-tap/e_select1.test.lua
+++ b/test/sql-tap/e_select1.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(510)
+test:plan(509)
 
 --!./tcltestrunner.lua
 -- 2010 July 16
@@ -2150,7 +2150,6 @@ test:do_select_tests(
         {"2", "SELECT b FROM f1 ORDER BY a LIMIT 2+3 ", {"a",  "b", "c", "d", "e"}},
         {"3", "SELECT b FROM f1 ORDER BY a LIMIT (SELECT a FROM f1 WHERE b = 'e') ", {"a",  "b", "c", "d", "e"}},
         {"4", "SELECT b FROM f1 ORDER BY a LIMIT 5.0 ", {"a",  "b", "c", "d", "e"}},
-        {"5", "SELECT b FROM f1 ORDER BY a LIMIT '5' ", {"a",  "b", "c", "d", "e"}},
     })
 
 -- EVIDENCE-OF: R-46155-47219 If the expression evaluates to a NULL value
@@ -2195,7 +2194,7 @@ test:do_select_tests(
         {"1", "SELECT b FROM f1 ORDER BY a LIMIT 0 ", {}},
         {"2", "SELECT b FROM f1 ORDER BY a DESC LIMIT 4 ", {"z", "y", "x", "w"}},
         {"3", "SELECT b FROM f1 ORDER BY a DESC LIMIT 8 ", {"z", "y", "x", "w", "v", "u", "t", "s"}},
-        {"4", "SELECT b FROM f1 ORDER BY a DESC LIMIT '12' ", {"z", y, "x", "w", "v", "u", "t", "s", "r", "q", "p", "o"}},
+        {"4", "SELECT b FROM f1 ORDER BY a DESC LIMIT 12 ", {"z", y, "x", "w", "v", "u", "t", "s", "r", "q", "p", "o"}},
     })
 
 -- EVIDENCE-OF: R-54935-19057 Or, if the SELECT statement would return
@@ -2240,10 +2239,10 @@ test:do_select_tests(
         {"1", "SELECT b FROM f1 ORDER BY a LIMIT 10 OFFSET 5", {"f", "g", "h", "i", "j", "k", "l", "m", "n", "o"}},
         {"2", "SELECT b FROM f1 ORDER BY a LIMIT 2+3 OFFSET 10", {"k", "l", "m", "n", "o"}},
         {"3", "SELECT b FROM f1 ORDER BY a LIMIT  (SELECT a FROM f1 WHERE b='j') OFFSET (SELECT a FROM f1 WHERE b='b') ", {"c", "d", "e", "f", "g", "h", "i", "j", "k", "l"}},
-        {"4", "SELECT b FROM f1 ORDER BY a LIMIT '5' OFFSET 3.0 ", {"d", "e", "f", "g", "h"}},
-        {"5", "SELECT b FROM f1 ORDER BY a LIMIT '5' OFFSET 0 ", {"a", "b", "c", "d", "e"}},
+        {"4", "SELECT b FROM f1 ORDER BY a LIMIT 5 OFFSET 3.0 ", {"d", "e", "f", "g", "h"}},
+        {"5", "SELECT b FROM f1 ORDER BY a LIMIT 5 OFFSET 0 ", {"a", "b", "c", "d", "e"}},
         {"6", "SELECT b FROM f1 ORDER BY a LIMIT 0 OFFSET 10 ", {}},
-        {"7", "SELECT b FROM f1 ORDER BY a LIMIT 3 OFFSET '1'||'5' ", {"p", "q", "r"}},
+        {"7", "SELECT b FROM f1 ORDER BY a LIMIT 3 OFFSET CAST('1'||'5' AS INTEGER) ", {"p", "q", "r"}},
     })
 
 -- EVIDENCE-OF: R-34648-44875 Or, if the SELECT would return less than
@@ -2279,10 +2278,10 @@ test:do_select_tests(
         {"1", "SELECT b FROM f1 ORDER BY a LIMIT 5, 10 ", {"f", "g", "h", "i", "j", "k", "l", "m", "n", "o"}},
         {"2", "SELECT b FROM f1 ORDER BY a LIMIT 10, 2+3 ", {"k", "l", "m", "n", "o"}},
         {"3", "SELECT b FROM f1 ORDER BY a LIMIT (SELECT a FROM f1 WHERE b='b'), (SELECT a FROM f1 WHERE b='j')", {"c", "d", "e", "f", "g", "h", "i", "j", "k", "l"}},
-        {"4", "SELECT b FROM f1 ORDER BY a LIMIT 3.0, '5' ", {"d", "e", "f", "g", "h"}},
-        {"5", "SELECT b FROM f1 ORDER BY a LIMIT 0, '5' ", {"a", "b", "c", "d", "e"}},
+        {"4", "SELECT b FROM f1 ORDER BY a LIMIT 3.0, 5 ", {"d", "e", "f", "g", "h"}},
+        {"5", "SELECT b FROM f1 ORDER BY a LIMIT 0, 5 ", {"a", "b", "c", "d", "e"}},
         {"6", "SELECT b FROM f1 ORDER BY a LIMIT 10, 0 ", {}},
-        {"7", "SELECT b FROM f1 ORDER BY a LIMIT '1'||'5', 3 ", {"p", "q", "r"}},
+        {"7", "SELECT b FROM f1 ORDER BY a LIMIT CAST('1'||'5' AS INTEGER), 3 ", {"p", "q", "r"}},
         {"8", "SELECT b FROM f1 ORDER BY a LIMIT 20, 10 ", {"u", "v", "w", "x", "y", "z"}},
         {"9", "SELECT a FROM f1 ORDER BY a DESC LIMIT 18+4, 100 ", {4, 3, 2, 1}},
         {"10", "SELECT b FROM f1 ORDER BY a LIMIT 0, 5 ", {"a", "b", "c", "d", "e"}},
diff --git a/test/sql-tap/in4.test.lua b/test/sql-tap/in4.test.lua
index 8c6917379..33947d0ab 100755
--- a/test/sql-tap/in4.test.lua
+++ b/test/sql-tap/in4.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(61)
+test:plan(52)
 
 --!./tcltestrunner.lua
 -- 2008 September 1
@@ -140,7 +140,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "in4-2.7",
     [[
-        SELECT b FROM t2 WHERE a IN ('1', '2') 
+        SELECT b FROM t2 WHERE a IN (1, 2)
     ]], {
         -- <in4-2.7>
         "one", "two"
@@ -153,7 +153,6 @@ test:do_execsql_test(
         SELECT b FROM t2 WHERE a IN ('', '0.0.0', '2') 
     ]], {
         -- <in4-2.8>
-        "two"
         -- </in4-2.8>
     })
 
@@ -585,98 +584,6 @@ test:do_execsql_test(
         -- </in4-4.6>
     })
 
-test:do_execsql_test(
-    "in4-4.11",
-    [[
-        CREATE TABLE t4b(a TEXT, b NUMBER, c  INT PRIMARY KEY);
-        INSERT INTO t4b VALUES('1.0',1,4);
-        SELECT c FROM t4b WHERE a=b;
-    ]], {
-        -- <in4-4.11>
-        4
-        -- </in4-4.11>
-    })
-
-test:do_execsql_test(
-    "in4-4.12",
-    [[
-        SELECT c FROM t4b WHERE b=a;
-    ]], {
-        -- <in4-4.12>
-        4
-        -- </in4-4.12>
-    })
-
-test:do_execsql_test(
-    "in4-4.13",
-    [[
-        SELECT c FROM t4b WHERE +a=b;
-    ]], {
-        -- <in4-4.13>
-        4
-        -- </in4-4.13>
-    })
-
-test:do_execsql_test(
-    "in4-4.14",
-    [[
-        SELECT c FROM t4b WHERE a=+b;
-    ]], {
-        -- <in4-4.14>
-        4
-        -- </in4-4.14>
-    })
-
-test:do_execsql_test(
-    "in4-4.15",
-    [[
-        SELECT c FROM t4b WHERE +b=a;
-    ]], {
-        -- <in4-4.15>
-        4
-        -- </in4-4.15>
-    })
-
-test:do_execsql_test(
-    "in4-4.16",
-    [[
-        SELECT c FROM t4b WHERE b=+a;
-    ]], {
-        -- <in4-4.16>
-        4
-        -- </in4-4.16>
-    })
-
-test:do_execsql_test(
-    "in4-4.17",
-    [[
-        SELECT c FROM t4b WHERE a IN (b);
-    ]], {
-        -- <in4-4.17>
-        4
-        -- </in4-4.17>
-    })
-
-test:do_execsql_test(
-    "in4-4.18",
-    [[
-        SELECT c FROM t4b WHERE b IN (a);
-    ]], {
-        -- <in4-4.18>
-        4
-        -- </in4-4.18>
-    })
-
-test:do_execsql_test(
-    "in4-4.19",
-    [[
-        SELECT c FROM t4b WHERE +b IN (a);
-    ]], {
-        -- <in4-4.19>
-        4
-        -- </in4-4.19>
-    })
-
 -- MUST_WORK_TEST
 -- Tarantool: TBI: Need to support collations. Depends on #2121
 -- test:do_execsql_test(
diff --git a/test/sql-tap/join.test.lua b/test/sql-tap/join.test.lua
index 840b780a3..51e0ecb79 100755
--- a/test/sql-tap/join.test.lua
+++ b/test/sql-tap/join.test.lua
@@ -1034,7 +1034,6 @@ test:do_execsql_test(
         SELECT * FROM t1 NATURAL JOIN t2 
     ]], {
         -- <join-11.9>
-        "one", "1", "two", "2"
         -- </join-11.9>
     })
 
diff --git a/test/sql-tap/limit.test.lua b/test/sql-tap/limit.test.lua
index 870233942..a7d1451f7 100755
--- a/test/sql-tap/limit.test.lua
+++ b/test/sql-tap/limit.test.lua
@@ -441,7 +441,7 @@ test:do_catchsql_test(
 test:do_execsql_test(
     "limit-6.5.2",
     [[
-        SELECT * FROM t6 LIMIT '12'
+        SELECT * FROM t6 LIMIT 12
     ]], {
     -- <limit-6.5>
     1, 2, 3, 4
diff --git a/test/sql-tap/tkt-9a8b09f8e6.test.lua b/test/sql-tap/tkt-9a8b09f8e6.test.lua
index cb5348ab4..854ed774f 100755
--- a/test/sql-tap/tkt-9a8b09f8e6.test.lua
+++ b/test/sql-tap/tkt-9a8b09f8e6.test.lua
@@ -189,7 +189,6 @@ test:do_execsql_test(
         SELECT x FROM t2 WHERE x IN ('1');
     ]], {
         -- <3.3>
-        1
         -- </3.3>
     })
 
@@ -199,7 +198,6 @@ test:do_execsql_test(
         SELECT x FROM t2 WHERE x IN ('1');
     ]], {
         -- <3.4>
-        1
         -- </3.4>
     })
 
@@ -229,7 +227,6 @@ test:do_execsql_test(
         SELECT x FROM t2 WHERE '1' IN (x);
     ]], {
         -- <3.7>
-        1
         -- </3.7>
     })
 
@@ -239,7 +236,6 @@ test:do_execsql_test(
         SELECT x FROM t2 WHERE '1' IN (x);
     ]], {
         -- <3.8>
-        1
         -- </3.8>
     })
 
diff --git a/test/sql-tap/tkt-fc7bd6358f.test.lua b/test/sql-tap/tkt-fc7bd6358f.test.lua
index fe5d6200f..f38ffa3d6 100755
--- a/test/sql-tap/tkt-fc7bd6358f.test.lua
+++ b/test/sql-tap/tkt-fc7bd6358f.test.lua
@@ -80,7 +80,6 @@ for a, from in ipairs(froms) do
             function()
                 return test:execsql(string.format("SELECT t1.textid, i.intid, t2.textid %s %s", from, where))
             end, {
-                "12", 12, "12", "34", 34, "34"
             })
 
         test:do_test(
@@ -88,7 +87,6 @@ for a, from in ipairs(froms) do
             function()
                 return test:execsql(string.format("SELECT t1.textid, i.intid, t2.textid %s %s", from, where))
             end, {
-                "12", 12, "12", "34", 34, "34"
             })
 
     end
diff --git a/test/sql-tap/transitive1.test.lua b/test/sql-tap/transitive1.test.lua
index e96056580..96895b4a7 100755
--- a/test/sql-tap/transitive1.test.lua
+++ b/test/sql-tap/transitive1.test.lua
@@ -338,7 +338,7 @@ test:do_execsql_test(
                    ON tvshow.idshow = episode.idshow
                  LEFT JOIN seasons
                         ON seasons.idshow = episode.idshow
-                           AND seasons.season = episode.c12
+                           AND seasons.season = CAST(episode.c12 AS INTEGER)
                  JOIN path
                    ON files.idpath = path.idpath
                  LEFT JOIN bookmark
@@ -378,7 +378,7 @@ test:do_execsql_test(
         FROM episodeview
             JOIN tvshowview ON tvshowview.idShow = episodeview.idShow
             JOIN seasons ON (seasons.idShow = tvshowview.idShow
-                             AND seasons.season = episodeview.c12)
+                             AND seasons.season = CAST(episodeview.c12 AS INTEGER))
             JOIN files ON files.idFile = episodeview.idFile
             JOIN tvshowlinkpath ON tvshowlinkpath.idShow = tvshowview.idShow
             JOIN path ON path.idPath = tvshowlinkpath.idPath
diff --git a/test/sql-tap/whereB.test.lua b/test/sql-tap/whereB.test.lua
index fe5e28c70..970ff1dec 100755
--- a/test/sql-tap/whereB.test.lua
+++ b/test/sql-tap/whereB.test.lua
@@ -432,7 +432,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-5.2>
-    1, 2, true
     -- </whereB-5.2>
     })
 
@@ -443,7 +442,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-5.3>
-    1, 2, true
     -- </whereB-5.3>
     })
 
diff --git a/test/sql-tap/whereC.test.lua b/test/sql-tap/whereC.test.lua
index 89459dee3..58c049553 100755
--- a/test/sql-tap/whereC.test.lua
+++ b/test/sql-tap/whereC.test.lua
@@ -55,9 +55,9 @@ test:do_execsql_test(
 test:test("main", function()
     local data = {{"SELECT i FROM t1 WHERE a=1 AND b=2 AND i>3",         {4, 5}},
                   -- {"SELECT i FROM t1 WHERE rowid='12'",                  {12}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2'",               {3, 4, 5}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2' AND i>'3'",     {4, 5}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2' AND i<5",       {3, 4}},
+                  {"SELECT i FROM t1 WHERE a=1 AND b=2",               {3, 4, 5}},
+                  {"SELECT i FROM t1 WHERE a=1 AND b=2 AND i>3",     {4, 5}},
+                  {"SELECT i FROM t1 WHERE a=1 AND b=2 AND i<5",       {3, 4}},
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i<12",        {10, 11}},
                   {"SELECT i FROM t1 WHERE a IN(1, 2) AND b=2 AND i<11", {3, 4, 5, 10}},
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 10 AND 12", {10, 11, 12}},
@@ -66,7 +66,7 @@ test:test("main", function()
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 12 AND 10", {}},
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i<NULL",      {}},
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i>=NULL",     {}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2' AND i<4.5",     {3, 4}}}
+                  {"SELECT i FROM t1 WHERE a=1 AND b=2 AND i<4.5",     {3, 4}}}
                   -- {"SELECT i FROM t1 WHERE rowid IS '12'",               {12}}}
 
     for tn, t in ipairs(data) do
-- 
2.25.1

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [Tarantool-patches] [PATCH 5/6] sql: remove implicit cast from string for comparison
  2020-05-28 14:17 [Tarantool-patches] [PATCH 0/6] Remove implicit cast Mergen Imeev
                   ` (3 preceding siblings ...)
  2020-05-28 14:17 ` [Tarantool-patches] [PATCH 4/6] sql: remove mem_apply_type() from OP_MustBeInt Mergen Imeev
@ 2020-05-28 14:17 ` Mergen Imeev
  2020-06-01 17:04   ` Vladislav Shpilevoy
  2020-05-28 14:17 ` [Tarantool-patches] [PATCH 6/6] sql: remove OP_ApplyType Mergen Imeev
  2020-06-01 17:03 ` [Tarantool-patches] [PATCH 0/6] Remove implicit cast Vladislav Shpilevoy
  6 siblings, 1 reply; 21+ messages in thread
From: Mergen Imeev @ 2020-05-28 14:17 UTC (permalink / raw)
  To: v.shpilevoy, tsafin, tarantool-patches

This patch removes implicit cast from strings to numbers for
comparison.

Closes #4230

@TarantoolBot document
Title: remove implicit cast between strings and numbers

This patch-set removes implicit cast from string to number and
from number to string.

Example:

For comparison:

tarantool> box.execute([[SELECT '1' > 0;]])
---
- null
- 'Type mismatch: can not convert 1 to numeric'
...

tarantool> box.execute([[SELECT "id" FROM "_space" WHERE '1' > "id";]])
---
- null
- 'Type mismatch: can not convert text to unsigned'
...

For assignment:

tarantool> box.execute([[CREATE TABLE t1(i INT PRIMARY KEY);]])
tarantool> box.execute([[INSERT INTO t1 VALUES ('1');]])
---
- null
- 'Type mismatch: can not convert text to integer'
...

tarantool> box.execute([[CREATE TABLE t2(t text PRIMARY KEY);]])
tarantool> box.execute([[INSERT INTO t2 VALUES (1);]])
---
- null
- 'Type mismatch: can not convert unsigned to string'
...
---
 src/box/sql/vdbe.c                            | 105 ++++----
 src/box/sql/wherecode.c                       | 203 +--------------
 .../gh-4230-del-impl-cast-str-to-num.test.lua |  78 ++++++
 test/sql-tap/identifier_case.test.lua         |   6 +-
 test/sql-tap/in1.test.lua                     |   4 +-
 test/sql-tap/in4.test.lua                     |   3 +-
 test/sql-tap/insert3.test.lua                 |   2 +-
 test/sql-tap/intpkey.test.lua                 |  24 +-
 test/sql-tap/join.test.lua                    |   7 +-
 test/sql-tap/misc1.test.lua                   |  32 +--
 test/sql-tap/select1.test.lua                 |   4 +-
 test/sql-tap/select7.test.lua                 |   2 +-
 test/sql-tap/subquery.test.lua                |   4 +-
 test/sql-tap/tkt-9a8b09f8e6.test.lua          |  84 ++++---
 test/sql-tap/tkt-f973c7ac31.test.lua          |  32 +--
 test/sql-tap/tkt-fc7bd6358f.test.lua          |   6 +-
 test/sql-tap/tkt3493.test.lua                 |  40 ++-
 test/sql-tap/transitive1.test.lua             |  12 +-
 test/sql-tap/where2.test.lua                  | 183 +-------------
 test/sql-tap/where5.test.lua                  |  12 +-
 test/sql-tap/whereB.test.lua                  | 238 ++++++++++--------
 test/sql/types.result                         |  12 +-
 test/sql/types.test.lua                       |   1 -
 23 files changed, 418 insertions(+), 676 deletions(-)
 create mode 100755 test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua

diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 7add67ae7..021e09d1e 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -2237,8 +2237,6 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
 	pIn3 = &aMem[pOp->p3];
 	flags1 = pIn1->flags;
 	flags3 = pIn3->flags;
-	enum field_type ft_p1 = pIn1->field_type;
-	enum field_type ft_p3 = pIn3->field_type;
 	if ((flags1 | flags3)&MEM_Null) {
 		/* One or both operands are NULL */
 		if (pOp->p5 & SQL_NULLEQ) {
@@ -2297,22 +2295,17 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
 	} else {
 		enum field_type type = pOp->p5 & FIELD_TYPE_MASK;
 		if (sql_type_is_numeric(type)) {
-			if ((flags1 | flags3)&MEM_Str) {
-				if ((flags1 & MEM_Str) == MEM_Str) {
-					mem_apply_numeric_type(pIn1);
-					testcase( flags3!=pIn3->flags); /* Possible if pIn1==pIn3 */
-					flags3 = pIn3->flags;
-				}
-				if ((flags3 & MEM_Str) == MEM_Str) {
-					if (mem_apply_numeric_type(pIn3) != 0) {
-						diag_set(ClientError,
-							 ER_SQL_TYPE_MISMATCH,
-							 sql_value_to_diag_str(pIn3),
-							 "numeric");
-						goto abort_due_to_error;
-					}
-
-				}
+			if ((flags1 & MEM_Str) == MEM_Str) {
+				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+					 sql_value_to_diag_str(pIn1),
+					 "numeric");
+				goto abort_due_to_error;
+			}
+			if ((flags3 & MEM_Str) == MEM_Str) {
+				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+					 sql_value_to_diag_str(pIn3),
+					 "numeric");
+				goto abort_due_to_error;
 			}
 			/* Handle the common case of integer comparison here, as an
 			 * optimization, to avoid a call to sqlMemCompare()
@@ -2345,22 +2338,17 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
 				goto compare_op;
 			}
 		} else if (type == FIELD_TYPE_STRING) {
-			if ((flags1 & MEM_Str) == 0 &&
-			    (flags1 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
-				testcase( pIn1->flags & MEM_Int);
-				testcase( pIn1->flags & MEM_Real);
-				sqlVdbeMemStringify(pIn1);
-				testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn));
-				flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
-				assert(pIn1!=pIn3);
+			if ((flags1 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
+				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+					 mem_type_to_str(pIn3),
+					 mem_type_to_str(pIn1));
+				goto abort_due_to_error;
 			}
-			if ((flags3 & MEM_Str) == 0 &&
-			    (flags3 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
-				testcase( pIn3->flags & MEM_Int);
-				testcase( pIn3->flags & MEM_Real);
-				sqlVdbeMemStringify(pIn3);
-				testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn));
-				flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask);
+			if ((flags3 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
+				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+					 mem_type_to_str(pIn1),
+					 mem_type_to_str(pIn3));
+				goto abort_due_to_error;
 			}
 		}
 		assert(pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0);
@@ -2376,14 +2364,6 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
 	default:       res2 = res>=0;     break;
 	}
 
-	/* Undo any changes made by mem_apply_type() to the input registers. */
-	assert((pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn));
-	pIn1->flags = flags1;
-	pIn1->field_type = ft_p1;
-	assert((pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn));
-	pIn3->flags = flags3;
-	pIn3->field_type = ft_p3;
-
 	if (pOp->p5 & SQL_STOREP2) {
 		iCompare = res;
 		res2 = res2!=0;  /* For this path res2 must be exactly 0 or 1 */
@@ -3479,8 +3459,6 @@ case OP_SeekGT: {       /* jump, in3 */
 		pIn3 = &aMem[int_field];
 		if ((pIn3->flags & MEM_Null) != 0)
 			goto skip_truncate;
-		if ((pIn3->flags & MEM_Str) != 0)
-			mem_apply_numeric_type(pIn3);
 		int64_t i;
 		if ((pIn3->flags & MEM_Int) == MEM_Int) {
 			i = pIn3->u.i;
@@ -3573,6 +3551,26 @@ skip_truncate:
 	assert(oc!=OP_SeekLT || r.default_rc==+1);
 
 	r.aMem = &aMem[pOp->p3];
+	for (int i = 0; i < r.nField; ++i) {
+		enum field_type type = r.key_def->parts[i].type;
+		struct Mem *mem = &r.aMem[i];
+		if ((mem->flags & MEM_Str) != 0 && sql_type_is_numeric(type)) {
+			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+				field_type_strs[type], mem_type_to_str(mem));
+			goto abort_due_to_error;
+		}
+		if (mem_check_types(mem, type) == 0)
+			continue;
+		if ((mem->flags & MEM_Real) != 0 &&
+		    (type == FIELD_TYPE_INTEGER ||
+		     type == FIELD_TYPE_UNSIGNED)) {
+			res = 1;
+			goto seek_not_found;
+		}
+		diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+			field_type_strs[type], mem_type_to_str(mem));
+		goto abort_due_to_error;
+	}
 #ifdef SQL_DEBUG
 	{ int i; for(i=0; i<r.nField; i++) assert(memIsValid(&r.aMem[i])); }
 #endif
@@ -4700,6 +4698,27 @@ case OP_IdxGE:  {       /* jump */
 		r.default_rc = 0;
 	}
 	r.aMem = &aMem[pOp->p3];
+	for (int i = 0; i < r.nField; ++i) {
+		struct Mem *mem = &r.aMem[i];
+		enum mp_type mp_type = sql_value_type(mem);
+		enum field_type field_type = r.key_def->parts[i].type;
+		if (field_type == FIELD_TYPE_SCALAR ||
+		    mem->field_type == FIELD_TYPE_SCALAR)
+			continue;
+		bool is_nullable = r.key_def->parts[i].nullable_action ==
+				   ON_CONFLICT_ACTION_NONE;
+		if (field_mp_plain_type_is_compatible(field_type, mp_type,
+						      is_nullable))
+			continue;
+		if (!sql_type_is_numeric(field_type) ||
+		    !(mp_type == MP_INT || mp_type == MP_UINT ||
+		      mp_type == MP_DOUBLE || mp_type == MP_FLOAT)) {
+			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+				 mem_type_to_str(mem),
+				 field_type_strs[field_type]);
+			goto abort_due_to_error;
+		}
+	}
 #ifdef SQL_DEBUG
 	{ int i; for(i=0; i<r.nField; i++) assert(memIsValid(&r.aMem[i])); }
 #endif
diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
index 5bc27f134..1d7c76670 100644
--- a/src/box/sql/wherecode.c
+++ b/src/box/sql/wherecode.c
@@ -335,72 +335,6 @@ disableTerm(WhereLevel * pLevel, WhereTerm * pTerm)
 	}
 }
 
-/**
- * Code an OP_ApplyType opcode to apply the column type string
- * @types to the n registers starting at @base.
- *
- * As an optimization, SCALAR entries (which are no-ops) at the
- * beginning and end of @types are ignored.  If all entries in
- * @types are SCALAR, then no code gets generated.
- *
- * This routine makes its own copy of @types so that the caller is
- * free to modify @types after this routine returns.
- */
-static void
-emit_apply_type(Parse *pParse, int base, int n, enum field_type *types)
-{
-	Vdbe *v = pParse->pVdbe;
-	if (types == NULL) {
-		assert(pParse->db->mallocFailed);
-		return;
-	}
-	assert(v != 0);
-
-	/*
-	 * Adjust base and n to skip over SCALAR entries at the
-	 * beginning and end of the type sequence.
-	 */
-	while (n > 0 && types[0] == FIELD_TYPE_SCALAR) {
-		n--;
-		base++;
-		types++;
-	}
-	while (n > 1 && types[n - 1] == FIELD_TYPE_SCALAR) {
-		n--;
-	}
-
-	if (n > 0) {
-		enum field_type *types_dup = field_type_sequence_dup(pParse,
-								     types, n);
-		sqlVdbeAddOp4(v, OP_ApplyType, base, n, 0,
-				  (char *) types_dup, P4_DYNAMIC);
-		sql_expr_type_cache_change(pParse, base, n);
-	}
-}
-
-/**
- * Expression @rhs, which is the RHS of a comparison operation, is
- * either a vector of n elements or, if n==1, a scalar expression.
- * Before the comparison operation, types @types are to be applied
- * to the @rhs values. This function modifies entries within the
- * field sequence to SCALAR if either:
- *
- *   * the comparison will be performed with no type, or
- *   * the type change in @types is guaranteed not to change the value.
- */
-static void
-expr_cmp_update_rhs_type(struct Expr *rhs, int n, enum field_type *types)
-{
-	for (int i = 0; i < n; i++) {
-		Expr *p = sqlVectorFieldSubexpr(rhs, i);
-		enum field_type expr_type = sql_expr_type(p);
-		if (sql_type_result(expr_type, types[i]) == FIELD_TYPE_SCALAR ||
-		    sql_expr_needs_no_type_change(p, types[i])) {
-			types[i] = FIELD_TYPE_SCALAR;
-		}
-	}
-}
-
 /*
  * Generate code for a single equality term of the WHERE clause.  An equality
  * term can be either X=expr or X IN (...).   pTerm is the term to be
@@ -644,8 +578,7 @@ static int
 codeAllEqualityTerms(Parse * pParse,	/* Parsing context */
 		     WhereLevel * pLevel,	/* Which nested loop of the FROM we are coding */
 		     int bRev,		/* Reverse the order of IN operators */
-		     int nExtraReg,	/* Number of extra registers to allocate */
-		     enum field_type **res_type)
+		     int nExtraReg)	/* Number of extra registers to allocate */
 {
 	u16 nEq;		/* The number of == or IN constraints to code */
 	u16 nSkip;		/* Number of left-most columns to skip */
@@ -669,9 +602,6 @@ codeAllEqualityTerms(Parse * pParse,	/* Parsing context */
 	nReg = pLoop->nEq + nExtraReg;
 	pParse->nMem += nReg;
 
-	enum field_type *type = sql_index_type_str(pParse->db, idx_def);
-	assert(type != NULL || pParse->db->mallocFailed);
-
 	if (nSkip) {
 		int iIdxCur = pLevel->iIdxCur;
 		sqlVdbeAddOp1(v, (bRev ? OP_Last : OP_Rewind), iIdxCur);
@@ -714,17 +644,7 @@ codeAllEqualityTerms(Parse * pParse,	/* Parsing context */
 				sqlVdbeAddOp2(v, OP_SCopy, r1, regBase + j);
 			}
 		}
-		if (pTerm->eOperator & WO_IN) {
-			if (pTerm->pExpr->flags & EP_xIsSelect) {
-				/* No type ever needs to be (or should be) applied to a value
-				 * from the RHS of an "? IN (SELECT ...)" expression. The
-				 * sqlFindInIndex() routine has already ensured that the
-				 * type of the comparison has been applied to the value.
-				 */
-				if (type != NULL)
-					type[j] = FIELD_TYPE_SCALAR;
-			}
-		} else if ((pTerm->eOperator & WO_ISNULL) == 0) {
+		if ((pTerm->eOperator & (WO_IN | WO_ISNULL)) == 0) {
 			Expr *pRight = pTerm->pExpr->pRight;
 			if (sqlExprCanBeNull(pRight)) {
 				sqlVdbeAddOp2(v, OP_IsNull, regBase + j,
@@ -733,7 +653,6 @@ codeAllEqualityTerms(Parse * pParse,	/* Parsing context */
 			}
 		}
 	}
-	*res_type = type;
 	return regBase;
 }
 
@@ -904,10 +823,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 		int iIdxCur;	/* The VDBE cursor for the index */
 		int nExtraReg = 0;	/* Number of extra registers needed */
 		int op;		/* Instruction opcode */
-		/* Types for start of range constraint. */
-		enum field_type *start_types;
-		/* Types for end of range constraint */
-		enum field_type *end_types = NULL;
 		u8 bSeekPastNull = 0;	/* True to seek past initial nulls */
 		u8 bStopAtNull = 0;	/* Add condition to terminate at NULLs */
 		int force_integer_reg = -1;  /* If non-negative: number of
@@ -994,17 +909,7 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 		 * and store the values of those terms in an array of registers
 		 * starting at regBase.
 		 */
-		regBase =
-		    codeAllEqualityTerms(pParse, pLevel, bRev, nExtraReg,
-					 &start_types);
-		if (start_types != NULL && nTop) {
-			uint32_t len = 0;
-			for (enum field_type *tmp = &start_types[nEq];
-			     *tmp != field_type_MAX; tmp++, len++);
-			uint32_t sz = len * sizeof(enum field_type);
-			end_types = sqlDbMallocRaw(db, sz);
-			memcpy(end_types, &start_types[nEq], sz);
-		}
+		regBase = codeAllEqualityTerms(pParse, pLevel, bRev, nExtraReg);
 		addrNxt = pLevel->addrNxt;
 
 		testcase(pRangeStart && (pRangeStart->eOperator & WO_LE) != 0);
@@ -1029,10 +934,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 				VdbeCoverage(v);
 			}
 
-			if (start_types) {
-				expr_cmp_update_rhs_type(pRight, nBtm,
-							 &start_types[nEq]);
-			}
 			nConstraint += nBtm;
 			testcase(pRangeStart->wtFlags & TERM_VIRTUAL);
 			if (sqlExprIsVector(pRight) == 0) {
@@ -1049,91 +950,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 		}
 		struct index_def *idx_pk = space->index[0]->def;
 		uint32_t pk_part_count = idx_pk->key_def->part_count;
-		/*
-		 * Tarantool's iterator over integer fields doesn't
-		 * tolerate floating point values. Hence, if term
-		 * is equality comparison and value of operand is
-		 * not integer, we can skip it since it always
-		 * results in false: INT a == 0.5 -> false;
-		 * It is done using OP_MustBeInt facilities.
-		 * In case term is greater comparison (a > ?), we
-		 * should notify OP_SeekGT to process truncation of
-		 * floating point value: a > 0.5 -> a >= 1;
-		 * It is done by setting P5 flag for OP_Seek*.
-		 * It is worth mentioning that we do not need
-		 * this step when it comes for less (<) comparison
-		 * of nullable field. Key is NULL in this case:
-		 * values are ordered as  NULL, ... NULL, min_value,
-		 * so to fetch min value we pass NULL to GT iterator.
-		 * The only exception is less comparison in
-		 * conjunction with ORDER BY DESC clause:
-		 * in such situation we use LE iterator and
-		 * truncated value to compare. But then
-		 * pRangeStart == NULL.
-		 * This procedure is correct for compound index:
-		 * only one comparison of less/greater type can be
-		 * used at the same time. For instance,
-		 * a < 1.5 AND b > 0.5 is handled by SeekGT using
-		 * column a and fetching column b from tuple and
-		 * OP_Le comparison.
-		 *
-		 * Note that OP_ApplyType, which is emitted before
-		 * OP_Seek** doesn't truncate floating point to
-		 * integer. That's why we need this routine.
-		 * Also, note that terms are separated by OR
-		 * predicates, so we consider term as sequence
-		 * of AND'ed predicates.
-		 */
-		size_t addrs_sz = sizeof(int) * nEq;
-		int *seek_addrs = region_alloc(&pParse->region, addrs_sz);
-		if (seek_addrs == NULL) {
-			diag_set(OutOfMemory, addrs_sz, "region", "seek_addrs");
-			pParse->is_aborted = true;
-			return 0;
-		}
-		memset(seek_addrs, 0, addrs_sz);
-		for (int i = 0; i < nEq; i++) {
-			enum field_type type = idx_def->key_def->parts[i].type;
-			if (type == FIELD_TYPE_INTEGER ||
-			    type == FIELD_TYPE_UNSIGNED) {
-				/*
-				 * OP_MustBeInt consider NULLs as
-				 * non-integer values, so firstly
-				 * check whether value is NULL or not.
-				 */
-				seek_addrs[i] = sqlVdbeAddOp1(v, OP_IsNull,
-							      regBase);
-				sqlVdbeAddOp2(v, OP_MustBeInt, regBase + i,
-					      addrNxt);
-				start_types[i] = FIELD_TYPE_SCALAR;
-				/*
-				 * We need to notify column cache
-				 * that type of value may change
-				 * so we should fetch value from
-				 * tuple again rather then copy
-				 * from register.
-				 */
-				sql_expr_type_cache_change(pParse, regBase + i,
-							   1);
-			}
-		}
-		/* Inequality constraint comes always at the end of list. */
-		part_count = idx_def->key_def->part_count;
-		if (pRangeStart != NULL) {
-			/*
-			 * nEq == 0 means that filter condition
-			 * contains only inequality.
-			 */
-			uint32_t ineq_idx = nEq == 0 ? 0 : nEq - 1;
-			assert(ineq_idx < part_count);
-			enum field_type ineq_type =
-				idx_def->key_def->parts[ineq_idx].type;
-			if (ineq_type == FIELD_TYPE_INTEGER ||
-			    ineq_type == FIELD_TYPE_UNSIGNED)
-				force_integer_reg = regBase + nEq;
-		}
-		emit_apply_type(pParse, regBase, nConstraint - bSeekPastNull,
-				start_types);
 		if (pLoop->nSkip > 0 && nConstraint == pLoop->nSkip) {
 			/* The skip-scan logic inside the call to codeAllEqualityConstraints()
 			 * above has already left the cursor sitting on the correct row,
@@ -1143,10 +959,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 			op = aStartOp[(start_constraints << 2) +
 				      (startEq << 1) + bRev];
 			assert(op != 0);
-			for (uint32_t i = 0; i < nEq; ++i) {
-				if (seek_addrs[i] != 0)
-					sqlVdbeJumpHere(v, seek_addrs[i]);
-			}
 			sqlVdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase,
 					     nConstraint);
 			/* If this is Seek* opcode, and IPK is detected in the
@@ -1186,13 +998,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 						  addrNxt);
 				VdbeCoverage(v);
 			}
-			if (end_types) {
-				expr_cmp_update_rhs_type(pRight, nTop, end_types);
-				emit_apply_type(pParse, regBase + nEq, nTop,
-						end_types);
-			} else {
-				assert(pParse->db->mallocFailed);
-			}
 			nConstraint += nTop;
 			testcase(pRangeEnd->wtFlags & TERM_VIRTUAL);
 
@@ -1206,8 +1011,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 			endEq = 0;
 			nConstraint++;
 		}
-		sqlDbFree(db, start_types);
-		sqlDbFree(db, end_types);
 
 		/* Top of the loop body */
 		pLevel->p2 = sqlVdbeCurrentAddr(v);
diff --git a/test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua b/test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua
new file mode 100755
index 000000000..ef4127e0e
--- /dev/null
+++ b/test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua
@@ -0,0 +1,78 @@
+#!/usr/bin/env tarantool
+test = require("sqltester")
+test:plan(8)
+
+--
+-- Make sure that there is no implicit cast between string and
+-- number.
+--
+test:do_catchsql_test(
+    "gh-4230-1",
+    [[
+        SELECT '1' > 0;
+    ]], {
+        1, "Type mismatch: can not convert 1 to numeric"
+    })
+
+test:do_catchsql_test(
+    "gh-4230-2",
+    [[
+        SELECT 0 > '1';
+    ]], {
+        1, "Type mismatch: can not convert 1 to numeric"
+    })
+
+test:execsql([[
+        CREATE TABLE t (i INT PRIMARY KEY, d DOUBLE, n NUMBER, s STRING);
+        INSERT INTO t VALUES (1, 1.0, 1, '2'), (2, 2.0, 2.0, '2');
+    ]])
+
+test:do_catchsql_test(
+    "gh-4230-3",
+    [[
+        SELECT * from t where i > s;
+    ]], {
+        1, "Type mismatch: can not convert 2 to numeric"
+    })
+
+test:do_catchsql_test(
+    "gh-4230-4",
+    [[
+        SELECT * from t WHERE s > i;
+    ]], {
+        1, "Type mismatch: can not convert 2 to numeric"
+    })
+
+test:do_catchsql_test(
+    "gh-4230-5",
+    [[
+        SELECT * from t WHERE d > s;
+    ]], {
+        1, "Type mismatch: can not convert 2 to numeric"
+    })
+
+test:do_catchsql_test(
+    "gh-4230-6",
+    [[
+        SELECT * from t WHERE s > d;
+    ]], {
+        1, "Type mismatch: can not convert 2 to numeric"
+    })
+
+test:do_catchsql_test(
+    "gh-4230-7",
+    [[
+        SELECT * from t WHERE i = 1 and n > s;
+    ]], {
+        1, "Type mismatch: can not convert 2 to numeric"
+    })
+
+test:do_catchsql_test(
+    "gh-4230-8",
+    [[
+        SELECT * from t WHERE i = 2 and s > n;
+    ]], {
+        1, "Type mismatch: can not convert 2 to numeric"
+    })
+
+test:finish_test()
diff --git a/test/sql-tap/identifier_case.test.lua b/test/sql-tap/identifier_case.test.lua
index 2a00626fc..1d56ffb44 100755
--- a/test/sql-tap/identifier_case.test.lua
+++ b/test/sql-tap/identifier_case.test.lua
@@ -242,11 +242,11 @@ data = {
     { 2,  [[ 'a' < 'b' collate "binary" ]], {0, {true}}},
     { 3,  [[ 'a' < 'b' collate 'binary' ]], {1, [[Syntax error at line 1 near ''binary'']]}},
     { 4,  [[ 'a' < 'b' collate "unicode" ]], {0, {true}}},
-    { 5,  [[ 5 < 'b' collate "unicode" ]], {0, {true}}},
+    { 5,  [[ 5 < 'b' collate "unicode" ]], {1, "Type mismatch: can not convert b to numeric"}},
     { 6,  [[ 5 < 'b' collate unicode ]], {1,"Collation 'UNICODE' does not exist"}},
-    { 7,  [[ 5 < 'b' collate "unicode_ci" ]], {0, {true}}},
+    { 7,  [[ 5 < 'b' collate "unicode_ci" ]], {1, "Type mismatch: can not convert b to numeric"}},
     { 8,  [[ 5 < 'b' collate NONE ]], {1, "Collation 'NONE' does not exist"}},
-    { 9,  [[ 5 < 'b' collate "none" ]], {0, {true}}},
+    { 9,  [[ 5 < 'b' collate "none" ]], {1, "Type mismatch: can not convert b to numeric"}},
 }
 
 for _, row in ipairs(data) do
diff --git a/test/sql-tap/in1.test.lua b/test/sql-tap/in1.test.lua
index 570cc1779..e2f498889 100755
--- a/test/sql-tap/in1.test.lua
+++ b/test/sql-tap/in1.test.lua
@@ -637,12 +637,12 @@ test:do_test(
     "in-11.2",
     function()
         -- The '2' should be coerced into 2 because t6.b is NUMERIC
-        return test:execsql [[
+        return test:catchsql [[
             SELECT * FROM t6 WHERE b IN ('2');
         ]]
     end, {
         -- <in-11.2>
-        1, 2
+        1, "Type mismatch: can not convert 2 to numeric"
         -- </in-11.2>
     })
 
diff --git a/test/sql-tap/in4.test.lua b/test/sql-tap/in4.test.lua
index 33947d0ab..a494e846f 100755
--- a/test/sql-tap/in4.test.lua
+++ b/test/sql-tap/in4.test.lua
@@ -147,12 +147,13 @@ test:do_execsql_test(
         -- </in4-2.7>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "in4-2.8",
     [[
         SELECT b FROM t2 WHERE a IN ('', '0.0.0', '2') 
     ]], {
         -- <in4-2.8>
+        1, "Type mismatch: can not convert integer to text"
         -- </in4-2.8>
     })
 
diff --git a/test/sql-tap/insert3.test.lua b/test/sql-tap/insert3.test.lua
index b92bc508e..3276f0db2 100755
--- a/test/sql-tap/insert3.test.lua
+++ b/test/sql-tap/insert3.test.lua
@@ -59,7 +59,7 @@ test:do_execsql_test(
     [[
             CREATE TABLE log2(rowid INTEGER PRIMARY KEY AUTOINCREMENT, x TEXT UNIQUE,y INT );
             CREATE TRIGGER r2 BEFORE INSERT ON t1 FOR EACH ROW BEGIN
-              UPDATE log2 SET y=y+1 WHERE x=new.b;
+              UPDATE log2 SET y=y+1 WHERE x=CAST(new.b AS STRING);
               INSERT OR IGNORE INTO log2(x, y) VALUES(CAST(new.b AS STRING),1);
             END;
             INSERT INTO t1(a, b) VALUES('hi', 453);
diff --git a/test/sql-tap/intpkey.test.lua b/test/sql-tap/intpkey.test.lua
index 0db18ba91..bc3d701a7 100755
--- a/test/sql-tap/intpkey.test.lua
+++ b/test/sql-tap/intpkey.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(40)
+test:plan(39)
 
 --!./tcltestrunner.lua
 -- 2001 September 15
@@ -854,43 +854,33 @@ test:do_execsql_test(
         -- </intpkey-14.2>
     })
 
-test:do_execsql_test(
-    "intpkey-14.3",
-    [[
-        SELECT * FROM t3 WHERE a>'2';
-    ]], {
-        -- <intpkey-14.3>
-        3, 3, "3"
-        -- </intpkey-14.3>
-    })
-
-test:do_execsql_test(
+test:do_catchsql_test(
     "intpkey-14.4",
     [[
         SELECT * FROM t3 WHERE a<'2';
     ]], {
         -- <intpkey-14.4>
-        1, 1, "one"
+        1, "Type mismatch: can not convert text to integer"
         -- </intpkey-14.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "intpkey-14.5",
     [[
         SELECT * FROM t3 WHERE a<c;
     ]], {
         -- <intpkey-14.5>
-        1, 1, "one"
+        1, "Type mismatch: can not convert one to numeric"
         -- </intpkey-14.5>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "intpkey-14.6",
     [[
         SELECT * FROM t3 WHERE a=c;
     ]], {
         -- <intpkey-14.6>
-        2, 2, "2", 3, 3, "3"
+        1, "Type mismatch: can not convert one to numeric"
         -- </intpkey-14.6>
     })
 
diff --git a/test/sql-tap/join.test.lua b/test/sql-tap/join.test.lua
index 51e0ecb79..792302ab5 100755
--- a/test/sql-tap/join.test.lua
+++ b/test/sql-tap/join.test.lua
@@ -1028,22 +1028,23 @@ test:do_test(
         -- </join-11.8>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "join-11.9",
     [[
         SELECT * FROM t1 NATURAL JOIN t2 
     ]], {
         -- <join-11.9>
+        1, "Type mismatch: can not convert integer to text"
         -- </join-11.9>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "join-11.10",
     [[
         SELECT * FROM t2 NATURAL JOIN t1 
     ]], {
         -- <join-11.10>
-        1, "one", 2, "two"
+        1, "Type mismatch: can not convert 1 to numeric"
         -- </join-11.10>
     })
 
diff --git a/test/sql-tap/misc1.test.lua b/test/sql-tap/misc1.test.lua
index e0fe50bbe..3cef617f4 100755
--- a/test/sql-tap/misc1.test.lua
+++ b/test/sql-tap/misc1.test.lua
@@ -88,7 +88,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-1.4",
     [[
-        SELECT x75 FROM manycol WHERE x50=350
+        SELECT x75 FROM manycol WHERE x50='350'
     ]], {
         -- <misc1-1.4>
         "375"
@@ -98,7 +98,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-1.5",
     [[
-        SELECT x50 FROM manycol WHERE x99=599
+        SELECT x50 FROM manycol WHERE x99='599'
     ]], {
         -- <misc1-1.5>
         "550"
@@ -109,7 +109,7 @@ test:do_test(
     "misc1-1.6",
     function()
         test:execsql("CREATE INDEX manycol_idx1 ON manycol(x99)")
-        return test:execsql("SELECT x50 FROM manycol WHERE x99=899")
+        return test:execsql("SELECT x50 FROM manycol WHERE x99='899'")
     end, {
         -- <misc1-1.6>
         "850"
@@ -129,7 +129,7 @@ test:do_execsql_test(
 test:do_test(
     "misc1-1.8",
     function()
-        test:execsql("DELETE FROM manycol WHERE x98=1234")
+        test:execsql("DELETE FROM manycol WHERE x98='1234'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.8>
@@ -140,7 +140,7 @@ test:do_test(
 test:do_test(
     "misc1-1.9",
     function()
-        test:execsql("DELETE FROM manycol WHERE x98=998")
+        test:execsql("DELETE FROM manycol WHERE x98='998'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.9>
@@ -151,7 +151,7 @@ test:do_test(
 test:do_test(
     "misc1-1.10",
     function()
-        test:execsql("DELETE FROM manycol WHERE x99=500")
+        test:execsql("DELETE FROM manycol WHERE x99='500'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.10>
@@ -162,7 +162,7 @@ test:do_test(
 test:do_test(
     "misc1-1.11",
     function()
-        test:execsql("DELETE FROM manycol WHERE x99=599")
+        test:execsql("DELETE FROM manycol WHERE x99='599'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.11>
@@ -479,9 +479,9 @@ local where = ""
 test:do_test(
     "misc1-10.1",
     function()
-        where = "WHERE x0>=0"
+        where = "WHERE x0>='0'"
         for i = 1, 99, 1 do
-            where = where .. " AND x"..i.."<>0"
+            where = where .. " AND x"..i.."<>'0'"
         end
         return test:catchsql("SELECT count(*) FROM manycol "..where.."")
     end, {
@@ -496,7 +496,7 @@ test:do_test(
 test:do_test(
     "misc1-10.3",
     function()
-        where = string.gsub(where,"x0>=0", "x0=0")
+        where = string.gsub(where,"x0>='0'", "x0='0'")
         return test:catchsql("DELETE FROM manycol "..where.."")
     end, {
         -- <misc1-10.3>
@@ -520,7 +520,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-10.6",
     [[
-        SELECT x1 FROM manycol WHERE x0=100
+        SELECT x1 FROM manycol WHERE x0='100'
     ]], {
         -- <misc1-10.6>
         "101"
@@ -530,7 +530,7 @@ test:do_execsql_test(
 test:do_test(
     "misc1-10.7",
     function()
-        where = string.gsub(where, "x0=0", "x0=100")
+        where = string.gsub(where, "x0='0'", "x0='100'")
         return test:catchsql("UPDATE manycol SET x1=CAST(x1+1 AS STRING) "..where.."")
     end, {
         -- <misc1-10.7>
@@ -541,7 +541,7 @@ test:do_test(
 test:do_execsql_test(
     "misc1-10.8",
     [[
-        SELECT x1 FROM manycol WHERE x0=100
+        SELECT x1 FROM manycol WHERE x0='100'
     ]], {
         -- <misc1-10.8>
         "102"
@@ -563,7 +563,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-10.10",
     [[
-        SELECT x1 FROM manycol WHERE x0=100
+        SELECT x1 FROM manycol WHERE x0='100'
     ]], {
         -- <misc1-10.10>
         "103"
@@ -619,13 +619,13 @@ test:do_execsql_test(
         -- </misc1-12.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "misc1-12.2",
     [[
         SELECT '0'==0.0
     ]], {
         -- <misc1-12.2>
-        true
+        1, "Type mismatch: can not convert 0 to numeric"
         -- </misc1-12.2>
     })
 
diff --git a/test/sql-tap/select1.test.lua b/test/sql-tap/select1.test.lua
index 9a969bf3c..f5a9b63fe 100755
--- a/test/sql-tap/select1.test.lua
+++ b/test/sql-tap/select1.test.lua
@@ -1912,7 +1912,7 @@ test:do_execsql_test(
 test:do_execsql_test(
         "select1-12.7",
         [[
-            SELECT * FROM t3 WHERE a=(SELECT 1);
+            SELECT * FROM t3 WHERE a=(SELECT '1');
         ]], {
             -- <select1-12.7>
             0, "1", "2"
@@ -1922,7 +1922,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "select1-12.8",
     [[
-        SELECT * FROM t3 WHERE a=(SELECT 2);
+        SELECT * FROM t3 WHERE a=(SELECT '2');
     ]], {
         -- <select1-12.8>
 
diff --git a/test/sql-tap/select7.test.lua b/test/sql-tap/select7.test.lua
index e1e43c557..0d1390fd6 100755
--- a/test/sql-tap/select7.test.lua
+++ b/test/sql-tap/select7.test.lua
@@ -256,7 +256,7 @@ test:do_execsql_test(
         DROP TABLE IF EXISTS t5;
         CREATE TABLE t5(a TEXT primary key, b INT);
         INSERT INTO t5 VALUES('123', 456);
-        SELECT typeof(a), a FROM t5 GROUP BY a HAVING a<b;
+        SELECT typeof(a), a FROM t5 GROUP BY a HAVING CAST(a AS INTEGER)<b;
     ]], {
         -- <select7-7.7>
         "string", "123"
diff --git a/test/sql-tap/subquery.test.lua b/test/sql-tap/subquery.test.lua
index e0771825e..bad702de9 100755
--- a/test/sql-tap/subquery.test.lua
+++ b/test/sql-tap/subquery.test.lua
@@ -284,13 +284,13 @@ test:do_execsql_test(
         -- </subquery-2.3.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "subquery-2.3.2",
     [[
         SELECT a IN (10.0, 20) FROM t3;
     ]], {
         -- <subquery-2.3.2>
-        false
+        1, "Type mismatch: can not convert text to real"
         -- </subquery-2.3.2>
     })
 
diff --git a/test/sql-tap/tkt-9a8b09f8e6.test.lua b/test/sql-tap/tkt-9a8b09f8e6.test.lua
index 854ed774f..2a18b17be 100755
--- a/test/sql-tap/tkt-9a8b09f8e6.test.lua
+++ b/test/sql-tap/tkt-9a8b09f8e6.test.lua
@@ -83,23 +83,23 @@ test:do_execsql_test(
         -- </1.5>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     2.1,
     [[
         SELECT x FROM t1 WHERE x IN (1);
     ]], {
         -- <2.1>
-        "1"
+        1,"Type mismatch: can not convert 1 to numeric"
         -- </2.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     2.2,
     [[
         SELECT x FROM t1 WHERE x IN (1.0);
     ]], {
         -- <2.2>
-        "1"
+        1,"Type mismatch: can not convert 1 to numeric"
         -- </2.2>
     })
 
@@ -123,23 +123,23 @@ test:do_execsql_test(
         -- </2.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     2.5,
     [[
         SELECT x FROM t1 WHERE 1 IN (x);
     ]], {
         -- <2.5>
-        "1"
+        1,"Type mismatch: can not convert 1 to numeric"
         -- </2.5>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     2.6,
     [[
         SELECT x FROM t1 WHERE 1.0 IN (x);
     ]], {
         -- <2.6>
-        "1"
+        1,"Type mismatch: can not convert 1 to numeric"
         -- </2.6>
     })
 
@@ -183,21 +183,23 @@ test:do_execsql_test(
         -- </3.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     3.3,
     [[
         SELECT x FROM t2 WHERE x IN ('1');
     ]], {
         -- <3.3>
+        1, "Type mismatch: can not convert integer to text"
         -- </3.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     3.4,
     [[
         SELECT x FROM t2 WHERE x IN ('1');
     ]], {
         -- <3.4>
+        1, "Type mismatch: can not convert integer to text"
         -- </3.4>
     })
 
@@ -221,21 +223,23 @@ test:do_execsql_test(
         -- </3.6>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     3.7,
     [[
         SELECT x FROM t2 WHERE '1' IN (x);
     ]], {
         -- <3.7>
+        1, "Type mismatch: can not convert integer to text"
         -- </3.7>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     3.8,
     [[
         SELECT x FROM t2 WHERE '1' IN (x);
     ]], {
         -- <3.8>
+        1, "Type mismatch: can not convert integer to text"
         -- </3.8>
     })
 
@@ -259,23 +263,23 @@ test:do_execsql_test(
         -- </4.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     4.3,
     [[
         SELECT x FROM t3 WHERE x IN ('1');
     ]], {
         -- <4.3>
-        1.0
+        1, "Type mismatch: can not convert number to text"
         -- </4.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     4.4,
     [[
         SELECT x FROM t3 WHERE x IN ('1.0');
     ]], {
         -- <4.4>
-        1.0
+        1, "Type mismatch: can not convert number to text"
         -- </4.4>
     })
 
@@ -299,23 +303,23 @@ test:do_execsql_test(
         -- </4.6>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     4.7,
     [[
         SELECT x FROM t3 WHERE '1' IN (x);
     ]], {
         -- <4.7>
-        1
+        1, "Type mismatch: can not convert number to text"
         -- </4.7>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     4.8,
     [[
         SELECT x FROM t3 WHERE '1.0' IN (x);
     ]], {
         -- <4.8>
-        1
+        1, "Type mismatch: can not convert number to text"
         -- </4.8>
     })
 
@@ -339,23 +343,23 @@ test:do_execsql_test(
         -- </5.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     5.3,
     [[
         SELECT x FROM t4 WHERE x IN ('1');
     ]], {
         -- <5.3>
-        
+        1, "Type mismatch: can not convert number to text"
         -- </5.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     5.4,
     [[
         SELECT x FROM t4 WHERE x IN ('1.0');
     ]], {
         -- <5.4>
-        
+        1, "Type mismatch: can not convert number to text"
         -- </5.4>
     })
 
@@ -369,13 +373,13 @@ test:do_execsql_test(
         -- </5.5>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     5.6,
     [[
         SELECT x FROM t4 WHERE x IN ('1.11');
     ]], {
         -- <5.6>
-        1.11
+        1, "Type mismatch: can not convert number to text"
         -- </5.6>
     })
 
@@ -399,23 +403,23 @@ test:do_execsql_test(
         -- </5.8>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     5.9,
     [[
         SELECT x FROM t4 WHERE '1' IN (x);
     ]], {
         -- <5.9>
-        
+        1, "Type mismatch: can not convert number to text"
         -- </5.9>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     5.10,
     [[
         SELECT x FROM t4 WHERE '1.0' IN (x);
     ]], {
         -- <5.10>
-        
+        1, "Type mismatch: can not convert number to text"
         -- </5.10>
     })
 
@@ -429,13 +433,13 @@ test:do_execsql_test(
         -- </5.11>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     5.12,
     [[
         SELECT x FROM t4 WHERE '1.11' IN (x);
     ]], {
         -- <5.12>
-        1.11
+        1, "Type mismatch: can not convert number to text"
         -- </5.12>
     })
 
@@ -459,23 +463,23 @@ test:do_execsql_test(
         -- </6.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     6.3,
     [[
         SELECT x, y FROM t5 WHERE x IN ('1');
     ]], {
         -- <6.3>
-        1, "one", 1, "two", 1, "three", 1.0, "four"
+        1, "Type mismatch: can not convert 1 to numeric"
         -- </6.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     6.4,
     [[
         SELECT x, y FROM t5 WHERE x IN ('1.0');
     ]], {
         -- <6.4>
-        1, "one", 1, "two", 1, "three", 1.0, "four"
+        1, "Type mismatch: can not convert 1.0 to numeric"
         -- </6.4>
     })
 
@@ -499,23 +503,23 @@ test:do_execsql_test(
         -- </6.6>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     6.7,
     [[
         SELECT x, y FROM t5 WHERE '1' IN (x);
     ]], {
         -- <6.7>
-        1, "one", 1, "two", 1, "three", 1.0, "four"
+        1, "Type mismatch: can not convert 1 to numeric"
         -- </6.7>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     6.8,
     [[
         SELECT x, y FROM t5 WHERE '1.0' IN (x);
     ]], {
         -- <6.8>
-        1, "one", 1, "two", 1, "three", 1, "four"
+        1, "Type mismatch: can not convert 1.0 to numeric"
         -- </6.8>
     })
 
diff --git a/test/sql-tap/tkt-f973c7ac31.test.lua b/test/sql-tap/tkt-f973c7ac31.test.lua
index 82bdb52f8..5239a7785 100755
--- a/test/sql-tap/tkt-f973c7ac31.test.lua
+++ b/test/sql-tap/tkt-f973c7ac31.test.lua
@@ -36,12 +36,12 @@ local sqls = {
 
 for tn, sql in ipairs(sqls) do
     test:execsql(sql)
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".1",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='2' ORDER BY c2 DESC 
         ]], {
-            
+            1, "/Type mismatch: can not convert/"
         })
 
     test:do_execsql_test(
@@ -52,36 +52,36 @@ for tn, sql in ipairs(sqls) do
             5, 5, 5, 4
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".3",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='5' ORDER BY c2 DESC 
         ]], {
-            5, 5, 5, 4
+            1, "/Type mismatch: can not convert/"
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".4",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<=5 ORDER BY c2 DESC 
         ]], {
-            5, 5, 5, 4
+            1, "/Type mismatch: can not convert/"
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".5",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<='5' ORDER BY c2 DESC 
         ]], {
-            5, 5, 5, 4
+            1, "/Type mismatch: can not convert/"
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".6",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='2' ORDER BY c2 ASC 
         ]], {
-            
+            1, "/Type mismatch: can not convert/"
         })
 
     test:do_execsql_test(
@@ -92,28 +92,28 @@ for tn, sql in ipairs(sqls) do
             5, 4, 5, 5
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".8",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='5' ORDER BY c2 ASC 
         ]], {
-            5, 4, 5, 5
+            1, "/Type mismatch: can not convert/"
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".9",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<=5 ORDER BY c2 ASC 
         ]], {
-            5, 4, 5, 5
+            1, "/Type mismatch: can not convert/"
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".10",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<='5' ORDER BY c2 ASC 
         ]], {
-            5, 4, 5, 5
+            1, "/Type mismatch: can not convert/"
         })
 
 end
diff --git a/test/sql-tap/tkt-fc7bd6358f.test.lua b/test/sql-tap/tkt-fc7bd6358f.test.lua
index f38ffa3d6..f77e4bea8 100755
--- a/test/sql-tap/tkt-fc7bd6358f.test.lua
+++ b/test/sql-tap/tkt-fc7bd6358f.test.lua
@@ -78,15 +78,17 @@ for a, from in ipairs(froms) do
         test:do_test(
             string.format("tkt-fc7bd6358f.110.%s.%s.1", a, b),
             function()
-                return test:execsql(string.format("SELECT t1.textid, i.intid, t2.textid %s %s", from, where))
+                return test:catchsql(string.format("SELECT t1.textid, i.intid, t2.textid %s %s", from, where))
             end, {
+                1, "Type mismatch: can not convert integer to text"
             })
 
         test:do_test(
             string.format("tkt-fc7bd6358f.110.%s.%s.2", a, b),
             function()
-                return test:execsql(string.format("SELECT t1.textid, i.intid, t2.textid %s %s", from, where))
+                return test:catchsql(string.format("SELECT t1.textid, i.intid, t2.textid %s %s", from, where))
             end, {
+                1, "Type mismatch: can not convert integer to text"
             })
 
     end
diff --git a/test/sql-tap/tkt3493.test.lua b/test/sql-tap/tkt3493.test.lua
index de77e61e9..ec12a4492 100755
--- a/test/sql-tap/tkt3493.test.lua
+++ b/test/sql-tap/tkt3493.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(26)
+test:plan(25)
 
 --!./tcltestrunner.lua
 -- 2008 October 13
@@ -45,7 +45,7 @@ test:do_execsql_test(
     [[
         SELECT 
           CASE 
-             WHEN B.val = 1 THEN 'XYZ' 
+             WHEN B.val = '1' THEN 'XYZ'
              ELSE A.val 
           END AS Col1
         FROM B  
@@ -63,7 +63,7 @@ test:do_execsql_test(
     [[
         SELECT DISTINCT
           CASE 
-             WHEN B.val = 1 THEN 'XYZ' 
+             WHEN B.val = '1' THEN 'XYZ'
              ELSE A.val 
           END AS Col1
         FROM B  
@@ -79,7 +79,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-1.4",
     [[
-        SELECT b.val, CASE WHEN b.val = 1 THEN 'xyz' ELSE b.val END AS col1 FROM b;
+        SELECT b.val, CASE WHEN b.val = '1' THEN 'xyz' ELSE b.val END AS col1 FROM b;
     ]], {
         -- <tkt3493-1.4>
         "1", "xyz", "2", "2"
@@ -91,7 +91,7 @@ test:do_execsql_test(
     [[
         SELECT DISTINCT 
           b.val, 
-          CASE WHEN b.val = 1 THEN 'xyz' ELSE b.val END AS col1 
+          CASE WHEN b.val = '1' THEN 'xyz' ELSE b.val END AS col1
         FROM b;
     ]], {
         -- <tkt3493-1.5>
@@ -126,23 +126,13 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.2.1",
     [[
-        SELECT a=123 FROM t1 GROUP BY a 
+        SELECT a='123' FROM t1 GROUP BY a 
     ]], {
         -- <tkt3493-2.2.1>
         true
         -- </tkt3493-2.2.1>
     })
 
-test:do_execsql_test(
-    "tkt3493-2.2.2",
-    [[
-        SELECT a=123 FROM t1 
-    ]], {
-        -- <tkt3493-2.2.2>
-        true
-        -- </tkt3493-2.2.2>
-    })
-
 test:do_execsql_test(
     "tkt3493-2.2.3",
     [[
@@ -156,7 +146,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.2.4",
     [[
-        SELECT count(*), a=123 FROM t1 
+        SELECT count(*), a='123' FROM t1 
     ]], {
         -- <tkt3493-2.2.4>
         1, true
@@ -166,7 +156,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.2.5",
     [[
-        SELECT count(*), +a=123 FROM t1 
+        SELECT count(*), +a='123' FROM t1 
     ]], {
         -- <tkt3493-2.2.5>
         1, true
@@ -176,7 +166,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.3.3",
     [[
-        SELECT b='456' FROM t1 GROUP BY a 
+        SELECT b = 456 FROM t1 GROUP BY a
     ]], {
         -- <tkt3493-2.3.3>
         true
@@ -186,7 +176,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.3.1",
     [[
-        SELECT b='456' FROM t1 GROUP BY b 
+        SELECT b = 456 FROM t1 GROUP BY b
     ]], {
         -- <tkt3493-2.3.1>
         true
@@ -196,7 +186,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.3.2",
     [[
-        SELECT b='456' FROM t1 
+        SELECT b = 456 FROM t1
     ]], {
         -- <tkt3493-2.3.2>
         true
@@ -206,7 +196,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.4.1",
     [[
-        SELECT typeof(a), a FROM t1 GROUP BY a HAVING a=123 
+        SELECT typeof(a), a FROM t1 GROUP BY a HAVING a='123'
     ]], {
         -- <tkt3493-2.4.1>
         "string", "123"
@@ -216,7 +206,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.4.2",
     [[
-        SELECT typeof(a), a FROM t1 GROUP BY b HAVING a=123 
+        SELECT typeof(a), a FROM t1 GROUP BY b HAVING a='123'
     ]], {
         -- <tkt3493-2.4.2>
         "string", "123"
@@ -226,7 +216,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.5.1",
     [[
-        SELECT typeof(b), b FROM t1 GROUP BY a HAVING b='456' 
+        SELECT typeof(b), b FROM t1 GROUP BY a HAVING b=456
     ]], {
         -- <tkt3493-2.5.1>
         "integer", 456
@@ -236,7 +226,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.5.2",
     [[
-        SELECT typeof(b), b FROM t1 GROUP BY b HAVING b='456' 
+        SELECT typeof(b), b FROM t1 GROUP BY b HAVING b=456
     ]], {
         -- <tkt3493-2.5.2>
         "integer", 456
diff --git a/test/sql-tap/transitive1.test.lua b/test/sql-tap/transitive1.test.lua
index 96895b4a7..cc7e066bf 100755
--- a/test/sql-tap/transitive1.test.lua
+++ b/test/sql-tap/transitive1.test.lua
@@ -63,7 +63,7 @@ test:do_execsql_test(
         INSERT INTO t2 VALUES(2, 20,20,'20');
         INSERT INTO t2 VALUES(3, 3,3,'3');
 
-        SELECT a,b,c FROM t2 WHERE a=b AND c=b AND c=20;
+        SELECT a,b,c FROM t2 WHERE a=b AND c=CAST(b AS STRING) AND c='20';
     ]], {
         -- <transitive1-200>
         20, 20, "20"
@@ -73,7 +73,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "transitive1-210",
     [[
-        SELECT a,b,c FROM t2 WHERE a=b AND c=b AND c>='20' ORDER BY +a;
+        SELECT a,b,c FROM t2 WHERE a=b AND c=CAST(b AS STRING) AND c>='20' ORDER BY +a;
     ]], {
         -- <transitive1-210>
         3, 3, "3", 20, 20, "20"
@@ -83,7 +83,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "transitive1-220",
     [[
-        SELECT a,b,c FROM t2 WHERE a=b AND c=b AND c<='20' ORDER BY +a;
+        SELECT a,b,c FROM t2 WHERE a=b AND c=CAST(b AS STRING) AND c<='20' ORDER BY +a;
     ]], {
         -- <transitive1-220>
         20, 20, "20", 100, 100, "100"
@@ -402,7 +402,7 @@ test:do_execsql_test(
     [[
         CREATE TABLE x(i INTEGER PRIMARY KEY, y TEXT);
         INSERT INTO x VALUES(10, '10');
-        SELECT * FROM x WHERE x.y>='1' AND x.y<'2' AND x.i=x.y;
+        SELECT * FROM x WHERE x.y>='1' AND x.y<'2' AND CAST(x.i AS STRING)=x.y;
     ]], {
         -- <transitive1-500>
         10, "10"
@@ -430,7 +430,7 @@ test:do_execsql_test(
     [[
         CREATE TABLE t3(i INTEGER PRIMARY KEY, t TEXT);
         INSERT INTO t3 VALUES(10, '10');
-        SELECT * FROM t3 WHERE i=t AND t = '10 ';
+        SELECT * FROM t3 WHERE CAST(i AS STRING)=t AND t = '10 ';
     ]], {
         -- <transitive1-520>
 
@@ -443,7 +443,7 @@ test:do_execsql_test(
         CREATE TABLE u1(x TEXT PRIMARY KEY, y INTEGER, z TEXT);
         CREATE INDEX i1 ON u1(x);
         INSERT INTO u1 VALUES('00013', 13, '013');
-        SELECT * FROM u1 WHERE x=y AND y=z AND z='013';
+        SELECT * FROM u1 WHERE CAST(x AS INTEGER)=y AND y=CAST(z AS INTEGER) AND z='013';
     ]], {
         -- <transitive1-530>
         "00013",13,"013"
diff --git a/test/sql-tap/where2.test.lua b/test/sql-tap/where2.test.lua
index f267be8e6..7348a855a 100755
--- a/test/sql-tap/where2.test.lua
+++ b/test/sql-tap/where2.test.lua
@@ -4,7 +4,7 @@ yaml = require("yaml")
 fio = require("fio")
 
 ffi = require("ffi")
-test:plan(74)
+test:plan(62)
 
 ffi.cdef[[
        int dup(int oldfd);
@@ -622,181 +622,12 @@ test:do_test(
         -- </where2-6.6>
     })
 
--- if X(356, "X!cmd", [=[["expr","[permutation] != \"no_optimization\""]]=])
--- then
-    -- Ticket #2249.  Make sure the OR optimization is not attempted if
-    -- comparisons between columns of different affinities are needed.
-    --
-    test:do_test(
-        "where2-6.7",
-        function()
-            test:execsql [[
-                CREATE TABLE t2249a(a TEXT PRIMARY KEY, x VARCHAR(100));
-                CREATE TABLE t2249b(b INTEGER PRIMARY KEY);
-                INSERT INTO t2249a(a) VALUES('0123');
-                INSERT INTO t2249b VALUES(123);
-            ]]
-            return queryplan([[
-    -- Because a is type TEXT and b is type INTEGER, both a and b
-    -- will attempt to convert to NUMERIC before the comparison.
-    -- They will thus compare equal.
-    --
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=b;
-  ]])
-        end, {
-            -- <where2-6.7>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.7>
-        })
-
-    test:do_test(
-        "where2-6.9",
-        function()
-            return queryplan([[
-    -- The + operator doesn't affect RHS.
-    --
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b;
-  ]])
-        end, {
-            -- <where2-6.9>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.9>
-        })
-
-    test:do_test(
-        "where2-6.9.2",
-        function()
-            -- The same thing but with the expression flipped around.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=a
-  ]])
-        end, {
-            -- <where2-6.9.2>
-            123, "0123","nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.9.2>
-        })
-
-    test:do_test(
-        "where2-6.10",
-        function()
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +a=+b;
-  ]])
-        end, {
-            -- <where2-6.10>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.10>
-        })
-
-    test:do_test(
-        "where2-6.11",
-        function()
-            -- This will not attempt the OR optimization because of the a=b
-            -- comparison.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=b OR a='hello';
-  ]])
-        end, {
-            -- <where2-6.11>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.11>
-        })
-
-    test:do_test(
-        "where2-6.11.2",
-        function()
-            -- Permutations of the expression terms.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE b=a OR a='hello';
-  ]])
-        end, {
-            -- <where2-6.11.2>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.11.2>
-        })
-
-    test:do_test(
-        "where2-6.11.3",
-        function()
-            -- Permutations of the expression terms.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE 'hello'=a OR b=a;
-  ]])
-        end, {
-            -- <where2-6.11.3>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.11.3>
-        })
-
-    test:do_test(
-        "where2-6.11.4",
-        function()
-            -- Permutations of the expression terms.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR b=a;
-  ]])
-        end, {
-            -- <where2-6.11.4>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.11.4>
-        })
-
-    -- These tests are not run if subquery support is not included in the
-    -- build. This is because these tests test the "a = 1 OR a = 2" to
-    -- "a IN (1, 2)" optimisation transformation, which is not enabled if
-    -- subqueries and the IN operator is not available.
-    --
-    test:do_test(
-        "where2-6.12",
-        function()
-            return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b OR a='hello';
-    ]])
-        end, {
-            -- <where2-6.12>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.12>
-        })
-
-    test:do_test(
-        "where2-6.12.2",
-        function()
-            return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR +b=a;
-    ]])
-        end, {
-            -- <where2-6.12.2>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.12.2>
-        })
-
-    test:do_test(
-        "where2-6.12.3",
-        function()
-            return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=a OR a='hello';
-    ]])
-        end, {
-            -- <where2-6.12.3>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.12.3>
-        })
-
-    test:do_test(
-        "where2-6.13",
-        function()
-            -- The addition of +a on the second term disabled the OR optimization.
-            -- But we should still get the same empty-set result as in where2-6.9.
-            return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b OR +a='hello';
-    ]])
-        end, {
-            -- <where2-6.13>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.13>
-        })
-
-
+    test:execsql [[
+        CREATE TABLE t2249a(a TEXT PRIMARY KEY, x VARCHAR(100));
+        CREATE TABLE t2249b(b INTEGER PRIMARY KEY);
+        INSERT INTO t2249a(a) VALUES('0123');
+        INSERT INTO t2249b VALUES(123);
+    ]]
 
     -- Variations on the order of terms in a WHERE clause in order
     -- to make sure the OR optimizer can recognize them all.
diff --git a/test/sql-tap/where5.test.lua b/test/sql-tap/where5.test.lua
index 3aefcaca5..a93ba7854 100755
--- a/test/sql-tap/where5.test.lua
+++ b/test/sql-tap/where5.test.lua
@@ -34,7 +34,7 @@ test:do_test("where5-1.0", function()
         INSERT INTO t3 SELECT CAST(x AS INTEGER) FROM t1;
     ]]
     return test:execsql [[
-        SELECT * FROM t1 WHERE x<0
+        SELECT * FROM t1 WHERE CAST(x AS INTEGER)<0
     ]]
 end, {
     -- <where5-1.0>
@@ -43,7 +43,7 @@ end, {
 })
 
 test:do_execsql_test("where5-1.1", [[
-    SELECT * FROM t1 WHERE x<=0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)<=0
 ]], {
     -- <where5-1.1>
     '-1', '0'
@@ -51,7 +51,7 @@ test:do_execsql_test("where5-1.1", [[
 })
 
 test:do_execsql_test("where5-1.2", [[
-    SELECT * FROM t1 WHERE x=0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)=0
 ]], {
     -- <where5-1.2>
     '0'
@@ -59,7 +59,7 @@ test:do_execsql_test("where5-1.2", [[
 })
 
 test:do_execsql_test("where5-1.3", [[
-    SELECT * FROM t1 WHERE x>=0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)>=0
 ]], {
     -- <where5-1.3>
     '0', '1'
@@ -67,7 +67,7 @@ test:do_execsql_test("where5-1.3", [[
 })
 
 test:do_execsql_test("where5-1.4", [[
-    SELECT * FROM t1 WHERE x>0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)>0
 ]], {
     -- <where5-1.4>
     '1'
@@ -75,7 +75,7 @@ test:do_execsql_test("where5-1.4", [[
 })
 
 test:do_execsql_test("where5-1.5", [[
-    SELECT * FROM t1 WHERE x<>0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)<>0
 ]], {
     -- <where5-1.5>
     '-1', '1'
diff --git a/test/sql-tap/whereB.test.lua b/test/sql-tap/whereB.test.lua
index 970ff1dec..9e99ea41c 100755
--- a/test/sql-tap/whereB.test.lua
+++ b/test/sql-tap/whereB.test.lua
@@ -27,8 +27,7 @@ test:plan(63)
 -- These values are not equal and because neither affinity is NUMERIC
 -- no type conversion occurs.
 --
-test:do_execsql_test(
-    "whereB-1.1",
+test:execsql(
     [[
         CREATE TABLE t1(x  INT primary key,y INT );    -- affinity of t1.y is NONE
         INSERT INTO t1 VALUES(1,99);
@@ -36,49 +35,54 @@ test:do_execsql_test(
         CREATE TABLE t2(a  INT primary key, b TEXT);  -- affinity of t2.b is TEXT
         CREATE INDEX t2b ON t2(b);
         INSERT INTO t2 VALUES(2,'99');
+    ]]
+)
 
+test:do_catchsql_test(
+    "whereB-1.1",
+    [[
         SELECT x, a, y=b FROM t1, t2 ORDER BY +x, +a;
     ]],
     {
     -- <whereB-1.1>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-1.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-1.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-1.2>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-1.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-1.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-1.3>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-1.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-1.4",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
     ]],
     {
     -- <whereB-1.4>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-1.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-1.100",
     [[
         DROP INDEX t2b ON t2;
@@ -86,29 +90,29 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-1.100>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-1.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-1.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-1.101>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-1.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-1.102",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
     ]],
     {
     -- <whereB-1.102>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-1.102>
     })
 
@@ -304,8 +308,7 @@ test:do_execsql_test(
 -- Because t2.b has a numeric affinity, type conversion should occur
 -- and the two fields should be equal.
 --
-test:do_execsql_test(
-    "whereB-4.1",
+test:execsql(
     [[
         DROP TABLE IF EXISTS t1;
         DROP TABLE IF EXISTS t2;
@@ -316,38 +319,44 @@ test:do_execsql_test(
         CREATE TABLE t2(a  INT primary key, b NUMBER);  -- affinity of t2.b is NUMERIC
         CREATE INDEX t2b ON t2(b);
         INSERT INTO t2 VALUES(2,99);
+    ]]
+)
 
+
+test:do_catchsql_test(
+    "whereB-4.1",
+    [[
         SELECT x, a, y=b FROM t1, t2;
     ]],
     {
     -- <whereB-4.1>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-4.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-4.2>
-    1, 2, true
+    1, "Type mismatch: can not convert number to text"
     -- </whereB-4.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-4.3>
-    1, 2, true
+    1, "Type mismatch: can not convert number to text"
     -- </whereB-4.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.4",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -356,11 +365,11 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-4.4>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-4.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.100",
     [[
         DROP INDEX t2b ON t2;
@@ -368,22 +377,22 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-4.100>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-4.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-4.101>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-4.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.102",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -392,7 +401,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-4.102>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-4.102>
     })
 
@@ -404,8 +413,7 @@ test:do_execsql_test(
 -- Because t2.b has a numeric affinity, type conversion should occur
 -- and the two fields should be equal.
 --
-test:do_execsql_test(
-    "whereB-5.1",
+test:execsql(
     [[
         DROP TABLE t1;
         DROP TABLE t2;
@@ -416,36 +424,43 @@ test:do_execsql_test(
         CREATE TABLE t2(a  INT primary key, b INT);  -- affinity of t2.b is INTEGER
         CREATE INDEX t2b ON t2(b);
         INSERT INTO t2 VALUES(2,99);
+    ]]
+)
 
+test:do_catchsql_test(
+    "whereB-5.1",
+    [[
         SELECT x, a, y=b FROM t1, t2;
     ]],
     {
     -- <whereB-5.1>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-5.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-5.2>
+    1, "Type mismatch: can not convert integer to text"
     -- </whereB-5.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-5.3>
+    1, "Type mismatch: can not convert integer to text"
     -- </whereB-5.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.4",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -454,11 +469,11 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-5.4>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-5.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.100",
     [[
         DROP INDEX t2b ON t2;
@@ -466,22 +481,22 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-5.100>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-5.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-5.101>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-5.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.102",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -490,7 +505,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-5.102>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-5.102>
     })
 
@@ -502,8 +517,8 @@ test:do_execsql_test(
 -- Because t2.b has a numeric affinity, type conversion should occur
 -- and the two fields should be equal.
 --
-test:do_execsql_test(
-    "whereB-6.1",
+
+test:execsql(
     [[
         DROP TABLE t1;
         DROP TABLE t2;
@@ -514,38 +529,43 @@ test:do_execsql_test(
         CREATE TABLE t2(a  INT primary key, b NUMBER);  -- affinity of t2.b is REAL
         CREATE INDEX t2b ON t2(b);
         INSERT INTO t2 VALUES(2,99.0);
+    ]]
+)
 
+test:do_catchsql_test(
+    "whereB-6.1",
+    [[
         SELECT x, a, y=b FROM t1, t2;
     ]],
     {
     -- <whereB-6.1>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-6.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-6.2>
-    1, 2, true
+    1, "Type mismatch: can not convert number to text"
     -- </whereB-6.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-6.3>
-    1, 2, true
+    1, "Type mismatch: can not convert number to text"
     -- </whereB-6.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.4",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -554,11 +574,11 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-6.4>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-6.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.100",
     [[
         DROP INDEX t2b ON t2;
@@ -566,22 +586,22 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-6.100>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-6.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-6.101>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-6.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.102",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -590,7 +610,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-6.102>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-6.102>
     })
 
@@ -602,8 +622,7 @@ test:do_execsql_test(
 -- Because t1.y has a numeric affinity, type conversion should occur
 -- and the two fields should be equal.
 --
-test:do_execsql_test(
-    "whereB-7.1",
+test:execsql(
     [[
         DROP TABLE t1;
         DROP TABLE t2;
@@ -614,38 +633,43 @@ test:do_execsql_test(
         CREATE TABLE t2(a  INT primary key, b SCALAR);  -- affinity of t2.b is NONE
         CREATE INDEX t2b ON t2(b);
         INSERT INTO t2 VALUES(2,'99');
+    ]]
+)
 
+test:do_catchsql_test(
+    "whereB-7.1",
+    [[
         SELECT x, a, y=b FROM t1, t2;
     ]],
     {
     -- <whereB-7.1>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-7.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-7.2>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-7.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-7.3>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-7.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.4",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -654,11 +678,11 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-7.4>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-7.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.100",
     [[
         DROP INDEX t2b ON t2;
@@ -666,22 +690,22 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-7.100>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-7.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-7.101>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-7.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.102",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -690,7 +714,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-7.102>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-7.102>
     })
 
@@ -702,8 +726,7 @@ test:do_execsql_test(
 -- Because t1.y has a numeric affinity, type conversion should occur
 -- and the two fields should be equal.
 --
-test:do_execsql_test(
-    "whereB-8.1",
+test:execsql(
     [[
         DROP TABLE t1;
         DROP TABLE t2;
@@ -714,38 +737,43 @@ test:do_execsql_test(
         CREATE TABLE t2(a  INT primary key, b SCALAR);  -- affinity of t2.b is NONE
         CREATE INDEX t2b ON t2(b);
         INSERT INTO t2 VALUES(2,'99');
+    ]]
+)
 
+test:do_catchsql_test(
+    "whereB-8.1",
+    [[
         SELECT x, a, y=b FROM t1, t2;
     ]],
     {
     -- <whereB-8.1>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-8.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-8.2>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-8.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-8.3>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-8.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.4",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -754,11 +782,11 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-8.4>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-8.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.100",
     [[
         DROP INDEX t2b ON t2;
@@ -766,22 +794,22 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-8.100>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-8.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-8.101>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-8.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.102",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -790,7 +818,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-8.102>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-8.102>
     })
 
@@ -802,8 +830,7 @@ test:do_execsql_test(
 -- Because t1.y has a numeric affinity, type conversion should occur
 -- and the two fields should be equal.
 --
-test:do_execsql_test(
-    "whereB-9.1",
+test:execsql(
     [[
         DROP TABLE t1;
         DROP TABLE t2;
@@ -814,38 +841,43 @@ test:do_execsql_test(
         CREATE TABLE t2(a  INT primary key, b SCALAR);  -- affinity of t2.b is NONE
         CREATE INDEX t2b ON t2(b);
         INSERT INTO t2 VALUES(2,'99');
+    ]]
+)
 
+test:do_catchsql_test(
+    "whereB-9.1",
+    [[
         SELECT x, a, y=b FROM t1, t2;
     ]],
     {
     -- <whereB-9.1>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-9.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-9.2>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-9.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-9.3>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-9.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.4",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -854,11 +886,11 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-9.4>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-9.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.100",
     [[
         DROP INDEX t2b ON t2;
@@ -866,22 +898,22 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-9.100>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-9.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-9.101>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-9.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.102",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -890,7 +922,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-9.102>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-9.102>
     })
 
diff --git a/test/sql/types.result b/test/sql/types.result
index 6b0f7a651..9099bcea4 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -339,12 +339,12 @@ box.execute("INSERT INTO tboolean VALUES (TRUE);")
 box.execute("SELECT * FROM tboolean WHERE s1 = x'44';")
 ---
 - null
-- 'Type mismatch: can not convert varbinary to boolean'
+- 'Type mismatch: can not convert boolean to varbinary'
 ...
 box.execute("SELECT * FROM tboolean WHERE s1 = 'abc';")
 ---
 - null
-- 'Type mismatch: can not convert abc to boolean'
+- 'Type mismatch: can not convert boolean to text'
 ...
 box.execute("SELECT * FROM tboolean WHERE s1 = 1;")
 ---
@@ -606,14 +606,6 @@ box.execute("SELECT 18446744073709551615.0 > 18446744073709551615")
   rows:
   - [true]
 ...
-box.execute("SELECT 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0)")
----
-- metadata:
-  - name: 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0)
-    type: boolean
-  rows:
-  - [true]
-...
 box.execute("SELECT 1 LIMIT 18446744073709551615;")
 ---
 - metadata:
diff --git a/test/sql/types.test.lua b/test/sql/types.test.lua
index bd14b342d..f9603c60d 100644
--- a/test/sql/types.test.lua
+++ b/test/sql/types.test.lua
@@ -151,7 +151,6 @@ box.execute("SELECT 18446744073709551610 - 18446744073709551615;")
 box.execute("SELECT 18446744073709551615 = null;")
 box.execute("SELECT 18446744073709551615 = 18446744073709551615.0;")
 box.execute("SELECT 18446744073709551615.0 > 18446744073709551615")
-box.execute("SELECT 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0)")
 box.execute("SELECT 1 LIMIT 18446744073709551615;")
 box.execute("SELECT 1 LIMIT 1 OFFSET 18446744073709551614;")
 box.execute("SELECT CAST('18446744073' || '709551616' AS INTEGER);")
-- 
2.25.1

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [Tarantool-patches] [PATCH 6/6] sql: remove OP_ApplyType
  2020-05-28 14:17 [Tarantool-patches] [PATCH 0/6] Remove implicit cast Mergen Imeev
                   ` (4 preceding siblings ...)
  2020-05-28 14:17 ` [Tarantool-patches] [PATCH 5/6] sql: remove implicit cast from string for comparison Mergen Imeev
@ 2020-05-28 14:17 ` Mergen Imeev
  2020-06-09 22:29   ` Vladislav Shpilevoy
  2020-06-01 17:03 ` [Tarantool-patches] [PATCH 0/6] Remove implicit cast Vladislav Shpilevoy
  6 siblings, 1 reply; 21+ messages in thread
From: Mergen Imeev @ 2020-05-28 14:17 UTC (permalink / raw)
  To: v.shpilevoy, tsafin, tarantool-patches

Opcode OP_ApplyType is not needed now, so it should be removed.

Follow-up #4230
---
 src/box/sql/expr.c      | 30 ------------------------------
 src/box/sql/sqlInt.h    | 13 -------------
 src/box/sql/vdbe.c      | 29 -----------------------------
 src/box/sql/wherecode.c |  2 +-
 4 files changed, 1 insertion(+), 73 deletions(-)

diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index 8ec685cd9..55db089cc 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -2246,36 +2246,6 @@ sqlExprCanBeNull(const Expr * p)
 	}
 }
 
-bool
-sql_expr_needs_no_type_change(const struct Expr *p, enum field_type type)
-{
-	u8 op;
-	if (type == FIELD_TYPE_SCALAR)
-		return true;
-	while (p->op == TK_UPLUS || p->op == TK_UMINUS) {
-		p = p->pLeft;
-	}
-	op = p->op;
-	if (op == TK_REGISTER)
-		op = p->op2;
-	switch (op) {
-	case TK_INTEGER:
-		return type == FIELD_TYPE_INTEGER;
-	case TK_FLOAT:
-		return type == FIELD_TYPE_DOUBLE;
-	case TK_STRING:
-		return type == FIELD_TYPE_STRING;
-	case TK_BLOB:
-		return type == FIELD_TYPE_VARBINARY;
-	case TK_COLUMN:
-		/* p cannot be part of a CHECK constraint. */
-		assert(p->iTable >= 0);
-		return p->iColumn < 0 && sql_type_is_numeric(type);
-	default:
-		return false;
-	}
-}
-
 /*
  * pX is the RHS of an IN operator.  If pX is a SELECT statement
  * that can be simplified to a direct table access, then return
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 37283e506..8314e7176 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -3229,19 +3229,6 @@ int sqlExprIsTableConstant(Expr *, int);
 int sqlExprIsInteger(Expr *, int *);
 int sqlExprCanBeNull(const Expr *);
 
-/**
- * Return TRUE if the given expression is a constant which would
- * be unchanged by OP_ApplyType with the type given in the second
- * argument.
- *
- * This routine is used to determine if the OP_ApplyType operation
- * can be omitted.  When in doubt return FALSE.  A false negative
- * is harmless. A false positive, however, can result in the wrong
- * answer.
- */
-bool
-sql_expr_needs_no_type_change(const struct Expr *expr, enum field_type type);
-
 /**
  * This routine generates VDBE code that causes a single row of a
  * single table to be deleted.  Both the original table entry and
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 021e09d1e..1fea86098 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -2811,35 +2811,6 @@ case OP_Fetch: {
 	break;
 }
 
-/* Opcode: ApplyType P1 P2 * P4 *
- * Synopsis: type(r[P1@P2])
- *
- * Apply types to a range of P2 registers starting with P1.
- *
- * P4 is a string that is P2 characters long. The nth character of the
- * string indicates the column type that should be used for the nth
- * memory cell in the range.
- */
-case OP_ApplyType: {
-	enum field_type *types = pOp->p4.types;
-	assert(types != NULL);
-	assert(types[pOp->p2] == field_type_MAX);
-	pIn1 = &aMem[pOp->p1];
-	enum field_type type;
-	while((type = *(types++)) != field_type_MAX) {
-		assert(pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)]);
-		assert(memIsValid(pIn1));
-		if (mem_apply_type(pIn1, type) != 0) {
-			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
-				 sql_value_to_diag_str(pIn1),
-				 field_type_strs[type]);
-			goto abort_due_to_error;
-		}
-		pIn1++;
-	}
-	break;
-}
-
 /* Opcode: CheckType P1 P2 * P4 *
  * Synopsis: type(r[P1@P2])
  *
diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
index 1d7c76670..1ec9f4ed7 100644
--- a/src/box/sql/wherecode.c
+++ b/src/box/sql/wherecode.c
@@ -571,7 +571,7 @@ codeEqualityTerm(Parse * pParse,	/* The parsing context */
  *
  * Before returning, @types is set to point to a buffer containing a
  * copy of the column types array of the index allocated using
- * sqlDbMalloc(). This array is passed to OP_ApplyType to provide
+ * sqlDbMalloc(). This array is passed to OP_CheckType to provide
  * correct implicit conversions.
  */
 static int
-- 
2.25.1

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Tarantool-patches] [PATCH 0/6] Remove implicit cast
  2020-05-28 14:17 [Tarantool-patches] [PATCH 0/6] Remove implicit cast Mergen Imeev
                   ` (5 preceding siblings ...)
  2020-05-28 14:17 ` [Tarantool-patches] [PATCH 6/6] sql: remove OP_ApplyType Mergen Imeev
@ 2020-06-01 17:03 ` Vladislav Shpilevoy
  2020-06-09 11:25   ` Mergen Imeev
  6 siblings, 1 reply; 21+ messages in thread
From: Vladislav Shpilevoy @ 2020-06-01 17:03 UTC (permalink / raw)
  To: Mergen Imeev, tsafin, tarantool-patches

Hi! Thanks for the patchset!

We need a changelog record here, with 'breaking change' label.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Tarantool-patches] [PATCH 1/6] sql: remove implicit cast for assignment
  2020-05-28 14:17 ` [Tarantool-patches] [PATCH 1/6] sql: remove implicit cast for assignment Mergen Imeev
@ 2020-06-01 17:03   ` Vladislav Shpilevoy
  2020-06-09 11:41     ` Mergen Imeev
  0 siblings, 1 reply; 21+ messages in thread
From: Vladislav Shpilevoy @ 2020-06-01 17:03 UTC (permalink / raw)
  To: Mergen Imeev, tsafin, tarantool-patches

Thanks for the patch!

See 9 comments below.

On 28/05/2020 16:17, Mergen Imeev wrote:
> This patch removes implicit cast for assignment, however,
> it is allowed to implicitly cast DOUBLE to INTEGER and
> vice versa.
> 
> Closes #3809
> ---
> diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
> index 724bc188b..2a941025c 100644
> --- a/src/box/sql/vdbe.c
> +++ b/src/box/sql/vdbe.c
> @@ -414,6 +414,94 @@ sql_value_apply_type(
>  	mem_apply_type((Mem *) pVal, type);
>  }
>  
> +/**
> + * Check that mem_type of the mem compatible with given type. In

1. 'compatible' -> 'is compatible'.

> + * case of numeric values this fuction tries to comvert mem to

2. 'fuction' -> 'function', 'comvert' -> 'convert'.

> + * given type and returns -1 if it is impossible.
> + *
> + * @param mem The value to check.
> + * @param type The type to check.
> + */
> +static int
> +mem_check_types(struct Mem *mem, enum field_type type)
> +{
> +	if ((mem->flags & MEM_Null) != 0)
> +		return 0;
> +	assert(type < field_type_MAX);
> +	uint32_t flags = mem->flags;
> +	switch (type) {
> +	case FIELD_TYPE_UNSIGNED:
> +		if ((flags & MEM_Int) != 0)
> +			return -1;
> +		if ((flags & MEM_Real) != 0 && mem->u.r < 0)
> +			return -1;
> +		FALLTHROUGH;
> +	case FIELD_TYPE_INTEGER:
> +		if ((flags & (MEM_Int | MEM_UInt)) != 0)
> +			return 0;
> +		if ((flags & MEM_Real) != 0) {
> +			double d = mem->u.r;
> +			int64_t i = (int64_t) d;
> +			uint64_t u = (uint64_t) d;

3. This is undefined behaviour to cast double to int,
if the double value is out of range of the int.
For example, if double is < 0 or > UINT64_MAX, it is
UB to cast it to uint64_t. If double is < INT64_MIN or
> INT64_MAX, it is UB to cast it to int64_t.

However until clang sanitizer is turned on, I don't know
how you could test it. So up to you whether try to fix it
now, or wait until the sanitizer is on board. And then
probably I will fix it.

> +			if (i == d) {
> +				mem_set_int(mem, i, i <= -1);
> +				return 0;
> +			}
> +			if (u == d) {
> +				mem_set_u64(mem, u);
> +				return 0;
> +			}
> +		}
> +		return -1;
> +	case FIELD_TYPE_BOOLEAN:
> +		if ((flags & MEM_Bool) != 0)
> +			return 0;
> +		return -1;
> +	case FIELD_TYPE_NUMBER:
> +		if ((flags & (MEM_Real | MEM_Int | MEM_UInt)) != 0)
> +			return 0;
> +		return -1;
> +	case FIELD_TYPE_DOUBLE:
> +		if ((flags & MEM_Real) != 0)
> +			return 0;
> +		if ((flags & (MEM_Int | MEM_UInt)) != 0)
> +			return sqlVdbeMemRealify(mem);
> +		return -1;
> +	case FIELD_TYPE_STRING:
> +		if ((flags & MEM_Str) != 0)
> +			return 0;
> +		return -1;
> +	case FIELD_TYPE_VARBINARY:
> +		if ((flags & MEM_Blob) != 0)
> +			return 0;
> +		return -1;
> +	case FIELD_TYPE_SCALAR:
> +		/* Can't cast MAP and ARRAY to scalar types. */
> +		if ((flags & MEM_Subtype) == 0 ||
> +		    mem->subtype != SQL_SUBTYPE_MSGPACK)
> +			return 0;
> +		assert(mp_typeof(*mem->z) == MP_MAP ||
> +		       mp_typeof(*mem->z) == MP_ARRAY);
> +		return -1;
> +	case FIELD_TYPE_MAP:
> +		if ((flags & MEM_Subtype) != 0 &&
> +		    mem->subtype == SQL_SUBTYPE_MSGPACK &&
> +		    mp_typeof(*mem->z) == MP_MAP)
> +			return 0;
> +		return -1;
> +	case FIELD_TYPE_ARRAY:
> +		if ((flags & MEM_Subtype) != 0 &&
> +		    mem->subtype == SQL_SUBTYPE_MSGPACK &&
> +		    mp_typeof(*mem->z) == MP_ARRAY)
> +			return 0;
> +		return -1;
> +	case FIELD_TYPE_ANY:
> +		return 0;
> +	default:
> +		return -1;
> +	}
> +}
> +
>  /*
>   * pMem currently only holds a string type (or maybe a BLOB that we can
>   * interpret as a string if we want to).  Compute its corresponding
> @@ -2772,6 +2860,31 @@ case OP_ApplyType: {
>  	break;
>  }
>  
> +/* Opcode: CheckType P1 P2 * P4 *
> + * Synopsis: type(r[P1@P2])
> + *
> + * Check that types of P2 registers starting from register
> + * P1 are compatible with given field_types.

4. 'with given field types in P4'.

> + */
> +case OP_CheckType: {
> +	enum field_type *types = pOp->p4.types;
> +	assert(types != NULL);
> +	assert(types[pOp->p2] == field_type_MAX);
> +	pIn1 = &aMem[pOp->p1];
> +	enum field_type type;
> +	while((type = *(types++)) != field_type_MAX) {
> +		assert(pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)]);
> +		assert(memIsValid(pIn1));
> +		if (mem_check_types(pIn1, type) != 0) {
> +			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
> +				 mem_type_to_str(pIn1), field_type_strs[type]);
> +			goto abort_due_to_error;
> +		}
> +		pIn1++;
> +	}
> +	break;
> +}
> +
>  /* Opcode: MakeRecord P1 P2 P3 P4 P5
>   * Synopsis: r[P3]=mkrec(r[P1@P2])
>   *
> diff --git a/test/sql-tap/gh-3809-implicit-cast-assignment.test.lua b/test/sql-tap/gh-3809-implicit-cast-assignment.test.lua
> new file mode 100755
> index 000000000..9df90bf72
> --- /dev/null
> +++ b/test/sql-tap/gh-3809-implicit-cast-assignment.test.lua
> @@ -0,0 +1,633 @@
> +#!/usr/bin/env tarantool
> +test = require("sqltester")
> +test:plan(75)
> +
> +--
> +-- Make sure that duting assignment there is no impolicit casts

5. 'duting' -> 'during', 'impolicit' -> 'implicit'.

> +-- with exception of implicit cast between numeric values.
> +--
> +test:execsql([[
> +    CREATE TABLE ti (a INT PRIMARY KEY AUTOINCREMENT, i INTEGER);
> +    CREATE TABLE td (a INT PRIMARY KEY AUTOINCREMENT, d DOUBLE);
> +    CREATE TABLE tb (a INT PRIMARY KEY AUTOINCREMENT, b BOOLEAN);
> +    CREATE TABLE tt (a INT PRIMARY KEY AUTOINCREMENT, t TEXT);
> +    CREATE TABLE tv (a INT PRIMARY KEY AUTOINCREMENT, v VARBINARY);
> +    CREATE TABLE ts (a INT PRIMARY KEY AUTOINCREMENT, s SCALAR);
> +]])
> +
> +test:do_catchsql_test(
> +    "gh-3809-1",
> +    [[
> +        INSERT INTO ti(i) VALUES (11)
> +    ]], {
> +        0
> +    })
> +
> +test:do_catchsql_test(
> +    "gh-3809-2",
> +    [[
> +        INSERT INTO ti(i) VALUES (22.2)
> +    ]], {
> +        1, "Type mismatch: can not convert real to integer"
> +    })
> +
> +test:do_catchsql_test(
> +    "gh-3809-3",
> +    [[
> +        INSERT INTO ti(i) VALUES (33.0)

6. Do we really want to keep this type of implicit
assignment? After all, it is still double. Even though with 0
fraction.

What if I insert a double value > INT64_MAX? Double can store
integers bigger than int64_t/uint64_t can.

> +    ]], {
> +        0
> +    })
> +
> +test:do_catchsql_test(
> +    "gh-3809-4",
> +    [[
> +        INSERT INTO ti(i) VALUES (true)
> +    ]], {
> +        1, "Type mismatch: can not convert boolean to integer"
> +    })
> +
> +test:do_catchsql_test(
> +    "gh-3809-5",
> +    [[
> +        INSERT INTO ti(i) VALUES ('33')
> +    ]], {
> +        1, "Type mismatch: can not convert text to integer"
> +    })
> +
> +test:do_catchsql_test(
> +    "gh-3809-6",
> +    [[
> +        INSERT INTO ti(i) VALUES (X'3434')
> +    ]], {
> +        1, "Type mismatch: can not convert varbinary to integer"
> +    })
> +
> +test:do_execsql_test(
> +    "gh-3809-7",
> +    [[
> +        SELECT * FROM ti;
> +    ]], {
> +        1, 11, 2, 33
> +    })
> +
> +test:do_catchsql_test(
> +    "gh-3809-8",
> +    [[
> +        INSERT INTO td(d) VALUES (11)

7. What if I insert something > 2^53 or < -2^53? It
can't be stored in double as is. Is it an error?

> +    ]], {
> +        0
> +    })
> +
> diff --git a/test/sql-tap/numcast.test.lua b/test/sql-tap/numcast.test.lua
> index eeac5353a..9bbae5ca4 100755
> --- a/test/sql-tap/numcast.test.lua
> +++ b/test/sql-tap/numcast.test.lua
> @@ -135,7 +135,7 @@ test:do_catchsql_test(
>          INSERT INTO t VALUES(20000000000000000000.01);
>          SELECT * FROM t;
>      ]], {
> -        1,"Tuple field 1 type does not match one required by operation: expected integer"
> +        1,"Type mismatch: can not convert real to integer"

8. Is it correct, that we can remove all the checks from OP_CheckType
except numeric conversions, and everything will work fine, because
box makes the type checks anyway? It seems OP_CheckType duplicates
box's work.

> diff --git a/test/sql-tap/tkt-3998683a16.test.lua b/test/sql-tap/tkt-3998683a16.test.lua
> index 885dcf5cd..c91960c2c 100755
> --- a/test/sql-tap/tkt-3998683a16.test.lua
> +++ b/test/sql-tap/tkt-3998683a16.test.lua
> @@ -26,24 +26,24 @@ test:do_test(
>      function()
>          return test:execsql [[
>              CREATE TABLE t1(x  INT primary key, y NUMBER);
> -            INSERT INTO t1 VALUES(1, '1.0');
> -            INSERT INTO t1 VALUES(2, '.125');
> -            INSERT INTO t1 VALUES(3, '123.');
> -            INSERT INTO t1 VALUES(4, '123.e+2');
> -            INSERT INTO t1 VALUES(5, '.125e+3');
> -            INSERT INTO t1 VALUES(6, '123e4');
> -            INSERT INTO t1 VALUES(11, '  1.0');
> -            INSERT INTO t1 VALUES(12, '  .125');
> -            INSERT INTO t1 VALUES(13, '  123.');
> -            INSERT INTO t1 VALUES(14, '  123.e+2');
> -            INSERT INTO t1 VALUES(15, '  .125e+3');
> -            INSERT INTO t1 VALUES(16, '  123e4');
> -            INSERT INTO t1 VALUES(21, '1.0  ');
> -            INSERT INTO t1 VALUES(22, '.125  ');
> -            INSERT INTO t1 VALUES(23, '123.  ');
> -            INSERT INTO t1 VALUES(24, '123.e+2  ');
> -            INSERT INTO t1 VALUES(25, '.125e+3  ');
> -            INSERT INTO t1 VALUES(26, '123e4  ');
> +            INSERT INTO t1 VALUES(1, 1.0);
> +            INSERT INTO t1 VALUES(2, .125);
> +            INSERT INTO t1 VALUES(3, 123.);
> +            INSERT INTO t1 VALUES(4, 123.e+2);
> +            INSERT INTO t1 VALUES(5, .125e+3);
> +            INSERT INTO t1 VALUES(6, 123e4);
> +            INSERT INTO t1 VALUES(11, 1.0);
> +            INSERT INTO t1 VALUES(12, .125);
> +            INSERT INTO t1 VALUES(13, 123.);
> +            INSERT INTO t1 VALUES(14, 123.e+2);
> +            INSERT INTO t1 VALUES(15, .125e+3);
> +            INSERT INTO t1 VALUES(16, 123e4);
> +            INSERT INTO t1 VALUES(21, 1.0);
> +            INSERT INTO t1 VALUES(22, .125);
> +            INSERT INTO t1 VALUES(23, 123.);
> +            INSERT INTO t1 VALUES(24, 123.e+2);
> +            INSERT INTO t1 VALUES(25, .125e+3);
> +            INSERT INTO t1 VALUES(26, 123e4);

9. There are lines where the second column is a duplicate. I guess
they can be removed now. Previously they were different in spacing
only.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Tarantool-patches] [PATCH 2/6] sql: remove mem_apply_type() from OP_MakeRecord
  2020-05-28 14:17 ` [Tarantool-patches] [PATCH 2/6] sql: remove mem_apply_type() from OP_MakeRecord Mergen Imeev
@ 2020-06-01 17:03   ` Vladislav Shpilevoy
  2020-06-09 11:43     ` Mergen Imeev
  0 siblings, 1 reply; 21+ messages in thread
From: Vladislav Shpilevoy @ 2020-06-01 17:03 UTC (permalink / raw)
  To: Mergen Imeev, tsafin, tarantool-patches

Thanks for the patch!

> diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
> index 2a941025c..fc41ee0d6 100644
> --- a/src/box/sql/vdbe.c
> +++ b/src/box/sql/vdbe.c
> @@ -2902,7 +2902,6 @@ case OP_CheckType: {
>   * into ephemeral space. Thus, sort of memory optimization can be performed.
>   */

P4 should be removed from the comment too.

>  case OP_MakeRecord: {
> -	Mem *pRec;             /* The new record */
>  	Mem *pData0;           /* First field to be combined into the record */
>  	Mem MAYBE_UNUSED *pLast;  /* Last field of the record */
>  	int nField;            /* Number of fields in the record */

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Tarantool-patches] [PATCH 4/6] sql: remove mem_apply_type() from OP_MustBeInt
  2020-05-28 14:17 ` [Tarantool-patches] [PATCH 4/6] sql: remove mem_apply_type() from OP_MustBeInt Mergen Imeev
@ 2020-06-01 17:04   ` Vladislav Shpilevoy
  2020-06-09 11:47     ` Mergen Imeev
  0 siblings, 1 reply; 21+ messages in thread
From: Vladislav Shpilevoy @ 2020-06-01 17:04 UTC (permalink / raw)
  To: Mergen Imeev, tsafin, tarantool-patches

Thanks for the patch!

See 3 comments below.

On 28/05/2020 16:17, Mergen Imeev wrote:
> This patch replaces mem_apply_type() by mem_check_types() in
> OP_MustBeInt, which allows to remove implicit case in some places,

1. 'case' -> 'cast'.

> for example in IN operator.
> 
> Part of #4230
> ---
> diff --git a/test/sql-tap/tkt-fc7bd6358f.test.lua b/test/sql-tap/tkt-fc7bd6358f.test.lua
> index fe5d6200f..f38ffa3d6 100755
> --- a/test/sql-tap/tkt-fc7bd6358f.test.lua
> +++ b/test/sql-tap/tkt-fc7bd6358f.test.lua
> @@ -80,7 +80,6 @@ for a, from in ipairs(froms) do
>              function()
>                  return test:execsql(string.format("SELECT t1.textid, i.intid, t2.textid %s %s", from, where))
>              end, {
> -                "12", 12, "12", "34", 34, "34"
>              })
>  
>          test:do_test(
> @@ -88,7 +87,6 @@ for a, from in ipairs(froms) do
>              function()
>                  return test:execsql(string.format("SELECT t1.textid, i.intid, t2.textid %s %s", from, where))
>              end, {
> -                "12", 12, "12", "34", 34, "34"
>              })

2. In the header of this file it is said, that the whole test's
purpose is to ensure, that these values are returned. Do we
need this test file now at all? Or can it be fixed in a way, that
the results are not changed?

>  
>      end
> diff --git a/test/sql-tap/whereB.test.lua b/test/sql-tap/whereB.test.lua
> index fe5e28c70..970ff1dec 100755
> --- a/test/sql-tap/whereB.test.lua
> +++ b/test/sql-tap/whereB.test.lua
> @@ -432,7 +432,6 @@ test:do_execsql_test(
>      ]],
>      {
>      -- <whereB-5.2>
> -    1, 2, true
>      -- </whereB-5.2>
>      })
>  
> @@ -443,7 +442,6 @@ test:do_execsql_test(
>      ]],
>      {
>      -- <whereB-5.3>
> -    1, 2, true

3. These tests also look useless now. Their comment
says:

	-- Because t2.b has a numeric affinity, type conversion should occur
	-- and the two fields should be equal.

And now they are not equal. Do we need these tests?

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Tarantool-patches] [PATCH 5/6] sql: remove implicit cast from string for comparison
  2020-05-28 14:17 ` [Tarantool-patches] [PATCH 5/6] sql: remove implicit cast from string for comparison Mergen Imeev
@ 2020-06-01 17:04   ` Vladislav Shpilevoy
  2020-06-09 11:51     ` Mergen Imeev
  0 siblings, 1 reply; 21+ messages in thread
From: Vladislav Shpilevoy @ 2020-06-01 17:04 UTC (permalink / raw)
  To: Mergen Imeev, tsafin, tarantool-patches

Thanks for the patch!

See 7 comments below.

On 28/05/2020 16:17, Mergen Imeev wrote:
> This patch removes implicit cast from strings to numbers for
> comparison.
> 
> Closes #4230
> 
> @TarantoolBot document
> Title: remove implicit cast between strings and numbers
> 
> This patch-set removes implicit cast from string to number and
> from number to string.
> 
> Example:
> 
> For comparison:
> 
> tarantool> box.execute([[SELECT '1' > 0;]])
> ---
> - null
> - 'Type mismatch: can not convert 1 to numeric'
> ...
> 
> tarantool> box.execute([[SELECT "id" FROM "_space" WHERE '1' > "id";]])
> ---
> - null
> - 'Type mismatch: can not convert text to unsigned'
> ...
> 
> For assignment:
> 
> tarantool> box.execute([[CREATE TABLE t1(i INT PRIMARY KEY);]])
> tarantool> box.execute([[INSERT INTO t1 VALUES ('1');]])
> ---
> - null
> - 'Type mismatch: can not convert text to integer'
> ...
> 
> tarantool> box.execute([[CREATE TABLE t2(t text PRIMARY KEY);]])
> tarantool> box.execute([[INSERT INTO t2 VALUES (1);]])
> ---
> - null
> - 'Type mismatch: can not convert unsigned to string'
> ...
> ---
>  src/box/sql/vdbe.c                            | 105 ++++----
>  src/box/sql/wherecode.c                       | 203 +--------------
>  .../gh-4230-del-impl-cast-str-to-num.test.lua |  78 ++++++
>  test/sql-tap/identifier_case.test.lua         |   6 +-
>  test/sql-tap/in1.test.lua                     |   4 +-
>  test/sql-tap/in4.test.lua                     |   3 +-
>  test/sql-tap/insert3.test.lua                 |   2 +-
>  test/sql-tap/intpkey.test.lua                 |  24 +-
>  test/sql-tap/join.test.lua                    |   7 +-
>  test/sql-tap/misc1.test.lua                   |  32 +--
>  test/sql-tap/select1.test.lua                 |   4 +-
>  test/sql-tap/select7.test.lua                 |   2 +-
>  test/sql-tap/subquery.test.lua                |   4 +-
>  test/sql-tap/tkt-9a8b09f8e6.test.lua          |  84 ++++---
>  test/sql-tap/tkt-f973c7ac31.test.lua          |  32 +--
>  test/sql-tap/tkt-fc7bd6358f.test.lua          |   6 +-
>  test/sql-tap/tkt3493.test.lua                 |  40 ++-
>  test/sql-tap/transitive1.test.lua             |  12 +-
>  test/sql-tap/where2.test.lua                  | 183 +-------------
>  test/sql-tap/where5.test.lua                  |  12 +-
>  test/sql-tap/whereB.test.lua                  | 238 ++++++++++--------
>  test/sql/types.result                         |  12 +-
>  test/sql/types.test.lua                       |   1 -
>  23 files changed, 418 insertions(+), 676 deletions(-)
>  create mode 100755 test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua
> 
> diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
> index 7add67ae7..021e09d1e 100644
> --- a/src/box/sql/vdbe.c
> +++ b/src/box/sql/vdbe.c
> @@ -2345,22 +2338,17 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
>  				goto compare_op;
>  			}
>  		} else if (type == FIELD_TYPE_STRING) {
> -			if ((flags1 & MEM_Str) == 0 &&
> -			    (flags1 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
> -				testcase( pIn1->flags & MEM_Int);
> -				testcase( pIn1->flags & MEM_Real);
> -				sqlVdbeMemStringify(pIn1);
> -				testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn));
> -				flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
> -				assert(pIn1!=pIn3);
> +			if ((flags1 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {

1. Maybe it would be better to check '(flags1 & MEM_Str) == 0'. Otherwise
every time when we will add a new type, we will need to add it here. The
same below.

> +				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
> +					 mem_type_to_str(pIn3),
> +					 mem_type_to_str(pIn1));
> +				goto abort_due_to_error;
>  			}
> -			if ((flags3 & MEM_Str) == 0 &&
> -			    (flags3 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
> -				testcase( pIn3->flags & MEM_Int);
> -				testcase( pIn3->flags & MEM_Real);
> -				sqlVdbeMemStringify(pIn3);
> -				testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn));
> -				flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask);
> +			if ((flags3 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
> +				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
> +					 mem_type_to_str(pIn1),
> +					 mem_type_to_str(pIn3));
> +				goto abort_due_to_error;
>  			}
>  		}
>  		assert(pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0);
> diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
> index 5bc27f134..1d7c76670 100644
> --- a/src/box/sql/wherecode.c
> +++ b/src/box/sql/wherecode.c
> @@ -644,8 +578,7 @@ static int
>  codeAllEqualityTerms(Parse * pParse,	/* Parsing context */
>  		     WhereLevel * pLevel,	/* Which nested loop of the FROM we are coding */
>  		     int bRev,		/* Reverse the order of IN operators */
> -		     int nExtraReg,	/* Number of extra registers to allocate */
> -		     enum field_type **res_type)
> +		     int nExtraReg)	/* Number of extra registers to allocate */
>  {
>  	u16 nEq;		/* The number of == or IN constraints to code */
>  	u16 nSkip;		/* Number of left-most columns to skip */
> @@ -669,9 +602,6 @@ codeAllEqualityTerms(Parse * pParse,	/* Parsing context */
>  	nReg = pLoop->nEq + nExtraReg;
>  	pParse->nMem += nReg;
>  
> -	enum field_type *type = sql_index_type_str(pParse->db, idx_def);

2. This function is now unused and can be deleted.

> -	assert(type != NULL || pParse->db->mallocFailed);
> -
>  	if (nSkip) {
>  		int iIdxCur = pLevel->iIdxCur;
>  		sqlVdbeAddOp1(v, (bRev ? OP_Last : OP_Rewind), iIdxCur);> diff --git a/test/sql-tap/tkt-9a8b09f8e6.test.lua b/test/sql-tap/tkt-9a8b09f8e6.test.lua
> index 854ed774f..2a18b17be 100755
> --- a/test/sql-tap/tkt-9a8b09f8e6.test.lua
> +++ b/test/sql-tap/tkt-9a8b09f8e6.test.lua
> @@ -83,23 +83,23 @@ test:do_execsql_test(
>          -- </1.5>
>      })
>  
> -test:do_execsql_test(
> +test:do_catchsql_test(
>      2.1,
>      [[
>          SELECT x FROM t1 WHERE x IN (1);
>      ]], {
>          -- <2.1>
> -        "1"
> +        1,"Type mismatch: can not convert 1 to numeric"

3. Can tests in this file be fixed to return the same results
as before?

>          -- </2.1>
>      })
>  
> -test:do_execsql_test(
> +test:do_catchsql_test(
>      2.2,
>      [[
>          SELECT x FROM t1 WHERE x IN (1.0);
>      ]], {
>          -- <2.2>
> -        "1"
> +        1,"Type mismatch: can not convert 1 to numeric"
>          -- </2.2>
>      })
>  
> diff --git a/test/sql-tap/tkt-f973c7ac31.test.lua b/test/sql-tap/tkt-f973c7ac31.test.lua
> index 82bdb52f8..5239a7785 100755
> --- a/test/sql-tap/tkt-f973c7ac31.test.lua
> +++ b/test/sql-tap/tkt-f973c7ac31.test.lua
> @@ -36,12 +36,12 @@ local sqls = {
>  
>  for tn, sql in ipairs(sqls) do
>      test:execsql(sql)
> -    test:do_execsql_test(
> +    test:do_catchsql_test(
>          "tkt-f973c7ac3-1."..tn..".1",
>          [[
>              SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='2' ORDER BY c2 DESC 
>          ]], {
> -            
> +            1, "/Type mismatch: can not convert/"

4. The same for this file.

>          })
>  
>      test:do_execsql_test(
> diff --git a/test/sql-tap/tkt3493.test.lua b/test/sql-tap/tkt3493.test.lua
> index de77e61e9..ec12a4492 100755
> --- a/test/sql-tap/tkt3493.test.lua
> +++ b/test/sql-tap/tkt3493.test.lua
> @@ -126,23 +126,13 @@ test:do_execsql_test(
>  test:do_execsql_test(
>      "tkt3493-2.2.1",
>      [[
> -        SELECT a=123 FROM t1 GROUP BY a 
> +        SELECT a='123' FROM t1 GROUP BY a 

5. Trailing whitespace.

>      ]], {
>          -- <tkt3493-2.2.1>
>          true
>          -- </tkt3493-2.2.1>
>      })
> @@ -166,7 +156,7 @@ test:do_execsql_test(
>  test:do_execsql_test(
>      "tkt3493-2.2.5",
>      [[
> -        SELECT count(*), +a=123 FROM t1 
> +        SELECT count(*), +a='123' FROM t1 

6. Trailing whitespace here and in the test above.

>      ]], {
>          -- <tkt3493-2.2.5>
>          1, true
> diff --git a/test/sql-tap/whereB.test.lua b/test/sql-tap/whereB.test.lua
> index 970ff1dec..9e99ea41c 100755
> --- a/test/sql-tap/whereB.test.lua
> +++ b/test/sql-tap/whereB.test.lua
> @@ -36,49 +35,54 @@ test:do_execsql_test(
>          CREATE TABLE t2(a  INT primary key, b TEXT);  -- affinity of t2.b is TEXT
>          CREATE INDEX t2b ON t2(b);
>          INSERT INTO t2 VALUES(2,'99');
> +    ]]
> +)
>  
> +test:do_catchsql_test(
> +    "whereB-1.1",

7. The whole whereB-1 now fails because of type conversions banned.
Is this test still needed at all? I didn't check other whereB tests,
but seems like most of them also fail now. So either almost the entire
test file is not needed, or it should be fixed so as the test still
would work.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Tarantool-patches] [PATCH 0/6] Remove implicit cast
  2020-06-01 17:03 ` [Tarantool-patches] [PATCH 0/6] Remove implicit cast Vladislav Shpilevoy
@ 2020-06-09 11:25   ` Mergen Imeev
  0 siblings, 0 replies; 21+ messages in thread
From: Mergen Imeev @ 2020-06-09 11:25 UTC (permalink / raw)
  To: Vladislav Shpilevoy, tsafin, tarantool-patches

Hi! Thank you for the review.

On 01.06.2020 20:03, Vladislav Shpilevoy wrote:
> Hi! Thanks for the patchset!
>
> We need a changelog record here, with 'breaking change' label.
@ChangeLog
  - [Breaking change] Removed implicit cast from string to numbers
    and vice versa to addignment and to comparison.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Tarantool-patches] [PATCH 1/6] sql: remove implicit cast for assignment
  2020-06-01 17:03   ` Vladislav Shpilevoy
@ 2020-06-09 11:41     ` Mergen Imeev
  2020-06-09 22:28       ` Vladislav Shpilevoy
  0 siblings, 1 reply; 21+ messages in thread
From: Mergen Imeev @ 2020-06-09 11:41 UTC (permalink / raw)
  To: Vladislav Shpilevoy, tsafin, tarantool-patches

Thank you for the review. My answers and new patch below. Also,
there may be some problems with tabs replaced by spaces due to
sending answers from Thunderbird. Should I re-send patches?

On 01.06.2020 20:03, Vladislav Shpilevoy wrote:
> Thanks for the patch!
>
> See 9 comments below.
>
> On 28/05/2020 16:17, Mergen Imeev wrote:
>> This patch removes implicit cast for assignment, however,
>> it is allowed to implicitly cast DOUBLE to INTEGER and
>> vice versa.
>>
>> Closes #3809
>> ---
>> diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
>> index 724bc188b..2a941025c 100644
>> --- a/src/box/sql/vdbe.c
>> +++ b/src/box/sql/vdbe.c
>> @@ -414,6 +414,94 @@ sql_value_apply_type(
>>   	mem_apply_type((Mem *) pVal, type);
>>   }
>>   
>> +/**
>> + * Check that mem_type of the mem compatible with given type. In
> 1. 'compatible' -> 'is compatible'.

Fixed.


>
>> + * case of numeric values this fuction tries to comvert mem to
> 2. 'fuction' -> 'function', 'comvert' -> 'convert'.

Fixed.


>
>> + * given type and returns -1 if it is impossible.
>> + *
>> + * @param mem The value to check.
>> + * @param type The type to check.
>> + */
>> +static int
>> +mem_check_types(struct Mem *mem, enum field_type type)
>> +{
>> +	if ((mem->flags & MEM_Null) != 0)
>> +		return 0;
>> +	assert(type < field_type_MAX);
>> +	uint32_t flags = mem->flags;
>> +	switch (type) {
>> +	case FIELD_TYPE_UNSIGNED:
>> +		if ((flags & MEM_Int) != 0)
>> +			return -1;
>> +		if ((flags & MEM_Real) != 0 && mem->u.r < 0)
>> +			return -1;
>> +		FALLTHROUGH;
>> +	case FIELD_TYPE_INTEGER:
>> +		if ((flags & (MEM_Int | MEM_UInt)) != 0)
>> +			return 0;
>> +		if ((flags & MEM_Real) != 0) {
>> +			double d = mem->u.r;
>> +			int64_t i = (int64_t) d;
>> +			uint64_t u = (uint64_t) d;
> 3. This is undefined behaviour to cast double to int,
> if the double value is out of range of the int.
> For example, if double is < 0 or > UINT64_MAX, it is
> UB to cast it to uint64_t. If double is < INT64_MIN or
>> INT64_MAX, it is UB to cast it to int64_t.
> However until clang sanitizer is turned on, I don't know
> how you could test it. So up to you whether try to fix it
> now, or wait until the sanitizer is on board. And then
> probably I will fix it.

Thanks, but i think it is fixed now.


>
>> +			if (i == d) {
>> +				mem_set_int(mem, i, i <= -1);
>> +				return 0;
>> +			}
>> +			if (u == d) {
>> +				mem_set_u64(mem, u);
>> +				return 0;
>> +			}
>> +		}
>> +		return -1;
>> +	case FIELD_TYPE_BOOLEAN:
>> +		if ((flags & MEM_Bool) != 0)
>> +			return 0;
>> +		return -1;
>> +	case FIELD_TYPE_NUMBER:
>> +		if ((flags & (MEM_Real | MEM_Int | MEM_UInt)) != 0)
>> +			return 0;
>> +		return -1;
>> +	case FIELD_TYPE_DOUBLE:
>> +		if ((flags & MEM_Real) != 0)
>> +			return 0;
>> +		if ((flags & (MEM_Int | MEM_UInt)) != 0)
>> +			return sqlVdbeMemRealify(mem);
>> +		return -1;
>> +	case FIELD_TYPE_STRING:
>> +		if ((flags & MEM_Str) != 0)
>> +			return 0;
>> +		return -1;
>> +	case FIELD_TYPE_VARBINARY:
>> +		if ((flags & MEM_Blob) != 0)
>> +			return 0;
>> +		return -1;
>> +	case FIELD_TYPE_SCALAR:
>> +		/* Can't cast MAP and ARRAY to scalar types. */
>> +		if ((flags & MEM_Subtype) == 0 ||
>> +		    mem->subtype != SQL_SUBTYPE_MSGPACK)
>> +			return 0;
>> +		assert(mp_typeof(*mem->z) == MP_MAP ||
>> +		       mp_typeof(*mem->z) == MP_ARRAY);
>> +		return -1;
>> +	case FIELD_TYPE_MAP:
>> +		if ((flags & MEM_Subtype) != 0 &&
>> +		    mem->subtype == SQL_SUBTYPE_MSGPACK &&
>> +		    mp_typeof(*mem->z) == MP_MAP)
>> +			return 0;
>> +		return -1;
>> +	case FIELD_TYPE_ARRAY:
>> +		if ((flags & MEM_Subtype) != 0 &&
>> +		    mem->subtype == SQL_SUBTYPE_MSGPACK &&
>> +		    mp_typeof(*mem->z) == MP_ARRAY)
>> +			return 0;
>> +		return -1;
>> +	case FIELD_TYPE_ANY:
>> +		return 0;
>> +	default:
>> +		return -1;
>> +	}
>> +}
>> +
>>   /*
>>    * pMem currently only holds a string type (or maybe a BLOB that we can
>>    * interpret as a string if we want to).  Compute its corresponding
>> @@ -2772,6 +2860,31 @@ case OP_ApplyType: {
>>   	break;
>>   }
>>   
>> +/* Opcode: CheckType P1 P2 * P4 *
>> + * Synopsis: type(r[P1@P2])
>> + *
>> + * Check that types of P2 registers starting from register
>> + * P1 are compatible with given field_types.
> 4. 'with given field types in P4'.

Fixed.


>
>> + */
>> +case OP_CheckType: {
>> +	enum field_type *types = pOp->p4.types;
>> +	assert(types != NULL);
>> +	assert(types[pOp->p2] == field_type_MAX);
>> +	pIn1 = &aMem[pOp->p1];
>> +	enum field_type type;
>> +	while((type = *(types++)) != field_type_MAX) {
>> +		assert(pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)]);
>> +		assert(memIsValid(pIn1));
>> +		if (mem_check_types(pIn1, type) != 0) {
>> +			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
>> +				 mem_type_to_str(pIn1), field_type_strs[type]);
>> +			goto abort_due_to_error;
>> +		}
>> +		pIn1++;
>> +	}
>> +	break;
>> +}
>> +
>>   /* Opcode: MakeRecord P1 P2 P3 P4 P5
>>    * Synopsis: r[P3]=mkrec(r[P1@P2])
>>    *
>> diff --git a/test/sql-tap/gh-3809-implicit-cast-assignment.test.lua b/test/sql-tap/gh-3809-implicit-cast-assignment.test.lua
>> new file mode 100755
>> index 000000000..9df90bf72
>> --- /dev/null
>> +++ b/test/sql-tap/gh-3809-implicit-cast-assignment.test.lua
>> @@ -0,0 +1,633 @@
>> +#!/usr/bin/env tarantool
>> +test = require("sqltester")
>> +test:plan(75)
>> +
>> +--
>> +-- Make sure that duting assignment there is no impolicit casts
> 5. 'duting' -> 'during', 'impolicit' -> 'implicit'.

Fixed.


>
>> +-- with exception of implicit cast between numeric values.
>> +--
>> +test:execsql([[
>> +    CREATE TABLE ti (a INT PRIMARY KEY AUTOINCREMENT, i INTEGER);
>> +    CREATE TABLE td (a INT PRIMARY KEY AUTOINCREMENT, d DOUBLE);
>> +    CREATE TABLE tb (a INT PRIMARY KEY AUTOINCREMENT, b BOOLEAN);
>> +    CREATE TABLE tt (a INT PRIMARY KEY AUTOINCREMENT, t TEXT);
>> +    CREATE TABLE tv (a INT PRIMARY KEY AUTOINCREMENT, v VARBINARY);
>> +    CREATE TABLE ts (a INT PRIMARY KEY AUTOINCREMENT, s SCALAR);
>> +]])
>> +
>> +test:do_catchsql_test(
>> +    "gh-3809-1",
>> +    [[
>> +        INSERT INTO ti(i) VALUES (11)
>> +    ]], {
>> +        0
>> +    })
>> +
>> +test:do_catchsql_test(
>> +    "gh-3809-2",
>> +    [[
>> +        INSERT INTO ti(i) VALUES (22.2)
>> +    ]], {
>> +        1, "Type mismatch: can not convert real to integer"
>> +    })
>> +
>> +test:do_catchsql_test(
>> +    "gh-3809-3",
>> +    [[
>> +        INSERT INTO ti(i) VALUES (33.0)
> 6. Do we really want to keep this type of implicit
> assignment? After all, it is still double. Even though with 0
> fraction.
>
> What if I insert a double value > INT64_MAX? Double can store
> integers bigger than int64_t/uint64_t can.
ANSI says that there should be implicit cast between numeric
types. Also, in the discussion I suggested to use C rules for
this. However, now I think that it is a bad idea, though it can
be implemented quite easly. For now i allowed to convert them only
in case they represent the same number. I will write a letter to
discussion about this.

>
>> +    ]], {
>> +        0
>> +    })
>> +
>> +test:do_catchsql_test(
>> +    "gh-3809-4",
>> +    [[
>> +        INSERT INTO ti(i) VALUES (true)
>> +    ]], {
>> +        1, "Type mismatch: can not convert boolean to integer"
>> +    })
>> +
>> +test:do_catchsql_test(
>> +    "gh-3809-5",
>> +    [[
>> +        INSERT INTO ti(i) VALUES ('33')
>> +    ]], {
>> +        1, "Type mismatch: can not convert text to integer"
>> +    })
>> +
>> +test:do_catchsql_test(
>> +    "gh-3809-6",
>> +    [[
>> +        INSERT INTO ti(i) VALUES (X'3434')
>> +    ]], {
>> +        1, "Type mismatch: can not convert varbinary to integer"
>> +    })
>> +
>> +test:do_execsql_test(
>> +    "gh-3809-7",
>> +    [[
>> +        SELECT * FROM ti;
>> +    ]], {
>> +        1, 11, 2, 33
>> +    })
>> +
>> +test:do_catchsql_test(
>> +    "gh-3809-8",
>> +    [[
>> +        INSERT INTO td(d) VALUES (11)
> 7. What if I insert something > 2^53 or < -2^53? It
> can't be stored in double as is. Is it an error?

Fixed, according to statement above.


>
>> +    ]], {
>> +        0
>> +    })
>> +
>> diff --git a/test/sql-tap/numcast.test.lua b/test/sql-tap/numcast.test.lua
>> index eeac5353a..9bbae5ca4 100755
>> --- a/test/sql-tap/numcast.test.lua
>> +++ b/test/sql-tap/numcast.test.lua
>> @@ -135,7 +135,7 @@ test:do_catchsql_test(
>>           INSERT INTO t VALUES(20000000000000000000.01);
>>           SELECT * FROM t;
>>       ]], {
>> -        1,"Tuple field 1 type does not match one required by operation: expected integer"
>> +        1,"Type mismatch: can not convert real to integer"
> 8. Is it correct, that we can remove all the checks from OP_CheckType
> except numeric conversions, and everything will work fine, because
> box makes the type checks anyway? It seems OP_CheckType duplicates
> box's work.
This is correct in most cases. We will lose the implicit cast
between numeric values, but this can be done, for example, during
MakeRecord. In addition, all type mismatch errors will look the
same as in Lua.

>
>> diff --git a/test/sql-tap/tkt-3998683a16.test.lua b/test/sql-tap/tkt-3998683a16.test.lua
>> index 885dcf5cd..c91960c2c 100755
>> --- a/test/sql-tap/tkt-3998683a16.test.lua
>> +++ b/test/sql-tap/tkt-3998683a16.test.lua
>> @@ -26,24 +26,24 @@ test:do_test(
>>       function()
>>           return test:execsql [[
>>               CREATE TABLE t1(x  INT primary key, y NUMBER);
>> -            INSERT INTO t1 VALUES(1, '1.0');
>> -            INSERT INTO t1 VALUES(2, '.125');
>> -            INSERT INTO t1 VALUES(3, '123.');
>> -            INSERT INTO t1 VALUES(4, '123.e+2');
>> -            INSERT INTO t1 VALUES(5, '.125e+3');
>> -            INSERT INTO t1 VALUES(6, '123e4');
>> -            INSERT INTO t1 VALUES(11, '  1.0');
>> -            INSERT INTO t1 VALUES(12, '  .125');
>> -            INSERT INTO t1 VALUES(13, '  123.');
>> -            INSERT INTO t1 VALUES(14, '  123.e+2');
>> -            INSERT INTO t1 VALUES(15, '  .125e+3');
>> -            INSERT INTO t1 VALUES(16, '  123e4');
>> -            INSERT INTO t1 VALUES(21, '1.0  ');
>> -            INSERT INTO t1 VALUES(22, '.125  ');
>> -            INSERT INTO t1 VALUES(23, '123.  ');
>> -            INSERT INTO t1 VALUES(24, '123.e+2  ');
>> -            INSERT INTO t1 VALUES(25, '.125e+3  ');
>> -            INSERT INTO t1 VALUES(26, '123e4  ');
>> +            INSERT INTO t1 VALUES(1, 1.0);
>> +            INSERT INTO t1 VALUES(2, .125);
>> +            INSERT INTO t1 VALUES(3, 123.);
>> +            INSERT INTO t1 VALUES(4, 123.e+2);
>> +            INSERT INTO t1 VALUES(5, .125e+3);
>> +            INSERT INTO t1 VALUES(6, 123e4);
>> +            INSERT INTO t1 VALUES(11, 1.0);
>> +            INSERT INTO t1 VALUES(12, .125);
>> +            INSERT INTO t1 VALUES(13, 123.);
>> +            INSERT INTO t1 VALUES(14, 123.e+2);
>> +            INSERT INTO t1 VALUES(15, .125e+3);
>> +            INSERT INTO t1 VALUES(16, 123e4);
>> +            INSERT INTO t1 VALUES(21, 1.0);
>> +            INSERT INTO t1 VALUES(22, .125);
>> +            INSERT INTO t1 VALUES(23, 123.);
>> +            INSERT INTO t1 VALUES(24, 123.e+2);
>> +            INSERT INTO t1 VALUES(25, .125e+3);
>> +            INSERT INTO t1 VALUES(26, 123e4);
> 9. There are lines where the second column is a duplicate. I guess
> they can be removed now. Previously they were different in spacing
> only.
Fixed, duplicate tests removed. Not sure we should keep those the
ones left there.



New patch:


 From ed81efdca71104a8fefa95afa45e956a6b2d2743 Mon Sep 17 00:00:00 2001
From: Mergen Imeev <imeevma@gmail.com>
Date: Wed, 27 May 2020 13:49:11 +0300
Subject: [PATCH] sql: remove implicit cast for assignment

This patch removes implicit cast for assignment, however,
it is allowed to implicitly cast DOUBLE to INTEGER and
vice versa.

Closes #3809

diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index 588e142d2..253304ba3 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -69,7 +69,7 @@ sql_emit_table_types(struct Vdbe *v, struct space_def 
*def, int reg)
      for (uint32_t i = 0; i < field_count; ++i)
          colls_type[i] = def->fields[i].type;
      colls_type[field_count] = field_type_MAX;
-    sqlVdbeAddOp4(v, OP_ApplyType, reg, field_count, 0,
+    sqlVdbeAddOp4(v, OP_CheckType, reg, field_count, 0,
                (char *)colls_type, P4_DYNAMIC);
  }

diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 6b769805c..ae2622c9e 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -418,6 +418,113 @@ sql_value_apply_type(
      mem_apply_type((Mem *) pVal, type);
  }

+/**
+ * Check that mem_type of the mem is compatible with given type.
+ * In the case of numeric values, this function tries to convert
+ * the mem to the specified type and returns -1 if this is not
+ * possible.
+ *
+ * @param mem The value to check.
+ * @param type The type to check.
+ */
+static int
+mem_check_types(struct Mem *mem, enum field_type type)
+{
+    if ((mem->flags & MEM_Null) != 0)
+        return 0;
+    assert(type < field_type_MAX);
+    uint32_t flags = mem->flags;
+    switch (type) {
+    case FIELD_TYPE_UNSIGNED:
+        if ((flags & MEM_Int) != 0)
+            return -1;
+        if ((flags & MEM_Real) != 0 && mem->u.r < 0)
+            return -1;
+        FALLTHROUGH;
+    case FIELD_TYPE_INTEGER:
+        if ((flags & (MEM_Int | MEM_UInt)) != 0)
+            return 0;
+        if ((flags & MEM_Real) == 0)
+            return -1;
+        double d = mem->u.r;
+        if (d >= (double)UINT64_MAX || d < (double)INT64_MIN)
+            return -1;
+        if (d < (double)INT64_MAX) {
+            int64_t i = (int64_t) d;
+            if (i == d) {
+                mem_set_int(mem, i, i <= -1);
+                return 0;
+            }
+            return -1;
+        }
+        uint64_t u = (uint64_t) d;
+        if (u == d) {
+            mem_set_u64(mem, u);
+            return 0;
+        }
+        return -1;
+    case FIELD_TYPE_BOOLEAN:
+        if ((flags & MEM_Bool) != 0)
+            return 0;
+        return -1;
+    case FIELD_TYPE_NUMBER:
+        if ((flags & (MEM_Real | MEM_Int | MEM_UInt)) != 0)
+            return 0;
+        return -1;
+    case FIELD_TYPE_DOUBLE:
+        if ((flags & MEM_Real) != 0)
+            return 0;
+        if ((flags & (MEM_Int | MEM_UInt)) == 0)
+            return -1;
+        if ((flags & MEM_Int) != 0) {
+            double d = mem->u.i;
+            if (mem->u.i == (int64_t)d) {
+                mem_set_double(mem, d);
+                return 0;
+            }
+        } else {
+            double d = mem->u.u;
+            if (mem->u.u == (uint64_t)d) {
+                mem_set_double(mem, d);
+                return 0;
+            }
+        }
+        return -1;
+    case FIELD_TYPE_STRING:
+        if ((flags & MEM_Str) != 0)
+            return 0;
+        return -1;
+    case FIELD_TYPE_VARBINARY:
+        if ((flags & MEM_Blob) != 0)
+            return 0;
+        return -1;
+    case FIELD_TYPE_SCALAR:
+        /* Can't cast MAP and ARRAY to scalar types. */
+        if ((flags & MEM_Subtype) == 0 ||
+            mem->subtype != SQL_SUBTYPE_MSGPACK)
+            return 0;
+        assert(mp_typeof(*mem->z) == MP_MAP ||
+               mp_typeof(*mem->z) == MP_ARRAY);
+        return -1;
+    case FIELD_TYPE_MAP:
+        if ((flags & MEM_Subtype) != 0 &&
+            mem->subtype == SQL_SUBTYPE_MSGPACK &&
+            mp_typeof(*mem->z) == MP_MAP)
+            return 0;
+        return -1;
+    case FIELD_TYPE_ARRAY:
+        if ((flags & MEM_Subtype) != 0 &&
+            mem->subtype == SQL_SUBTYPE_MSGPACK &&
+            mp_typeof(*mem->z) == MP_ARRAY)
+            return 0;
+        return -1;
+    case FIELD_TYPE_ANY:
+        return 0;
+    default:
+        return -1;
+    }
+}
+
  /*
   * pMem currently only holds a string type (or maybe a BLOB that we can
   * interpret as a string if we want to).  Compute its corresponding
@@ -2776,6 +2883,31 @@ case OP_ApplyType: {
      break;
  }

+/* Opcode: CheckType P1 P2 * P4 *
+ * Synopsis: type(r[P1@P2])
+ *
+ * Check that types of P2 registers starting from register
+ * P1 are compatible with given with given field types in P4.
+ */
+case OP_CheckType: {
+    enum field_type *types = pOp->p4.types;
+    assert(types != NULL);
+    assert(types[pOp->p2] == field_type_MAX);
+    pIn1 = &aMem[pOp->p1];
+    enum field_type type;
+    while((type = *(types++)) != field_type_MAX) {
+        assert(pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)]);
+        assert(memIsValid(pIn1));
+        if (mem_check_types(pIn1, type) != 0) {
+            diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+                 mem_type_to_str(pIn1), field_type_strs[type]);
+            goto abort_due_to_error;
+        }
+        pIn1++;
+    }
+    break;
+}
+
  /* Opcode: MakeRecord P1 P2 P3 P4 P5
   * Synopsis: r[P3]=mkrec(r[P1@P2])
   *
diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index 2c50b6768..edb216a8a 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -517,6 +517,11 @@ mem_set_u64(struct Mem *mem, uint64_t value);
  void
  mem_set_int(struct Mem *mem, int64_t value, bool is_neg);

+/** Set double value and MEM_Real flag. */
+void
+mem_set_double(struct Mem *mem, double value);
+
+
  void sqlVdbeMemSetDouble(Mem *, double);
  void sqlVdbeMemInit(Mem *, sql *, u32);
  void sqlVdbeMemSetNull(Mem *);
diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c
index 8dad2db9a..9e8586ffc 100644
--- a/src/box/sql/vdbemem.c
+++ b/src/box/sql/vdbemem.c
@@ -839,6 +839,13 @@ mem_set_int(struct Mem *mem, int64_t value, bool 
is_neg)
      }
  }

+void
+mem_set_double(struct Mem *mem, double value)
+{
+    mem->u.r = value;
+    MemSetTypeFlag(mem, MEM_Real);
+}
+
  /*
   * Delete any previous value and set the value stored in *pMem to val,
   * manifest type REAL.
diff --git a/test/sql-tap/autoinc.test.lua b/test/sql-tap/autoinc.test.lua
index 37e65e541..ec8dfeab1 100755
--- a/test/sql-tap/autoinc.test.lua
+++ b/test/sql-tap/autoinc.test.lua
@@ -618,7 +618,7 @@ test:do_catchsql_test(
              INSERT INTO t2 VALUES('asd');
      ]], {
          -- <autoinc-10.2>
-        1, "Type mismatch: can not convert asd to integer"
+        1, "Type mismatch: can not convert text to integer"
          -- </autoinc-10.2>
      })

@@ -694,7 +694,7 @@ test:do_test(
                   INSERT INTO t3928(b) VALUES('after-int-' || 
CAST(new.b AS TEXT));
              END;
              DELETE FROM t3928 WHERE a!=1;
-            UPDATE t3928 SET b=456 WHERE a=1;
+            UPDATE t3928 SET b='456' WHERE a=1;
              SELECT * FROM t3928 ORDER BY a;
          ]])
      end, {
diff --git a/test/sql-tap/default.test.lua b/test/sql-tap/default.test.lua
index d3e35c71c..f1def2b10 100755
--- a/test/sql-tap/default.test.lua
+++ b/test/sql-tap/default.test.lua
@@ -109,16 +109,12 @@ test:do_execsql_test(
      f VARCHAR(15), --COLLATE RTRIM,
      g INTEGER DEFAULT( 3600*12 )
      );
-    INSERT INTO t3 VALUES(null, 5, 'row1', 5.25, 8.67, 321, 432);
+    INSERT INTO t3 VALUES(null, 5, 'row1', 5.25, 8.67, '321', 432);
      SELECT a, typeof(a), b, typeof(b), c, typeof(c),
      d, typeof(d), e, typeof(e), f, typeof(f),
      g, typeof(g) FROM t3;
      ]], {
      -- <default-3.1>
-    -- TODO: In original test "321" is not a string, its a value.
-    -- In current situation I don't know what to do, need Kirill's
-    -- advice.
-    -- Bulat
      1, "integer", 5, "integer", "row1", "string", 5.25, "number", 
8.67, "number", "321", "string", 432, "integer"
      -- </default-3.1>
  })
diff --git a/test/sql-tap/e_select1.test.lua 
b/test/sql-tap/e_select1.test.lua
index 1d3b964b9..7673426f4 100755
--- a/test/sql-tap/e_select1.test.lua
+++ b/test/sql-tap/e_select1.test.lua
@@ -753,11 +753,11 @@ test:do_execsql_test(
          CREATE TABLE z3(id  INT primary key, a NUMBER, b NUMBER);

          INSERT INTO z1 VALUES(1, 51.65, -59.58, 'belfries');
-        INSERT INTO z1 VALUES(2, -5, NULL, 75);
+        INSERT INTO z1 VALUES(2, -5, NULL, '75');
          INSERT INTO z1 VALUES(3, -2.2, -23.18, 'suiters');
          INSERT INTO z1 VALUES(4, NULL, 67, 'quartets');
          INSERT INTO z1 VALUES(5, -1.04, -32.3, 'aspen');
-        INSERT INTO z1 VALUES(6, 63, '0', -26);
+        INSERT INTO z1 VALUES(6, 63, 0, '-26');

          INSERT INTO z2 VALUES(1, NULL, 21);
          INSERT INTO z2 VALUES(2, 36.0, 6.0);
@@ -1457,13 +1457,13 @@ test:do_execsql_test(
          CREATE TABLE q2(id  INT primary key, d TEXT, e NUMBER);
          CREATE TABLE q3(id  INT primary key, f TEXT, g INT);

-        INSERT INTO q1 VALUES(1, 16, -87.66, NULL);
+        INSERT INTO q1 VALUES(1, '16', -87.66, NULL);
          INSERT INTO q1 VALUES(2, 'legible', 94, -42.47);
          INSERT INTO q1 VALUES(3, 'beauty', 36, NULL);

          INSERT INTO q2 VALUES(1, 'legible', 1);
          INSERT INTO q2 VALUES(2, 'beauty', 2);
-        INSERT INTO q2 VALUES(3, -65, 4);
+        INSERT INTO q2 VALUES(3, '-65', 4);
          INSERT INTO q2 VALUES(4, 'emanating', -16.56);

          INSERT INTO q3 VALUES(1, 'beauty', 2);
@@ -1603,7 +1603,7 @@ test:do_execsql_test(
          CREATE TABLE w2(a  INT PRIMARY KEY, b TEXT);

          INSERT INTO w1 VALUES('1', 4.1);
-        INSERT INTO w2 VALUES(1, 4.1);
+        INSERT INTO w2 VALUES(1, '4.1');
      ]], {
          -- <e_select-7.10.0>

diff --git a/test/sql-tap/gh-3809-implicit-cast-assignment.test.lua 
b/test/sql-tap/gh-3809-implicit-cast-assignment.test.lua
new file mode 100755
index 000000000..de72cf3a4
--- /dev/null
+++ b/test/sql-tap/gh-3809-implicit-cast-assignment.test.lua
@@ -0,0 +1,649 @@
+#!/usr/bin/env tarantool
+test = require("sqltester")
+test:plan(77)
+
+--
+-- Make sure there are no implicit casts during assignment,
+-- except for the implicit cast between numeric values.
+--
+test:execsql([[
+    CREATE TABLE ti (a INT PRIMARY KEY AUTOINCREMENT, i INTEGER);
+    CREATE TABLE td (a INT PRIMARY KEY AUTOINCREMENT, d DOUBLE);
+    CREATE TABLE tb (a INT PRIMARY KEY AUTOINCREMENT, b BOOLEAN);
+    CREATE TABLE tt (a INT PRIMARY KEY AUTOINCREMENT, t TEXT);
+    CREATE TABLE tv (a INT PRIMARY KEY AUTOINCREMENT, v VARBINARY);
+    CREATE TABLE ts (a INT PRIMARY KEY AUTOINCREMENT, s SCALAR);
+]])
+
+test:do_catchsql_test(
+    "gh-3809-1",
+    [[
+        INSERT INTO ti(i) VALUES (11)
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-2",
+    [[
+        INSERT INTO ti(i) VALUES (22.2)
+    ]], {
+        1, "Type mismatch: can not convert real to integer"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-3",
+    [[
+        INSERT INTO ti(i) VALUES (33.0)
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-4",
+    [[
+        INSERT INTO ti(i) VALUES (true)
+    ]], {
+        1, "Type mismatch: can not convert boolean to integer"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-5",
+    [[
+        INSERT INTO ti(i) VALUES ('33')
+    ]], {
+        1, "Type mismatch: can not convert text to integer"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-6",
+    [[
+        INSERT INTO ti(i) VALUES (X'3434')
+    ]], {
+        1, "Type mismatch: can not convert varbinary to integer"
+    })
+
+test:do_execsql_test(
+    "gh-3809-7",
+    [[
+        SELECT * FROM ti;
+    ]], {
+        1, 11, 2, 33
+    })
+
+test:do_catchsql_test(
+    "gh-3809-8",
+    [[
+        INSERT INTO td(d) VALUES (11)
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-9",
+    [[
+        INSERT INTO td(d) VALUES (100000000000000001);
+    ]], {
+        1, "Type mismatch: can not convert unsigned to double"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-10",
+    [[
+        INSERT INTO td(d) VALUES (22.2)
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-11",
+    [[
+        INSERT INTO td(d) VALUES (true)
+    ]], {
+        1, "Type mismatch: can not convert boolean to double"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-12",
+    [[
+        INSERT INTO td(d) VALUES ('33')
+    ]], {
+        1, "Type mismatch: can not convert text to double"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-13",
+    [[
+        INSERT INTO td(d) VALUES (X'3434')
+    ]], {
+        1, "Type mismatch: can not convert varbinary to double"
+    })
+
+test:do_execsql_test(
+    "gh-3809-14",
+    [[
+        SELECT * FROM td;
+    ]], {
+        1, 11, 2, 22.2
+    })
+
+test:do_catchsql_test(
+    "gh-3809-15",
+    [[
+        INSERT INTO tb(b) VALUES (11)
+    ]], {
+        1, "Type mismatch: can not convert unsigned to boolean"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-16",
+    [[
+        INSERT INTO tb(b) VALUES (22.2)
+    ]], {
+        1, "Type mismatch: can not convert real to boolean"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-17",
+    [[
+        INSERT INTO tb(b) VALUES (true)
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-18",
+    [[
+        INSERT INTO tb(b) VALUES ('33')
+    ]], {
+        1, "Type mismatch: can not convert text to boolean"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-19",
+    [[
+        INSERT INTO tb(b) VALUES (X'3434')
+    ]], {
+        1, "Type mismatch: can not convert varbinary to boolean"
+    })
+
+test:do_execsql_test(
+    "gh-3809-20",
+    [[
+        SELECT * FROM tb;
+    ]], {
+        1, true
+    })
+
+test:do_catchsql_test(
+    "gh-3809-21",
+    [[
+        INSERT INTO tt(t) VALUES (11)
+    ]], {
+        1, "Type mismatch: can not convert unsigned to string"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-22",
+    [[
+        INSERT INTO tt(t) VALUES (22.2)
+    ]], {
+        1, "Type mismatch: can not convert real to string"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-23",
+    [[
+        INSERT INTO tt(t) VALUES (true)
+    ]], {
+        1, "Type mismatch: can not convert boolean to string"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-24",
+    [[
+        INSERT INTO tt(t) VALUES ('33')
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-25",
+    [[
+        INSERT INTO tt(t) VALUES (X'3434')
+    ]], {
+        1, "Type mismatch: can not convert varbinary to string"
+    })
+
+test:do_execsql_test(
+    "gh-3809-26",
+    [[
+        SELECT * FROM tt;
+    ]], {
+        1, "33"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-27",
+    [[
+        INSERT INTO tv(v) VALUES (11)
+    ]], {
+        1, "Type mismatch: can not convert unsigned to varbinary"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-28",
+    [[
+        INSERT INTO tv(v) VALUES (22.2)
+    ]], {
+        1, "Type mismatch: can not convert real to varbinary"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-29",
+    [[
+        INSERT INTO tv(v) VALUES (true)
+    ]], {
+        1, "Type mismatch: can not convert boolean to varbinary"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-30",
+    [[
+        INSERT INTO tv(v) VALUES ('33')
+    ]], {
+        1, "Type mismatch: can not convert text to varbinary"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-31",
+    [[
+        INSERT INTO tv(v) VALUES (X'3434')
+    ]], {
+        0
+    })
+
+test:do_execsql_test(
+    "gh-3809-32",
+    [[
+        SELECT * FROM tv;
+    ]], {
+        1, "44"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-33",
+    [[
+        INSERT INTO ts(s) VALUES (11)
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-34",
+    [[
+        INSERT INTO ts(s) VALUES (22.2)
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-35",
+    [[
+        INSERT INTO ts(s) VALUES (true)
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-36",
+    [[
+        INSERT INTO ts(s) VALUES ('33')
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-37",
+    [[
+        INSERT INTO ts(s) VALUES (X'3434')
+    ]], {
+        0
+    })
+
+test:do_execsql_test(
+    "gh-3809-38",
+    [[
+        SELECT * FROM ts;
+    ]], {
+        1, 11, 2, 22.2, 3, true, 4, "33", 5, "44"
+    })
+
+test:execsql([[
+    DELETE FROM ti;
+    DELETE FROM td;
+    DELETE FROM tb;
+    DELETE FROM tt;
+    DELETE FROM tv;
+    DELETE FROM ts;
+    INSERT INTO ti(a) VALUES(1);
+    INSERT INTO td(a) VALUES(1);
+    INSERT INTO tb(a) VALUES(1);
+    INSERT INTO tt(a) VALUES(1);
+    INSERT INTO tv(a) VALUES(1);
+    INSERT INTO ts(a) VALUES(1);
+]])
+
+test:do_execsql_test(
+    "gh-3809-39",
+    [[
+        SELECT * FROM ti, td, tb, tt, tv, ts;
+    ]], {
+        1, "", 1, "", 1, "", 1, "", 1, "", 1, ""
+    })
+
+test:do_catchsql_test(
+    "gh-3809-40",
+    [[
+        UPDATE ti SET i = 11 WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-41",
+    [[
+        UPDATE ti SET i = 22.2 WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert real to integer"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-42",
+    [[
+        UPDATE ti SET i = 33.0 WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-43",
+    [[
+        UPDATE ti SET i = true WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert boolean to integer"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-44",
+    [[
+        UPDATE ti SET i = '33' WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert text to integer"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-45",
+    [[
+        UPDATE ti SET i = X'3434' WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert varbinary to integer"
+    })
+
+test:do_execsql_test(
+    "gh-3809-46",
+    [[
+        SELECT * FROM ti;
+    ]], {
+        1, 33
+    })
+
+test:do_catchsql_test(
+    "gh-3809-47",
+    [[
+        UPDATE td SET d = 11 WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-48",
+    [[
+        UPDATE td SET d = 100000000000000001 WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert unsigned to double"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-49",
+    [[
+        UPDATE td SET d = 22.2 WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-50",
+    [[
+        UPDATE td SET d = true WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert boolean to double"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-51",
+    [[
+        UPDATE td SET d = '33' WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert text to double"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-52",
+    [[
+        UPDATE td SET d = X'3434' WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert varbinary to double"
+    })
+
+test:do_execsql_test(
+    "gh-3809-53",
+    [[
+        SELECT * FROM td;
+    ]], {
+        1, 22.2
+    })
+
+test:do_catchsql_test(
+    "gh-3809-54",
+    [[
+        UPDATE tb SET b = 11 WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert unsigned to boolean"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-55",
+    [[
+        UPDATE tb SET b = 22.2 WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert real to boolean"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-56",
+    [[
+        UPDATE tb SET b = true WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-57",
+    [[
+        UPDATE tb SET b = '33' WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert text to boolean"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-58",
+    [[
+        UPDATE tb SET b = X'3434' WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert varbinary to boolean"
+    })
+
+test:do_execsql_test(
+    "gh-3809-59",
+    [[
+        SELECT * FROM tb;
+    ]], {
+        1, true
+    })
+
+test:do_catchsql_test(
+    "gh-3809-60",
+    [[
+        UPDATE tt SET t = 11 WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert unsigned to string"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-61",
+    [[
+        UPDATE tt SET t = 22.2 WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert real to string"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-62",
+    [[
+        UPDATE tt SET t = true WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert boolean to string"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-63",
+    [[
+        UPDATE tt SET t = '33' WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-64",
+    [[
+        UPDATE tt SET t = X'3434' WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert varbinary to string"
+    })
+
+test:do_execsql_test(
+    "gh-3809-65",
+    [[
+        SELECT * FROM tt;
+    ]], {
+        1, "33"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-66",
+    [[
+        UPDATE tv SET v = 11 WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert unsigned to varbinary"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-67",
+    [[
+        UPDATE tv SET v = 22.2 WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert real to varbinary"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-68",
+    [[
+        UPDATE tv SET v = true WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert boolean to varbinary"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-69",
+    [[
+        UPDATE tv SET v = '33' WHERE a = 1;
+    ]], {
+        1, "Type mismatch: can not convert text to varbinary"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-70",
+    [[
+        UPDATE tv SET v = X'3434' WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_execsql_test(
+    "gh-3809-71",
+    [[
+        SELECT * FROM tv;
+    ]], {
+        1, "44"
+    })
+
+test:do_catchsql_test(
+    "gh-3809-72",
+    [[
+        UPDATE ts SET s = 11 WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-73",
+    [[
+        UPDATE ts SET s = 22.2 WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-74",
+    [[
+        UPDATE ts SET s = true WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-75",
+    [[
+        UPDATE ts SET s = '33' WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_catchsql_test(
+    "gh-3809-76",
+    [[
+        UPDATE ts SET s = X'3434' WHERE a = 1;
+    ]], {
+        0
+    })
+
+test:do_execsql_test(
+    "gh-3809-77",
+    [[
+        SELECT * FROM ts;
+    ]], {
+        1, "44"
+    })
+
+test:finish_test()
diff --git a/test/sql-tap/index1.test.lua b/test/sql-tap/index1.test.lua
index e173e685c..ce66b7c1e 100755
--- a/test/sql-tap/index1.test.lua
+++ b/test/sql-tap/index1.test.lua
@@ -593,25 +593,17 @@ test:do_test(
          -- </index-11.1>
      })
  end
--- integrity_check index-11.2
--- Numeric strings should compare as if they were numbers.  So even if the
--- strings are not character-by-character the same, if they represent the
--- same number they should compare equal to one another.  Verify that this
--- is true in indices.
---
--- Updated for sql v3: sql will now store these values as numbers
--- (because the affinity of column a is NUMERIC) so the quirky
--- representations are not retained. i.e. '+1.0' becomes '1'.
+
  test:do_execsql_test(
      "index-12.1",
      [[
          CREATE TABLE t4(id  INT primary key, a NUMBER,b INT );
-        INSERT INTO t4 VALUES(1, '0.0',1);
-        INSERT INTO t4 VALUES(2, '0.00',2);
-        INSERT INTO t4 VALUES(4, '-1.0',4);
-        INSERT INTO t4 VALUES(5, '+1.0',5);
-        INSERT INTO t4 VALUES(6, '0',6);
-        INSERT INTO t4 VALUES(7, '00000',7);
+        INSERT INTO t4 VALUES(1, 0.0, 1);
+        INSERT INTO t4 VALUES(2, 0.00, 2);
+        INSERT INTO t4 VALUES(4, -1.0, 4);
+        INSERT INTO t4 VALUES(5, +1.0, 5);
+        INSERT INTO t4 VALUES(6, 0, 6);
+        INSERT INTO t4 VALUES(7, 00000, 7);
          SELECT a FROM t4 ORDER BY b;
      ]], {
          -- <index-12.1>
@@ -692,7 +684,7 @@ test:do_execsql_test(
             c  TEXT,
             UNIQUE(a,c)
          );
-        INSERT INTO t5 VALUES(1,2,3);
+        INSERT INTO t5 VALUES(1,2,'3');
          SELECT * FROM t5;
      ]], {
          -- <index-13.1>
diff --git a/test/sql-tap/insert3.test.lua b/test/sql-tap/insert3.test.lua
index 43bb06630..b92bc508e 100755
--- a/test/sql-tap/insert3.test.lua
+++ b/test/sql-tap/insert3.test.lua
@@ -60,7 +60,7 @@ test:do_execsql_test(
              CREATE TABLE log2(rowid INTEGER PRIMARY KEY AUTOINCREMENT, 
x TEXT UNIQUE,y INT );
              CREATE TRIGGER r2 BEFORE INSERT ON t1 FOR EACH ROW BEGIN
                UPDATE log2 SET y=y+1 WHERE x=new.b;
-              INSERT OR IGNORE INTO log2(x, y) VALUES(new.b,1);
+              INSERT OR IGNORE INTO log2(x, y) VALUES(CAST(new.b AS 
STRING),1);
              END;
              INSERT INTO t1(a, b) VALUES('hi', 453);
              SELECT x,y FROM log ORDER BY x;
@@ -129,8 +129,8 @@ test:do_execsql_test(
                INSERT INTO t2dup(a,b,c) VALUES(new.a,new.b,new.c);
              END;
              INSERT INTO t2(a) VALUES(123);
-            INSERT INTO t2(b) VALUES(234);
-            INSERT INTO t2(c) VALUES(345);
+            INSERT INTO t2(b) VALUES('234');
+            INSERT INTO t2(c) VALUES('345');
              SELECT * FROM t2dup;
      ]], {
          -- <insert3-2.1>
@@ -143,8 +143,8 @@ test:do_execsql_test(
      [[
              DELETE FROM t2dup;
              INSERT INTO t2(a) SELECT 1 FROM t1 LIMIT 1;
-            INSERT INTO t2(b) SELECT 987 FROM t1 LIMIT 1;
-            INSERT INTO t2(c) SELECT 876 FROM t1 LIMIT 1;
+            INSERT INTO t2(b) SELECT '987' FROM t1 LIMIT 1;
+            INSERT INTO t2(c) SELECT '876' FROM t1 LIMIT 1;
              SELECT * FROM t2dup;
      ]], {
          -- <insert3-2.2>
diff --git a/test/sql-tap/intpkey.test.lua b/test/sql-tap/intpkey.test.lua
index b6b186632..0db18ba91 100755
--- a/test/sql-tap/intpkey.test.lua
+++ b/test/sql-tap/intpkey.test.lua
@@ -770,11 +770,6 @@ test:do_execsql_test(
          -- </intpkey-11.1>
      })

--- integrity_check intpkey-12.1
--- Try to use a string that looks like a floating point number as
--- an integer primary key.  This should actually work when the floating
--- point value can be rounded to an integer without loss of data.
---
  test:do_execsql_test(
      "intpkey-13.1",
      [[
@@ -788,7 +783,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "intpkey-13.2",
      [[
-        INSERT INTO t1 VALUES('1',2,3);
+        INSERT INTO t1 VALUES(1,'2','3');
          SELECT * FROM t1 WHERE a=1;
      ]], {
          -- <intpkey-13.2>
@@ -825,7 +820,7 @@ end
  test:do_catchsql_test(
      "intpkey-13.5",
      [[
-        INSERT INTO t1 VALUES('+1234567890',3,4);
+        INSERT INTO t1 VALUES(1234567890,'3','4');
      ]], {
          -- <intpkey-13.5>
          0
@@ -842,7 +837,7 @@ test:do_execsql_test(
          CREATE TABLE t3(a INTEGER PRIMARY KEY, b INTEGER, c TEXT);
          INSERT INTO t3 VALUES(1, 1, 'one');
          INSERT INTO t3 VALUES(2, 2, '2');
-        INSERT INTO t3 VALUES(3, 3, 3);
+        INSERT INTO t3 VALUES(3, 3, '3');
      ]], {
          -- <intpkey-14.1>

@@ -905,7 +900,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "intpkey-15.1",
      [[
-        INSERT INTO t1 VALUES(2147483647, 'big-1', 123);
+        INSERT INTO t1 VALUES(2147483647, 'big-1', '123');
          SELECT * FROM t1 WHERE a>2147483648;
      ]], {
          -- <intpkey-15.1>
diff --git a/test/sql-tap/minmax2.test.lua b/test/sql-tap/minmax2.test.lua
index 0e0f0d08e..707d1c4da 100755
--- a/test/sql-tap/minmax2.test.lua
+++ b/test/sql-tap/minmax2.test.lua
@@ -441,9 +441,9 @@ test:do_execsql_test(
      "minmax2-8.2",
      [[
          CREATE TABLE t5(a INTEGER PRIMARY KEY);
-        INSERT INTO t5 VALUES('1234');
-        INSERT INTO t5 VALUES('234');
-        INSERT INTO t5 VALUES('34');
+        INSERT INTO t5 VALUES(1234);
+        INSERT INTO t5 VALUES(234);
+        INSERT INTO t5 VALUES(34);
          SELECT min(a), max(a) FROM t5;
      ]], {
          -- <minmax2-8.2>
diff --git a/test/sql-tap/misc1.test.lua b/test/sql-tap/misc1.test.lua
index 32f38cc97..e0fe50bbe 100755
--- a/test/sql-tap/misc1.test.lua
+++ b/test/sql-tap/misc1.test.lua
@@ -34,9 +34,9 @@ test:do_test(
          end
          cmd = cmd .. ")"
          test:execsql(cmd)
-        cmd = "INSERT INTO manycol VALUES(1, 0"
+        cmd = "INSERT INTO manycol VALUES(1, '0'"
          for i = 1, 99, 1 do
-            cmd = cmd .. ","..i..""
+            cmd = cmd .. ",'"..i.."'"
          end
          cmd = cmd .. ")"
          test:execsql(cmd)
@@ -61,9 +61,9 @@ test:do_test(
      "misc1-1.3.1",
      function()
          for j = 100, 1000, 100 do
-            local cmd = string.format("INSERT INTO manycol VALUES(%s, 
%s", j, j)
+            local cmd = string.format("INSERT INTO manycol VALUES(%s, 
'%s'", j, j)
              for i = 1, 99, 1 do
-                cmd = cmd .. ","..(i + j)..""
+                cmd = cmd .. ",'"..(i + j).."'"
              end
              cmd = cmd .. ")"
              test:execsql(cmd)
@@ -178,12 +178,12 @@ test:do_test(
          test:execsql([[
              CREATE TABLE agger(one text primary key, two text, three 
text, four text);
              START TRANSACTION;
-            INSERT INTO agger VALUES(1, 'one', 'hello', 'yes');
-            INSERT INTO agger VALUES(2, 'two', 'howdy', 'no');
-            INSERT INTO agger VALUES(3, 'thr', 'howareya', 'yes');
-            INSERT INTO agger VALUES(4, 'two', 'lothere', 'yes');
-            INSERT INTO agger VALUES(5, 'one', 'atcha', 'yes');
-            INSERT INTO agger VALUES(6, 'two', 'hello', 'no');
+            INSERT INTO agger VALUES('1', 'one', 'hello', 'yes');
+            INSERT INTO agger VALUES('2', 'two', 'howdy', 'no');
+            INSERT INTO agger VALUES('3', 'thr', 'howareya', 'yes');
+            INSERT INTO agger VALUES('4', 'two', 'lothere', 'yes');
+            INSERT INTO agger VALUES('5', 'one', 'atcha', 'yes');
+            INSERT INTO agger VALUES('6', 'two', 'hello', 'no');
              COMMIT
          ]])
          return test:execsql("SELECT count(*) FROM agger")
@@ -531,7 +531,7 @@ test:do_test(
      "misc1-10.7",
      function()
          where = string.gsub(where, "x0=0", "x0=100")
-        return test:catchsql("UPDATE manycol SET x1=x1+1 "..where.."")
+        return test:catchsql("UPDATE manycol SET x1=CAST(x1+1 AS 
STRING) "..where.."")
      end, {
          -- <misc1-10.7>
          0
@@ -553,7 +553,7 @@ test:do_execsql_test(
  -- } {0 {}}
  test:do_execsql_test(
      "misc1-10.9",
-    "UPDATE manycol SET x1=x1+1 "..where
+    "UPDATE manycol SET x1=CAST(x1+1 AS STRING) "..where
          --"UPDATE manycol SET x1=x1+1 $::where AND rowid>0"
      , {})

@@ -665,7 +665,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "misc1-12.6",
      [[
-        INSERT OR IGNORE INTO t6 VALUES('y',0);
+        INSERT OR IGNORE INTO t6 VALUES('y','0');
          SELECT * FROM t6;
      ]], {
          -- <misc1-12.6>
@@ -679,10 +679,10 @@ test:do_execsql_test(
      "misc1-12.7",
      [[
          CREATE TABLE t7(x INTEGER, y TEXT, z  INT primary key);
-        INSERT INTO t7 VALUES(0,0,1);
-        INSERT INTO t7 VALUES(0.0,0,2);
-        INSERT INTO t7 VALUES(0,0.0,3);
-        INSERT INTO t7 VALUES(0.0,0.0,4);
+        INSERT INTO t7 VALUES(0,'0',1);
+        INSERT INTO t7 VALUES(0.0,'0',2);
+        INSERT INTO t7 VALUES(0,'0.0',3);
+        INSERT INTO t7 VALUES(0.0,'0.0',4);
          SELECT DISTINCT x, y FROM t7 ORDER BY z;
      ]], {
          -- <misc1-12.7>
diff --git a/test/sql-tap/numcast.test.lua b/test/sql-tap/numcast.test.lua
index eeac5353a..9bbae5ca4 100755
--- a/test/sql-tap/numcast.test.lua
+++ b/test/sql-tap/numcast.test.lua
@@ -135,7 +135,7 @@ test:do_catchsql_test(
          INSERT INTO t VALUES(20000000000000000000.01);
          SELECT * FROM t;
      ]], {
-        1,"Tuple field 1 type does not match one required by operation: 
expected integer"
+        1,"Type mismatch: can not convert real to integer"
      })

  test:do_catchsql_test(
@@ -144,7 +144,7 @@ test:do_catchsql_test(
          INSERT INTO t VALUES(2.1);
          SELECT * FROM t;
      ]], {
-        1,"Tuple field 1 type does not match one required by operation: 
expected integer"
+        1,"Type mismatch: can not convert real to integer"
      })

  --
diff --git a/test/sql-tap/select1.test.lua b/test/sql-tap/select1.test.lua
index fbebfab37..9a969bf3c 100755
--- a/test/sql-tap/select1.test.lua
+++ b/test/sql-tap/select1.test.lua
@@ -231,7 +231,7 @@ string.format([[
          CREATE TABLE t3(id INT, a TEXT, b TEXT, PRIMARY KEY(id));
          INSERT INTO t3 VALUES(1, 'abc',NULL);
          INSERT INTO t3 VALUES(2, NULL,'xyz');
-        INSERT INTO t3 SELECT f1, * FROM test1;
+        INSERT INTO t3 SELECT f1, CAST(f1 AS STRING), CAST(f2 AS 
STRING) FROM test1;
          DROP TABLE IF EXISTS t4;
          CREATE TABLE t4(id INT, a INT , b TEXT , PRIMARY KEY(id));
          INSERT INTO t4 VALUES(1, NULL,'%s');
@@ -1671,8 +1671,8 @@ test:do_execsql_test(
      [[
          DELETE FROM t3;
          DELETE FROM t4;
-        INSERT INTO t3 VALUES(0,1,2);
-        INSERT INTO t4 VALUES(0,3,4);
+        INSERT INTO t3 VALUES(0,'1','2');
+        INSERT INTO t4 VALUES(0,3,'4');
          SELECT * FROM t3, t4;
      ]], {
          -- <select1-11.1>
@@ -1878,7 +1878,7 @@ test:do_execsql_test(
      "select1-12.4",
      [[
          DELETE FROM t3;
-        INSERT INTO t3 VALUES(0,1,2);
+        INSERT INTO t3 VALUES(0,'1','2');
      ]], {
          -- <select1-12.4>

diff --git a/test/sql-tap/select4.test.lua b/test/sql-tap/select4.test.lua
index 23cf1bf1b..f7a320438 100755
--- a/test/sql-tap/select4.test.lua
+++ b/test/sql-tap/select4.test.lua
@@ -761,12 +761,12 @@ test:do_test(
          test:execsql [[
              CREATE TABLE t3(a text primary key, b NUMBER, c text);
              START TRANSACTION;
-            INSERT INTO t3 VALUES(1, 1.1, '1.1');
-            INSERT INTO t3 VALUES(2, 1.10, '1.10');
-            INSERT INTO t3 VALUES(3, 1.10, '1.1');
-            INSERT INTO t3 VALUES(4, 1.1, '1.10');
-            INSERT INTO t3 VALUES(5, 1.2, '1.2');
-            INSERT INTO t3 VALUES(6, 1.3, '1.3');
+            INSERT INTO t3 VALUES('1', 1.1, '1.1');
+            INSERT INTO t3 VALUES('2', 1.10, '1.10');
+            INSERT INTO t3 VALUES('3', 1.10, '1.1');
+            INSERT INTO t3 VALUES('4', 1.1, '1.10');
+            INSERT INTO t3 VALUES('5', 1.2, '1.2');
+            INSERT INTO t3 VALUES('6', 1.3, '1.3');
              COMMIT;
          ]]
          return test:execsql [[
diff --git a/test/sql-tap/select7.test.lua b/test/sql-tap/select7.test.lua
index fec5d7a41..e1e43c557 100755
--- a/test/sql-tap/select7.test.lua
+++ b/test/sql-tap/select7.test.lua
@@ -255,7 +255,7 @@ test:do_execsql_test(
      [[
          DROP TABLE IF EXISTS t5;
          CREATE TABLE t5(a TEXT primary key, b INT);
-        INSERT INTO t5 VALUES(123, 456);
+        INSERT INTO t5 VALUES('123', 456);
          SELECT typeof(a), a FROM t5 GROUP BY a HAVING a<b;
      ]], {
          -- <select7-7.7>
diff --git a/test/sql-tap/sort.test.lua b/test/sql-tap/sort.test.lua
index 36074d6ef..18bfd443d 100755
--- a/test/sql-tap/sort.test.lua
+++ b/test/sql-tap/sort.test.lua
@@ -505,10 +505,10 @@ test:do_execsql_test(
            a INTEGER PRIMARY KEY,
            b VARCHAR(30)
          );
-        INSERT INTO t4 VALUES(1,1);
-        INSERT INTO t4 VALUES(2,2);
-        INSERT INTO t4 VALUES(11,11);
-        INSERT INTO t4 VALUES(12,12);
+        INSERT INTO t4 VALUES(1,'1');
+        INSERT INTO t4 VALUES(2,'2');
+        INSERT INTO t4 VALUES(11,'11');
+        INSERT INTO t4 VALUES(12,'12');
          SELECT a FROM t4 ORDER BY 1;
      ]], {
          -- <sort-7.1>
diff --git a/test/sql-tap/tkt-3998683a16.test.lua 
b/test/sql-tap/tkt-3998683a16.test.lua
index 885dcf5cd..9bc310358 100755
--- a/test/sql-tap/tkt-3998683a16.test.lua
+++ b/test/sql-tap/tkt-3998683a16.test.lua
@@ -26,29 +26,17 @@ test:do_test(
      function()
          return test:execsql [[
              CREATE TABLE t1(x  INT primary key, y NUMBER);
-            INSERT INTO t1 VALUES(1, '1.0');
-            INSERT INTO t1 VALUES(2, '.125');
-            INSERT INTO t1 VALUES(3, '123.');
-            INSERT INTO t1 VALUES(4, '123.e+2');
-            INSERT INTO t1 VALUES(5, '.125e+3');
-            INSERT INTO t1 VALUES(6, '123e4');
-            INSERT INTO t1 VALUES(11, '  1.0');
-            INSERT INTO t1 VALUES(12, '  .125');
-            INSERT INTO t1 VALUES(13, '  123.');
-            INSERT INTO t1 VALUES(14, '  123.e+2');
-            INSERT INTO t1 VALUES(15, '  .125e+3');
-            INSERT INTO t1 VALUES(16, '  123e4');
-            INSERT INTO t1 VALUES(21, '1.0  ');
-            INSERT INTO t1 VALUES(22, '.125  ');
-            INSERT INTO t1 VALUES(23, '123.  ');
-            INSERT INTO t1 VALUES(24, '123.e+2  ');
-            INSERT INTO t1 VALUES(25, '.125e+3  ');
-            INSERT INTO t1 VALUES(26, '123e4  ');
+            INSERT INTO t1 VALUES(1, 1.0);
+            INSERT INTO t1 VALUES(2, .125);
+            INSERT INTO t1 VALUES(3, 123.);
+            INSERT INTO t1 VALUES(4, 123.e+2);
+            INSERT INTO t1 VALUES(5, .125e+3);
+            INSERT INTO t1 VALUES(6, 123e4);
              SELECT x FROM t1 WHERE typeof(y)=='number' ORDER BY x;
          ]]
      end, {
          -- <tkt-3998683a16.1>
-        1, 2, 3, 4, 5, 6, 11, 12, 13, 14, 15, 16, 21, 22, 23, 24, 25, 26
+        1, 2, 3, 4, 5, 6
          -- </tkt-3998683a16.1>
      })

diff --git a/test/sql-tap/tkt-54844eea3f.test.lua 
b/test/sql-tap/tkt-54844eea3f.test.lua
index d6cd56e52..89d0d1218 100755
--- a/test/sql-tap/tkt-54844eea3f.test.lua
+++ b/test/sql-tap/tkt-54844eea3f.test.lua
@@ -62,10 +62,10 @@ test:do_execsql_test(
      "1.2",
      [[
          CREATE TABLE t4(id INT primary key, a TEXT, b TEXT, c TEXT);
-        INSERT INTO t4 VALUES(1, 'a', 1, 'one');
-        INSERT INTO t4 VALUES(2, 'a', 2, 'two');
-        INSERT INTO t4 VALUES(3, 'b', 1, 'three');
-        INSERT INTO t4 VALUES(4, 'b', 2, 'four');
+        INSERT INTO t4 VALUES(1, 'a', '1', 'one');
+        INSERT INTO t4 VALUES(2, 'a', '2', 'two');
+        INSERT INTO t4 VALUES(3, 'b', '1', 'three');
+        INSERT INTO t4 VALUES(4, 'b', '2', 'four');
          SELECT (
            SELECT c FROM (
              SELECT a,b,c FROM t4 WHERE a=output.a ORDER BY b LIMIT 10 
OFFSET 1
diff --git a/test/sql-tap/tkt-7bbfb7d442.test.lua 
b/test/sql-tap/tkt-7bbfb7d442.test.lua
index 535303771..bfddcd920 100755
--- a/test/sql-tap/tkt-7bbfb7d442.test.lua
+++ b/test/sql-tap/tkt-7bbfb7d442.test.lua
@@ -109,13 +109,13 @@ if (1 > 0)
                      T1.Variant AS Variant,
                      T1.ControlDate AS ControlDate,
                      1 AS ControlState,
-                    COALESCE(T2.DeliveredQty,0) AS DeliveredQty
+                    CAST(COALESCE(T2.DeliveredQty,0) AS STRING) AS 
DeliveredQty
                  FROM (
                      SELECT
                          NEW.InventoryControlId AS InventoryControlId,
                          II.SKU AS SKU,
                          II.Variant AS Variant,
- COALESCE(LastClosedIC.ControlDate,NEW.ControlDate) AS ControlDate
+ CAST(COALESCE(LastClosedIC.ControlDate,NEW.ControlDate) AS STRING) AS 
ControlDate
                      FROM
                          InventoryItem II
                      LEFT JOIN
diff --git a/test/sql-tap/tkt1444.test.lua b/test/sql-tap/tkt1444.test.lua
index 82a5ded25..fb148bc5f 100755
--- a/test/sql-tap/tkt1444.test.lua
+++ b/test/sql-tap/tkt1444.test.lua
@@ -30,8 +30,8 @@ test:do_execsql_test(
      [[
          CREATE TABLE DemoTable (id  INT primary key, x INTEGER, 
TextKey TEXT, DKey NUMBER);
          CREATE INDEX DemoTableIdx ON DemoTable (TextKey);
-        INSERT INTO DemoTable VALUES(1, 9,8,7);
-        INSERT INTO DemoTable VALUES(2, 1,2,3);
+        INSERT INTO DemoTable VALUES(1, 9,'8',7);
+        INSERT INTO DemoTable VALUES(2, 1,'2',3);
          CREATE VIEW DemoView AS SELECT x, TextKey, DKey FROM DemoTable 
ORDER BY TextKey;
          SELECT x,TextKey,DKey FROM DemoTable UNION ALL SELECT * FROM 
DemoView ORDER BY 1;
      ]], {
diff --git a/test/sql-tap/tkt3493.test.lua b/test/sql-tap/tkt3493.test.lua
index 7ceec4702..de77e61e9 100755
--- a/test/sql-tap/tkt3493.test.lua
+++ b/test/sql-tap/tkt3493.test.lua
@@ -29,8 +29,8 @@ test:do_execsql_test(
          START TRANSACTION;
          INSERT INTO A VALUES(1,'123');
          INSERT INTO A VALUES(2,'456');
-        INSERT INTO B VALUES(1,1);
-        INSERT INTO B VALUES(2,2);
+        INSERT INTO B VALUES(1,'1');
+        INSERT INTO B VALUES(2,'2');
          INSERT INTO A_B VALUES(1,1);
          INSERT INTO A_B VALUES(2,2);
          COMMIT;
@@ -116,7 +116,7 @@ test:do_execsql_test(
      "tkt3493-2.1",
      [[
          CREATE TABLE t1(a TEXT PRIMARY KEY, b INT);
-        INSERT INTO t1 VALUES(123, 456);
+        INSERT INTO t1 VALUES('123', 456);
      ]], {
          -- <tkt3493-2.1>

diff --git a/test/sql-tap/tkt3841.test.lua b/test/sql-tap/tkt3841.test.lua
index 5203d0cd4..56668f6a3 100755
--- a/test/sql-tap/tkt3841.test.lua
+++ b/test/sql-tap/tkt3841.test.lua
@@ -31,12 +31,12 @@ test:do_execsql_test(

          INSERT INTO table2 VALUES ('a', 'alist');
          INSERT INTO table2 VALUES ('b', 'blist');
-        INSERT INTO list VALUES ('a', 1);
-        INSERT INTO list VALUES ('a', 2);
-        INSERT INTO list VALUES ('a', 3);
-        INSERT INTO list VALUES ('b', 4);
-        INSERT INTO list VALUES ('b', 5);
-        INSERT INTO list VALUES ('b', 6);
+        INSERT INTO list VALUES ('a', '1');
+        INSERT INTO list VALUES ('a', '2');
+        INSERT INTO list VALUES ('a', '3');
+        INSERT INTO list VALUES ('b', '4');
+        INSERT INTO list VALUES ('b', '5');
+        INSERT INTO list VALUES ('b', '6');

          SELECT
            table2.x,
diff --git a/test/sql-tap/triggerA.test.lua b/test/sql-tap/triggerA.test.lua
index fac51ca14..fc8ecfe17 100755
--- a/test/sql-tap/triggerA.test.lua
+++ b/test/sql-tap/triggerA.test.lua
@@ -283,7 +283,7 @@ test:do_test(
              CREATE TABLE result2(id INTEGER PRIMARY KEY, a TEXT,b INT);
              CREATE TRIGGER r5d INSTEAD OF DELETE ON v5 FOR EACH ROW BEGIN
                INSERT INTO result2(id, a,b) VALUES((SELECT 
coalesce(max(id),0) + 1 FROM result2),
-                                                  old.x, old.b);
+                                                  CAST(old.x AS 
STRING), old.b);
              END;
              DELETE FROM v5 WHERE x=5;
              SELECT a, b FROM result2;
@@ -301,7 +301,7 @@ test:do_test(
              DELETE FROM result4;
              CREATE TRIGGER r5u INSTEAD OF UPDATE ON v5 FOR EACH ROW BEGIN
                INSERT INTO result4(id, a,b,c,d) VALUES((SELECT 
coalesce(max(id),0) + 1 FROM result4),
-                                                      old.x, old.b, 
new.x, new.b);
+                                                      CAST(old.x AS 
STRING), old.b, CAST(new.x AS STRING), new.b);
              END;
              UPDATE v5 SET b = b+9900000 WHERE x BETWEEN 3 AND 5;
              SELECT a,b,c,d FROM result4 ORDER BY a;
diff --git a/test/sql-tap/unique.test.lua b/test/sql-tap/unique.test.lua
index 9818f90a8..6b0a7e20d 100755
--- a/test/sql-tap/unique.test.lua
+++ b/test/sql-tap/unique.test.lua
@@ -52,7 +52,7 @@ test:do_catchsql_test(
  test:do_catchsql_test(
      "unique-1.2",
      [[
-        INSERT INTO t1(a,b,c) VALUES(1,2,3)
+        INSERT INTO t1(a,b,c) VALUES(1,2,'3')
      ]], {
          -- <unique-1.2>
          0
@@ -62,7 +62,7 @@ test:do_catchsql_test(
  test:do_catchsql_test(
      "unique-1.3",
      [[
-        INSERT INTO t1(a,b,c) VALUES(1,3,4)
+        INSERT INTO t1(a,b,c) VALUES(1,3,'4')
      ]], {
          -- <unique-1.3>
          1, "Duplicate key exists in unique index 'pk_unnamed_T1_1' in 
space 'T1'"
@@ -83,7 +83,7 @@ test:do_execsql_test(
  test:do_catchsql_test(
      "unique-1.5",
      [[
-        INSERT INTO t1(a,b,c) VALUES(3,2,4)
+        INSERT INTO t1(a,b,c) VALUES(3,2,'4')
      ]], {
          -- <unique-1.5>
          1, "Duplicate key exists in unique index 'unique_unnamed_T1_2' 
in space 'T1'"
@@ -104,7 +104,7 @@ test:do_execsql_test(
  test:do_catchsql_test(
      "unique-1.7",
      [[
-        INSERT INTO t1(a,b,c) VALUES(3,4,5)
+        INSERT INTO t1(a,b,c) VALUES(3,4,'5')
      ]], {
          -- <unique-1.7>
          0
diff --git a/test/sql-tap/view.test.lua b/test/sql-tap/view.test.lua
index e553b91c7..ab14c5edb 100755
--- a/test/sql-tap/view.test.lua
+++ b/test/sql-tap/view.test.lua
@@ -757,7 +757,7 @@ test:do_execsql_test(
      "view-10.1",
      [=[
          CREATE TABLE t3("9" integer primary key, "4" text);
-        INSERT INTO t3 VALUES(1,2);
+        INSERT INTO t3 VALUES(1,'2');
          CREATE VIEW v_t3_a AS SELECT a."9" FROM t3 AS a;
          CREATE VIEW v_t3_b AS SELECT "4" FROM t3;
          SELECT * FROM v_t3_a;
diff --git a/test/sql-tap/where5.test.lua b/test/sql-tap/where5.test.lua
index 749201564..3aefcaca5 100755
--- a/test/sql-tap/where5.test.lua
+++ b/test/sql-tap/where5.test.lua
@@ -27,11 +27,11 @@ test:do_test("where5-1.0", function()
          CREATE TABLE t1(x TEXT primary key);
          CREATE TABLE t2(x integer primary key);
          CREATE TABLE t3(x integer PRIMARY KEY);
-        INSERT INTO t1 VALUES(-1);
-        INSERT INTO t1 VALUES(0);
-        INSERT INTO t1 VALUES(1);
-        INSERT INTO t2 SELECT * FROM t1;
-        INSERT INTO t3 SELECT * FROM t1;
+        INSERT INTO t1 VALUES('-1');
+        INSERT INTO t1 VALUES('0');
+        INSERT INTO t1 VALUES('1');
+        INSERT INTO t2 SELECT CAST(x AS INTEGER) FROM t1;
+        INSERT INTO t3 SELECT CAST(x AS INTEGER) FROM t1;
      ]]
      return test:execsql [[
          SELECT * FROM t1 WHERE x<0
diff --git a/test/sql-tap/whereB.test.lua b/test/sql-tap/whereB.test.lua
index d98645fdc..fe5e28c70 100755
--- a/test/sql-tap/whereB.test.lua
+++ b/test/sql-tap/whereB.test.lua
@@ -112,24 +112,16 @@ test:do_execsql_test(
      -- </whereB-1.102>
      })

--- For this set of tests:
---
---  *   t1.y holds a text value with affinity TEXT
---  *   t2.b holds an integer value with affinity NONE
---
--- These values are not equal and because neither affinity is NUMERIC
--- no type conversion occurs.
---
  test:do_execsql_test(
      "whereB-2.1",
      [[
          DROP TABLE t1;
          DROP TABLE t2;

-        CREATE TABLE t1(x  INT primary key, y TEXT);    -- affinity of 
t1.y is TEXT
-        INSERT INTO t1 VALUES(1,99);
+        CREATE TABLE t1(x  INT primary key, y TEXT);
+        INSERT INTO t1 VALUES(1,'99');

-        CREATE TABLE t2(a  INT primary key, b SCALAR);  -- affinity of 
t2.b is NONE
+        CREATE TABLE t2(a  INT primary key, b SCALAR);
          CREATE INDEX t2b ON t2(b);
          INSERT INTO t2 VALUES(2, 99);

diff --git a/test/sql/boolean.result b/test/sql/boolean.result
index 112e41a12..e88183854 100644
--- a/test/sql/boolean.result
+++ b/test/sql/boolean.result
@@ -161,7 +161,7 @@ SELECT s FROM ts WHERE s IN (true, 1, 'abcd');
  INSERT INTO ts VALUES (true, 12345);
   | ---
   | - null
- | - 'Type mismatch: can not convert TRUE to integer'
+ | - 'Type mismatch: can not convert boolean to integer'
   | ...

  -- Check that we can create index on field of type BOOLEAN.
diff --git a/test/sql/persistency.result b/test/sql/persistency.result
index 6d14d4c4e..6ec2f06fc 100644
--- a/test/sql/persistency.result
+++ b/test/sql/persistency.result
@@ -370,7 +370,7 @@ box.execute("SELECT \"name\", \"opts\" FROM 
\"_trigger\"");
  box.execute("INSERT INTO foobar VALUES ('foobar trigger test', 8888)")
  ---
  - null
-- 'Type mismatch: can not convert foobar trigger test to integer'
+- 'Type mismatch: can not convert text to integer'
  ...
  box.execute("SELECT * FROM barfoo WHERE foo = 9999");
  ---
diff --git a/test/sql/types.result b/test/sql/types.result
index 54aff460e..6b0f7a651 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -1062,7 +1062,7 @@ 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'
+- 'Type mismatch: can not convert integer to unsigned'
  ...
  box.execute("SELECT id FROM t1;")
  ---
@@ -1220,22 +1220,22 @@ box.execute("CREATE TABLE t (id INT PRIMARY KEY, 
v VARBINARY);")
  box.execute("INSERT INTO t VALUES(1, 1);")
  ---
  - null
-- 'Type mismatch: can not convert 1 to varbinary'
+- 'Type mismatch: can not convert unsigned to varbinary'
  ...
  box.execute("INSERT INTO t VALUES(1, 1.123);")
  ---
  - null
-- 'Type mismatch: can not convert 1.123 to varbinary'
+- 'Type mismatch: can not convert real to varbinary'
  ...
  box.execute("INSERT INTO t VALUES(1, true);")
  ---
  - null
-- 'Type mismatch: can not convert TRUE to varbinary'
+- 'Type mismatch: can not convert boolean to varbinary'
  ...
  box.execute("INSERT INTO t VALUES(1, 'asd');")
  ---
  - null
-- 'Type mismatch: can not convert asd to varbinary'
+- 'Type mismatch: can not convert text to varbinary'
  ...
  box.execute("INSERT INTO t VALUES(1, x'616263');")
  ---
@@ -1617,7 +1617,7 @@ s:insert({1, {1,2,3}})
  box.execute('INSERT INTO t1(a) SELECT a FROM t2;')
  ---
  - null
-- 'Type mismatch: can not convert [1, 2, 3] to scalar'
+- 'Type mismatch: can not convert varbinary to scalar'
  ...
  s:replace({1, 
{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30}})
  ---
@@ -1627,8 +1627,7 @@ s:replace({1, 
{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25
  box.execute('INSERT INTO t1(a) SELECT a FROM t2;')
  ---
  - null
-- 'Type mismatch: can not convert [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 
12, 13, 14,
-  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30] to 
scalar'
+- 'Type mismatch: can not convert varbinary to scalar'
  ...
  --
  -- Make sure that the error will be displayed correctly even if
@@ -1653,13 +1652,7 @@ s:replace({1, long_array})
  box.execute('INSERT INTO t1(a) SELECT a FROM t2;')
  ---
  - null
-- 'Type mismatch: can not convert [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 
12, 13, 14,
-  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 
32, 33, 34,
-  35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 
52, 53, 54,
-  55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 
72, 73, 74,
-  75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 
92, 93, 94,
-  95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 
110, 111,
-  112, 113, 114, 115, 116, 117, 11'
+- 'Type mismatch: can not convert varbinary to scalar'
  ...
  s:drop()
  ---
@@ -1680,7 +1673,7 @@ s:insert({1, {b = 1}})
  box.execute('INSERT INTO t1(a) SELECT a FROM t2;')
  ---
  - null
-- 'Type mismatch: can not convert {"b": 1} to scalar'
+- 'Type mismatch: can not convert varbinary to scalar'
  ...
  s:drop()
  ---

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Tarantool-patches] [PATCH 2/6] sql: remove mem_apply_type() from OP_MakeRecord
  2020-06-01 17:03   ` Vladislav Shpilevoy
@ 2020-06-09 11:43     ` Mergen Imeev
  0 siblings, 0 replies; 21+ messages in thread
From: Mergen Imeev @ 2020-06-09 11:43 UTC (permalink / raw)
  To: Vladislav Shpilevoy, tsafin, tarantool-patches

Thank you for the review! New patch below.


On 01.06.2020 20:03, Vladislav Shpilevoy wrote:
> Thanks for the patch!
>
>> diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
>> index 2a941025c..fc41ee0d6 100644
>> --- a/src/box/sql/vdbe.c
>> +++ b/src/box/sql/vdbe.c
>> @@ -2902,7 +2902,6 @@ case OP_CheckType: {
>>    * into ephemeral space. Thus, sort of memory optimization can be performed.
>>    */
> P4 should be removed from the comment too.
Fixed.
>
>>   case OP_MakeRecord: {
>> -	Mem *pRec;             /* The new record */
>>   	Mem *pData0;           /* First field to be combined into the record */
>>   	Mem MAYBE_UNUSED *pLast;  /* Last field of the record */
>>   	int nField;            /* Number of fields in the record */



New patch:


 From f87e9b757844bde856bc41de5ad90754c66b0ef3 Mon Sep 17 00:00:00 2001
From: Mergen Imeev <imeevma@gmail.com>
Date: Wed, 27 May 2020 11:16:43 +0300
Subject: [PATCH] sql: remove mem_apply_type() from OP_MakeRecord

This patch removes type changing from OP_MakeRecord.

Part of #4230

diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
index f74f9b358..23fbb15de 100644
--- a/src/box/sql/analyze.c
+++ b/src/box/sql/analyze.c
@@ -965,12 +965,7 @@ vdbe_emit_analyze_space(struct Parse *parse, struct 
space *space)
          sqlVdbeAddOp2(v, OP_Next, idx_cursor, next_row_addr);
          /* Add the entry to the stat1 table. */
          callStatGet(v, stat4_reg, STAT_GET_STAT1, stat1_reg);
-        enum field_type types[4] = { FIELD_TYPE_STRING,
-                         FIELD_TYPE_STRING,
-                         FIELD_TYPE_STRING,
-                         field_type_MAX };
-        sqlVdbeAddOp4(v, OP_MakeRecord, tab_name_reg, 4, tmp_reg,
-                  (char *)types, sizeof(types));
+        sqlVdbeAddOp3(v, OP_MakeRecord, tab_name_reg, 4, tmp_reg);
          sqlVdbeAddOp4(v, OP_IdxInsert, tmp_reg, 0, 0,
                    (char *)stat1, P4_SPACEPTR);
          /* Add the entries to the stat4 table. */
diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
index 68abd1f58..0b6f0bd62 100644
--- a/src/box/sql/delete.c
+++ b/src/box/sql/delete.c
@@ -328,12 +328,8 @@ sql_table_delete_from(struct Parse *parse, struct 
SrcList *tab_list,
               * key.
               */
              key_len = 0;
-            struct index *pk = space_index(space, 0);
-            enum field_type *types = is_view ? NULL :
-                         sql_index_type_str(parse->db,
-                                    pk->def);
-            sqlVdbeAddOp4(v, OP_MakeRecord, reg_pk, pk_len,
-                      reg_key, (char *)types, P4_DYNAMIC);
+            sqlVdbeAddOp3(v, OP_MakeRecord, reg_pk, pk_len,
+                      reg_key);
              /* Set flag to save memory allocating one
               * by malloc.
               */
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index bc2182446..019628a26 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -2859,8 +2859,6 @@ sqlCodeSubselect(Parse * pParse,    /* Parsing 
context */
                  struct ExprList_item *pItem;
                  int r1, r2, r3;

-                enum field_type lhs_type =
-                    sql_expr_type(pLeft);
                  bool unused;
                  struct coll *unused_coll;
                  if (sql_expr_coll(pParse, pExpr->pLeft, &unused,
@@ -2886,11 +2884,7 @@ sqlCodeSubselect(Parse * pParse,    /* Parsing 
context */
                          jmpIfDynamic = -1;
                      }
                      r3 = sqlExprCodeTarget(pParse, pE2, r1);
-                    enum field_type types[2] =
-                        { lhs_type, field_type_MAX };
-                     sqlVdbeAddOp4(v, OP_MakeRecord, r3,
-                              1, r2, (char *)types,
-                              sizeof(types));
+                    sqlVdbeAddOp3(v, OP_MakeRecord, r3, 1, r2);
                      sql_expr_type_cache_change(pParse,
                                     r3, 1);
                      sqlVdbeAddOp2(v, OP_IdxInsert, r2,
diff --git a/src/box/sql/fk_constraint.c b/src/box/sql/fk_constraint.c
index 482220a95..43471d51a 100644
--- a/src/box/sql/fk_constraint.c
+++ b/src/box/sql/fk_constraint.c
@@ -262,13 +262,8 @@ fk_constraint_lookup_parent(struct Parse 
*parse_context, struct space *parent,
                        link->child_field + 1 + reg_data,
                        temp_regs + i);
          }
-        struct index *idx = space_index(parent, referenced_idx);
-        assert(idx != NULL);
-        sqlVdbeAddOp4(v, OP_MakeRecord, temp_regs, field_count,
-                  rec_reg,
-                  (char *) sql_index_type_str(parse_context->db,
-                                  idx->def),
-                  P4_DYNAMIC);
+        sqlVdbeAddOp3(v, OP_MakeRecord, temp_regs, field_count,
+                  rec_reg);
          sqlVdbeAddOp4Int(v, OP_Found, cursor, ok_label, rec_reg, 0);
          sqlReleaseTempReg(parse_context, rec_reg);
          sqlReleaseTempRange(parse_context, temp_regs, field_count);
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 0b7358af4..f3f5dad76 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -1270,13 +1270,8 @@ selectInnerLoop(Parse * pParse,        /* The 
parser context */
                             regOrig, nResultCol, nPrefixReg);
              } else {
                  int r1 = sqlGetTempReg(pParse);
-                enum field_type *types =
-                    field_type_sequence_dup(pParse,
-                                pDest->dest_type,
-                                nResultCol);
-                sqlVdbeAddOp4(v, OP_MakeRecord, regResult,
-                          nResultCol, r1, (char *)types,
-                          P4_DYNAMIC);
+                sqlVdbeAddOp3(v, OP_MakeRecord, regResult,
+                          nResultCol, r1);
                  sql_expr_type_cache_change(pParse,
                                 regResult,
                                 nResultCol);
@@ -1693,12 +1688,8 @@ generateSortTail(Parse * pParse,    /* Parsing 
context */
              break;
          }
      case SRT_Set:{
-            enum field_type *types =
-                field_type_sequence_dup(pParse, pDest->dest_type,
-                            nColumn);
-            sqlVdbeAddOp4(v, OP_MakeRecord, regRow, nColumn,
-                      regTupleid, (char *)types,
-                      P4_DYNAMIC);
+            sqlVdbeAddOp3(v, OP_MakeRecord, regRow, nColumn,
+                      regTupleid);
              sql_expr_type_cache_change(pParse, regRow, nColumn);
              sqlVdbeAddOp2(v, OP_IdxInsert, regTupleid, pDest->reg_eph);
              break;
@@ -3136,12 +3127,8 @@ generateOutputSubroutine(struct Parse *parse, 
struct Select *p,
              int r1;
              testcase(in->nSdst > 1);
              r1 = sqlGetTempReg(parse);
-            enum field_type *types =
-                field_type_sequence_dup(parse, dest->dest_type,
-                            in->nSdst);
-            sqlVdbeAddOp4(v, OP_MakeRecord, in->iSdst,
-                      in->nSdst, r1, (char *)types,
-                      P4_DYNAMIC);
+            sqlVdbeAddOp3(v, OP_MakeRecord, in->iSdst, in->nSdst,
+                      r1);
              sql_expr_type_cache_change(parse, in->iSdst,
                             in->nSdst);
              sqlVdbeAddOp2(v, OP_IdxInsert, r1, dest->reg_eph);
diff --git a/src/box/sql/update.c b/src/box/sql/update.c
index 24c7cfa27..22f82390c 100644
--- a/src/box/sql/update.c
+++ b/src/box/sql/update.c
@@ -251,11 +251,7 @@ sqlUpdate(Parse * pParse,        /* The parser 
context */
          nKey = pk_part_count;
          regKey = iPk;
      } else {
-        enum field_type *types = is_view ? NULL :
-                     sql_index_type_str(pParse->db,
-                                pPk->def);
-        sqlVdbeAddOp4(v, OP_MakeRecord, iPk, pk_part_count,
-                  regKey, (char *) types, P4_DYNAMIC);
+        sqlVdbeAddOp3(v, OP_MakeRecord, iPk, pk_part_count, regKey);
          /*
           * Set flag to save memory allocating one by
           * malloc.
@@ -420,12 +416,8 @@ sqlUpdate(Parse * pParse,        /* The parser 
context */
              int key_reg;
              if (okOnePass) {
                  key_reg = sqlGetTempReg(pParse);
-                enum field_type *types =
-                    sql_index_type_str(pParse->db,
-                               pPk->def);
-                sqlVdbeAddOp4(v, OP_MakeRecord, iPk,
-                          pk_part_count, key_reg,
-                          (char *) types, P4_DYNAMIC);
+                sqlVdbeAddOp3(v, OP_MakeRecord, iPk,
+                          pk_part_count, key_reg);
              } else {
                  assert(nKey == 0);
                  key_reg = regKey;
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index ae2622c9e..eb5c89e9d 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -2908,24 +2908,17 @@ case OP_CheckType: {
      break;
  }

-/* Opcode: MakeRecord P1 P2 P3 P4 P5
+/* Opcode: MakeRecord P1 P2 P3 * P5
   * Synopsis: r[P3]=mkrec(r[P1@P2])
   *
   * Convert P2 registers beginning with P1 into the [record format]
   * use as a data record in a database table or as a key
   * in an index.  The OP_Column opcode can decode the record later.
   *
- * P4 may be a string that is P2 characters long.  The nth character of the
- * string indicates the column type that should be used for the nth
- * field of the index key.
- *
- * If P4 is NULL then all index fields have type SCALAR.
- *
   * If P5 is not NULL then record under construction is intended to be 
inserted
   * into ephemeral space. Thus, sort of memory optimization can be 
performed.
   */
  case OP_MakeRecord: {
-    Mem *pRec;             /* The new record */
      Mem *pData0;           /* First field to be combined into the 
record */
      Mem MAYBE_UNUSED *pLast;  /* Last field of the record */
      int nField;            /* Number of fields in the record */
@@ -2947,7 +2940,6 @@ case OP_MakeRecord: {
       * of the record to data0.
       */
      nField = pOp->p1;
-    enum field_type *types = pOp->p4.types;
      bIsEphemeral = pOp->p5;
      assert(nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem+1 - 
p->nCursor)+1);
      pData0 = &aMem[nField];
@@ -2958,15 +2950,6 @@ case OP_MakeRecord: {
      assert(pOp->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2);
      pOut = vdbe_prepare_null_out(p, pOp->p3);

-    /* Apply the requested types to all inputs */
-    assert(pData0<=pLast);
-    if (types != NULL) {
-        pRec = pData0;
-        do {
-            mem_apply_type(pRec++, *(types++));
-        } while(types[0] != field_type_MAX);
-    }
-
      struct region *region = &fiber()->gc;
      size_t used = region_used(region);
      uint32_t tuple_size;
diff --git a/test/sql-tap/in3.test.lua b/test/sql-tap/in3.test.lua
index e29db9d93..f7681640e 100755
--- a/test/sql-tap/in3.test.lua
+++ b/test/sql-tap/in3.test.lua
@@ -354,7 +354,7 @@ test:do_test(
          return exec_neph(" SELECT y IN (SELECT a FROM t1) FROM t2 ")
      end, {
          -- <in3-3.5>
-        1, true
+        1, false
          -- </in3-3.5>
      })

@@ -378,7 +378,7 @@ test:do_test(
          return exec_neph(" SELECT y IN (SELECT c FROM t1) FROM t2 ")
      end, {
          -- <in3-3.7>
-        1, true
+        1, false
          -- </in3-3.7>
      })

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Tarantool-patches] [PATCH 4/6] sql: remove mem_apply_type() from OP_MustBeInt
  2020-06-01 17:04   ` Vladislav Shpilevoy
@ 2020-06-09 11:47     ` Mergen Imeev
  2020-06-09 22:28       ` Vladislav Shpilevoy
  0 siblings, 1 reply; 21+ messages in thread
From: Mergen Imeev @ 2020-06-09 11:47 UTC (permalink / raw)
  To: Vladislav Shpilevoy, tsafin, tarantool-patches

Thanks for the review! My answers and new patch below. I removed
the tests tkt-fc7bd6358f.test.lua and whereB.test.lua
(from comments 2. and 3.), because they do not make sense now.

On 01.06.2020 20:04, Vladislav Shpilevoy wrote:

> Thanks for the patch!
>
> See 3 comments below.
>
> On 28/05/2020 16:17, Mergen Imeev wrote:
>> This patch replaces mem_apply_type() by mem_check_types() in
>> OP_MustBeInt, which allows to remove implicit case in some places,
> 1. 'case' -> 'cast'.

Fixed.


>
>> for example in IN operator.
>>
>> Part of #4230
>> ---
>> diff --git a/test/sql-tap/tkt-fc7bd6358f.test.lua b/test/sql-tap/tkt-fc7bd6358f.test.lua
>> index fe5d6200f..f38ffa3d6 100755
>> --- a/test/sql-tap/tkt-fc7bd6358f.test.lua
>> +++ b/test/sql-tap/tkt-fc7bd6358f.test.lua
>> @@ -80,7 +80,6 @@ for a, from in ipairs(froms) do
>>               function()
>>                   return test:execsql(string.format("SELECT t1.textid, i.intid, t2.textid %s %s", from, where))
>>               end, {
>> -                "12", 12, "12", "34", 34, "34"
>>               })
>>   
>>           test:do_test(
>> @@ -88,7 +87,6 @@ for a, from in ipairs(froms) do
>>               function()
>>                   return test:execsql(string.format("SELECT t1.textid, i.intid, t2.textid %s %s", from, where))
>>               end, {
>> -                "12", 12, "12", "34", 34, "34"
>>               })
> 2. In the header of this file it is said, that the whole test's
> purpose is to ensure, that these values are returned. Do we
> need this test file now at all? Or can it be fixed in a way, that
> the results are not changed?
>
>>   
>>       end
>> diff --git a/test/sql-tap/whereB.test.lua b/test/sql-tap/whereB.test.lua
>> index fe5e28c70..970ff1dec 100755
>> --- a/test/sql-tap/whereB.test.lua
>> +++ b/test/sql-tap/whereB.test.lua
>> @@ -432,7 +432,6 @@ test:do_execsql_test(
>>       ]],
>>       {
>>       -- <whereB-5.2>
>> -    1, 2, true
>>       -- </whereB-5.2>
>>       })
>>   
>> @@ -443,7 +442,6 @@ test:do_execsql_test(
>>       ]],
>>       {
>>       -- <whereB-5.3>
>> -    1, 2, true
> 3. These tests also look useless now. Their comment
> says:
>
> 	-- Because t2.b has a numeric affinity, type conversion should occur
> 	-- and the two fields should be equal.
>
> And now they are not equal. Do we need these tests?


New patch:


 From c5478fc613301127090c8439e78eff7d76ca9e1e Mon Sep 17 00:00:00 2001
From: Mergen Imeev <imeevma@gmail.com>
Date: Thu, 28 May 2020 13:10:35 +0300
Subject: [PATCH] sql: remove mem_apply_type() from OP_MustBeInt

This patch replaces mem_apply_type() with mem_check_types() in
OP_MustBeInt, which allows to remove implicit cast in some places,
for example, in the IN statement.

Part of #4230

diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index eb5c89e9d..77b758833 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -2096,7 +2096,7 @@ case OP_AddImm: {            /* in1 */
  case OP_MustBeInt: {            /* jump, in1 */
      pIn1 = &aMem[pOp->p1];
      if ((pIn1->flags & (MEM_Int | MEM_UInt)) == 0) {
-        mem_apply_type(pIn1, FIELD_TYPE_INTEGER);
+        mem_check_types(pIn1, FIELD_TYPE_INTEGER);
          if ((pIn1->flags & (MEM_Int | MEM_UInt)) == 0) {
              if (pOp->p2==0) {
                  diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
diff --git a/test/sql-tap/e_select1.test.lua 
b/test/sql-tap/e_select1.test.lua
index 7673426f4..578620fca 100755
--- a/test/sql-tap/e_select1.test.lua
+++ b/test/sql-tap/e_select1.test.lua
@@ -1,6 +1,6 @@
  #!/usr/bin/env tarantool
  test = require("sqltester")
-test:plan(510)
+test:plan(509)

  --!./tcltestrunner.lua
  -- 2010 July 16
@@ -2150,7 +2150,6 @@ test:do_select_tests(
          {"2", "SELECT b FROM f1 ORDER BY a LIMIT 2+3 ", {"a", "b", 
"c", "d", "e"}},
          {"3", "SELECT b FROM f1 ORDER BY a LIMIT (SELECT a FROM f1 
WHERE b = 'e') ", {"a",  "b", "c", "d", "e"}},
          {"4", "SELECT b FROM f1 ORDER BY a LIMIT 5.0 ", {"a", "b", 
"c", "d", "e"}},
-        {"5", "SELECT b FROM f1 ORDER BY a LIMIT '5' ", {"a", "b", "c", 
"d", "e"}},
      })

  -- EVIDENCE-OF: R-46155-47219 If the expression evaluates to a NULL value
@@ -2195,7 +2194,7 @@ test:do_select_tests(
          {"1", "SELECT b FROM f1 ORDER BY a LIMIT 0 ", {}},
          {"2", "SELECT b FROM f1 ORDER BY a DESC LIMIT 4 ", {"z", "y", 
"x", "w"}},
          {"3", "SELECT b FROM f1 ORDER BY a DESC LIMIT 8 ", {"z", "y", 
"x", "w", "v", "u", "t", "s"}},
-        {"4", "SELECT b FROM f1 ORDER BY a DESC LIMIT '12' ", {"z", y, 
"x", "w", "v", "u", "t", "s", "r", "q", "p", "o"}},
+        {"4", "SELECT b FROM f1 ORDER BY a DESC LIMIT 12 ", {"z", y, 
"x", "w", "v", "u", "t", "s", "r", "q", "p", "o"}},
      })

  -- EVIDENCE-OF: R-54935-19057 Or, if the SELECT statement would return
@@ -2240,10 +2239,10 @@ test:do_select_tests(
          {"1", "SELECT b FROM f1 ORDER BY a LIMIT 10 OFFSET 5", {"f", 
"g", "h", "i", "j", "k", "l", "m", "n", "o"}},
          {"2", "SELECT b FROM f1 ORDER BY a LIMIT 2+3 OFFSET 10", {"k", 
"l", "m", "n", "o"}},
          {"3", "SELECT b FROM f1 ORDER BY a LIMIT  (SELECT a FROM f1 
WHERE b='j') OFFSET (SELECT a FROM f1 WHERE b='b') ", {"c", "d", "e", 
"f", "g", "h", "i", "j", "k", "l"}},
-        {"4", "SELECT b FROM f1 ORDER BY a LIMIT '5' OFFSET 3.0 ", 
{"d", "e", "f", "g", "h"}},
-        {"5", "SELECT b FROM f1 ORDER BY a LIMIT '5' OFFSET 0 ", {"a", 
"b", "c", "d", "e"}},
+        {"4", "SELECT b FROM f1 ORDER BY a LIMIT 5 OFFSET 3.0 ", {"d", 
"e", "f", "g", "h"}},
+        {"5", "SELECT b FROM f1 ORDER BY a LIMIT 5 OFFSET 0 ", {"a", 
"b", "c", "d", "e"}},
          {"6", "SELECT b FROM f1 ORDER BY a LIMIT 0 OFFSET 10 ", {}},
-        {"7", "SELECT b FROM f1 ORDER BY a LIMIT 3 OFFSET '1'||'5' ", 
{"p", "q", "r"}},
+        {"7", "SELECT b FROM f1 ORDER BY a LIMIT 3 OFFSET CAST('1'||'5' 
AS INTEGER) ", {"p", "q", "r"}},
      })

  -- EVIDENCE-OF: R-34648-44875 Or, if the SELECT would return less than
@@ -2279,10 +2278,10 @@ test:do_select_tests(
          {"1", "SELECT b FROM f1 ORDER BY a LIMIT 5, 10 ", {"f", "g", 
"h", "i", "j", "k", "l", "m", "n", "o"}},
          {"2", "SELECT b FROM f1 ORDER BY a LIMIT 10, 2+3 ", {"k", "l", 
"m", "n", "o"}},
          {"3", "SELECT b FROM f1 ORDER BY a LIMIT (SELECT a FROM f1 
WHERE b='b'), (SELECT a FROM f1 WHERE b='j')", {"c", "d", "e", "f", "g", 
"h", "i", "j", "k", "l"}},
-        {"4", "SELECT b FROM f1 ORDER BY a LIMIT 3.0, '5' ", {"d", "e", 
"f", "g", "h"}},
-        {"5", "SELECT b FROM f1 ORDER BY a LIMIT 0, '5' ", {"a", "b", 
"c", "d", "e"}},
+        {"4", "SELECT b FROM f1 ORDER BY a LIMIT 3.0, 5 ", {"d", "e", 
"f", "g", "h"}},
+        {"5", "SELECT b FROM f1 ORDER BY a LIMIT 0, 5 ", {"a", "b", 
"c", "d", "e"}},
          {"6", "SELECT b FROM f1 ORDER BY a LIMIT 10, 0 ", {}},
-        {"7", "SELECT b FROM f1 ORDER BY a LIMIT '1'||'5', 3 ", {"p", 
"q", "r"}},
+        {"7", "SELECT b FROM f1 ORDER BY a LIMIT CAST('1'||'5' AS 
INTEGER), 3 ", {"p", "q", "r"}},
          {"8", "SELECT b FROM f1 ORDER BY a LIMIT 20, 10 ", {"u", "v", 
"w", "x", "y", "z"}},
          {"9", "SELECT a FROM f1 ORDER BY a DESC LIMIT 18+4, 100 ", {4, 
3, 2, 1}},
          {"10", "SELECT b FROM f1 ORDER BY a LIMIT 0, 5 ", {"a", "b", 
"c", "d", "e"}},
diff --git a/test/sql-tap/in4.test.lua b/test/sql-tap/in4.test.lua
index 8c6917379..33947d0ab 100755
--- a/test/sql-tap/in4.test.lua
+++ b/test/sql-tap/in4.test.lua
@@ -1,6 +1,6 @@
  #!/usr/bin/env tarantool
  test = require("sqltester")
-test:plan(61)
+test:plan(52)

  --!./tcltestrunner.lua
  -- 2008 September 1
@@ -140,7 +140,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "in4-2.7",
      [[
-        SELECT b FROM t2 WHERE a IN ('1', '2')
+        SELECT b FROM t2 WHERE a IN (1, 2)
      ]], {
          -- <in4-2.7>
          "one", "two"
@@ -153,7 +153,6 @@ test:do_execsql_test(
          SELECT b FROM t2 WHERE a IN ('', '0.0.0', '2')
      ]], {
          -- <in4-2.8>
-        "two"
          -- </in4-2.8>
      })

@@ -585,98 +584,6 @@ test:do_execsql_test(
          -- </in4-4.6>
      })

-test:do_execsql_test(
-    "in4-4.11",
-    [[
-        CREATE TABLE t4b(a TEXT, b NUMBER, c  INT PRIMARY KEY);
-        INSERT INTO t4b VALUES('1.0',1,4);
-        SELECT c FROM t4b WHERE a=b;
-    ]], {
-        -- <in4-4.11>
-        4
-        -- </in4-4.11>
-    })
-
-test:do_execsql_test(
-    "in4-4.12",
-    [[
-        SELECT c FROM t4b WHERE b=a;
-    ]], {
-        -- <in4-4.12>
-        4
-        -- </in4-4.12>
-    })
-
-test:do_execsql_test(
-    "in4-4.13",
-    [[
-        SELECT c FROM t4b WHERE +a=b;
-    ]], {
-        -- <in4-4.13>
-        4
-        -- </in4-4.13>
-    })
-
-test:do_execsql_test(
-    "in4-4.14",
-    [[
-        SELECT c FROM t4b WHERE a=+b;
-    ]], {
-        -- <in4-4.14>
-        4
-        -- </in4-4.14>
-    })
-
-test:do_execsql_test(
-    "in4-4.15",
-    [[
-        SELECT c FROM t4b WHERE +b=a;
-    ]], {
-        -- <in4-4.15>
-        4
-        -- </in4-4.15>
-    })
-
-test:do_execsql_test(
-    "in4-4.16",
-    [[
-        SELECT c FROM t4b WHERE b=+a;
-    ]], {
-        -- <in4-4.16>
-        4
-        -- </in4-4.16>
-    })
-
-test:do_execsql_test(
-    "in4-4.17",
-    [[
-        SELECT c FROM t4b WHERE a IN (b);
-    ]], {
-        -- <in4-4.17>
-        4
-        -- </in4-4.17>
-    })
-
-test:do_execsql_test(
-    "in4-4.18",
-    [[
-        SELECT c FROM t4b WHERE b IN (a);
-    ]], {
-        -- <in4-4.18>
-        4
-        -- </in4-4.18>
-    })
-
-test:do_execsql_test(
-    "in4-4.19",
-    [[
-        SELECT c FROM t4b WHERE +b IN (a);
-    ]], {
-        -- <in4-4.19>
-        4
-        -- </in4-4.19>
-    })
-
  -- MUST_WORK_TEST
  -- Tarantool: TBI: Need to support collations. Depends on #2121
  -- test:do_execsql_test(
diff --git a/test/sql-tap/join.test.lua b/test/sql-tap/join.test.lua
index 840b780a3..51e0ecb79 100755
--- a/test/sql-tap/join.test.lua
+++ b/test/sql-tap/join.test.lua
@@ -1034,7 +1034,6 @@ test:do_execsql_test(
          SELECT * FROM t1 NATURAL JOIN t2
      ]], {
          -- <join-11.9>
-        "one", "1", "two", "2"
          -- </join-11.9>
      })

diff --git a/test/sql-tap/limit.test.lua b/test/sql-tap/limit.test.lua
index 870233942..a7d1451f7 100755
--- a/test/sql-tap/limit.test.lua
+++ b/test/sql-tap/limit.test.lua
@@ -441,7 +441,7 @@ test:do_catchsql_test(
  test:do_execsql_test(
      "limit-6.5.2",
      [[
-        SELECT * FROM t6 LIMIT '12'
+        SELECT * FROM t6 LIMIT 12
      ]], {
      -- <limit-6.5>
      1, 2, 3, 4
diff --git a/test/sql-tap/tkt-9a8b09f8e6.test.lua 
b/test/sql-tap/tkt-9a8b09f8e6.test.lua
index cb5348ab4..854ed774f 100755
--- a/test/sql-tap/tkt-9a8b09f8e6.test.lua
+++ b/test/sql-tap/tkt-9a8b09f8e6.test.lua
@@ -189,7 +189,6 @@ test:do_execsql_test(
          SELECT x FROM t2 WHERE x IN ('1');
      ]], {
          -- <3.3>
-        1
          -- </3.3>
      })

@@ -199,7 +198,6 @@ test:do_execsql_test(
          SELECT x FROM t2 WHERE x IN ('1');
      ]], {
          -- <3.4>
-        1
          -- </3.4>
      })

@@ -229,7 +227,6 @@ test:do_execsql_test(
          SELECT x FROM t2 WHERE '1' IN (x);
      ]], {
          -- <3.7>
-        1
          -- </3.7>
      })

@@ -239,7 +236,6 @@ test:do_execsql_test(
          SELECT x FROM t2 WHERE '1' IN (x);
      ]], {
          -- <3.8>
-        1
          -- </3.8>
      })

diff --git a/test/sql-tap/tkt-fc7bd6358f.test.lua 
b/test/sql-tap/tkt-fc7bd6358f.test.lua
deleted file mode 100755
index fe5d6200f..000000000
--- a/test/sql-tap/tkt-fc7bd6358f.test.lua
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/usr/bin/env tarantool
-test = require("sqltester")
-test:plan(50)
-
---!./tcltestrunner.lua
--- 2013 March 05
---
--- The author disclaims copyright to this source code.  In place of
--- a legal notice, here is a blessing:
---
---    May you do good and not evil.
---    May you find forgiveness for yourself and forgive others.
---    May you share freely, never taking more than you give.
---
--------------------------------------------------------------------------
--- This file implements regression tests for sql library. Specifically,
--- it tests that ticket [fc7bd6358f]:
---
--- The following SQL yields an incorrect result (zero rows) in all
--- versions of sql between 3.6.14 and 3.7.15.2:
---
---    CREATE TABLE t(textid TEXT);
---    INSERT INTO t VALUES('12');
---    INSERT INTO t VALUES('34');
---    CREATE TABLE i(intid INTEGER PRIMARY KEY);
---    INSERT INTO i VALUES(12);
---    INSERT INTO i VALUES(34);
---
---    SELECT t1.textid AS a, i.intid AS b, t2.textid AS c
---      FROM t t1, i, t t2
---     WHERE t1.textid = i.intid
---       AND t1.textid = t2.textid;
---
--- The correct result should be two rows, one with 12|12|12 and the other
--- with 34|34|34. With this bug, no rows are returned. Bisecting shows that
--- this bug was introduced with check-in [dd4d67a67454] on 2009-04-23.
---
--- ["set","testdir",[["file","dirname",["argv0"]]]]
--- ["source",[["testdir"],"\/tester.tcl"]]
-test:do_test(
-    "tkt-fc7bd6358f.100",
-    function()
-        return test:execsql [[
-            CREATE TABLE t(textid TEXT PRIMARY KEY);
-            INSERT INTO t VALUES('12');
-            INSERT INTO t VALUES('34');
-            CREATE TABLE i(intid INTEGER PRIMARY KEY);
-            INSERT INTO i VALUES(12);
-            INSERT INTO i VALUES(34);
-        ]]
-    end, {
-        -- <tkt-fc7bd6358f.100>
-
-        -- </tkt-fc7bd6358f.100>
-    })
-
--- ["unset","-nocomplain","from"]
--- ["unset","-nocomplain","where"]
--- ["unset","-nocomplain","a"]
--- ["unset","-nocomplain","b"]
-local froms = {
-    "FROM t t1, i, t t2",
-    "FROM i, t t1, t t2",
-    "FROM t t1, t t2, i",
-}
-local wheres = {
-    "WHERE t1.textid=i.intid AND t1.textid=t2.textid",
-    "WHERE i.intid=t1.textid AND t1.textid=t2.textid",
-    "WHERE t1.textid=i.intid AND i.intid=t2.textid",
-    "WHERE t1.textid=i.intid AND t2.textid=i.intid",
-    "WHERE i.intid=t1.textid AND i.intid=t2.textid",
-    "WHERE i.intid=t1.textid AND t2.textid=i.intid",
-    "WHERE t1.textid=t2.textid AND i.intid=t2.textid",
-    "WHERE t1.textid=t2.textid AND t2.textid=i.intid",
-}
-for a, from in ipairs(froms) do
-    for b, where in ipairs(wheres) do
-        test:do_test(
-            string.format("tkt-fc7bd6358f.110.%s.%s.1", a, b),
-            function()
-                return test:execsql(string.format("SELECT t1.textid, 
i.intid, t2.textid %s %s", from, where))
-            end, {
-                "12", 12, "12", "34", 34, "34"
-            })
-
-        test:do_test(
-            string.format("tkt-fc7bd6358f.110.%s.%s.2", a, b),
-            function()
-                return test:execsql(string.format("SELECT t1.textid, 
i.intid, t2.textid %s %s", from, where))
-            end, {
-                "12", 12, "12", "34", 34, "34"
-            })
-
-    end
-end
-
-test:do_test(
-    "tkt-fc7bd6358f.200",
-    function()
-        return test:execsql [[
-            DROP TABLE t;
-            DROP TABLE i;
-        ]]
-    end, {
-        -- <tkt-fc7bd6358f.100>
-
-        -- </tkt-fc7bd6358f.100>
-    })
-
-test:finish_test()
-
diff --git a/test/sql-tap/transitive1.test.lua 
b/test/sql-tap/transitive1.test.lua
index e96056580..96895b4a7 100755
--- a/test/sql-tap/transitive1.test.lua
+++ b/test/sql-tap/transitive1.test.lua
@@ -338,7 +338,7 @@ test:do_execsql_test(
                     ON tvshow.idshow = episode.idshow
                   LEFT JOIN seasons
                          ON seasons.idshow = episode.idshow
-                           AND seasons.season = episode.c12
+                           AND seasons.season = CAST(episode.c12 AS 
INTEGER)
                   JOIN path
                     ON files.idpath = path.idpath
                   LEFT JOIN bookmark
@@ -378,7 +378,7 @@ test:do_execsql_test(
          FROM episodeview
              JOIN tvshowview ON tvshowview.idShow = episodeview.idShow
              JOIN seasons ON (seasons.idShow = tvshowview.idShow
-                             AND seasons.season = episodeview.c12)
+                             AND seasons.season = CAST(episodeview.c12 
AS INTEGER))
              JOIN files ON files.idFile = episodeview.idFile
              JOIN tvshowlinkpath ON tvshowlinkpath.idShow = 
tvshowview.idShow
              JOIN path ON path.idPath = tvshowlinkpath.idPath
diff --git a/test/sql-tap/whereB.test.lua b/test/sql-tap/whereB.test.lua
deleted file mode 100755
index fe5e28c70..000000000
--- a/test/sql-tap/whereB.test.lua
+++ /dev/null
@@ -1,900 +0,0 @@
-#!/usr/bin/env tarantool
-test = require("sqltester")
-test:plan(63)
-
---!./tcltestrunner.lua
--- 2009 August 13
---
--- The author disclaims copyright to this source code.  In place of
--- a legal notice, here is a blessing:
---
---    May you do good and not evil.
---    May you find forgiveness for yourself and forgive others.
---    May you share freely, never taking more than you give.
---
--------------------------------------------------------------------------
--- This file implements regression tests for sql library. The
--- focus of this file is testing WHERE clause conditions with
--- subtle affinity issues.
---
--- ["set","testdir",[["file","dirname",["argv0"]]]]
--- ["source",[["testdir"],"\/tester.tcl"]]
--- For this set of tests:
---
---  *   t1.y holds an integer value with affinity NONE
---  *   t2.b holds a text value with affinity TEXT
---
--- These values are not equal and because neither affinity is NUMERIC
--- no type conversion occurs.
---
-test:do_execsql_test(
-    "whereB-1.1",
-    [[
-        CREATE TABLE t1(x  INT primary key,y INT );    -- affinity of 
t1.y is NONE
-        INSERT INTO t1 VALUES(1,99);
-
-        CREATE TABLE t2(a  INT primary key, b TEXT);  -- affinity of 
t2.b is TEXT
-        CREATE INDEX t2b ON t2(b);
-        INSERT INTO t2 VALUES(2,'99');
-
-        SELECT x, a, y=b FROM t1, t2 ORDER BY +x, +a;
-    ]],
-    {
-    -- <whereB-1.1>
-    1, 2, true
-    -- </whereB-1.1>
-    })
-
-test:do_execsql_test(
-    "whereB-1.2",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
-    ]],
-    {
-    -- <whereB-1.2>
-    1, 2, true
-    -- </whereB-1.2>
-    })
-
-test:do_execsql_test(
-    "whereB-1.3",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
-    ]],
-    {
-    -- <whereB-1.3>
-    1, 2, true
-    -- </whereB-1.3>
-    })
-
-test:do_execsql_test(
-    "whereB-1.4",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
-    ]],
-    {
-    -- <whereB-1.4>
-    1, 2, true
-    -- </whereB-1.4>
-    })
-
-test:do_execsql_test(
-    "whereB-1.100",
-    [[
-        DROP INDEX t2b ON t2;
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
-    ]],
-    {
-    -- <whereB-1.100>
-    1, 2, true
-    -- </whereB-1.100>
-    })
-
-test:do_execsql_test(
-    "whereB-1.101",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
-    ]],
-    {
-    -- <whereB-1.101>
-    1, 2, true
-    -- </whereB-1.101>
-    })
-
-test:do_execsql_test(
-    "whereB-1.102",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
-    ]],
-    {
-    -- <whereB-1.102>
-    1, 2, true
-    -- </whereB-1.102>
-    })
-
-test:do_execsql_test(
-    "whereB-2.1",
-    [[
-        DROP TABLE t1;
-        DROP TABLE t2;
-
-        CREATE TABLE t1(x  INT primary key, y TEXT);
-        INSERT INTO t1 VALUES(1,'99');
-
-        CREATE TABLE t2(a  INT primary key, b SCALAR);
-        CREATE INDEX t2b ON t2(b);
-        INSERT INTO t2 VALUES(2, 99);
-
-        SELECT x, a, y=b FROM t1, t2 ORDER BY +x, +a;
-    ]],
-    {
-    -- <whereB-2.1>
-    1, 2, false
-    -- </whereB-2.1>
-    })
-
-test:do_execsql_test(
-    "whereB-2.2",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
-    ]],
-    {
-    -- <whereB-2.2>
-
-    -- </whereB-2.2>
-    })
-
-test:do_execsql_test(
-    "whereB-2.3",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
-    ]],
-    {
-    -- <whereB-2.3>
-
-    -- </whereB-2.3>
-    })
-
-test:do_execsql_test(
-    "whereB-2.4",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
-    ]],
-    {
-    -- <whereB-2.4>
-
-    -- </whereB-2.4>
-    })
-
-test:do_execsql_test(
-    "whereB-2.100",
-    [[
-        DROP INDEX t2b ON t2;
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
-    ]],
-    {
-    -- <whereB-2.100>
-
-    -- </whereB-2.100>
-    })
-
-test:do_execsql_test(
-    "whereB-2.101",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
-    ]],
-    {
-    -- <whereB-2.101>
-
-    -- </whereB-2.101>
-    })
-
-test:do_execsql_test(
-    "whereB-2.102",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
-    ]],
-    {
-    -- <whereB-2.102>
-
-    -- </whereB-2.102>
-    })
-
--- For this set of tests:
---
---  *   t1.y holds a text value with affinity NONE
---  *   t2.b holds an integer value with affinity NONE
---
--- These values are not equal and because neither affinity is NUMERIC
--- no type conversion occurs.
---
-test:do_execsql_test(
-    "whereB-3.1",
-    [[
-        DROP TABLE t1;
-        DROP TABLE t2;
-
-        CREATE TABLE t1(x  INT primary key, y SCALAR);    -- affinity 
of t1.y is NONE
-        INSERT INTO t1 VALUES(1,99);
-
-        CREATE TABLE t2(a  INT primary key, b SCALAR);  -- affinity of 
t2.b is NONE
-        CREATE INDEX t2b ON t2(b);
-        INSERT INTO t2 VALUES(2,'99');
-
-        SELECT x, a, y=b FROM t1, t2;
-    ]],
-    {
-    -- <whereB-3.1>
-    1, 2, false
-    -- </whereB-3.1>
-    })
-
-test:do_execsql_test(
-    "whereB-3.2",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
-    ]],
-    {
-    -- <whereB-3.2>
-
-    -- </whereB-3.2>
-    })
-
-test:do_execsql_test(
-    "whereB-3.3",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
-    ]],
-    {
-    -- <whereB-3.3>
-
-    -- </whereB-3.3>
-    })
-
-test:do_execsql_test(
-    "whereB-3.4",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
-    ]],
-    {
-    -- <whereB-3.4>
-
-    -- </whereB-3.4>
-    })
-
-test:do_execsql_test(
-    "whereB-3.100",
-    [[
-        DROP INDEX t2b ON t2;
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
-    ]],
-    {
-    -- <whereB-3.100>
-
-    -- </whereB-3.100>
-    })
-
-test:do_execsql_test(
-    "whereB-3.101",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
-    ]],
-    {
-    -- <whereB-3.101>
-
-    -- </whereB-3.101>
-    })
-
-test:do_execsql_test(
-    "whereB-3.102",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
-    ]],
-    {
-    -- <whereB-3.102>
-
-    -- </whereB-3.102>
-    })
-
--- For this set of tests:
---
---  *   t1.y holds a text value with affinity NONE
---  *   t2.b holds an integer value with affinity NUMERIC
---
--- Because t2.b has a numeric affinity, type conversion should occur
--- and the two fields should be equal.
---
-test:do_execsql_test(
-    "whereB-4.1",
-    [[
-        DROP TABLE IF EXISTS t1;
-        DROP TABLE IF EXISTS t2;
-
-        CREATE TABLE t1(x  INT primary key, y SCALAR);    -- affinity 
of t1.y is NONE
-        INSERT INTO t1 VALUES(1,'99');
-
-        CREATE TABLE t2(a  INT primary key, b NUMBER);  -- affinity of 
t2.b is NUMERIC
-        CREATE INDEX t2b ON t2(b);
-        INSERT INTO t2 VALUES(2,99);
-
-        SELECT x, a, y=b FROM t1, t2;
-    ]],
-    {
-    -- <whereB-4.1>
-    1, 2, true
-    -- </whereB-4.1>
-    })
-
-test:do_execsql_test(
-    "whereB-4.2",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
-    ]],
-    {
-    -- <whereB-4.2>
-    1, 2, true
-    -- </whereB-4.2>
-    })
-
-test:do_execsql_test(
-    "whereB-4.3",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
-    ]],
-    {
-    -- <whereB-4.3>
-    1, 2, true
-    -- </whereB-4.3>
-    })
-
-test:do_execsql_test(
-    "whereB-4.4",
-    -- In this case the unary "+" operator shouldn't
-    -- affect result set of query.
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
-    ]],
-    {
-    -- <whereB-4.4>
-    1, 2, true
-    -- </whereB-4.4>
-    })
-
-test:do_execsql_test(
-    "whereB-4.100",
-    [[
-        DROP INDEX t2b ON t2;
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
-    ]],
-    {
-    -- <whereB-4.100>
-    1, 2, true
-    -- </whereB-4.100>
-    })
-
-test:do_execsql_test(
-    "whereB-4.101",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
-    ]],
-    {
-    -- <whereB-4.101>
-    1, 2, true
-    -- </whereB-4.101>
-    })
-
-test:do_execsql_test(
-    "whereB-4.102",
-    -- In this case the unary "+" operator shouldn't
-    -- affect result set of query.
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
-    ]],
-    {
-    -- <whereB-4.102>
-    1, 2, true
-    -- </whereB-4.102>
-    })
-
--- For this set of tests:
---
---  *   t1.y holds a text value with affinity NONE
---  *   t2.b holds an integer value with affinity INTEGER
---
--- Because t2.b has a numeric affinity, type conversion should occur
--- and the two fields should be equal.
---
-test:do_execsql_test(
-    "whereB-5.1",
-    [[
-        DROP TABLE t1;
-        DROP TABLE t2;
-
-        CREATE TABLE t1(x  INT primary key, y SCALAR);    -- affinity 
of t1.y is NONE
-        INSERT INTO t1 VALUES(1,'99');
-
-        CREATE TABLE t2(a  INT primary key, b INT);  -- affinity of 
t2.b is INTEGER
-        CREATE INDEX t2b ON t2(b);
-        INSERT INTO t2 VALUES(2,99);
-
-        SELECT x, a, y=b FROM t1, t2;
-    ]],
-    {
-    -- <whereB-5.1>
-    1, 2, true
-    -- </whereB-5.1>
-    })
-
-test:do_execsql_test(
-    "whereB-5.2",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
-    ]],
-    {
-    -- <whereB-5.2>
-    1, 2, true
-    -- </whereB-5.2>
-    })
-
-test:do_execsql_test(
-    "whereB-5.3",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
-    ]],
-    {
-    -- <whereB-5.3>
-    1, 2, true
-    -- </whereB-5.3>
-    })
-
-test:do_execsql_test(
-    "whereB-5.4",
-    -- In this case the unary "+" operator shouldn't
-    -- affect result set of query.
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
-    ]],
-    {
-    -- <whereB-5.4>
-    1, 2, true
-    -- </whereB-5.4>
-    })
-
-test:do_execsql_test(
-    "whereB-5.100",
-    [[
-        DROP INDEX t2b ON t2;
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
-    ]],
-    {
-    -- <whereB-5.100>
-    1, 2, true
-    -- </whereB-5.100>
-    })
-
-test:do_execsql_test(
-    "whereB-5.101",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
-    ]],
-    {
-    -- <whereB-5.101>
-    1, 2, true
-    -- </whereB-5.101>
-    })
-
-test:do_execsql_test(
-    "whereB-5.102",
-    -- In this case the unary "+" operator shouldn't
-    -- affect result set of query.
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
-    ]],
-    {
-    -- <whereB-5.102>
-    1, 2, true
-    -- </whereB-5.102>
-    })
-
--- For this set of tests:
---
---  *   t1.y holds a text value with affinity NONE
---  *   t2.b holds an integer value with affinity REAL
---
--- Because t2.b has a numeric affinity, type conversion should occur
--- and the two fields should be equal.
---
-test:do_execsql_test(
-    "whereB-6.1",
-    [[
-        DROP TABLE t1;
-        DROP TABLE t2;
-
-        CREATE TABLE t1(x  INT primary key, y SCALAR);    -- affinity 
of t1.y is NONE
-        INSERT INTO t1 VALUES(1,'99');
-
-        CREATE TABLE t2(a  INT primary key, b NUMBER);  -- affinity of 
t2.b is REAL
-        CREATE INDEX t2b ON t2(b);
-        INSERT INTO t2 VALUES(2,99.0);
-
-        SELECT x, a, y=b FROM t1, t2;
-    ]],
-    {
-    -- <whereB-6.1>
-    1, 2, true
-    -- </whereB-6.1>
-    })
-
-test:do_execsql_test(
-    "whereB-6.2",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
-    ]],
-    {
-    -- <whereB-6.2>
-    1, 2, true
-    -- </whereB-6.2>
-    })
-
-test:do_execsql_test(
-    "whereB-6.3",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
-    ]],
-    {
-    -- <whereB-6.3>
-    1, 2, true
-    -- </whereB-6.3>
-    })
-
-test:do_execsql_test(
-    "whereB-6.4",
-    -- In this case the unary "+" operator shouldn't
-    -- affect result set of query.
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
-    ]],
-    {
-    -- <whereB-6.4>
-    1, 2, true
-    -- </whereB-6.4>
-    })
-
-test:do_execsql_test(
-    "whereB-6.100",
-    [[
-        DROP INDEX t2b ON t2;
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
-    ]],
-    {
-    -- <whereB-6.100>
-    1, 2, true
-    -- </whereB-6.100>
-    })
-
-test:do_execsql_test(
-    "whereB-6.101",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
-    ]],
-    {
-    -- <whereB-6.101>
-    1, 2, true
-    -- </whereB-6.101>
-    })
-
-test:do_execsql_test(
-    "whereB-6.102",
-    -- In this case the unary "+" operator shouldn't
-    -- affect result set of query.
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
-    ]],
-    {
-    -- <whereB-6.102>
-    1, 2, true
-    -- </whereB-6.102>
-    })
-
--- For this set of tests:
---
---  *   t1.y holds an integer value with affinity NUMERIC
---  *   t2.b holds a text value with affinity NONE
---
--- Because t1.y has a numeric affinity, type conversion should occur
--- and the two fields should be equal.
---
-test:do_execsql_test(
-    "whereB-7.1",
-    [[
-        DROP TABLE t1;
-        DROP TABLE t2;
-
-        CREATE TABLE t1(x  INT primary key, y NUMBER);  -- affinity of 
t1.y is NUMERIC
-        INSERT INTO t1 VALUES(1,99);
-
-        CREATE TABLE t2(a  INT primary key, b SCALAR);  -- affinity of 
t2.b is NONE
-        CREATE INDEX t2b ON t2(b);
-        INSERT INTO t2 VALUES(2,'99');
-
-        SELECT x, a, y=b FROM t1, t2;
-    ]],
-    {
-    -- <whereB-7.1>
-    1, 2, true
-    -- </whereB-7.1>
-    })
-
-test:do_execsql_test(
-    "whereB-7.2",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
-    ]],
-    {
-    -- <whereB-7.2>
-    1, 2, true
-    -- </whereB-7.2>
-    })
-
-test:do_execsql_test(
-    "whereB-7.3",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
-    ]],
-    {
-    -- <whereB-7.3>
-    1, 2, true
-    -- </whereB-7.3>
-    })
-
-test:do_execsql_test(
-    "whereB-7.4",
-    -- In this case the unary "+" operator shouldn't
-    -- affect result set of query.
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
-    ]],
-    {
-    -- <whereB-7.4>
-    1, 2, true
-    -- </whereB-7.4>
-    })
-
-test:do_execsql_test(
-    "whereB-7.100",
-    [[
-        DROP INDEX t2b ON t2;
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
-    ]],
-    {
-    -- <whereB-7.100>
-    1, 2, true
-    -- </whereB-7.100>
-    })
-
-test:do_execsql_test(
-    "whereB-7.101",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
-    ]],
-    {
-    -- <whereB-7.101>
-    1, 2, true
-    -- </whereB-7.101>
-    })
-
-test:do_execsql_test(
-    "whereB-7.102",
-    -- In this case the unary "+" operator shouldn't
-    -- affect result set of query.
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
-    ]],
-    {
-    -- <whereB-7.102>
-    1, 2, true
-    -- </whereB-7.102>
-    })
-
--- For this set of tests:
---
---  *   t1.y holds an integer value with affinity INTEGER
---  *   t2.b holds a text value with affinity NONE
---
--- Because t1.y has a numeric affinity, type conversion should occur
--- and the two fields should be equal.
---
-test:do_execsql_test(
-    "whereB-8.1",
-    [[
-        DROP TABLE t1;
-        DROP TABLE t2;
-
-        CREATE TABLE t1(x  INT primary key, y INT);  -- affinity of 
t1.y is INTEGER
-        INSERT INTO t1 VALUES(1,99);
-
-        CREATE TABLE t2(a  INT primary key, b SCALAR);  -- affinity of 
t2.b is NONE
-        CREATE INDEX t2b ON t2(b);
-        INSERT INTO t2 VALUES(2,'99');
-
-        SELECT x, a, y=b FROM t1, t2;
-    ]],
-    {
-    -- <whereB-8.1>
-    1, 2, true
-    -- </whereB-8.1>
-    })
-
-test:do_execsql_test(
-    "whereB-8.2",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
-    ]],
-    {
-    -- <whereB-8.2>
-    1, 2, true
-    -- </whereB-8.2>
-    })
-
-test:do_execsql_test(
-    "whereB-8.3",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
-    ]],
-    {
-    -- <whereB-8.3>
-    1, 2, true
-    -- </whereB-8.3>
-    })
-
-test:do_execsql_test(
-    "whereB-8.4",
-    -- In this case the unary "+" operator shouldn't
-    -- affect result set of query.
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
-    ]],
-    {
-    -- <whereB-8.4>
-    1, 2, true
-    -- </whereB-8.4>
-    })
-
-test:do_execsql_test(
-    "whereB-8.100",
-    [[
-        DROP INDEX t2b ON t2;
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
-    ]],
-    {
-    -- <whereB-8.100>
-    1, 2, true
-    -- </whereB-8.100>
-    })
-
-test:do_execsql_test(
-    "whereB-8.101",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
-    ]],
-    {
-    -- <whereB-8.101>
-    1, 2, true
-    -- </whereB-8.101>
-    })
-
-test:do_execsql_test(
-    "whereB-8.102",
-    -- In this case the unary "+" operator shouldn't
-    -- affect result set of query.
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
-    ]],
-    {
-    -- <whereB-8.102>
-    1, 2, true
-    -- </whereB-8.102>
-    })
-
--- For this set of tests:
---
---  *   t1.y holds an integer value with affinity REAL
---  *   t2.b holds a text value with affinity NONE
---
--- Because t1.y has a numeric affinity, type conversion should occur
--- and the two fields should be equal.
---
-test:do_execsql_test(
-    "whereB-9.1",
-    [[
-        DROP TABLE t1;
-        DROP TABLE t2;
-
-        CREATE TABLE t1(x  INT primary key, y NUMBER);  -- affinity of 
t1.y is REAL
-        INSERT INTO t1 VALUES(1,99.0);
-
-        CREATE TABLE t2(a  INT primary key, b SCALAR);  -- affinity of 
t2.b is NONE
-        CREATE INDEX t2b ON t2(b);
-        INSERT INTO t2 VALUES(2,'99');
-
-        SELECT x, a, y=b FROM t1, t2;
-    ]],
-    {
-    -- <whereB-9.1>
-    1, 2, true
-    -- </whereB-9.1>
-    })
-
-test:do_execsql_test(
-    "whereB-9.2",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
-    ]],
-    {
-    -- <whereB-9.2>
-    1, 2, true
-    -- </whereB-9.2>
-    })
-
-test:do_execsql_test(
-    "whereB-9.3",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
-    ]],
-    {
-    -- <whereB-9.3>
-    1, 2, true
-    -- </whereB-9.3>
-    })
-
-test:do_execsql_test(
-    "whereB-9.4",
-    -- In this case the unary "+" operator shouldn't
-    -- affect result set of query.
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
-    ]],
-    {
-    -- <whereB-9.4>
-    1, 2, true
-    -- </whereB-9.4>
-    })
-
-test:do_execsql_test(
-    "whereB-9.100",
-    [[
-        DROP INDEX t2b ON t2;
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
-    ]],
-    {
-    -- <whereB-9.100>
-    1, 2, true
-    -- </whereB-9.100>
-    })
-
-test:do_execsql_test(
-    "whereB-9.101",
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
-    ]],
-    {
-    -- <whereB-9.101>
-    1, 2, true
-    -- </whereB-9.101>
-    })
-
-test:do_execsql_test(
-    "whereB-9.102",
-    -- In this case the unary "+" operator shouldn't
-    -- affect result set of query.
-    [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
-    ]],
-    {
-    -- <whereB-9.102>
-    1, 2, true
-    -- </whereB-9.102>
-    })
-
-test:finish_test()
-
diff --git a/test/sql-tap/whereC.test.lua b/test/sql-tap/whereC.test.lua
index 89459dee3..58c049553 100755
--- a/test/sql-tap/whereC.test.lua
+++ b/test/sql-tap/whereC.test.lua
@@ -55,9 +55,9 @@ test:do_execsql_test(
  test:test("main", function()
      local data = {{"SELECT i FROM t1 WHERE a=1 AND b=2 AND 
i>3",         {4, 5}},
                    -- {"SELECT i FROM t1 WHERE 
rowid='12'",                  {12}},
-                  {"SELECT i FROM t1 WHERE a=1 AND 
b='2'",               {3, 4, 5}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2' AND 
i>'3'",     {4, 5}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2' AND 
i<5",       {3, 4}},
+                  {"SELECT i FROM t1 WHERE a=1 AND b=2",               
{3, 4, 5}},
+                  {"SELECT i FROM t1 WHERE a=1 AND b=2 AND i>3",     
{4, 5}},
+                  {"SELECT i FROM t1 WHERE a=1 AND b=2 AND i<5",       
{3, 4}},
                    {"SELECT i FROM t1 WHERE a=2 AND b=2 AND 
i<12",        {10, 11}},
                    {"SELECT i FROM t1 WHERE a IN(1, 2) AND b=2 AND 
i<11", {3, 4, 5, 10}},
                    {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 
10 AND 12", {10, 11, 12}},
@@ -66,7 +66,7 @@ test:test("main", function()
                    {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 
12 AND 10", {}},
                    {"SELECT i FROM t1 WHERE a=2 AND b=2 AND 
i<NULL",      {}},
                    {"SELECT i FROM t1 WHERE a=2 AND b=2 AND 
i>=NULL",     {}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2' AND 
i<4.5",     {3, 4}}}
+                  {"SELECT i FROM t1 WHERE a=1 AND b=2 AND i<4.5",     
{3, 4}}}
                    -- {"SELECT i FROM t1 WHERE rowid IS 
'12'",               {12}}}

      for tn, t in ipairs(data) do

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Tarantool-patches] [PATCH 5/6] sql: remove implicit cast from string for comparison
  2020-06-01 17:04   ` Vladislav Shpilevoy
@ 2020-06-09 11:51     ` Mergen Imeev
  2020-06-09 22:29       ` Vladislav Shpilevoy
  0 siblings, 1 reply; 21+ messages in thread
From: Mergen Imeev @ 2020-06-09 11:51 UTC (permalink / raw)
  To: Vladislav Shpilevoy, tsafin, tarantool-patches

Thanks for the review! My answers and new patch below.


On 01.06.2020 20:04, Vladislav Shpilevoy wrote:
> Thanks for the patch!
>
> See 7 comments below.
>
> On 28/05/2020 16:17, Mergen Imeev wrote:
>> This patch removes implicit cast from strings to numbers for
>> comparison.
>>
>> Closes #4230
>>
>> @TarantoolBot document
>> Title: remove implicit cast between strings and numbers
>>
>> This patch-set removes implicit cast from string to number and
>> from number to string.
>>
>> Example:
>>
>> For comparison:
>>
>> tarantool> box.execute([[SELECT '1' > 0;]])
>> ---
>> - null
>> - 'Type mismatch: can not convert 1 to numeric'
>> ...
>>
>> tarantool> box.execute([[SELECT "id" FROM "_space" WHERE '1' > "id";]])
>> ---
>> - null
>> - 'Type mismatch: can not convert text to unsigned'
>> ...
>>
>> For assignment:
>>
>> tarantool> box.execute([[CREATE TABLE t1(i INT PRIMARY KEY);]])
>> tarantool> box.execute([[INSERT INTO t1 VALUES ('1');]])
>> ---
>> - null
>> - 'Type mismatch: can not convert text to integer'
>> ...
>>
>> tarantool> box.execute([[CREATE TABLE t2(t text PRIMARY KEY);]])
>> tarantool> box.execute([[INSERT INTO t2 VALUES (1);]])
>> ---
>> - null
>> - 'Type mismatch: can not convert unsigned to string'
>> ...
>> ---
>>   src/box/sql/vdbe.c                            | 105 ++++----
>>   src/box/sql/wherecode.c                       | 203 +--------------
>>   .../gh-4230-del-impl-cast-str-to-num.test.lua |  78 ++++++
>>   test/sql-tap/identifier_case.test.lua         |   6 +-
>>   test/sql-tap/in1.test.lua                     |   4 +-
>>   test/sql-tap/in4.test.lua                     |   3 +-
>>   test/sql-tap/insert3.test.lua                 |   2 +-
>>   test/sql-tap/intpkey.test.lua                 |  24 +-
>>   test/sql-tap/join.test.lua                    |   7 +-
>>   test/sql-tap/misc1.test.lua                   |  32 +--
>>   test/sql-tap/select1.test.lua                 |   4 +-
>>   test/sql-tap/select7.test.lua                 |   2 +-
>>   test/sql-tap/subquery.test.lua                |   4 +-
>>   test/sql-tap/tkt-9a8b09f8e6.test.lua          |  84 ++++---
>>   test/sql-tap/tkt-f973c7ac31.test.lua          |  32 +--
>>   test/sql-tap/tkt-fc7bd6358f.test.lua          |   6 +-
>>   test/sql-tap/tkt3493.test.lua                 |  40 ++-
>>   test/sql-tap/transitive1.test.lua             |  12 +-
>>   test/sql-tap/where2.test.lua                  | 183 +-------------
>>   test/sql-tap/where5.test.lua                  |  12 +-
>>   test/sql-tap/whereB.test.lua                  | 238 ++++++++++--------
>>   test/sql/types.result                         |  12 +-
>>   test/sql/types.test.lua                       |   1 -
>>   23 files changed, 418 insertions(+), 676 deletions(-)
>>   create mode 100755 test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua
>>
>> diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
>> index 7add67ae7..021e09d1e 100644
>> --- a/src/box/sql/vdbe.c
>> +++ b/src/box/sql/vdbe.c
>> @@ -2345,22 +2338,17 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
>>   				goto compare_op;
>>   			}
>>   		} else if (type == FIELD_TYPE_STRING) {
>> -			if ((flags1 & MEM_Str) == 0 &&
>> -			    (flags1 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
>> -				testcase( pIn1->flags & MEM_Int);
>> -				testcase( pIn1->flags & MEM_Real);
>> -				sqlVdbeMemStringify(pIn1);
>> -				testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn));
>> -				flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
>> -				assert(pIn1!=pIn3);
>> +			if ((flags1 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
> 1. Maybe it would be better to check '(flags1 & MEM_Str) == 0'. Otherwise
> every time when we will add a new type, we will need to add it here. The
> same below.

Thanks, fixed.


>
>> +				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
>> +					 mem_type_to_str(pIn3),
>> +					 mem_type_to_str(pIn1));
>> +				goto abort_due_to_error;
>>   			}
>> -			if ((flags3 & MEM_Str) == 0 &&
>> -			    (flags3 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
>> -				testcase( pIn3->flags & MEM_Int);
>> -				testcase( pIn3->flags & MEM_Real);
>> -				sqlVdbeMemStringify(pIn3);
>> -				testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn));
>> -				flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask);
>> +			if ((flags3 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
>> +				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
>> +					 mem_type_to_str(pIn1),
>> +					 mem_type_to_str(pIn3));
>> +				goto abort_due_to_error;
>>   			}
>>   		}
>>   		assert(pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0);
>> diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
>> index 5bc27f134..1d7c76670 100644
>> --- a/src/box/sql/wherecode.c
>> +++ b/src/box/sql/wherecode.c
>> @@ -644,8 +578,7 @@ static int
>>   codeAllEqualityTerms(Parse * pParse,	/* Parsing context */
>>   		     WhereLevel * pLevel,	/* Which nested loop of the FROM we are coding */
>>   		     int bRev,		/* Reverse the order of IN operators */
>> -		     int nExtraReg,	/* Number of extra registers to allocate */
>> -		     enum field_type **res_type)
>> +		     int nExtraReg)	/* Number of extra registers to allocate */
>>   {
>>   	u16 nEq;		/* The number of == or IN constraints to code */
>>   	u16 nSkip;		/* Number of left-most columns to skip */
>> @@ -669,9 +602,6 @@ codeAllEqualityTerms(Parse * pParse,	/* Parsing context */
>>   	nReg = pLoop->nEq + nExtraReg;
>>   	pParse->nMem += nReg;
>>   
>> -	enum field_type *type = sql_index_type_str(pParse->db, idx_def);
> 2. This function is now unused and can be deleted.

Removed.


>
>> -	assert(type != NULL || pParse->db->mallocFailed);
>> -
>>   	if (nSkip) {
>>   		int iIdxCur = pLevel->iIdxCur;
>>   		sqlVdbeAddOp1(v, (bRev ? OP_Last : OP_Rewind), iIdxCur);> diff --git a/test/sql-tap/tkt-9a8b09f8e6.test.lua b/test/sql-tap/tkt-9a8b09f8e6.test.lua
>> index 854ed774f..2a18b17be 100755
>> --- a/test/sql-tap/tkt-9a8b09f8e6.test.lua
>> +++ b/test/sql-tap/tkt-9a8b09f8e6.test.lua
>> @@ -83,23 +83,23 @@ test:do_execsql_test(
>>           -- </1.5>
>>       })
>>   
>> -test:do_execsql_test(
>> +test:do_catchsql_test(
>>       2.1,
>>       [[
>>           SELECT x FROM t1 WHERE x IN (1);
>>       ]], {
>>           -- <2.1>
>> -        "1"
>> +        1,"Type mismatch: can not convert 1 to numeric"
> 3. Can tests in this file be fixed to return the same results
> as before?
I fixed this in most cases, but am not sure if this is correct.
I think most tests are out of date.

>
>>           -- </2.1>
>>       })
>>   
>> -test:do_execsql_test(
>> +test:do_catchsql_test(
>>       2.2,
>>       [[
>>           SELECT x FROM t1 WHERE x IN (1.0);
>>       ]], {
>>           -- <2.2>
>> -        "1"
>> +        1,"Type mismatch: can not convert 1 to numeric"
>>           -- </2.2>
>>       })
>>   
>> diff --git a/test/sql-tap/tkt-f973c7ac31.test.lua b/test/sql-tap/tkt-f973c7ac31.test.lua
>> index 82bdb52f8..5239a7785 100755
>> --- a/test/sql-tap/tkt-f973c7ac31.test.lua
>> +++ b/test/sql-tap/tkt-f973c7ac31.test.lua
>> @@ -36,12 +36,12 @@ local sqls = {
>>   
>>   for tn, sql in ipairs(sqls) do
>>       test:execsql(sql)
>> -    test:do_execsql_test(
>> +    test:do_catchsql_test(
>>           "tkt-f973c7ac3-1."..tn..".1",
>>           [[
>>               SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='2' ORDER BY c2 DESC
>>           ]], {
>> -
>> +            1, "/Type mismatch: can not convert/"
> 4. The same for this file.

Fixed, used CAST().


>
>>           })
>>   
>>       test:do_execsql_test(
>> diff --git a/test/sql-tap/tkt3493.test.lua b/test/sql-tap/tkt3493.test.lua
>> index de77e61e9..ec12a4492 100755
>> --- a/test/sql-tap/tkt3493.test.lua
>> +++ b/test/sql-tap/tkt3493.test.lua
>> @@ -126,23 +126,13 @@ test:do_execsql_test(
>>   test:do_execsql_test(
>>       "tkt3493-2.2.1",
>>       [[
>> -        SELECT a=123 FROM t1 GROUP BY a
>> +        SELECT a='123' FROM t1 GROUP BY a
> 5. Trailing whitespace.

Removed.


>
>>       ]], {
>>           -- <tkt3493-2.2.1>
>>           true
>>           -- </tkt3493-2.2.1>
>>       })
>> @@ -166,7 +156,7 @@ test:do_execsql_test(
>>   test:do_execsql_test(
>>       "tkt3493-2.2.5",
>>       [[
>> -        SELECT count(*), +a=123 FROM t1
>> +        SELECT count(*), +a='123' FROM t1
> 6. Trailing whitespace here and in the test above.

Removed.


>
>>       ]], {
>>           -- <tkt3493-2.2.5>
>>           1, true
>> diff --git a/test/sql-tap/whereB.test.lua b/test/sql-tap/whereB.test.lua
>> index 970ff1dec..9e99ea41c 100755
>> --- a/test/sql-tap/whereB.test.lua
>> +++ b/test/sql-tap/whereB.test.lua
>> @@ -36,49 +35,54 @@ test:do_execsql_test(
>>           CREATE TABLE t2(a  INT primary key, b TEXT);  -- affinity of t2.b is TEXT
>>           CREATE INDEX t2b ON t2(b);
>>           INSERT INTO t2 VALUES(2,'99');
>> +    ]]
>> +)
>>   
>> +test:do_catchsql_test(
>> +    "whereB-1.1",
> 7. The whole whereB-1 now fails because of type conversions banned.
> Is this test still needed at all? I didn't check other whereB tests,
> but seems like most of them also fail now. So either almost the entire
> test file is not needed, or it should be fixed so as the test still
> would work.

Removed whereB.test.lua in the previous patch.


New patch:


 From 5c3feffdfd6837438de4b7ce3d728b356bb4be8a Mon Sep 17 00:00:00 2001
From: Mergen Imeev <imeevma@gmail.com>
Date: Thu, 16 Apr 2020 12:52:59 +0300
Subject: [PATCH] sql: remove implicit cast from string for comparison

This patch removes implicit cast from strings to numbers for
comparison.

Closes #4230

@TarantoolBot document
Title: remove implicit cast between strings and numbers

This patch-set removes implicit cast from string to number and
from number to string.

Example:

For comparison:

tarantool> box.execute([[SELECT '1' > 0;]])
---
- null
- 'Type mismatch: can not convert 1 to numeric'
...

tarantool> box.execute([[SELECT "id" FROM "_space" WHERE '1' > "id";]])
---
- null
- 'Type mismatch: can not convert text to unsigned'
...

For assignment:

tarantool> box.execute([[CREATE TABLE t1(i INT PRIMARY KEY);]])
tarantool> box.execute([[INSERT INTO t1 VALUES ('1');]])
---
- null
- 'Type mismatch: can not convert text to integer'
...

tarantool> box.execute([[CREATE TABLE t2(t text PRIMARY KEY);]])
tarantool> box.execute([[INSERT INTO t2 VALUES (1);]])
---
- null
- 'Type mismatch: can not convert unsigned to string'
...

review fix

diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index 253304ba3..7b9cda504 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -41,20 +41,6 @@
  #include "box/box.h"
  #include "box/schema.h"

-enum field_type *
-sql_index_type_str(struct sql *db, const struct index_def *idx_def)
-{
-    uint32_t column_count = idx_def->key_def->part_count;
-    uint32_t sz = (column_count + 1) * sizeof(enum field_type);
-    enum field_type *types = (enum field_type *) sqlDbMallocRaw(db, sz);
-    if (types == NULL)
-        return NULL;
-    for (uint32_t i = 0; i < column_count; i++)
-        types[i] = idx_def->key_def->parts[i].type;
-    types[column_count] = field_type_MAX;
-    return types;
-}
-
  void
  sql_emit_table_types(struct Vdbe *v, struct space_def *def, int reg)
  {
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 37283e506..01c32d518 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -3866,10 +3866,6 @@ int sqlVarintLen(u64 v);
  #define getVarint    sqlGetVarint
  #define putVarint    sqlPutVarint

-/** Return string consisting of fields types of given index. */
-enum field_type *
-sql_index_type_str(struct sql *db, const struct index_def *idx_def);
-
  /**
   * Code an OP_ApplyType opcode that will force types
   * for given range of register starting from @reg.
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 77b758833..a92c9f60f 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -2260,8 +2260,6 @@ case OP_Ge: {             /* same as TK_GE, jump, 
in1, in3 */
      pIn3 = &aMem[pOp->p3];
      flags1 = pIn1->flags;
      flags3 = pIn3->flags;
-    enum field_type ft_p1 = pIn1->field_type;
-    enum field_type ft_p3 = pIn3->field_type;
      if ((flags1 | flags3)&MEM_Null) {
          /* One or both operands are NULL */
          if (pOp->p5 & SQL_NULLEQ) {
@@ -2320,22 +2318,17 @@ case OP_Ge: {             /* same as TK_GE, 
jump, in1, in3 */
      } else {
          enum field_type type = pOp->p5 & FIELD_TYPE_MASK;
          if (sql_type_is_numeric(type)) {
-            if ((flags1 | flags3)&MEM_Str) {
-                if ((flags1 & MEM_Str) == MEM_Str) {
-                    mem_apply_numeric_type(pIn1);
-                    testcase( flags3!=pIn3->flags); /* Possible if 
pIn1==pIn3 */
-                    flags3 = pIn3->flags;
-                }
-                if ((flags3 & MEM_Str) == MEM_Str) {
-                    if (mem_apply_numeric_type(pIn3) != 0) {
-                        diag_set(ClientError,
-                             ER_SQL_TYPE_MISMATCH,
-                             sql_value_to_diag_str(pIn3),
-                             "numeric");
-                        goto abort_due_to_error;
-                    }
-
-                }
+            if ((flags1 & MEM_Str) == MEM_Str) {
+                diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+                     sql_value_to_diag_str(pIn1),
+                     "numeric");
+                goto abort_due_to_error;
+            }
+            if ((flags3 & MEM_Str) == MEM_Str) {
+                diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+                     sql_value_to_diag_str(pIn3),
+                     "numeric");
+                goto abort_due_to_error;
              }
              /* Handle the common case of integer comparison here, as an
               * optimization, to avoid a call to sqlMemCompare()
@@ -2368,22 +2361,17 @@ case OP_Ge: {             /* same as TK_GE, 
jump, in1, in3 */
                  goto compare_op;
              }
          } else if (type == FIELD_TYPE_STRING) {
-            if ((flags1 & MEM_Str) == 0 &&
-                (flags1 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
-                testcase( pIn1->flags & MEM_Int);
-                testcase( pIn1->flags & MEM_Real);
-                sqlVdbeMemStringify(pIn1);
-                testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn));
-                flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & 
MEM_TypeMask);
-                assert(pIn1!=pIn3);
+            if ((flags1 & MEM_Str) == 0) {
+                diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+                     mem_type_to_str(pIn3),
+                     mem_type_to_str(pIn1));
+                goto abort_due_to_error;
              }
-            if ((flags3 & MEM_Str) == 0 &&
-                (flags3 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
-                testcase( pIn3->flags & MEM_Int);
-                testcase( pIn3->flags & MEM_Real);
-                sqlVdbeMemStringify(pIn3);
-                testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn));
-                flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & 
MEM_TypeMask);
+            if ((flags3 & MEM_Str) == 0) {
+                diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+                     mem_type_to_str(pIn1),
+                     mem_type_to_str(pIn3));
+                goto abort_due_to_error;
              }
          }
          assert(pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0);
@@ -2399,14 +2387,6 @@ case OP_Ge: {             /* same as TK_GE, jump, 
in1, in3 */
      default:       res2 = res>=0;     break;
      }

-    /* Undo any changes made by mem_apply_type() to the input registers. */
-    assert((pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn));
-    pIn1->flags = flags1;
-    pIn1->field_type = ft_p1;
-    assert((pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn));
-    pIn3->flags = flags3;
-    pIn3->field_type = ft_p3;
-
      if (pOp->p5 & SQL_STOREP2) {
          iCompare = res;
          res2 = res2!=0;  /* For this path res2 must be exactly 0 or 1 */
@@ -3496,8 +3476,6 @@ case OP_SeekGT: {       /* jump, in3 */
          pIn3 = &aMem[int_field];
          if ((pIn3->flags & MEM_Null) != 0)
              goto skip_truncate;
-        if ((pIn3->flags & MEM_Str) != 0)
-            mem_apply_numeric_type(pIn3);
          int64_t i;
          if ((pIn3->flags & MEM_Int) == MEM_Int) {
              i = pIn3->u.i;
@@ -3590,6 +3568,26 @@ skip_truncate:
      assert(oc!=OP_SeekLT || r.default_rc==+1);

      r.aMem = &aMem[pOp->p3];
+    for (int i = 0; i < r.nField; ++i) {
+        enum field_type type = r.key_def->parts[i].type;
+        struct Mem *mem = &r.aMem[i];
+        if ((mem->flags & MEM_Str) != 0 && sql_type_is_numeric(type)) {
+            diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+                field_type_strs[type], mem_type_to_str(mem));
+            goto abort_due_to_error;
+        }
+        if (mem_check_types(mem, type) == 0)
+            continue;
+        if ((mem->flags & MEM_Real) != 0 &&
+            (type == FIELD_TYPE_INTEGER ||
+             type == FIELD_TYPE_UNSIGNED)) {
+            res = 1;
+            goto seek_not_found;
+        }
+        diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+            field_type_strs[type], mem_type_to_str(mem));
+        goto abort_due_to_error;
+    }
  #ifdef SQL_DEBUG
      { int i; for(i=0; i<r.nField; i++) assert(memIsValid(&r.aMem[i])); }
  #endif
@@ -4717,6 +4715,27 @@ case OP_IdxGE:  {       /* jump */
          r.default_rc = 0;
      }
      r.aMem = &aMem[pOp->p3];
+    for (int i = 0; i < r.nField; ++i) {
+        struct Mem *mem = &r.aMem[i];
+        enum mp_type mp_type = sql_value_type(mem);
+        enum field_type field_type = r.key_def->parts[i].type;
+        if (field_type == FIELD_TYPE_SCALAR ||
+            mem->field_type == FIELD_TYPE_SCALAR)
+            continue;
+        bool is_nullable = r.key_def->parts[i].nullable_action ==
+                   ON_CONFLICT_ACTION_NONE;
+        if (field_mp_plain_type_is_compatible(field_type, mp_type,
+                              is_nullable))
+            continue;
+        if (!sql_type_is_numeric(field_type) ||
+            !(mp_type == MP_INT || mp_type == MP_UINT ||
+              mp_type == MP_DOUBLE || mp_type == MP_FLOAT)) {
+            diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+                 mem_type_to_str(mem),
+                 field_type_strs[field_type]);
+            goto abort_due_to_error;
+        }
+    }
  #ifdef SQL_DEBUG
      { int i; for(i=0; i<r.nField; i++) assert(memIsValid(&r.aMem[i])); }
  #endif
diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
index 6d8768865..1d7c76670 100644
--- a/src/box/sql/wherecode.c
+++ b/src/box/sql/wherecode.c
@@ -335,72 +335,6 @@ disableTerm(WhereLevel * pLevel, WhereTerm * pTerm)
      }
  }

-/**
- * Code an OP_ApplyType opcode to apply the column type string
- * @types to the n registers starting at @base.
- *
- * As an optimization, SCALAR entries (which are no-ops) at the
- * beginning and end of @types are ignored.  If all entries in
- * @types are SCALAR, then no code gets generated.
- *
- * This routine makes its own copy of @types so that the caller is
- * free to modify @types after this routine returns.
- */
-static void
-emit_apply_type(Parse *pParse, int base, int n, enum field_type *types)
-{
-    Vdbe *v = pParse->pVdbe;
-    if (types == NULL) {
-        assert(pParse->db->mallocFailed);
-        return;
-    }
-    assert(v != 0);
-
-    /*
-     * Adjust base and n to skip over SCALAR entries at the
-     * beginning and end of the type sequence.
-     */
-    while (n > 0 && types[0] == FIELD_TYPE_SCALAR) {
-        n--;
-        base++;
-        types++;
-    }
-    while (n > 1 && types[n - 1] == FIELD_TYPE_SCALAR) {
-        n--;
-    }
-
-    if (n > 0) {
-        enum field_type *types_dup = field_type_sequence_dup(pParse,
-                                     types, n);
-        sqlVdbeAddOp4(v, OP_ApplyType, base, n, 0,
-                  (char *) types_dup, P4_DYNAMIC);
-        sql_expr_type_cache_change(pParse, base, n);
-    }
-}
-
-/**
- * Expression @rhs, which is the RHS of a comparison operation, is
- * either a vector of n elements or, if n==1, a scalar expression.
- * Before the comparison operation, types @types are to be applied
- * to the @rhs values. This function modifies entries within the
- * field sequence to SCALAR if either:
- *
- *   * the comparison will be performed with no type, or
- *   * the type change in @types is guaranteed not to change the value.
- */
-static void
-expr_cmp_update_rhs_type(struct Expr *rhs, int n, enum field_type *types)
-{
-    for (int i = 0; i < n; i++) {
-        Expr *p = sqlVectorFieldSubexpr(rhs, i);
-        enum field_type expr_type = sql_expr_type(p);
-        if (sql_type_result(expr_type, types[i]) == FIELD_TYPE_SCALAR ||
-            sql_expr_needs_no_type_change(p, types[i])) {
-            types[i] = FIELD_TYPE_SCALAR;
-        }
-    }
-}
-
  /*
   * Generate code for a single equality term of the WHERE clause. An 
equality
   * term can be either X=expr or X IN (...).   pTerm is the term to be
@@ -644,8 +578,7 @@ static int
  codeAllEqualityTerms(Parse * pParse,    /* Parsing context */
               WhereLevel * pLevel,    /* Which nested loop of the FROM 
we are coding */
               int bRev,        /* Reverse the order of IN operators */
-             int nExtraReg,    /* Number of extra registers to allocate */
-             enum field_type **res_type)
+             int nExtraReg)    /* Number of extra registers to allocate */
  {
      u16 nEq;        /* The number of == or IN constraints to code */
      u16 nSkip;        /* Number of left-most columns to skip */
@@ -669,9 +602,6 @@ codeAllEqualityTerms(Parse * pParse,    /* Parsing 
context */
      nReg = pLoop->nEq + nExtraReg;
      pParse->nMem += nReg;

-    enum field_type *type = sql_index_type_str(pParse->db, idx_def);
-    assert(type != NULL || pParse->db->mallocFailed);
-
      if (nSkip) {
          int iIdxCur = pLevel->iIdxCur;
          sqlVdbeAddOp1(v, (bRev ? OP_Last : OP_Rewind), iIdxCur);
@@ -714,17 +644,7 @@ codeAllEqualityTerms(Parse * pParse,    /* Parsing 
context */
                  sqlVdbeAddOp2(v, OP_SCopy, r1, regBase + j);
              }
          }
-        if (pTerm->eOperator & WO_IN) {
-            if (pTerm->pExpr->flags & EP_xIsSelect) {
-                /* No type ever needs to be (or should be) applied to a 
value
-                 * from the RHS of an "? IN (SELECT ...)" expression. The
-                 * sqlFindInIndex() routine has already ensured that the
-                 * type of the comparison has been applied to the value.
-                 */
-                if (type != NULL)
-                    type[j] = FIELD_TYPE_SCALAR;
-            }
-        } else if ((pTerm->eOperator & WO_ISNULL) == 0) {
+        if ((pTerm->eOperator & (WO_IN | WO_ISNULL)) == 0) {
              Expr *pRight = pTerm->pExpr->pRight;
              if (sqlExprCanBeNull(pRight)) {
                  sqlVdbeAddOp2(v, OP_IsNull, regBase + j,
@@ -733,7 +653,6 @@ codeAllEqualityTerms(Parse * pParse,    /* Parsing 
context */
              }
          }
      }
-    *res_type = type;
      return regBase;
  }

@@ -904,10 +823,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,    /* 
Complete information about the W
          int iIdxCur;    /* The VDBE cursor for the index */
          int nExtraReg = 0;    /* Number of extra registers needed */
          int op;        /* Instruction opcode */
-        /* Types for start of range constraint. */
-        enum field_type *start_types;
-        /* Types for end of range constraint */
-        enum field_type *end_types = NULL;
          u8 bSeekPastNull = 0;    /* True to seek past initial nulls */
          u8 bStopAtNull = 0;    /* Add condition to terminate at NULLs */
          int force_integer_reg = -1;  /* If non-negative: number of
@@ -994,17 +909,7 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,    /* 
Complete information about the W
           * and store the values of those terms in an array of registers
           * starting at regBase.
           */
-        regBase =
-            codeAllEqualityTerms(pParse, pLevel, bRev, nExtraReg,
-                     &start_types);
-        if (start_types != NULL && nTop) {
-            uint32_t len = 0;
-            for (enum field_type *tmp = &start_types[nEq];
-                 *tmp != field_type_MAX; tmp++, len++);
-            uint32_t sz = len * sizeof(enum field_type);
-            end_types = sqlDbMallocRaw(db, sz);
-            memcpy(end_types, &start_types[nEq], sz);
-        }
+        regBase = codeAllEqualityTerms(pParse, pLevel, bRev, nExtraReg);
          addrNxt = pLevel->addrNxt;

          testcase(pRangeStart && (pRangeStart->eOperator & WO_LE) != 0);
@@ -1029,10 +934,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,    /* 
Complete information about the W
                  VdbeCoverage(v);
              }

-            if (start_types) {
-                expr_cmp_update_rhs_type(pRight, nBtm,
-                             &start_types[nEq]);
-            }
              nConstraint += nBtm;
              testcase(pRangeStart->wtFlags & TERM_VIRTUAL);
              if (sqlExprIsVector(pRight) == 0) {
@@ -1049,94 +950,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,    /* 
Complete information about the W
          }
          struct index_def *idx_pk = space->index[0]->def;
          uint32_t pk_part_count = idx_pk->key_def->part_count;
-        /*
-         * Tarantool's iterator over integer fields doesn't
-         * tolerate floating point values. Hence, if term
-         * is equality comparison and value of operand is
-         * not integer, we can skip it since it always
-         * results in false: INT a == 0.5 -> false;
-         * It is done using OP_MustBeInt facilities.
-         * In case term is greater comparison (a > ?), we
-         * should notify OP_SeekGT to process truncation of
-         * floating point value: a > 0.5 -> a >= 1;
-         * It is done by setting P5 flag for OP_Seek*.
-         * It is worth mentioning that we do not need
-         * this step when it comes for less (<) comparison
-         * of nullable field. Key is NULL in this case:
-         * values are ordered as  NULL, ... NULL, min_value,
-         * so to fetch min value we pass NULL to GT iterator.
-         * The only exception is less comparison in
-         * conjunction with ORDER BY DESC clause:
-         * in such situation we use LE iterator and
-         * truncated value to compare. But then
-         * pRangeStart == NULL.
-         * This procedure is correct for compound index:
-         * only one comparison of less/greater type can be
-         * used at the same time. For instance,
-         * a < 1.5 AND b > 0.5 is handled by SeekGT using
-         * column a and fetching column b from tuple and
-         * OP_Le comparison.
-         *
-         * Note that OP_ApplyType, which is emitted before
-         * OP_Seek** doesn't truncate floating point to
-         * integer. That's why we need this routine.
-         * Also, note that terms are separated by OR
-         * predicates, so we consider term as sequence
-         * of AND'ed predicates.
-         */
-        size_t addrs_sz;
-        int *seek_addrs = region_alloc_array(&pParse->region,
-                             typeof(seek_addrs[0]), nEq,
-                             &addrs_sz);
-        if (seek_addrs == NULL) {
-            diag_set(OutOfMemory, addrs_sz, "region_alloc_array",
-                 "seek_addrs");
-            pParse->is_aborted = true;
-            return 0;
-        }
-        memset(seek_addrs, 0, addrs_sz);
-        for (int i = 0; i < nEq; i++) {
-            enum field_type type = idx_def->key_def->parts[i].type;
-            if (type == FIELD_TYPE_INTEGER ||
-                type == FIELD_TYPE_UNSIGNED) {
-                /*
-                 * OP_MustBeInt consider NULLs as
-                 * non-integer values, so firstly
-                 * check whether value is NULL or not.
-                 */
-                seek_addrs[i] = sqlVdbeAddOp1(v, OP_IsNull,
-                                  regBase);
-                sqlVdbeAddOp2(v, OP_MustBeInt, regBase + i,
-                          addrNxt);
-                start_types[i] = FIELD_TYPE_SCALAR;
-                /*
-                 * We need to notify column cache
-                 * that type of value may change
-                 * so we should fetch value from
-                 * tuple again rather then copy
-                 * from register.
-                 */
-                sql_expr_type_cache_change(pParse, regBase + i,
-                               1);
-            }
-        }
-        /* Inequality constraint comes always at the end of list. */
-        part_count = idx_def->key_def->part_count;
-        if (pRangeStart != NULL) {
-            /*
-             * nEq == 0 means that filter condition
-             * contains only inequality.
-             */
-            uint32_t ineq_idx = nEq == 0 ? 0 : nEq - 1;
-            assert(ineq_idx < part_count);
-            enum field_type ineq_type =
-                idx_def->key_def->parts[ineq_idx].type;
-            if (ineq_type == FIELD_TYPE_INTEGER ||
-                ineq_type == FIELD_TYPE_UNSIGNED)
-                force_integer_reg = regBase + nEq;
-        }
-        emit_apply_type(pParse, regBase, nConstraint - bSeekPastNull,
-                start_types);
          if (pLoop->nSkip > 0 && nConstraint == pLoop->nSkip) {
              /* The skip-scan logic inside the call to 
codeAllEqualityConstraints()
               * above has already left the cursor sitting on the 
correct row,
@@ -1146,10 +959,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,    /* 
Complete information about the W
              op = aStartOp[(start_constraints << 2) +
                        (startEq << 1) + bRev];
              assert(op != 0);
-            for (uint32_t i = 0; i < nEq; ++i) {
-                if (seek_addrs[i] != 0)
-                    sqlVdbeJumpHere(v, seek_addrs[i]);
-            }
              sqlVdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase,
                           nConstraint);
              /* If this is Seek* opcode, and IPK is detected in the
@@ -1189,13 +998,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,    /* 
Complete information about the W
                            addrNxt);
                  VdbeCoverage(v);
              }
-            if (end_types) {
-                expr_cmp_update_rhs_type(pRight, nTop, end_types);
-                emit_apply_type(pParse, regBase + nEq, nTop,
-                        end_types);
-            } else {
-                assert(pParse->db->mallocFailed);
-            }
              nConstraint += nTop;
              testcase(pRangeEnd->wtFlags & TERM_VIRTUAL);

@@ -1209,8 +1011,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,    /* 
Complete information about the W
              endEq = 0;
              nConstraint++;
          }
-        sqlDbFree(db, start_types);
-        sqlDbFree(db, end_types);

          /* Top of the loop body */
          pLevel->p2 = sqlVdbeCurrentAddr(v);
diff --git a/test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua 
b/test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua
new file mode 100755
index 000000000..ef4127e0e
--- /dev/null
+++ b/test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua
@@ -0,0 +1,78 @@
+#!/usr/bin/env tarantool
+test = require("sqltester")
+test:plan(8)
+
+--
+-- Make sure that there is no implicit cast between string and
+-- number.
+--
+test:do_catchsql_test(
+    "gh-4230-1",
+    [[
+        SELECT '1' > 0;
+    ]], {
+        1, "Type mismatch: can not convert 1 to numeric"
+    })
+
+test:do_catchsql_test(
+    "gh-4230-2",
+    [[
+        SELECT 0 > '1';
+    ]], {
+        1, "Type mismatch: can not convert 1 to numeric"
+    })
+
+test:execsql([[
+        CREATE TABLE t (i INT PRIMARY KEY, d DOUBLE, n NUMBER, s STRING);
+        INSERT INTO t VALUES (1, 1.0, 1, '2'), (2, 2.0, 2.0, '2');
+    ]])
+
+test:do_catchsql_test(
+    "gh-4230-3",
+    [[
+        SELECT * from t where i > s;
+    ]], {
+        1, "Type mismatch: can not convert 2 to numeric"
+    })
+
+test:do_catchsql_test(
+    "gh-4230-4",
+    [[
+        SELECT * from t WHERE s > i;
+    ]], {
+        1, "Type mismatch: can not convert 2 to numeric"
+    })
+
+test:do_catchsql_test(
+    "gh-4230-5",
+    [[
+        SELECT * from t WHERE d > s;
+    ]], {
+        1, "Type mismatch: can not convert 2 to numeric"
+    })
+
+test:do_catchsql_test(
+    "gh-4230-6",
+    [[
+        SELECT * from t WHERE s > d;
+    ]], {
+        1, "Type mismatch: can not convert 2 to numeric"
+    })
+
+test:do_catchsql_test(
+    "gh-4230-7",
+    [[
+        SELECT * from t WHERE i = 1 and n > s;
+    ]], {
+        1, "Type mismatch: can not convert 2 to numeric"
+    })
+
+test:do_catchsql_test(
+    "gh-4230-8",
+    [[
+        SELECT * from t WHERE i = 2 and s > n;
+    ]], {
+        1, "Type mismatch: can not convert 2 to numeric"
+    })
+
+test:finish_test()
diff --git a/test/sql-tap/identifier_case.test.lua 
b/test/sql-tap/identifier_case.test.lua
index 2a00626fc..1d56ffb44 100755
--- a/test/sql-tap/identifier_case.test.lua
+++ b/test/sql-tap/identifier_case.test.lua
@@ -242,11 +242,11 @@ data = {
      { 2,  [[ 'a' < 'b' collate "binary" ]], {0, {true}}},
      { 3,  [[ 'a' < 'b' collate 'binary' ]], {1, [[Syntax error at line 
1 near ''binary'']]}},
      { 4,  [[ 'a' < 'b' collate "unicode" ]], {0, {true}}},
-    { 5,  [[ 5 < 'b' collate "unicode" ]], {0, {true}}},
+    { 5,  [[ 5 < 'b' collate "unicode" ]], {1, "Type mismatch: can not 
convert b to numeric"}},
      { 6,  [[ 5 < 'b' collate unicode ]], {1,"Collation 'UNICODE' does 
not exist"}},
-    { 7,  [[ 5 < 'b' collate "unicode_ci" ]], {0, {true}}},
+    { 7,  [[ 5 < 'b' collate "unicode_ci" ]], {1, "Type mismatch: can 
not convert b to numeric"}},
      { 8,  [[ 5 < 'b' collate NONE ]], {1, "Collation 'NONE' does not 
exist"}},
-    { 9,  [[ 5 < 'b' collate "none" ]], {0, {true}}},
+    { 9,  [[ 5 < 'b' collate "none" ]], {1, "Type mismatch: can not 
convert b to numeric"}},
  }

  for _, row in ipairs(data) do
diff --git a/test/sql-tap/in1.test.lua b/test/sql-tap/in1.test.lua
index 570cc1779..e2f498889 100755
--- a/test/sql-tap/in1.test.lua
+++ b/test/sql-tap/in1.test.lua
@@ -637,12 +637,12 @@ test:do_test(
      "in-11.2",
      function()
          -- The '2' should be coerced into 2 because t6.b is NUMERIC
-        return test:execsql [[
+        return test:catchsql [[
              SELECT * FROM t6 WHERE b IN ('2');
          ]]
      end, {
          -- <in-11.2>
-        1, 2
+        1, "Type mismatch: can not convert 2 to numeric"
          -- </in-11.2>
      })

diff --git a/test/sql-tap/in4.test.lua b/test/sql-tap/in4.test.lua
index 33947d0ab..a494e846f 100755
--- a/test/sql-tap/in4.test.lua
+++ b/test/sql-tap/in4.test.lua
@@ -147,12 +147,13 @@ test:do_execsql_test(
          -- </in4-2.7>
      })

-test:do_execsql_test(
+test:do_catchsql_test(
      "in4-2.8",
      [[
          SELECT b FROM t2 WHERE a IN ('', '0.0.0', '2')
      ]], {
          -- <in4-2.8>
+        1, "Type mismatch: can not convert integer to text"
          -- </in4-2.8>
      })

diff --git a/test/sql-tap/insert3.test.lua b/test/sql-tap/insert3.test.lua
index b92bc508e..3276f0db2 100755
--- a/test/sql-tap/insert3.test.lua
+++ b/test/sql-tap/insert3.test.lua
@@ -59,7 +59,7 @@ test:do_execsql_test(
      [[
              CREATE TABLE log2(rowid INTEGER PRIMARY KEY AUTOINCREMENT, 
x TEXT UNIQUE,y INT );
              CREATE TRIGGER r2 BEFORE INSERT ON t1 FOR EACH ROW BEGIN
-              UPDATE log2 SET y=y+1 WHERE x=new.b;
+              UPDATE log2 SET y=y+1 WHERE x=CAST(new.b AS STRING);
                INSERT OR IGNORE INTO log2(x, y) VALUES(CAST(new.b AS 
STRING),1);
              END;
              INSERT INTO t1(a, b) VALUES('hi', 453);
diff --git a/test/sql-tap/intpkey.test.lua b/test/sql-tap/intpkey.test.lua
index 0db18ba91..bc3d701a7 100755
--- a/test/sql-tap/intpkey.test.lua
+++ b/test/sql-tap/intpkey.test.lua
@@ -1,6 +1,6 @@
  #!/usr/bin/env tarantool
  test = require("sqltester")
-test:plan(40)
+test:plan(39)

  --!./tcltestrunner.lua
  -- 2001 September 15
@@ -854,43 +854,33 @@ test:do_execsql_test(
          -- </intpkey-14.2>
      })

-test:do_execsql_test(
-    "intpkey-14.3",
-    [[
-        SELECT * FROM t3 WHERE a>'2';
-    ]], {
-        -- <intpkey-14.3>
-        3, 3, "3"
-        -- </intpkey-14.3>
-    })
-
-test:do_execsql_test(
+test:do_catchsql_test(
      "intpkey-14.4",
      [[
          SELECT * FROM t3 WHERE a<'2';
      ]], {
          -- <intpkey-14.4>
-        1, 1, "one"
+        1, "Type mismatch: can not convert text to integer"
          -- </intpkey-14.4>
      })

-test:do_execsql_test(
+test:do_catchsql_test(
      "intpkey-14.5",
      [[
          SELECT * FROM t3 WHERE a<c;
      ]], {
          -- <intpkey-14.5>
-        1, 1, "one"
+        1, "Type mismatch: can not convert one to numeric"
          -- </intpkey-14.5>
      })

-test:do_execsql_test(
+test:do_catchsql_test(
      "intpkey-14.6",
      [[
          SELECT * FROM t3 WHERE a=c;
      ]], {
          -- <intpkey-14.6>
-        2, 2, "2", 3, 3, "3"
+        1, "Type mismatch: can not convert one to numeric"
          -- </intpkey-14.6>
      })

diff --git a/test/sql-tap/join.test.lua b/test/sql-tap/join.test.lua
index 51e0ecb79..792302ab5 100755
--- a/test/sql-tap/join.test.lua
+++ b/test/sql-tap/join.test.lua
@@ -1028,22 +1028,23 @@ test:do_test(
          -- </join-11.8>
      })

-test:do_execsql_test(
+test:do_catchsql_test(
      "join-11.9",
      [[
          SELECT * FROM t1 NATURAL JOIN t2
      ]], {
          -- <join-11.9>
+        1, "Type mismatch: can not convert integer to text"
          -- </join-11.9>
      })

-test:do_execsql_test(
+test:do_catchsql_test(
      "join-11.10",
      [[
          SELECT * FROM t2 NATURAL JOIN t1
      ]], {
          -- <join-11.10>
-        1, "one", 2, "two"
+        1, "Type mismatch: can not convert 1 to numeric"
          -- </join-11.10>
      })

diff --git a/test/sql-tap/misc1.test.lua b/test/sql-tap/misc1.test.lua
index e0fe50bbe..3cef617f4 100755
--- a/test/sql-tap/misc1.test.lua
+++ b/test/sql-tap/misc1.test.lua
@@ -88,7 +88,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "misc1-1.4",
      [[
-        SELECT x75 FROM manycol WHERE x50=350
+        SELECT x75 FROM manycol WHERE x50='350'
      ]], {
          -- <misc1-1.4>
          "375"
@@ -98,7 +98,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "misc1-1.5",
      [[
-        SELECT x50 FROM manycol WHERE x99=599
+        SELECT x50 FROM manycol WHERE x99='599'
      ]], {
          -- <misc1-1.5>
          "550"
@@ -109,7 +109,7 @@ test:do_test(
      "misc1-1.6",
      function()
          test:execsql("CREATE INDEX manycol_idx1 ON manycol(x99)")
-        return test:execsql("SELECT x50 FROM manycol WHERE x99=899")
+        return test:execsql("SELECT x50 FROM manycol WHERE x99='899'")
      end, {
          -- <misc1-1.6>
          "850"
@@ -129,7 +129,7 @@ test:do_execsql_test(
  test:do_test(
      "misc1-1.8",
      function()
-        test:execsql("DELETE FROM manycol WHERE x98=1234")
+        test:execsql("DELETE FROM manycol WHERE x98='1234'")
          return test:execsql("SELECT count(*) FROM manycol")
      end, {
          -- <misc1-1.8>
@@ -140,7 +140,7 @@ test:do_test(
  test:do_test(
      "misc1-1.9",
      function()
-        test:execsql("DELETE FROM manycol WHERE x98=998")
+        test:execsql("DELETE FROM manycol WHERE x98='998'")
          return test:execsql("SELECT count(*) FROM manycol")
      end, {
          -- <misc1-1.9>
@@ -151,7 +151,7 @@ test:do_test(
  test:do_test(
      "misc1-1.10",
      function()
-        test:execsql("DELETE FROM manycol WHERE x99=500")
+        test:execsql("DELETE FROM manycol WHERE x99='500'")
          return test:execsql("SELECT count(*) FROM manycol")
      end, {
          -- <misc1-1.10>
@@ -162,7 +162,7 @@ test:do_test(
  test:do_test(
      "misc1-1.11",
      function()
-        test:execsql("DELETE FROM manycol WHERE x99=599")
+        test:execsql("DELETE FROM manycol WHERE x99='599'")
          return test:execsql("SELECT count(*) FROM manycol")
      end, {
          -- <misc1-1.11>
@@ -479,9 +479,9 @@ local where = ""
  test:do_test(
      "misc1-10.1",
      function()
-        where = "WHERE x0>=0"
+        where = "WHERE x0>='0'"
          for i = 1, 99, 1 do
-            where = where .. " AND x"..i.."<>0"
+            where = where .. " AND x"..i.."<>'0'"
          end
          return test:catchsql("SELECT count(*) FROM manycol "..where.."")
      end, {
@@ -496,7 +496,7 @@ test:do_test(
  test:do_test(
      "misc1-10.3",
      function()
-        where = string.gsub(where,"x0>=0", "x0=0")
+        where = string.gsub(where,"x0>='0'", "x0='0'")
          return test:catchsql("DELETE FROM manycol "..where.."")
      end, {
          -- <misc1-10.3>
@@ -520,7 +520,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "misc1-10.6",
      [[
-        SELECT x1 FROM manycol WHERE x0=100
+        SELECT x1 FROM manycol WHERE x0='100'
      ]], {
          -- <misc1-10.6>
          "101"
@@ -530,7 +530,7 @@ test:do_execsql_test(
  test:do_test(
      "misc1-10.7",
      function()
-        where = string.gsub(where, "x0=0", "x0=100")
+        where = string.gsub(where, "x0='0'", "x0='100'")
          return test:catchsql("UPDATE manycol SET x1=CAST(x1+1 AS 
STRING) "..where.."")
      end, {
          -- <misc1-10.7>
@@ -541,7 +541,7 @@ test:do_test(
  test:do_execsql_test(
      "misc1-10.8",
      [[
-        SELECT x1 FROM manycol WHERE x0=100
+        SELECT x1 FROM manycol WHERE x0='100'
      ]], {
          -- <misc1-10.8>
          "102"
@@ -563,7 +563,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "misc1-10.10",
      [[
-        SELECT x1 FROM manycol WHERE x0=100
+        SELECT x1 FROM manycol WHERE x0='100'
      ]], {
          -- <misc1-10.10>
          "103"
@@ -619,13 +619,13 @@ test:do_execsql_test(
          -- </misc1-12.1>
      })

-test:do_execsql_test(
+test:do_catchsql_test(
      "misc1-12.2",
      [[
          SELECT '0'==0.0
      ]], {
          -- <misc1-12.2>
-        true
+        1, "Type mismatch: can not convert 0 to numeric"
          -- </misc1-12.2>
      })

diff --git a/test/sql-tap/select1.test.lua b/test/sql-tap/select1.test.lua
index 9a969bf3c..f5a9b63fe 100755
--- a/test/sql-tap/select1.test.lua
+++ b/test/sql-tap/select1.test.lua
@@ -1912,7 +1912,7 @@ test:do_execsql_test(
  test:do_execsql_test(
          "select1-12.7",
          [[
-            SELECT * FROM t3 WHERE a=(SELECT 1);
+            SELECT * FROM t3 WHERE a=(SELECT '1');
          ]], {
              -- <select1-12.7>
              0, "1", "2"
@@ -1922,7 +1922,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "select1-12.8",
      [[
-        SELECT * FROM t3 WHERE a=(SELECT 2);
+        SELECT * FROM t3 WHERE a=(SELECT '2');
      ]], {
          -- <select1-12.8>

diff --git a/test/sql-tap/select7.test.lua b/test/sql-tap/select7.test.lua
index e1e43c557..0d1390fd6 100755
--- a/test/sql-tap/select7.test.lua
+++ b/test/sql-tap/select7.test.lua
@@ -256,7 +256,7 @@ test:do_execsql_test(
          DROP TABLE IF EXISTS t5;
          CREATE TABLE t5(a TEXT primary key, b INT);
          INSERT INTO t5 VALUES('123', 456);
-        SELECT typeof(a), a FROM t5 GROUP BY a HAVING a<b;
+        SELECT typeof(a), a FROM t5 GROUP BY a HAVING CAST(a AS INTEGER)<b;
      ]], {
          -- <select7-7.7>
          "string", "123"
diff --git a/test/sql-tap/subquery.test.lua b/test/sql-tap/subquery.test.lua
index e0771825e..bad702de9 100755
--- a/test/sql-tap/subquery.test.lua
+++ b/test/sql-tap/subquery.test.lua
@@ -284,13 +284,13 @@ test:do_execsql_test(
          -- </subquery-2.3.1>
      })

-test:do_execsql_test(
+test:do_catchsql_test(
      "subquery-2.3.2",
      [[
          SELECT a IN (10.0, 20) FROM t3;
      ]], {
          -- <subquery-2.3.2>
-        false
+        1, "Type mismatch: can not convert text to real"
          -- </subquery-2.3.2>
      })

diff --git a/test/sql-tap/tkt-9a8b09f8e6.test.lua 
b/test/sql-tap/tkt-9a8b09f8e6.test.lua
index 854ed774f..083a87b45 100755
--- a/test/sql-tap/tkt-9a8b09f8e6.test.lua
+++ b/test/sql-tap/tkt-9a8b09f8e6.test.lua
@@ -1,6 +1,6 @@
  #!/usr/bin/env tarantool
  test = require("sqltester")
-test:plan(49)
+test:plan(47)

  --!./tcltestrunner.lua
  -- 2014 June 26
@@ -86,7 +86,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      2.1,
      [[
-        SELECT x FROM t1 WHERE x IN (1);
+        SELECT x FROM t1 WHERE CAST(x AS INTEGER) IN (1);
      ]], {
          -- <2.1>
          "1"
@@ -96,7 +96,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      2.2,
      [[
-        SELECT x FROM t1 WHERE x IN (1.0);
+        SELECT x FROM t1 WHERE CAST(x AS DOUBLE) IN (1);
      ]], {
          -- <2.2>
          "1"
@@ -126,7 +126,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      2.5,
      [[
-        SELECT x FROM t1 WHERE 1 IN (x);
+        SELECT x FROM t1 WHERE CAST(1 AS STRING) IN (x);
      ]], {
          -- <2.5>
          "1"
@@ -136,10 +136,9 @@ test:do_execsql_test(
  test:do_execsql_test(
      2.6,
      [[
-        SELECT x FROM t1 WHERE 1.0 IN (x);
+        SELECT x FROM t1 WHERE CAST(1.0 AS STRING) IN (x);
      ]], {
          -- <2.6>
-        "1"
          -- </2.6>
      })

@@ -186,21 +185,13 @@ test:do_execsql_test(
  test:do_execsql_test(
      3.3,
      [[
-        SELECT x FROM t2 WHERE x IN ('1');
+        SELECT x FROM t2 WHERE CAST(x AS STRING) IN ('1');
      ]], {
          -- <3.3>
+        1
          -- </3.3>
      })

-test:do_execsql_test(
-    3.4,
-    [[
-        SELECT x FROM t2 WHERE x IN ('1');
-    ]], {
-        -- <3.4>
-        -- </3.4>
-    })
-
  test:do_execsql_test(
      3.5,
      [[
@@ -224,21 +215,13 @@ test:do_execsql_test(
  test:do_execsql_test(
      3.7,
      [[
-        SELECT x FROM t2 WHERE '1' IN (x);
+        SELECT x FROM t2 WHERE CAST('1' AS INTEGER) IN (x);
      ]], {
          -- <3.7>
+        1
          -- </3.7>
      })

-test:do_execsql_test(
-    3.8,
-    [[
-        SELECT x FROM t2 WHERE '1' IN (x);
-    ]], {
-        -- <3.8>
-        -- </3.8>
-    })
-
  test:do_execsql_test(
      4.1,
      [[
@@ -262,17 +245,16 @@ test:do_execsql_test(
  test:do_execsql_test(
      4.3,
      [[
-        SELECT x FROM t3 WHERE x IN ('1');
+        SELECT x FROM t3 WHERE CAST(x AS STRING) IN ('1');
      ]], {
          -- <4.3>
-        1.0
          -- </4.3>
      })

  test:do_execsql_test(
      4.4,
      [[
-        SELECT x FROM t3 WHERE x IN ('1.0');
+        SELECT x FROM t3 WHERE CAST(x AS STRING) IN ('1.0');
      ]], {
          -- <4.4>
          1.0
@@ -302,20 +284,20 @@ test:do_execsql_test(
  test:do_execsql_test(
      4.7,
      [[
-        SELECT x FROM t3 WHERE '1' IN (x);
+        SELECT x FROM t3 WHERE CAST('1' AS DOUBLE) IN (x);
      ]], {
          -- <4.7>
-        1
+        1.0
          -- </4.7>
      })

  test:do_execsql_test(
      4.8,
      [[
-        SELECT x FROM t3 WHERE '1.0' IN (x);
+        SELECT x FROM t3 WHERE CAST('1.0' AS DOUBLE) IN (x);
      ]], {
          -- <4.8>
-        1
+        1.0
          -- </4.8>
      })

@@ -342,20 +324,20 @@ test:do_execsql_test(
  test:do_execsql_test(
      5.3,
      [[
-        SELECT x FROM t4 WHERE x IN ('1');
+        SELECT x FROM t4 WHERE CAST(x AS STRING) IN ('1');
      ]], {
          -- <5.3>
-
+
          -- </5.3>
      })

  test:do_execsql_test(
      5.4,
      [[
-        SELECT x FROM t4 WHERE x IN ('1.0');
+        SELECT x FROM t4 WHERE CAST(x AS STRING) IN ('1.0');
      ]], {
          -- <5.4>
-
+
          -- </5.4>
      })

@@ -372,7 +354,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      5.6,
      [[
-        SELECT x FROM t4 WHERE x IN ('1.11');
+        SELECT x FROM t4 WHERE CAST(x AS STRING) IN ('1.11');
      ]], {
          -- <5.6>
          1.11
@@ -402,20 +384,20 @@ test:do_execsql_test(
  test:do_execsql_test(
      5.9,
      [[
-        SELECT x FROM t4 WHERE '1' IN (x);
+        SELECT x FROM t4 WHERE CAST('1' AS DOUBLE) IN (x);
      ]], {
          -- <5.9>
-
+
          -- </5.9>
      })

  test:do_execsql_test(
      5.10,
      [[
-        SELECT x FROM t4 WHERE '1.0' IN (x);
+        SELECT x FROM t4 WHERE CAST('1.0' AS DOUBLE) IN (x);
      ]], {
          -- <5.10>
-
+
          -- </5.10>
      })

@@ -432,7 +414,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      5.12,
      [[
-        SELECT x FROM t4 WHERE '1.11' IN (x);
+        SELECT x FROM t4 WHERE CAST('1.11' AS DOUBLE) IN (x);
      ]], {
          -- <5.12>
          1.11
@@ -462,7 +444,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      6.3,
      [[
-        SELECT x, y FROM t5 WHERE x IN ('1');
+        SELECT x, y FROM t5 WHERE CAST(x AS STRING) IN ('1');
      ]], {
          -- <6.3>
          1, "one", 1, "two", 1, "three", 1.0, "four"
@@ -472,10 +454,10 @@ test:do_execsql_test(
  test:do_execsql_test(
      6.4,
      [[
-        SELECT x, y FROM t5 WHERE x IN ('1.0');
+        SELECT x, y FROM t5 WHERE CAST(x AS STRING) IN ('1.0');
      ]], {
          -- <6.4>
-        1, "one", 1, "two", 1, "three", 1.0, "four"
+
          -- </6.4>
      })

@@ -502,7 +484,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      6.7,
      [[
-        SELECT x, y FROM t5 WHERE '1' IN (x);
+        SELECT x, y FROM t5 WHERE CAST('1' AS INTEGER) IN (x);
      ]], {
          -- <6.7>
          1, "one", 1, "two", 1, "three", 1.0, "four"
@@ -512,7 +494,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      6.8,
      [[
-        SELECT x, y FROM t5 WHERE '1.0' IN (x);
+        SELECT x, y FROM t5 WHERE CAST('1.0' AS DOUBLE) IN (x);
      ]], {
          -- <6.8>
          1, "one", 1, "two", 1, "three", 1, "four"
diff --git a/test/sql-tap/tkt-f973c7ac31.test.lua 
b/test/sql-tap/tkt-f973c7ac31.test.lua
index 82bdb52f8..604a7e6bb 100755
--- a/test/sql-tap/tkt-f973c7ac31.test.lua
+++ b/test/sql-tap/tkt-f973c7ac31.test.lua
@@ -39,9 +39,8 @@ for tn, sql in ipairs(sqls) do
      test:do_execsql_test(
          "tkt-f973c7ac3-1."..tn..".1",
          [[
-            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='2' ORDER 
BY c2 DESC
+            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND CAST(c2 AS 
STRING)<='2' ORDER BY c2 DESC
          ]], {
-
          })

      test:do_execsql_test(
@@ -55,7 +54,7 @@ for tn, sql in ipairs(sqls) do
      test:do_execsql_test(
          "tkt-f973c7ac3-1."..tn..".3",
          [[
-            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='5' ORDER 
BY c2 DESC
+            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND CAST(c2 AS 
STRING)<='5' ORDER BY c2 DESC
          ]], {
              5, 5, 5, 4
          })
@@ -63,7 +62,7 @@ for tn, sql in ipairs(sqls) do
      test:do_execsql_test(
          "tkt-f973c7ac3-1."..tn..".4",
          [[
-            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<=5 ORDER 
BY c2 DESC
+            SELECT c1,c2 FROM t WHERE c1 = 5 AND CAST(c2 AS STRING)>'0' 
AND c2<=5 ORDER BY c2 DESC
          ]], {
              5, 5, 5, 4
          })
@@ -71,7 +70,7 @@ for tn, sql in ipairs(sqls) do
      test:do_execsql_test(
          "tkt-f973c7ac3-1."..tn..".5",
          [[
-            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<='5' 
ORDER BY c2 DESC
+            SELECT c1,c2 FROM t WHERE c1 = 5 AND CAST(c2 AS STRING)>'0' 
AND CAST(c2 AS STRING)<='5' ORDER BY c2 DESC
          ]], {
              5, 5, 5, 4
          })
@@ -79,9 +78,8 @@ for tn, sql in ipairs(sqls) do
      test:do_execsql_test(
          "tkt-f973c7ac3-1."..tn..".6",
          [[
-            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='2' ORDER 
BY c2 ASC
+            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND CAST(c2 AS 
STRING)<='2' ORDER BY c2 ASC
          ]], {
-
          })

      test:do_execsql_test(
@@ -95,7 +93,7 @@ for tn, sql in ipairs(sqls) do
      test:do_execsql_test(
          "tkt-f973c7ac3-1."..tn..".8",
          [[
-            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='5' ORDER 
BY c2 ASC
+            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND CAST(c2 AS 
STRING)<='5' ORDER BY c2 ASC
          ]], {
              5, 4, 5, 5
          })
@@ -103,7 +101,7 @@ for tn, sql in ipairs(sqls) do
      test:do_execsql_test(
          "tkt-f973c7ac3-1."..tn..".9",
          [[
-            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<=5 ORDER 
BY c2 ASC
+            SELECT c1,c2 FROM t WHERE c1 = 5 AND CAST(c2 AS STRING)>'0' 
AND c2<=5 ORDER BY c2 ASC
          ]], {
              5, 4, 5, 5
          })
@@ -111,7 +109,7 @@ for tn, sql in ipairs(sqls) do
      test:do_execsql_test(
          "tkt-f973c7ac3-1."..tn..".10",
          [[
-            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<='5' 
ORDER BY c2 ASC
+            SELECT c1,c2 FROM t WHERE c1 = 5 AND CAST(c2 AS STRING)>'0' 
AND CAST(c2 AS STRING)<='5' ORDER BY c2 ASC
          ]], {
              5, 4, 5, 5
          })
diff --git a/test/sql-tap/tkt3493.test.lua b/test/sql-tap/tkt3493.test.lua
index de77e61e9..82ba828d0 100755
--- a/test/sql-tap/tkt3493.test.lua
+++ b/test/sql-tap/tkt3493.test.lua
@@ -1,6 +1,6 @@
  #!/usr/bin/env tarantool
  test = require("sqltester")
-test:plan(26)
+test:plan(25)

  --!./tcltestrunner.lua
  -- 2008 October 13
@@ -45,7 +45,7 @@ test:do_execsql_test(
      [[
          SELECT
            CASE
-             WHEN B.val = 1 THEN 'XYZ'
+             WHEN B.val = '1' THEN 'XYZ'
               ELSE A.val
            END AS Col1
          FROM B
@@ -63,7 +63,7 @@ test:do_execsql_test(
      [[
          SELECT DISTINCT
            CASE
-             WHEN B.val = 1 THEN 'XYZ'
+             WHEN B.val = '1' THEN 'XYZ'
               ELSE A.val
            END AS Col1
          FROM B
@@ -79,7 +79,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "tkt3493-1.4",
      [[
-        SELECT b.val, CASE WHEN b.val = 1 THEN 'xyz' ELSE b.val END AS 
col1 FROM b;
+        SELECT b.val, CASE WHEN b.val = '1' THEN 'xyz' ELSE b.val END 
AS col1 FROM b;
      ]], {
          -- <tkt3493-1.4>
          "1", "xyz", "2", "2"
@@ -91,7 +91,7 @@ test:do_execsql_test(
      [[
          SELECT DISTINCT
            b.val,
-          CASE WHEN b.val = 1 THEN 'xyz' ELSE b.val END AS col1
+          CASE WHEN b.val = '1' THEN 'xyz' ELSE b.val END AS col1
          FROM b;
      ]], {
          -- <tkt3493-1.5>
@@ -126,23 +126,13 @@ test:do_execsql_test(
  test:do_execsql_test(
      "tkt3493-2.2.1",
      [[
-        SELECT a=123 FROM t1 GROUP BY a
+        SELECT a='123' FROM t1 GROUP BY a
      ]], {
          -- <tkt3493-2.2.1>
          true
          -- </tkt3493-2.2.1>
      })

-test:do_execsql_test(
-    "tkt3493-2.2.2",
-    [[
-        SELECT a=123 FROM t1
-    ]], {
-        -- <tkt3493-2.2.2>
-        true
-        -- </tkt3493-2.2.2>
-    })
-
  test:do_execsql_test(
      "tkt3493-2.2.3",
      [[
@@ -156,7 +146,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "tkt3493-2.2.4",
      [[
-        SELECT count(*), a=123 FROM t1
+        SELECT count(*), a='123' FROM t1
      ]], {
          -- <tkt3493-2.2.4>
          1, true
@@ -166,7 +156,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "tkt3493-2.2.5",
      [[
-        SELECT count(*), +a=123 FROM t1
+        SELECT count(*), +a='123' FROM t1
      ]], {
          -- <tkt3493-2.2.5>
          1, true
@@ -176,7 +166,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "tkt3493-2.3.3",
      [[
-        SELECT b='456' FROM t1 GROUP BY a
+        SELECT b = 456 FROM t1 GROUP BY a
      ]], {
          -- <tkt3493-2.3.3>
          true
@@ -186,7 +176,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "tkt3493-2.3.1",
      [[
-        SELECT b='456' FROM t1 GROUP BY b
+        SELECT b = 456 FROM t1 GROUP BY b
      ]], {
          -- <tkt3493-2.3.1>
          true
@@ -196,7 +186,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "tkt3493-2.3.2",
      [[
-        SELECT b='456' FROM t1
+        SELECT b = 456 FROM t1
      ]], {
          -- <tkt3493-2.3.2>
          true
@@ -206,7 +196,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "tkt3493-2.4.1",
      [[
-        SELECT typeof(a), a FROM t1 GROUP BY a HAVING a=123
+        SELECT typeof(a), a FROM t1 GROUP BY a HAVING a='123'
      ]], {
          -- <tkt3493-2.4.1>
          "string", "123"
@@ -216,7 +206,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "tkt3493-2.4.2",
      [[
-        SELECT typeof(a), a FROM t1 GROUP BY b HAVING a=123
+        SELECT typeof(a), a FROM t1 GROUP BY b HAVING a='123'
      ]], {
          -- <tkt3493-2.4.2>
          "string", "123"
@@ -226,7 +216,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "tkt3493-2.5.1",
      [[
-        SELECT typeof(b), b FROM t1 GROUP BY a HAVING b='456'
+        SELECT typeof(b), b FROM t1 GROUP BY a HAVING b=456
      ]], {
          -- <tkt3493-2.5.1>
          "integer", 456
@@ -236,7 +226,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "tkt3493-2.5.2",
      [[
-        SELECT typeof(b), b FROM t1 GROUP BY b HAVING b='456'
+        SELECT typeof(b), b FROM t1 GROUP BY b HAVING b=456
      ]], {
          -- <tkt3493-2.5.2>
          "integer", 456
diff --git a/test/sql-tap/transitive1.test.lua 
b/test/sql-tap/transitive1.test.lua
index 96895b4a7..cc7e066bf 100755
--- a/test/sql-tap/transitive1.test.lua
+++ b/test/sql-tap/transitive1.test.lua
@@ -63,7 +63,7 @@ test:do_execsql_test(
          INSERT INTO t2 VALUES(2, 20,20,'20');
          INSERT INTO t2 VALUES(3, 3,3,'3');

-        SELECT a,b,c FROM t2 WHERE a=b AND c=b AND c=20;
+        SELECT a,b,c FROM t2 WHERE a=b AND c=CAST(b AS STRING) AND c='20';
      ]], {
          -- <transitive1-200>
          20, 20, "20"
@@ -73,7 +73,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "transitive1-210",
      [[
-        SELECT a,b,c FROM t2 WHERE a=b AND c=b AND c>='20' ORDER BY +a;
+        SELECT a,b,c FROM t2 WHERE a=b AND c=CAST(b AS STRING) AND 
c>='20' ORDER BY +a;
      ]], {
          -- <transitive1-210>
          3, 3, "3", 20, 20, "20"
@@ -83,7 +83,7 @@ test:do_execsql_test(
  test:do_execsql_test(
      "transitive1-220",
      [[
-        SELECT a,b,c FROM t2 WHERE a=b AND c=b AND c<='20' ORDER BY +a;
+        SELECT a,b,c FROM t2 WHERE a=b AND c=CAST(b AS STRING) AND 
c<='20' ORDER BY +a;
      ]], {
          -- <transitive1-220>
          20, 20, "20", 100, 100, "100"
@@ -402,7 +402,7 @@ test:do_execsql_test(
      [[
          CREATE TABLE x(i INTEGER PRIMARY KEY, y TEXT);
          INSERT INTO x VALUES(10, '10');
-        SELECT * FROM x WHERE x.y>='1' AND x.y<'2' AND x.i=x.y;
+        SELECT * FROM x WHERE x.y>='1' AND x.y<'2' AND CAST(x.i AS 
STRING)=x.y;
      ]], {
          -- <transitive1-500>
          10, "10"
@@ -430,7 +430,7 @@ test:do_execsql_test(
      [[
          CREATE TABLE t3(i INTEGER PRIMARY KEY, t TEXT);
          INSERT INTO t3 VALUES(10, '10');
-        SELECT * FROM t3 WHERE i=t AND t = '10 ';
+        SELECT * FROM t3 WHERE CAST(i AS STRING)=t AND t = '10 ';
      ]], {
          -- <transitive1-520>

@@ -443,7 +443,7 @@ test:do_execsql_test(
          CREATE TABLE u1(x TEXT PRIMARY KEY, y INTEGER, z TEXT);
          CREATE INDEX i1 ON u1(x);
          INSERT INTO u1 VALUES('00013', 13, '013');
-        SELECT * FROM u1 WHERE x=y AND y=z AND z='013';
+        SELECT * FROM u1 WHERE CAST(x AS INTEGER)=y AND y=CAST(z AS 
INTEGER) AND z='013';
      ]], {
          -- <transitive1-530>
          "00013",13,"013"
diff --git a/test/sql-tap/where2.test.lua b/test/sql-tap/where2.test.lua
index f267be8e6..7348a855a 100755
--- a/test/sql-tap/where2.test.lua
+++ b/test/sql-tap/where2.test.lua
@@ -4,7 +4,7 @@ yaml = require("yaml")
  fio = require("fio")

  ffi = require("ffi")
-test:plan(74)
+test:plan(62)

  ffi.cdef[[
         int dup(int oldfd);
@@ -622,181 +622,12 @@ test:do_test(
          -- </where2-6.6>
      })

--- if X(356, "X!cmd", [=[["expr","[permutation] != 
\"no_optimization\""]]=])
--- then
-    -- Ticket #2249.  Make sure the OR optimization is not attempted if
-    -- comparisons between columns of different affinities are needed.
-    --
-    test:do_test(
-        "where2-6.7",
-        function()
-            test:execsql [[
-                CREATE TABLE t2249a(a TEXT PRIMARY KEY, x VARCHAR(100));
-                CREATE TABLE t2249b(b INTEGER PRIMARY KEY);
-                INSERT INTO t2249a(a) VALUES('0123');
-                INSERT INTO t2249b VALUES(123);
-            ]]
-            return queryplan([[
-    -- Because a is type TEXT and b is type INTEGER, both a and b
-    -- will attempt to convert to NUMERIC before the comparison.
-    -- They will thus compare equal.
-    --
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=b;
-  ]])
-        end, {
-            -- <where2-6.7>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.7>
-        })
-
-    test:do_test(
-        "where2-6.9",
-        function()
-            return queryplan([[
-    -- The + operator doesn't affect RHS.
-    --
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b;
-  ]])
-        end, {
-            -- <where2-6.9>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.9>
-        })
-
-    test:do_test(
-        "where2-6.9.2",
-        function()
-            -- The same thing but with the expression flipped around.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=a
-  ]])
-        end, {
-            -- <where2-6.9.2>
-            123, "0123","nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.9.2>
-        })
-
-    test:do_test(
-        "where2-6.10",
-        function()
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +a=+b;
-  ]])
-        end, {
-            -- <where2-6.10>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.10>
-        })
-
-    test:do_test(
-        "where2-6.11",
-        function()
-            -- This will not attempt the OR optimization because of the a=b
-            -- comparison.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=b OR a='hello';
-  ]])
-        end, {
-            -- <where2-6.11>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.11>
-        })
-
-    test:do_test(
-        "where2-6.11.2",
-        function()
-            -- Permutations of the expression terms.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE b=a OR a='hello';
-  ]])
-        end, {
-            -- <where2-6.11.2>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.11.2>
-        })
-
-    test:do_test(
-        "where2-6.11.3",
-        function()
-            -- Permutations of the expression terms.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE 'hello'=a OR b=a;
-  ]])
-        end, {
-            -- <where2-6.11.3>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.11.3>
-        })
-
-    test:do_test(
-        "where2-6.11.4",
-        function()
-            -- Permutations of the expression terms.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR b=a;
-  ]])
-        end, {
-            -- <where2-6.11.4>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.11.4>
-        })
-
-    -- These tests are not run if subquery support is not included in the
-    -- build. This is because these tests test the "a = 1 OR a = 2" to
-    -- "a IN (1, 2)" optimisation transformation, which is not enabled if
-    -- subqueries and the IN operator is not available.
-    --
-    test:do_test(
-        "where2-6.12",
-        function()
-            return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b OR a='hello';
-    ]])
-        end, {
-            -- <where2-6.12>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.12>
-        })
-
-    test:do_test(
-        "where2-6.12.2",
-        function()
-            return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR +b=a;
-    ]])
-        end, {
-            -- <where2-6.12.2>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.12.2>
-        })
-
-    test:do_test(
-        "where2-6.12.3",
-        function()
-            return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=a OR a='hello';
-    ]])
-        end, {
-            -- <where2-6.12.3>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.12.3>
-        })
-
-    test:do_test(
-        "where2-6.13",
-        function()
-            -- The addition of +a on the second term disabled the OR 
optimization.
-            -- But we should still get the same empty-set result as in 
where2-6.9.
-            return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b OR +a='hello';
-    ]])
-        end, {
-            -- <where2-6.13>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.13>
-        })
-
-
+    test:execsql [[
+        CREATE TABLE t2249a(a TEXT PRIMARY KEY, x VARCHAR(100));
+        CREATE TABLE t2249b(b INTEGER PRIMARY KEY);
+        INSERT INTO t2249a(a) VALUES('0123');
+        INSERT INTO t2249b VALUES(123);
+    ]]

      -- Variations on the order of terms in a WHERE clause in order
      -- to make sure the OR optimizer can recognize them all.
diff --git a/test/sql-tap/where5.test.lua b/test/sql-tap/where5.test.lua
index 3aefcaca5..a93ba7854 100755
--- a/test/sql-tap/where5.test.lua
+++ b/test/sql-tap/where5.test.lua
@@ -34,7 +34,7 @@ test:do_test("where5-1.0", function()
          INSERT INTO t3 SELECT CAST(x AS INTEGER) FROM t1;
      ]]
      return test:execsql [[
-        SELECT * FROM t1 WHERE x<0
+        SELECT * FROM t1 WHERE CAST(x AS INTEGER)<0
      ]]
  end, {
      -- <where5-1.0>
@@ -43,7 +43,7 @@ end, {
  })

  test:do_execsql_test("where5-1.1", [[
-    SELECT * FROM t1 WHERE x<=0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)<=0
  ]], {
      -- <where5-1.1>
      '-1', '0'
@@ -51,7 +51,7 @@ test:do_execsql_test("where5-1.1", [[
  })

  test:do_execsql_test("where5-1.2", [[
-    SELECT * FROM t1 WHERE x=0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)=0
  ]], {
      -- <where5-1.2>
      '0'
@@ -59,7 +59,7 @@ test:do_execsql_test("where5-1.2", [[
  })

  test:do_execsql_test("where5-1.3", [[
-    SELECT * FROM t1 WHERE x>=0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)>=0
  ]], {
      -- <where5-1.3>
      '0', '1'
@@ -67,7 +67,7 @@ test:do_execsql_test("where5-1.3", [[
  })

  test:do_execsql_test("where5-1.4", [[
-    SELECT * FROM t1 WHERE x>0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)>0
  ]], {
      -- <where5-1.4>
      '1'
@@ -75,7 +75,7 @@ test:do_execsql_test("where5-1.4", [[
  })

  test:do_execsql_test("where5-1.5", [[
-    SELECT * FROM t1 WHERE x<>0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)<>0
  ]], {
      -- <where5-1.5>
      '-1', '1'
diff --git a/test/sql/types.result b/test/sql/types.result
index 6b0f7a651..9099bcea4 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -339,12 +339,12 @@ box.execute("INSERT INTO tboolean VALUES (TRUE);")
  box.execute("SELECT * FROM tboolean WHERE s1 = x'44';")
  ---
  - null
-- 'Type mismatch: can not convert varbinary to boolean'
+- 'Type mismatch: can not convert boolean to varbinary'
  ...
  box.execute("SELECT * FROM tboolean WHERE s1 = 'abc';")
  ---
  - null
-- 'Type mismatch: can not convert abc to boolean'
+- 'Type mismatch: can not convert boolean to text'
  ...
  box.execute("SELECT * FROM tboolean WHERE s1 = 1;")
  ---
@@ -606,14 +606,6 @@ box.execute("SELECT 18446744073709551615.0 > 
18446744073709551615")
    rows:
    - [true]
  ...
-box.execute("SELECT 18446744073709551615 IN ('18446744073709551615', 
18446744073709551615.0)")
----
-- metadata:
-  - name: 18446744073709551615 IN ('18446744073709551615', 
18446744073709551615.0)
-    type: boolean
-  rows:
-  - [true]
-...
  box.execute("SELECT 1 LIMIT 18446744073709551615;")
  ---
  - metadata:
diff --git a/test/sql/types.test.lua b/test/sql/types.test.lua
index bd14b342d..f9603c60d 100644
--- a/test/sql/types.test.lua
+++ b/test/sql/types.test.lua
@@ -151,7 +151,6 @@ box.execute("SELECT 18446744073709551610 - 
18446744073709551615;")
  box.execute("SELECT 18446744073709551615 = null;")
  box.execute("SELECT 18446744073709551615 = 18446744073709551615.0;")
  box.execute("SELECT 18446744073709551615.0 > 18446744073709551615")
-box.execute("SELECT 18446744073709551615 IN ('18446744073709551615', 
18446744073709551615.0)")
  box.execute("SELECT 1 LIMIT 18446744073709551615;")
  box.execute("SELECT 1 LIMIT 1 OFFSET 18446744073709551614;")
  box.execute("SELECT CAST('18446744073' || '709551616' AS INTEGER);")

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Tarantool-patches] [PATCH 1/6] sql: remove implicit cast for assignment
  2020-06-09 11:41     ` Mergen Imeev
@ 2020-06-09 22:28       ` Vladislav Shpilevoy
  0 siblings, 0 replies; 21+ messages in thread
From: Vladislav Shpilevoy @ 2020-06-09 22:28 UTC (permalink / raw)
  To: Mergen Imeev, tsafin, tarantool-patches

Hi! Thanks for the patch!

>>> +    ]], {
>>> +        0
>>> +    })
>>> +
>>> diff --git a/test/sql-tap/numcast.test.lua b/test/sql-tap/numcast.test.lua
>>> index eeac5353a..9bbae5ca4 100755
>>> --- a/test/sql-tap/numcast.test.lua
>>> +++ b/test/sql-tap/numcast.test.lua
>>> @@ -135,7 +135,7 @@ test:do_catchsql_test(
>>>           INSERT INTO t VALUES(20000000000000000000.01);
>>>           SELECT * FROM t;
>>>       ]], {
>>> -        1,"Tuple field 1 type does not match one required by operation: expected integer"
>>> +        1,"Type mismatch: can not convert real to integer"
>> 8. Is it correct, that we can remove all the checks from OP_CheckType
>> except numeric conversions, and everything will work fine, because
>> box makes the type checks anyway? It seems OP_CheckType duplicates
>> box's work.
> This is correct in most cases. We will lose the implicit cast
> between numeric values, but this can be done, for example, during
> MakeRecord. In addition, all type mismatch errors will look the
> same as in Lua.

I didn't meant to remove number casts. Only non-numeric checks.
For example, if mem_check_type is called on a string, and target
is number, we can ignore that, and let box raise an error.

This should become even simpler, when MEM_<type> flags are
replaced with enum field_type.

Please, do it here, if it is easy, or file a new ticket (I mean
error fallthrough down to box, not MEM_<type> removal).

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Tarantool-patches] [PATCH 4/6] sql: remove mem_apply_type() from OP_MustBeInt
  2020-06-09 11:47     ` Mergen Imeev
@ 2020-06-09 22:28       ` Vladislav Shpilevoy
  0 siblings, 0 replies; 21+ messages in thread
From: Vladislav Shpilevoy @ 2020-06-09 22:28 UTC (permalink / raw)
  To: Mergen Imeev, tsafin, tarantool-patches

Thanks for the patch!

See 2 comments below.

> diff --git a/test/sql-tap/join.test.lua b/test/sql-tap/join.test.lua
> index 840b780a3..51e0ecb79 100755
> --- a/test/sql-tap/join.test.lua
> +++ b/test/sql-tap/join.test.lua
> @@ -1034,7 +1034,6 @@ test:do_execsql_test(
>          SELECT * FROM t1 NATURAL JOIN t2
>      ]], {
>          -- <join-11.9>
> -        "one", "1", "two", "2"
>          -- </join-11.9>
>      })

1. Why does "join-11.10" still work? I see it started failing
in the next commits, but why not here?

> diff --git a/test/sql-tap/tkt-9a8b09f8e6.test.lua b/test/sql-tap/tkt-9a8b09f8e6.test.lua
> index cb5348ab4..854ed774f 100755
> --- a/test/sql-tap/tkt-9a8b09f8e6.test.lua
> +++ b/test/sql-tap/tkt-9a8b09f8e6.test.lua
> @@ -189,7 +189,6 @@ test:do_execsql_test(
>          SELECT x FROM t2 WHERE x IN ('1');
>      ]], {
>          -- <3.3>
> -        1
>          -- </3.3>
>      })
> 
> @@ -199,7 +198,6 @@ test:do_execsql_test(
>          SELECT x FROM t2 WHERE x IN ('1');
>      ]], {
>          -- <3.4>
> -        1
>          -- </3.4>
>      })
> 
> @@ -229,7 +227,6 @@ test:do_execsql_test(
>          SELECT x FROM t2 WHERE '1' IN (x);
>      ]], {
>          -- <3.7>
> -        1
>          -- </3.7>
>      })
> 
> @@ -239,7 +236,6 @@ test:do_execsql_test(
>          SELECT x FROM t2 WHERE '1' IN (x);
>      ]], {
>          -- <3.8>
> -        1
>          -- </3.8>

2. 3.7 and 3.8 are absolutely the same. Maybe better to drop
one of them. The same about 3.4 <-> 3.3.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Tarantool-patches] [PATCH 5/6] sql: remove implicit cast from string for comparison
  2020-06-09 11:51     ` Mergen Imeev
@ 2020-06-09 22:29       ` Vladislav Shpilevoy
  0 siblings, 0 replies; 21+ messages in thread
From: Vladislav Shpilevoy @ 2020-06-09 22:29 UTC (permalink / raw)
  To: Mergen Imeev, tsafin, tarantool-patches

Thanks for the patch!

>>> index 854ed774f..2a18b17be 100755
>>> --- a/test/sql-tap/tkt-9a8b09f8e6.test.lua
>>> +++ b/test/sql-tap/tkt-9a8b09f8e6.test.lua
>>> @@ -83,23 +83,23 @@ test:do_execsql_test(
>>>           -- </1.5>
>>>       })
>>>   -test:do_execsql_test(
>>> +test:do_catchsql_test(
>>>       2.1,
>>>       [[
>>>           SELECT x FROM t1 WHERE x IN (1);
>>>       ]], {
>>>           -- <2.1>
>>> -        "1"
>>> +        1,"Type mismatch: can not convert 1 to numeric"
>> 3. Can tests in this file be fixed to return the same results
>> as before?
> I fixed this in most cases, but am not sure if this is correct.
> I think most tests are out of date.

Yeah, looks like the test file becomes mostly useless. It now
tests rather explicit CAST than implicit cast. The previous
version was better. At least it covered implicit cast errors.

I would try to rollback to the previous version, remove obviously
duplicated or not needed test cases, and see what is left.
Probably the whole test file is useless.

See 6 comments below.

> sql: remove implicit cast from string for comparison
> 
> This patch removes implicit cast from strings to numbers for
> comparison.
> 
> Closes #4230
> 
> @TarantoolBot document
> Title: remove implicit cast between strings and numbers
> 
> This patch-set removes implicit cast from string to number and
> from number to string.
> 
> Example:
> 
> For comparison:
> 
> tarantool> box.execute([[SELECT '1' > 0;]])
> ---
> - null
> - 'Type mismatch: can not convert 1 to numeric'
> ...
> 
> tarantool> box.execute([[SELECT "id" FROM "_space" WHERE '1' > "id";]])
> ---
> - null
> - 'Type mismatch: can not convert text to unsigned'
> ...
> 
> For assignment:
> 
> tarantool> box.execute([[CREATE TABLE t1(i INT PRIMARY KEY);]])
> tarantool> box.execute([[INSERT INTO t1 VALUES ('1');]])
> ---
> - null
> - 'Type mismatch: can not convert text to integer'
> ...
> 
> tarantool> box.execute([[CREATE TABLE t2(t text PRIMARY KEY);]])
> tarantool> box.execute([[INSERT INTO t2 VALUES (1);]])
> ---
> - null
> - 'Type mismatch: can not convert unsigned to string'
> ...

1. I suggest to wrap code samples into ``` to produce more
readable github markdown in the resulting doc issue.

> review fix

2. Hm.

> diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
> index 6d8768865..1d7c76670 100644
> --- a/src/box/sql/wherecode.c
> +++ b/src/box/sql/wherecode.c
> @@ -335,72 +335,6 @@ disableTerm(WhereLevel * pLevel, WhereTerm * pTerm)
>      }
>  }
> 
> -/**
> - * Code an OP_ApplyType opcode to apply the column type string
> - * @types to the n registers starting at @base.
> - *
> - * As an optimization, SCALAR entries (which are no-ops) at the
> - * beginning and end of @types are ignored.  If all entries in
> - * @types are SCALAR, then no code gets generated.
> - *
> - * This routine makes its own copy of @types so that the caller is
> - * free to modify @types after this routine returns.
> - */
> -static void
> -emit_apply_type(Parse *pParse, int base, int n, enum field_type *types)
> -{
> -    Vdbe *v = pParse->pVdbe;
> -    if (types == NULL) {
> -        assert(pParse->db->mallocFailed);
> -        return;
> -    }
> -    assert(v != 0);
> -
> -    /*
> -     * Adjust base and n to skip over SCALAR entries at the
> -     * beginning and end of the type sequence.
> -     */
> -    while (n > 0 && types[0] == FIELD_TYPE_SCALAR) {
> -        n--;
> -        base++;
> -        types++;
> -    }
> -    while (n > 1 && types[n - 1] == FIELD_TYPE_SCALAR) {
> -        n--;
> -    }
> -
> -    if (n > 0) {
> -        enum field_type *types_dup = field_type_sequence_dup(pParse,
> -                                     types, n);

3. This function is now unused and can be deleted.

> -        sqlVdbeAddOp4(v, OP_ApplyType, base, n, 0,
> -                  (char *) types_dup, P4_DYNAMIC);
> -        sql_expr_type_cache_change(pParse, base, n);
> -    }
> -}
> -
> -/**
> - * Expression @rhs, which is the RHS of a comparison operation, is
> - * either a vector of n elements or, if n==1, a scalar expression.
> - * Before the comparison operation, types @types are to be applied
> - * to the @rhs values. This function modifies entries within the
> - * field sequence to SCALAR if either:
> - *
> - *   * the comparison will be performed with no type, or
> - *   * the type change in @types is guaranteed not to change the value.
> - */
> -static void
> -expr_cmp_update_rhs_type(struct Expr *rhs, int n, enum field_type *types)
> -{
> -    for (int i = 0; i < n; i++) {
> -        Expr *p = sqlVectorFieldSubexpr(rhs, i);
> -        enum field_type expr_type = sql_expr_type(p);
> -        if (sql_type_result(expr_type, types[i]) == FIELD_TYPE_SCALAR ||
> -            sql_expr_needs_no_type_change(p, types[i])) {

4. Ditto (removed in the next commit, up to you if want to remove
here).

> -            types[i] = FIELD_TYPE_SCALAR;
> -        }
> -    }
> -}
> diff --git a/test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua b/test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua
> new file mode 100755
> index 000000000..ef4127e0e
> --- /dev/null
> +++ b/test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua
> @@ -0,0 +1,78 @@
> +#!/usr/bin/env tarantool
> +test = require("sqltester")
> +test:plan(8)
> +
> +--
> +-- Make sure that there is no implicit cast between string and
> +-- number.
> +--
> +test:do_catchsql_test(
> +    "gh-4230-1",
> +    [[
> +        SELECT '1' > 0;
> +    ]], {
> +        1, "Type mismatch: can not convert 1 to numeric"
> +    })
> +
> +test:do_catchsql_test(
> +    "gh-4230-2",
> +    [[
> +        SELECT 0 > '1';
> +    ]], {
> +        1, "Type mismatch: can not convert 1 to numeric"

5. The error messages are really weird. We should probably wrap
string value into quoutes. Or print it as 'text'. Without a
value. Not necessarily here. You can create an issue for that,
and do it later.

> diff --git a/test/sql-tap/tkt-f973c7ac31.test.lua b/test/sql-tap/tkt-f973c7ac31.test.lua
> index 82bdb52f8..604a7e6bb 100755
> --- a/test/sql-tap/tkt-f973c7ac31.test.lua
> +++ b/test/sql-tap/tkt-f973c7ac31.test.lua
> @@ -39,9 +39,8 @@ for tn, sql in ipairs(sqls) do
>      test:do_execsql_test(
>          "tkt-f973c7ac3-1."..tn..".1",
>          [[
> -            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='2' ORDER BY c2 DESC
> +            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND CAST(c2 AS STRING)<='2' ORDER BY c2 DESC

6. On the branch I see trailing whitespaces in this file.

>          ]], {
> -
>          })
> 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Tarantool-patches] [PATCH 6/6] sql: remove OP_ApplyType
  2020-05-28 14:17 ` [Tarantool-patches] [PATCH 6/6] sql: remove OP_ApplyType Mergen Imeev
@ 2020-06-09 22:29   ` Vladislav Shpilevoy
  0 siblings, 0 replies; 21+ messages in thread
From: Vladislav Shpilevoy @ 2020-06-09 22:29 UTC (permalink / raw)
  To: Mergen Imeev, tsafin, tarantool-patches

Thanks for the patch!

> diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
> index 1d7c76670..1ec9f4ed7 100644
> --- a/src/box/sql/wherecode.c
> +++ b/src/box/sql/wherecode.c
> @@ -571,7 +571,7 @@ codeEqualityTerm(Parse * pParse,	/* The parsing context */
>   *
>   * Before returning, @types is set to point to a buffer containing a
>   * copy of the column types array of the index allocated using
> - * sqlDbMalloc(). This array is passed to OP_ApplyType to provide
> + * sqlDbMalloc(). This array is passed to OP_CheckType to provide

@types parameter does not exist anymore. I guess it was removed in
one of the previous commits, and the comment should be updated there
too.

>   * correct implicit conversions.
>   */
>  static int

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2020-06-09 22:29 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-28 14:17 [Tarantool-patches] [PATCH 0/6] Remove implicit cast Mergen Imeev
2020-05-28 14:17 ` [Tarantool-patches] [PATCH 1/6] sql: remove implicit cast for assignment Mergen Imeev
2020-06-01 17:03   ` Vladislav Shpilevoy
2020-06-09 11:41     ` Mergen Imeev
2020-06-09 22:28       ` Vladislav Shpilevoy
2020-05-28 14:17 ` [Tarantool-patches] [PATCH 2/6] sql: remove mem_apply_type() from OP_MakeRecord Mergen Imeev
2020-06-01 17:03   ` Vladislav Shpilevoy
2020-06-09 11:43     ` Mergen Imeev
2020-05-28 14:17 ` [Tarantool-patches] [PATCH 3/6] sql: replace ApplyType by CheckType for IN operator Mergen Imeev
2020-05-28 14:17 ` [Tarantool-patches] [PATCH 4/6] sql: remove mem_apply_type() from OP_MustBeInt Mergen Imeev
2020-06-01 17:04   ` Vladislav Shpilevoy
2020-06-09 11:47     ` Mergen Imeev
2020-06-09 22:28       ` Vladislav Shpilevoy
2020-05-28 14:17 ` [Tarantool-patches] [PATCH 5/6] sql: remove implicit cast from string for comparison Mergen Imeev
2020-06-01 17:04   ` Vladislav Shpilevoy
2020-06-09 11:51     ` Mergen Imeev
2020-06-09 22:29       ` Vladislav Shpilevoy
2020-05-28 14:17 ` [Tarantool-patches] [PATCH 6/6] sql: remove OP_ApplyType Mergen Imeev
2020-06-09 22:29   ` Vladislav Shpilevoy
2020-06-01 17:03 ` [Tarantool-patches] [PATCH 0/6] Remove implicit cast Vladislav Shpilevoy
2020-06-09 11:25   ` Mergen Imeev

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox