Tarantool development patches archive
 help / color / mirror / Atom feed
* [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment
@ 2020-07-14 15:48 imeevma
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 01/17] sql: set field_type in mem_set_*() functions imeevma
                   ` (16 more replies)
  0 siblings, 17 replies; 20+ messages in thread
From: imeevma @ 2020-07-14 15:48 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

This patch-set changes implicit cast for assignment.

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

@ChangeLog
 - [Breaking change] Define new rules for implicit cast for assignment (gh-3809).

v2:
 - Added a commit that changes the type mismatch error
   description.

v3:
 - Introduction of mem_set_double() was moved to another commit.
 - Implicit cast rules for assigning were changed.

v4:
 - Added type checking and implicit casting of arguments to
   built-in functions.
 - Removed unnecessary patches from the set.
 - Now this patch-set fixes implicit cast only for assignment.

v5:
 - Removed unnecessary patches from the set.
 - The patch that changes the type checking of arguments to
   built-in functions is divided into 15 patches.

Mergen Imeev (17):
  sql: set field_type in mem_set_*() functions
  sql: change implicit cast for assignment
  sql: use ApplyType to check function arguments
  sql: check args of abs()
  sql: check args of avg(), sum() and total()
  sql: check args of char()
  sql: check args of length()
  sql: check operands of LIKE
  sql: check args of lower() and upper()
  sql: check args of position()
  sql: check args of randomblob()
  sql: check args of replace()
  sql: check args of round()
  sql: check args of soundex()
  sql: check args of substr()
  sql: check args of unicode()
  sql: check args of zeroblob()

 src/box/sql/expr.c                   |   2 +
 src/box/sql/func.c                   | 437 ++++++++-----
 src/box/sql/select.c                 |  35 +
 src/box/sql/sqlInt.h                 |  35 +
 src/box/sql/vdbe.c                   | 184 +++++-
 src/box/sql/vdbeInt.h                |   4 +
 src/box/sql/vdbemem.c                |  10 +
 test/sql-tap/autoinc.test.lua        |   2 +-
 test/sql-tap/cse.test.lua            |   8 +-
 test/sql-tap/default.test.lua        |   6 +-
 test/sql-tap/e_select1.test.lua      |  27 +-
 test/sql-tap/func.test.lua           |  44 +-
 test/sql-tap/func2.test.lua          |  18 +-
 test/sql-tap/func5.test.lua          | 936 ++++++++++++++++++++++++++-
 test/sql-tap/in3.test.lua            |  14 +-
 test/sql-tap/in4.test.lua            |  96 +--
 test/sql-tap/index1.test.lua         |  24 +-
 test/sql-tap/insert3.test.lua        |  10 +-
 test/sql-tap/intpkey.test.lua        | 133 +---
 test/sql-tap/limit.test.lua          |   2 +-
 test/sql-tap/minmax2.test.lua        |   6 +-
 test/sql-tap/misc1.test.lua          |  24 +-
 test/sql-tap/numcast.test.lua        |   6 +-
 test/sql-tap/orderby1.test.lua       |   2 +-
 test/sql-tap/position.test.lua       |   6 +-
 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/subquery.test.lua       |  69 +-
 test/sql-tap/tkt-3998683a16.test.lua |  26 +-
 test/sql-tap/tkt-54844eea3f.test.lua |   8 +-
 test/sql-tap/tkt-7bbfb7d442.test.lua |   4 +-
 test/sql-tap/tkt-9a8b09f8e6.test.lua |  62 +-
 test/sql-tap/tkt-f973c7ac31.test.lua |  18 +-
 test/sql-tap/tkt-fc7bd6358f.test.lua | 111 ----
 test/sql-tap/tkt1444.test.lua        |   4 +-
 test/sql-tap/tkt3493.test.lua        |   6 +-
 test/sql-tap/tkt3841.test.lua        |  12 +-
 test/sql-tap/transitive1.test.lua    |   4 +-
 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         | 908 --------------------------
 test/sql-tap/whereC.test.lua         |   8 +-
 test/sql/boolean.result              |  32 +-
 test/sql/collation.result            |   2 +-
 test/sql/types.result                | 684 ++++++++++++++++++--
 test/sql/types.test.lua              | 129 ++++
 50 files changed, 2440 insertions(+), 1772 deletions(-)
 delete mode 100755 test/sql-tap/tkt-fc7bd6358f.test.lua
 delete mode 100755 test/sql-tap/whereB.test.lua

-- 
2.25.1

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

* [Tarantool-patches] [PATCH v5 01/17] sql: set field_type in mem_set_*() functions
  2020-07-14 15:48 [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment imeevma
@ 2020-07-14 15:48 ` imeevma
  2020-07-15 12:22   ` Nikita Pettik
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 02/17] sql: change implicit cast for assignment imeevma
                   ` (15 subsequent siblings)
  16 siblings, 1 reply; 20+ messages in thread
From: imeevma @ 2020-07-14 15:48 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

After this patch, the mem_set _*() functions will set the mem field type
along with its MEM type flag. This will allow us to be sure that the MEM
type and field type are set correctly, which is important when
converting values from one type to another.

Needed for #3809
---
 src/box/sql/vdbemem.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c
index 2e0d0bc3b..8e9ebf7ab 100644
--- a/src/box/sql/vdbemem.c
+++ b/src/box/sql/vdbemem.c
@@ -829,6 +829,7 @@ mem_set_bool(struct Mem *mem, bool value)
 	sqlVdbeMemSetNull(mem);
 	mem->u.b = value;
 	mem->flags = MEM_Bool;
+	mem->field_type = FIELD_TYPE_BOOLEAN;
 }
 
 void
@@ -839,6 +840,7 @@ mem_set_i64(struct Mem *mem, int64_t value)
 	mem->u.i = value;
 	int flag = value < 0 ? MEM_Int : MEM_UInt;
 	MemSetTypeFlag(mem, flag);
+	mem->field_type = FIELD_TYPE_INTEGER;
 }
 
 void
@@ -848,6 +850,7 @@ mem_set_u64(struct Mem *mem, uint64_t value)
 		sqlVdbeMemSetNull(mem);
 	mem->u.u = value;
 	MemSetTypeFlag(mem, MEM_UInt);
+	mem->field_type = FIELD_TYPE_UNSIGNED;
 }
 
 void
@@ -863,6 +866,7 @@ mem_set_int(struct Mem *mem, int64_t value, bool is_neg)
 		mem->u.u = value;
 		MemSetTypeFlag(mem, MEM_UInt);
 	}
+	mem->field_type = FIELD_TYPE_INTEGER;
 }
 
 void
@@ -873,6 +877,7 @@ mem_set_double(struct Mem *mem, double value)
 		return;
 	mem->u.r = value;
 	MemSetTypeFlag(mem, MEM_Real);
+	mem->field_type = FIELD_TYPE_DOUBLE;
 }
 
 /*
@@ -1068,6 +1073,11 @@ sqlVdbeMemSetStr(Mem * pMem,	/* Memory cell to set to string value */
 
 	pMem->n = nByte;
 	pMem->flags = flags;
+	assert((pMem->flags & (MEM_Str | MEM_Blob)) != 0);
+	if ((pMem->flags & MEM_Str) != 0)
+		pMem->field_type = FIELD_TYPE_STRING;
+	else
+		pMem->field_type = FIELD_TYPE_VARBINARY;
 
 	if (nByte > iLimit) {
 		diag_set(ClientError, ER_SQL_EXECUTE, "string or binary string"\
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v5 02/17] sql: change implicit cast for assignment
  2020-07-14 15:48 [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment imeevma
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 01/17] sql: set field_type in mem_set_*() functions imeevma
@ 2020-07-14 15:48 ` imeevma
  2020-07-15 13:41   ` Mergen Imeev
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 03/17] sql: use ApplyType to check function arguments imeevma
                   ` (14 subsequent siblings)
  16 siblings, 1 reply; 20+ messages in thread
From: imeevma @ 2020-07-14 15:48 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

This patch changes implicit cast for assignment.

Closes #3809
Needed for #4159
Part of #4230

@TarantoolBot document
Title: change implicit cast for comparison

After this patch, these rules will apply during the implicit cast:

| | STRING | BINARY | BOOLEAN | INTEGER | UNSIGNED | DOUBLE |
| :--- | :---: | :---: | :---: | :---: | :---: | :---: |
| STRING | A | N | N | N | N | N |
| BINARY | N | A | N | N | N | N |
| BOOLEAN | N | N | A | N | N | N |
| INTEGER | N | N | N | A | S | Aa |
| UNSIGNED | N | N | N | A | A | Aa |
| DOUBLE | N | N | N | Sa | Sa | A |

In this table, the types of the assigned value are on the left,
and the types that should be after the assignment are at the top.

'A' - the assignment will be completed.
'N' - the assignment won't be completed.
'S' - the appointment may be unsuccessful.
'a' - after assignment, the resulting value may be approximated.

Rules for numeric values are these:
1) Loss of significant digits (overflow) is an error.
2) Loss of insignificant digits is not an error.

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

tarantool> box.execute('INSERT INTO t1 VALUES (1.2345);')
tarantool> box.execute('SELECT * FROM t1;')
---
- metadata:
  - name: I
    type: integer
  rows:
  - [1]
...

tarantool> box.execute([[CREATE TABLE t2(t text PRIMARY KEY);]])
tarantool> box.execute([[INSERT INTO t2 VALUES (1);]])
---
- null
- 'Type mismatch: can not convert 1 to string'
...
```
---
 src/box/sql/vdbe.c                   | 168 ++++-
 src/box/sql/vdbeInt.h                |   4 +
 test/sql-tap/autoinc.test.lua        |   2 +-
 test/sql-tap/default.test.lua        |   6 +-
 test/sql-tap/e_select1.test.lua      |  27 +-
 test/sql-tap/in3.test.lua            |  14 +-
 test/sql-tap/in4.test.lua            |  96 +--
 test/sql-tap/index1.test.lua         |  24 +-
 test/sql-tap/insert3.test.lua        |  10 +-
 test/sql-tap/intpkey.test.lua        | 133 +---
 test/sql-tap/limit.test.lua          |   2 +-
 test/sql-tap/minmax2.test.lua        |   6 +-
 test/sql-tap/misc1.test.lua          |  24 +-
 test/sql-tap/numcast.test.lua        |   6 +-
 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/subquery.test.lua       |  69 +-
 test/sql-tap/tkt-3998683a16.test.lua |  26 +-
 test/sql-tap/tkt-54844eea3f.test.lua |   8 +-
 test/sql-tap/tkt-7bbfb7d442.test.lua |   4 +-
 test/sql-tap/tkt-9a8b09f8e6.test.lua |  62 +-
 test/sql-tap/tkt-f973c7ac31.test.lua |  18 +-
 test/sql-tap/tkt-fc7bd6358f.test.lua | 111 ----
 test/sql-tap/tkt1444.test.lua        |   4 +-
 test/sql-tap/tkt3493.test.lua        |   6 +-
 test/sql-tap/tkt3841.test.lua        |  12 +-
 test/sql-tap/transitive1.test.lua    |   4 +-
 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         | 908 ---------------------------
 test/sql-tap/whereC.test.lua         |   8 +-
 test/sql/types.result                | 620 ++++++++++++++++++
 test/sql/types.test.lua              | 129 ++++
 37 files changed, 1050 insertions(+), 1515 deletions(-)
 delete mode 100755 test/sql-tap/tkt-fc7bd6358f.test.lua
 delete mode 100755 test/sql-tap/whereB.test.lua

diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 950f72ddd..41a4750da 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -417,6 +417,144 @@ sql_value_apply_type(
 	mem_apply_type((Mem *) pVal, type);
 }
 
+/**
+ * Check that MEM_type of the mem is compatible with given type.
+ *
+ * @param mem The MEM that contains the value to check.
+ * @param type The type to check.
+ * @retval TRUE if the MEM_type of the value and the given type
+ *         are compatible, FALSE otherwise.
+ */
+static bool
+mem_is_type_compatible(struct Mem *mem, enum field_type type)
+{
+	enum mp_type mp_type = mem_mp_type(mem);
+	assert(mp_type < MP_EXT);
+	return field_mp_plain_type_is_compatible(type, mp_type, true);
+}
+
+/**
+ * Convert the numeric value contained in MEM to double. If the
+ * is_precise flag is set, the conversion will succeed only if it
+ * is lossless.
+ *
+ * @param mem The MEM that contains the numeric value.
+ * @param is_precise Flag.
+ * @retval 0 if the conversion was successful, -1 otherwise.
+ */
+static int
+mem_convert_to_double(struct Mem *mem, bool is_precise)
+{
+	if ((mem->flags & MEM_Real) != 0)
+		return 0;
+	if ((mem->flags & (MEM_Int | MEM_UInt)) == 0)
+		return -1;
+	if ((mem->flags & MEM_Int) != 0) {
+		int64_t i = mem->u.i;
+		double d = (double)i;
+		if (!is_precise || i == (int64_t)d)
+			mem_set_double(mem, d);
+		else
+			return -1;
+	} else {
+		uint64_t u = mem->u.u;
+		double d = (double)u;
+		if (!is_precise || u == (uint64_t)d)
+			mem_set_double(mem, d);
+		else
+			return -1;
+	}
+	return 0;
+}
+
+/**
+ * Convert the numeric value contained in MEM to unsigned. If the
+ * is_precise flag is set, the conversion will succeed only if it
+ * is lossless.
+ *
+ * @param mem The MEM that contains the numeric value.
+ * @param is_precise Flag.
+ * @retval 0 if the conversion was successful, -1 otherwise.
+ */
+static int
+mem_convert_to_unsigned(struct Mem *mem, bool is_precise)
+{
+	if ((mem->flags & MEM_UInt) != 0)
+		return 0;
+	if ((mem->flags & MEM_Int) != 0)
+		return -1;
+	if ((mem->flags & MEM_Real) == 0)
+		return -1;
+	double d = mem->u.r;
+	if (d < 0.0 || d >= (double)UINT64_MAX)
+		return -1;
+	uint64_t u = (uint64_t)d;
+	if (!is_precise || d == (double)u)
+		mem_set_u64(mem, (uint64_t) d);
+	else
+		return -1;
+	return 0;
+}
+
+/**
+ * Convert the numeric value contained in MEM to integer. If the
+ * is_precise flag is set, the conversion will succeed only if it
+ * is lossless.
+ *
+ * @param mem The MEM that contains the numeric value.
+ * @param is_precise Flag.
+ * @retval 0 if the conversion was successful, -1 otherwise.
+ */
+static int
+mem_convert_to_integer(struct Mem *mem, bool is_precise)
+{
+	if ((mem->flags & (MEM_UInt | MEM_Int)) != 0)
+		return 0;
+	if ((mem->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 (!is_precise || d == (double)i)
+			mem_set_int(mem, (int64_t) d, d < 0);
+		else
+			return -1;
+	} else {
+		uint64_t u = (uint64_t)d;
+		if (!is_precise || d == (double)u)
+			mem_set_int(mem, (uint64_t) d, false);
+		else
+			return -1;
+	}
+	return 0;
+}
+
+/**
+ * Convert the numeric value contained in MEM to another numeric
+ * type. If the is_precise flag is set, the conversion will
+ * succeed only if it is lossless.
+ *
+ * @param mem The MEM that contains the numeric value.
+ * @param type The type to convert to.
+ * @param is_precise Flag.
+ * @retval 0 if the conversion was successful, -1 otherwise.
+ */
+static int
+mem_convert_to_numeric(struct Mem *mem, enum field_type type, bool is_precise)
+{
+	assert(mp_type_is_numeric(mem_mp_type(mem)) &&
+	       sql_type_is_numeric(type));
+	assert(type != FIELD_TYPE_NUMBER);
+	if (type == FIELD_TYPE_DOUBLE)
+		return mem_convert_to_double(mem, is_precise);
+	if (type == FIELD_TYPE_UNSIGNED)
+		return mem_convert_to_unsigned(mem, is_precise);
+	assert(type == FIELD_TYPE_INTEGER);
+	return mem_convert_to_integer(mem, is_precise);
+}
+
 /*
  * 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
@@ -2747,11 +2885,11 @@ case OP_Fetch: {
 /* 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.
+ * Check that types of P2 registers starting from register P1 are
+ * compatible with given field types in P4. If the MEM_type of the
+ * value and the given type are incompatible according to
+ * field_mp_plain_type_is_compatible(), but both are numeric,
+ * this opcode attempts to convert the value to the type.
  */
 case OP_ApplyType: {
 	enum field_type *types = pOp->p4.types;
@@ -2762,13 +2900,23 @@ case OP_ApplyType: {
 	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;
+		if (!mem_is_type_compatible(pIn1, type)) {
+			/* Implicit cast is allowed only to numeric type. */
+			if (!sql_type_is_numeric(type))
+				goto type_mismatch;
+			/* Implicit cast is allowed only from numeric type. */
+			if (!mp_type_is_numeric(mem_mp_type(pIn1)))
+				goto type_mismatch;
+			/* Try to convert numeric-to-numeric. */
+			if (mem_convert_to_numeric(pIn1, type, false) != 0)
+				goto type_mismatch;
 		}
 		pIn1++;
+		continue;
+type_mismatch:
+		diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+			 sql_value_to_diag_str(pIn1), field_type_strs[type]);
+		goto abort_due_to_error;
 	}
 	break;
 }
diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index 44c27bdb7..ad46ab129 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -566,6 +566,10 @@ mem_mp_type(struct Mem *mem);
  */
 #define mp_type_is_bloblike(X) ((X) == MP_BIN || (X) == MP_ARRAY || (X) == MP_MAP)
 
+/** Return TRUE if MP_type of X is numeric, FALSE otherwise. */
+#define mp_type_is_numeric(X) ((X) == MP_INT || (X) == MP_UINT ||\
+			       (X) == MP_DOUBLE)
+
 /**
  * Memory cell mem contains the context of an aggregate function.
  * This routine calls the finalize method for that function. The
diff --git a/test/sql-tap/autoinc.test.lua b/test/sql-tap/autoinc.test.lua
index 37e65e541..07442b60a 100755
--- a/test/sql-tap/autoinc.test.lua
+++ b/test/sql-tap/autoinc.test.lua
@@ -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..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
@@ -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>
 
@@ -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/in3.test.lua b/test/sql-tap/in3.test.lua
index e29db9d93..a6d842962 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/in4.test.lua b/test/sql-tap/in4.test.lua
index 8c6917379..5c01ccdab 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"
@@ -585,98 +585,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/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..684a24114 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(31)
 
 --!./tcltestrunner.lua
 -- 2001 September 15
@@ -770,142 +770,13 @@ 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",
-    [[
-        SELECT * FROM t1 WHERE a=1;
-    ]], {
-        -- <intpkey-13.1>
-        
-        -- </intpkey-13.1>
-    })
-
-test:do_execsql_test(
-    "intpkey-13.2",
-    [[
-        INSERT INTO t1 VALUES('1',2,3);
-        SELECT * FROM t1 WHERE a=1;
-    ]], {
-        -- <intpkey-13.2>
-        1, "2", "3"
-        -- </intpkey-13.2>
-    })
-
--- MUST_WORK_TEST
-if (0 > 0) then
-    -- Tarantool: issue submitted #2315
-    test:do_catchsql_test(
-        "intpkey-13.3",
-        [[
-            INSERT INTO t1 VALUES('1.5',3,4);
-        ]], {
-            -- <intpkey-13.3>
-            1, "datatype mismatch"
-            -- </intpkey-13.3>
-        })
-
-    test:do_catchsql_test(
-        "intpkey-13.4",
-        [[
-            INSERT INTO t1 VALUES(x'123456',3,4);
-        ]], {
-            -- <intpkey-13.4>
-            1, "datatype mismatch"
-            -- </intpkey-13.4>
-        })
-
-
-
-end
-test:do_catchsql_test(
-    "intpkey-13.5",
-    [[
-        INSERT INTO t1 VALUES('+1234567890',3,4);
-    ]], {
-        -- <intpkey-13.5>
-        0
-        -- </intpkey-13.5>
-    })
-
--- Compare an INTEGER PRIMARY KEY against a TEXT expression. The INTEGER
--- affinity should be applied to the text value before the comparison
--- takes place.
---
-test:do_execsql_test(
-    "intpkey-14.1",
-    [[
-        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);
-    ]], {
-        -- <intpkey-14.1>
-        
-        -- </intpkey-14.1>
-    })
-
-test:do_execsql_test(
-    "intpkey-14.2",
-    [[
-        SELECT * FROM t3 WHERE a>2;
-    ]], {
-        -- <intpkey-14.2>
-        3, 3, "3"
-        -- </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(
-    "intpkey-14.4",
-    [[
-        SELECT * FROM t3 WHERE a<'2';
-    ]], {
-        -- <intpkey-14.4>
-        1, 1, "one"
-        -- </intpkey-14.4>
-    })
-
-test:do_execsql_test(
-    "intpkey-14.5",
-    [[
-        SELECT * FROM t3 WHERE a<c;
-    ]], {
-        -- <intpkey-14.5>
-        1, 1, "one"
-        -- </intpkey-14.5>
-    })
-
-test:do_execsql_test(
-    "intpkey-14.6",
-    [[
-        SELECT * FROM t3 WHERE a=c;
-    ]], {
-        -- <intpkey-14.6>
-        2, 2, "2", 3, 3, "3"
-        -- </intpkey-14.6>
-    })
-
 -- Check for proper handling of primary keys greater than 2^31.
 -- Ticket #1188
 --
 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/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/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..c0136d04c 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)
@@ -176,7 +176,7 @@ test:do_test(
     "misc1-2.1",
     function()
         test:execsql([[
-            CREATE TABLE agger(one text primary key, two text, three text, four text);
+            CREATE TABLE agger(one int 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');
@@ -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..3161e48fa 100755
--- a/test/sql-tap/numcast.test.lua
+++ b/test/sql-tap/numcast.test.lua
@@ -135,16 +135,16 @@ 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 2.0e+19 to integer"
     })
 
-test:do_catchsql_test(
+test:do_execsql_test(
     "cast-2.9",
     [[
         INSERT INTO t VALUES(2.1);
         SELECT * FROM t;
     ]], {
-        1,"Tuple field 1 type does not match one required by operation: expected integer"
+        2, 9223372036854775808ULL, 18000000000000000000ULL
     })
 
 --
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/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-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/tkt-9a8b09f8e6.test.lua b/test/sql-tap/tkt-9a8b09f8e6.test.lua
index cb5348ab4..ca3a5427a 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
@@ -193,16 +193,6 @@ test:do_execsql_test(
         -- </3.3>
     })
 
-test:do_execsql_test(
-    3.4,
-    [[
-        SELECT x FROM t2 WHERE x IN ('1');
-    ]], {
-        -- <3.4>
-        1
-        -- </3.4>
-    })
-
 test:do_execsql_test(
     3.5,
     [[
@@ -233,16 +223,6 @@ test:do_execsql_test(
         -- </3.7>
     })
 
-test:do_execsql_test(
-    3.8,
-    [[
-        SELECT x FROM t2 WHERE '1' IN (x);
-    ]], {
-        -- <3.8>
-        1
-        -- </3.8>
-    })
-
 test:do_execsql_test(
     4.1,
     [[
@@ -263,23 +243,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 1 to number"
         -- </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 1.0 to number"
         -- </4.4>
     })
 
@@ -303,23 +283,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 1 to number"
         -- </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 1.0 to number"
         -- </4.8>
     })
 
@@ -343,23 +323,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 1 to number"
         -- </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 1.0 to number"
         -- </5.4>
     })
 
@@ -373,13 +353,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 1.11 to number"
         -- </5.6>
     })
 
@@ -403,23 +383,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 1 to number"
         -- </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 1.0 to number"
         -- </5.10>
     })
 
@@ -433,13 +413,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 1.11 to number"
         -- </5.12>
     })
 
diff --git a/test/sql-tap/tkt-f973c7ac31.test.lua b/test/sql-tap/tkt-f973c7ac31.test.lua
index 82bdb52f8..381f29c65 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/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/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/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/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
deleted file mode 100755
index d98645fdc..000000000
--- a/test/sql-tap/whereB.test.lua
+++ /dev/null
@@ -1,908 +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>
-    })
-
--- 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 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 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
diff --git a/test/sql/types.result b/test/sql/types.result
index 54aff460e..70fbbc5a2 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -2155,3 +2155,623 @@ box.execute([[SELECT * FROM "s" WHERE "id" = ?;]])
 s:drop()
 ---
 ...
+--
+-- gh-3809: Make sure there are no implicit casts during
+-- assignment, except for the implicit cast between numeric
+-- values.
+--
+-- Check INSERT.
+box.execute([[CREATE TABLE ti (a INT PRIMARY KEY AUTOINCREMENT, i INTEGER);]])
+---
+- row_count: 1
+...
+box.execute([[CREATE TABLE td (a INT PRIMARY KEY AUTOINCREMENT, d DOUBLE);]])
+---
+- row_count: 1
+...
+box.execute([[CREATE TABLE tb (a INT PRIMARY KEY AUTOINCREMENT, b BOOLEAN);]])
+---
+- row_count: 1
+...
+box.execute([[CREATE TABLE tt (a INT PRIMARY KEY AUTOINCREMENT, t TEXT);]])
+---
+- row_count: 1
+...
+box.execute([[CREATE TABLE tv (a INT PRIMARY KEY AUTOINCREMENT, v VARBINARY);]])
+---
+- row_count: 1
+...
+box.execute([[CREATE TABLE ts (a INT PRIMARY KEY AUTOINCREMENT, s SCALAR);]])
+---
+- row_count: 1
+...
+box.execute([[INSERT INTO ti(i) VALUES (NULL);]])
+---
+- autoincrement_ids:
+  - 1
+  row_count: 1
+...
+box.execute([[INSERT INTO ti(i) VALUES (11);]])
+---
+- autoincrement_ids:
+  - 2
+  row_count: 1
+...
+box.execute([[INSERT INTO ti(i) VALUES (100000000000000000000000000000000.1);]])
+---
+- null
+- 'Type mismatch: can not convert 1.0e+32 to integer'
+...
+box.execute([[INSERT INTO ti(i) VALUES (33.0);]])
+---
+- autoincrement_ids:
+  - 3
+  row_count: 1
+...
+box.execute([[INSERT INTO ti(i) VALUES (true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to integer'
+...
+box.execute([[INSERT INTO ti(i) VALUES ('33');]])
+---
+- null
+- 'Type mismatch: can not convert 33 to integer'
+...
+box.execute([[INSERT INTO ti(i) VALUES (X'3434');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to integer'
+...
+box.execute([[SELECT * FROM ti;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: I
+    type: integer
+  rows:
+  - [1, null]
+  - [2, 11]
+  - [3, 33]
+...
+box.execute([[INSERT INTO td(d) VALUES (NULL);]])
+---
+- autoincrement_ids:
+  - 1
+  row_count: 1
+...
+box.execute([[INSERT INTO td(d) VALUES (11);]])
+---
+- autoincrement_ids:
+  - 2
+  row_count: 1
+...
+box.execute([[INSERT INTO td(d) VALUES (100000000000000001);;]])
+---
+- null
+- Syntax error at line 1 near ';'
+...
+box.execute([[INSERT INTO td(d) VALUES (22.2);]])
+---
+- autoincrement_ids:
+  - 3
+  row_count: 1
+...
+box.execute([[INSERT INTO td(d) VALUES (true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to double'
+...
+box.execute([[INSERT INTO td(d) VALUES ('33');]])
+---
+- null
+- 'Type mismatch: can not convert 33 to double'
+...
+box.execute([[INSERT INTO td(d) VALUES (X'3434');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to double'
+...
+box.execute([[SELECT * FROM td;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: D
+    type: double
+  rows:
+  - [1, null]
+  - [2, 11]
+  - [3, 22.2]
+...
+box.execute([[INSERT INTO tb(b) VALUES (NULL);]])
+---
+- autoincrement_ids:
+  - 1
+  row_count: 1
+...
+box.execute([[INSERT INTO tb(b) VALUES (11);]])
+---
+- null
+- 'Type mismatch: can not convert 11 to boolean'
+...
+box.execute([[INSERT INTO tb(b) VALUES (22.2);]])
+---
+- null
+- 'Type mismatch: can not convert 22.2 to boolean'
+...
+box.execute([[INSERT INTO tb(b) VALUES (true);]])
+---
+- autoincrement_ids:
+  - 2
+  row_count: 1
+...
+box.execute([[INSERT INTO tb(b) VALUES ('33');]])
+---
+- null
+- 'Type mismatch: can not convert 33 to boolean'
+...
+box.execute([[INSERT INTO tb(b) VALUES (X'3434');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to boolean'
+...
+box.execute([[SELECT * FROM tb;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: B
+    type: boolean
+  rows:
+  - [1, null]
+  - [2, true]
+...
+box.execute([[INSERT INTO tt(t) VALUES (NULL);]])
+---
+- autoincrement_ids:
+  - 1
+  row_count: 1
+...
+box.execute([[INSERT INTO tt(t) VALUES (11);]])
+---
+- null
+- 'Type mismatch: can not convert 11 to string'
+...
+box.execute([[INSERT INTO tt(t) VALUES (22.2);]])
+---
+- null
+- 'Type mismatch: can not convert 22.2 to string'
+...
+box.execute([[INSERT INTO tt(t) VALUES (true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string'
+...
+box.execute([[INSERT INTO tt(t) VALUES ('33');]])
+---
+- autoincrement_ids:
+  - 2
+  row_count: 1
+...
+box.execute([[INSERT INTO tt(t) VALUES (X'3434');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to string'
+...
+box.execute([[SELECT * FROM tt;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: T
+    type: string
+  rows:
+  - [1, null]
+  - [2, '33']
+...
+box.execute([[INSERT INTO tv(v) VALUES (NULL);]])
+---
+- autoincrement_ids:
+  - 1
+  row_count: 1
+...
+box.execute([[INSERT INTO tv(v) VALUES (11);]])
+---
+- null
+- 'Type mismatch: can not convert 11 to varbinary'
+...
+box.execute([[INSERT INTO tv(v) VALUES (22.2);]])
+---
+- null
+- 'Type mismatch: can not convert 22.2 to varbinary'
+...
+box.execute([[INSERT INTO tv(v) VALUES (true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to varbinary'
+...
+box.execute([[INSERT INTO tv(v) VALUES ('33');]])
+---
+- null
+- 'Type mismatch: can not convert 33 to varbinary'
+...
+box.execute([[INSERT INTO tv(v) VALUES (X'3434');]])
+---
+- autoincrement_ids:
+  - 2
+  row_count: 1
+...
+box.execute([[SELECT * FROM tv;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: V
+    type: varbinary
+  rows:
+  - [1, null]
+  - [2, '44']
+...
+box.execute([[INSERT INTO ts(s) VALUES (NULL);]])
+---
+- autoincrement_ids:
+  - 1
+  row_count: 1
+...
+box.execute([[INSERT INTO ts(s) VALUES (11);]])
+---
+- autoincrement_ids:
+  - 2
+  row_count: 1
+...
+box.execute([[INSERT INTO ts(s) VALUES (22.2);]])
+---
+- autoincrement_ids:
+  - 3
+  row_count: 1
+...
+box.execute([[INSERT INTO ts(s) VALUES (true);]])
+---
+- autoincrement_ids:
+  - 4
+  row_count: 1
+...
+box.execute([[INSERT INTO ts(s) VALUES ('33');]])
+---
+- autoincrement_ids:
+  - 5
+  row_count: 1
+...
+box.execute([[INSERT INTO ts(s) VALUES (X'3434');]])
+---
+- autoincrement_ids:
+  - 6
+  row_count: 1
+...
+box.execute([[SELECT * FROM ts;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: S
+    type: scalar
+  rows:
+  - [1, null]
+  - [2, 11]
+  - [3, 22.2]
+  - [4, true]
+  - [5, '33']
+  - [6, '44']
+...
+-- Check for UPDATE.
+box.execute([[DELETE FROM ti;]])
+---
+- row_count: 3
+...
+box.execute([[DELETE FROM td;]])
+---
+- row_count: 3
+...
+box.execute([[DELETE FROM tb;]])
+---
+- row_count: 2
+...
+box.execute([[DELETE FROM tt;]])
+---
+- row_count: 2
+...
+box.execute([[DELETE FROM tv;]])
+---
+- row_count: 2
+...
+box.execute([[DELETE FROM ts;]])
+---
+- row_count: 6
+...
+box.execute([[INSERT INTO ti VALUES(1, NULL);]])
+---
+- row_count: 1
+...
+box.execute([[INSERT INTO td VALUES(1, NULL);]])
+---
+- row_count: 1
+...
+box.execute([[INSERT INTO tb VALUES(1, NULL);]])
+---
+- row_count: 1
+...
+box.execute([[INSERT INTO tt VALUES(1, NULL);]])
+---
+- row_count: 1
+...
+box.execute([[INSERT INTO tv VALUES(1, NULL);]])
+---
+- row_count: 1
+...
+box.execute([[INSERT INTO ts VALUES(1, NULL);]])
+---
+- row_count: 1
+...
+box.execute([[SELECT * FROM ti, td, tb, tt, tv, ts;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: I
+    type: integer
+  - name: A
+    type: integer
+  - name: D
+    type: double
+  - name: A
+    type: integer
+  - name: B
+    type: boolean
+  - name: A
+    type: integer
+  - name: T
+    type: string
+  - name: A
+    type: integer
+  - name: V
+    type: varbinary
+  - name: A
+    type: integer
+  - name: S
+    type: scalar
+  rows:
+  - [1, null, 1, null, 1, null, 1, null, 1, null, 1, null]
+...
+box.execute([[UPDATE ti SET i = NULL WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE ti SET i = 11 WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE ti SET i = 100000000000000000000000000000000.1 WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 1.0e+32 to integer'
+...
+box.execute([[UPDATE ti SET i = 33.0 WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE ti SET i = true WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to integer'
+...
+box.execute([[UPDATE ti SET i = '33' WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 33 to integer'
+...
+box.execute([[UPDATE ti SET i = X'3434' WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to integer'
+...
+box.execute([[SELECT * FROM ti;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: I
+    type: integer
+  rows:
+  - [1, 33]
+...
+box.execute([[UPDATE td SET d = NULL WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE td SET d = 11 WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE td SET d = 100000000000000001 WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE td SET d = 22.2 WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE td SET d = true WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to double'
+...
+box.execute([[UPDATE td SET d = '33' WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 33 to double'
+...
+box.execute([[UPDATE td SET d = X'3434' WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to double'
+...
+box.execute([[SELECT * FROM td;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: D
+    type: double
+  rows:
+  - [1, 22.2]
+...
+box.execute([[UPDATE tb SET b = NULL WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE tb SET b = 11 WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 11 to boolean'
+...
+box.execute([[UPDATE tb SET b = 22.2 WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 22.2 to boolean'
+...
+box.execute([[UPDATE tb SET b = true WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE tb SET b = '33' WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 33 to boolean'
+...
+box.execute([[UPDATE tb SET b = X'3434' WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to boolean'
+...
+box.execute([[SELECT * FROM tb;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: B
+    type: boolean
+  rows:
+  - [1, true]
+...
+box.execute([[UPDATE tt SET t = NULL WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE tt SET t = 11 WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 11 to string'
+...
+box.execute([[UPDATE tt SET t = 22.2 WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 22.2 to string'
+...
+box.execute([[UPDATE tt SET t = true WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string'
+...
+box.execute([[UPDATE tt SET t = '33' WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE tt SET t = X'3434' WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to string'
+...
+box.execute([[SELECT * FROM tt;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: T
+    type: string
+  rows:
+  - [1, '33']
+...
+box.execute([[UPDATE tv SET v = NULL WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE tv SET v = 11 WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 11 to varbinary'
+...
+box.execute([[UPDATE tv SET v = 22.2 WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 22.2 to varbinary'
+...
+box.execute([[UPDATE tv SET v = true WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to varbinary'
+...
+box.execute([[UPDATE tv SET v = '33' WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 33 to varbinary'
+...
+box.execute([[UPDATE tv SET v = X'3434' WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[SELECT * FROM tv;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: V
+    type: varbinary
+  rows:
+  - [1, '44']
+...
+box.execute([[UPDATE ts SET s = NULL WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE ts SET s = 11 WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE ts SET s = 22.2 WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE ts SET s = true WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE ts SET s = '33' WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE ts SET s = X'3434' WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[SELECT * FROM ts;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: S
+    type: scalar
+  rows:
+  - [1, '44']
+...
diff --git a/test/sql/types.test.lua b/test/sql/types.test.lua
index bd14b342d..2dc70f3c5 100644
--- a/test/sql/types.test.lua
+++ b/test/sql/types.test.lua
@@ -487,3 +487,132 @@ s:format({ \
 
 box.execute([[SELECT * FROM "s" WHERE "id" = ?;]])
 s:drop()
+
+--
+-- gh-3809: Make sure there are no implicit casts during
+-- assignment, except for the implicit cast between numeric
+-- values.
+--
+
+-- Check INSERT.
+box.execute([[CREATE TABLE ti (a INT PRIMARY KEY AUTOINCREMENT, i INTEGER);]])
+box.execute([[CREATE TABLE td (a INT PRIMARY KEY AUTOINCREMENT, d DOUBLE);]])
+box.execute([[CREATE TABLE tb (a INT PRIMARY KEY AUTOINCREMENT, b BOOLEAN);]])
+box.execute([[CREATE TABLE tt (a INT PRIMARY KEY AUTOINCREMENT, t TEXT);]])
+box.execute([[CREATE TABLE tv (a INT PRIMARY KEY AUTOINCREMENT, v VARBINARY);]])
+box.execute([[CREATE TABLE ts (a INT PRIMARY KEY AUTOINCREMENT, s SCALAR);]])
+
+box.execute([[INSERT INTO ti(i) VALUES (NULL);]])
+box.execute([[INSERT INTO ti(i) VALUES (11);]])
+box.execute([[INSERT INTO ti(i) VALUES (100000000000000000000000000000000.1);]])
+box.execute([[INSERT INTO ti(i) VALUES (33.0);]])
+box.execute([[INSERT INTO ti(i) VALUES (true);]])
+box.execute([[INSERT INTO ti(i) VALUES ('33');]])
+box.execute([[INSERT INTO ti(i) VALUES (X'3434');]])
+box.execute([[SELECT * FROM ti;]])
+
+box.execute([[INSERT INTO td(d) VALUES (NULL);]])
+box.execute([[INSERT INTO td(d) VALUES (11);]])
+box.execute([[INSERT INTO td(d) VALUES (100000000000000001);;]])
+box.execute([[INSERT INTO td(d) VALUES (22.2);]])
+box.execute([[INSERT INTO td(d) VALUES (true);]])
+box.execute([[INSERT INTO td(d) VALUES ('33');]])
+box.execute([[INSERT INTO td(d) VALUES (X'3434');]])
+box.execute([[SELECT * FROM td;]])
+
+box.execute([[INSERT INTO tb(b) VALUES (NULL);]])
+box.execute([[INSERT INTO tb(b) VALUES (11);]])
+box.execute([[INSERT INTO tb(b) VALUES (22.2);]])
+box.execute([[INSERT INTO tb(b) VALUES (true);]])
+box.execute([[INSERT INTO tb(b) VALUES ('33');]])
+box.execute([[INSERT INTO tb(b) VALUES (X'3434');]])
+box.execute([[SELECT * FROM tb;]])
+
+box.execute([[INSERT INTO tt(t) VALUES (NULL);]])
+box.execute([[INSERT INTO tt(t) VALUES (11);]])
+box.execute([[INSERT INTO tt(t) VALUES (22.2);]])
+box.execute([[INSERT INTO tt(t) VALUES (true);]])
+box.execute([[INSERT INTO tt(t) VALUES ('33');]])
+box.execute([[INSERT INTO tt(t) VALUES (X'3434');]])
+box.execute([[SELECT * FROM tt;]])
+
+box.execute([[INSERT INTO tv(v) VALUES (NULL);]])
+box.execute([[INSERT INTO tv(v) VALUES (11);]])
+box.execute([[INSERT INTO tv(v) VALUES (22.2);]])
+box.execute([[INSERT INTO tv(v) VALUES (true);]])
+box.execute([[INSERT INTO tv(v) VALUES ('33');]])
+box.execute([[INSERT INTO tv(v) VALUES (X'3434');]])
+box.execute([[SELECT * FROM tv;]])
+
+box.execute([[INSERT INTO ts(s) VALUES (NULL);]])
+box.execute([[INSERT INTO ts(s) VALUES (11);]])
+box.execute([[INSERT INTO ts(s) VALUES (22.2);]])
+box.execute([[INSERT INTO ts(s) VALUES (true);]])
+box.execute([[INSERT INTO ts(s) VALUES ('33');]])
+box.execute([[INSERT INTO ts(s) VALUES (X'3434');]])
+box.execute([[SELECT * FROM ts;]])
+
+-- Check for UPDATE.
+box.execute([[DELETE FROM ti;]])
+box.execute([[DELETE FROM td;]])
+box.execute([[DELETE FROM tb;]])
+box.execute([[DELETE FROM tt;]])
+box.execute([[DELETE FROM tv;]])
+box.execute([[DELETE FROM ts;]])
+box.execute([[INSERT INTO ti VALUES(1, NULL);]])
+box.execute([[INSERT INTO td VALUES(1, NULL);]])
+box.execute([[INSERT INTO tb VALUES(1, NULL);]])
+box.execute([[INSERT INTO tt VALUES(1, NULL);]])
+box.execute([[INSERT INTO tv VALUES(1, NULL);]])
+box.execute([[INSERT INTO ts VALUES(1, NULL);]])
+box.execute([[SELECT * FROM ti, td, tb, tt, tv, ts;]])
+
+box.execute([[UPDATE ti SET i = NULL WHERE a = 1;]])
+box.execute([[UPDATE ti SET i = 11 WHERE a = 1;]])
+box.execute([[UPDATE ti SET i = 100000000000000000000000000000000.1 WHERE a = 1;]])
+box.execute([[UPDATE ti SET i = 33.0 WHERE a = 1;]])
+box.execute([[UPDATE ti SET i = true WHERE a = 1;]])
+box.execute([[UPDATE ti SET i = '33' WHERE a = 1;]])
+box.execute([[UPDATE ti SET i = X'3434' WHERE a = 1;]])
+box.execute([[SELECT * FROM ti;]])
+
+box.execute([[UPDATE td SET d = NULL WHERE a = 1;]])
+box.execute([[UPDATE td SET d = 11 WHERE a = 1;]])
+box.execute([[UPDATE td SET d = 100000000000000001 WHERE a = 1;]])
+box.execute([[UPDATE td SET d = 22.2 WHERE a = 1;]])
+box.execute([[UPDATE td SET d = true WHERE a = 1;]])
+box.execute([[UPDATE td SET d = '33' WHERE a = 1;]])
+box.execute([[UPDATE td SET d = X'3434' WHERE a = 1;]])
+box.execute([[SELECT * FROM td;]])
+
+box.execute([[UPDATE tb SET b = NULL WHERE a = 1;]])
+box.execute([[UPDATE tb SET b = 11 WHERE a = 1;]])
+box.execute([[UPDATE tb SET b = 22.2 WHERE a = 1;]])
+box.execute([[UPDATE tb SET b = true WHERE a = 1;]])
+box.execute([[UPDATE tb SET b = '33' WHERE a = 1;]])
+box.execute([[UPDATE tb SET b = X'3434' WHERE a = 1;]])
+box.execute([[SELECT * FROM tb;]])
+
+box.execute([[UPDATE tt SET t = NULL WHERE a = 1;]])
+box.execute([[UPDATE tt SET t = 11 WHERE a = 1;]])
+box.execute([[UPDATE tt SET t = 22.2 WHERE a = 1;]])
+box.execute([[UPDATE tt SET t = true WHERE a = 1;]])
+box.execute([[UPDATE tt SET t = '33' WHERE a = 1;]])
+box.execute([[UPDATE tt SET t = X'3434' WHERE a = 1;]])
+box.execute([[SELECT * FROM tt;]])
+
+box.execute([[UPDATE tv SET v = NULL WHERE a = 1;]])
+box.execute([[UPDATE tv SET v = 11 WHERE a = 1;]])
+box.execute([[UPDATE tv SET v = 22.2 WHERE a = 1;]])
+box.execute([[UPDATE tv SET v = true WHERE a = 1;]])
+box.execute([[UPDATE tv SET v = '33' WHERE a = 1;]])
+box.execute([[UPDATE tv SET v = X'3434' WHERE a = 1;]])
+box.execute([[SELECT * FROM tv;]])
+
+box.execute([[UPDATE ts SET s = NULL WHERE a = 1;]])
+box.execute([[UPDATE ts SET s = 11 WHERE a = 1;]])
+box.execute([[UPDATE ts SET s = 22.2 WHERE a = 1;]])
+box.execute([[UPDATE ts SET s = true WHERE a = 1;]])
+box.execute([[UPDATE ts SET s = '33' WHERE a = 1;]])
+box.execute([[UPDATE ts SET s = X'3434' WHERE a = 1;]])
+box.execute([[SELECT * FROM ts;]])
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v5 03/17] sql: use ApplyType to check function arguments
  2020-07-14 15:48 [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment imeevma
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 01/17] sql: set field_type in mem_set_*() functions imeevma
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 02/17] sql: change implicit cast for assignment imeevma
@ 2020-07-14 15:48 ` imeevma
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 04/17] sql: check args of abs() imeevma
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: imeevma @ 2020-07-14 15:48 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

Hi! Thank you for the review. My answers and new patch below.


On 13.07.2020 17:56, Nikita Pettik wrote:
> On 13 Jul 08:33, imeevma@tarantool.org wrote:
>> After this patch, the function arguments will be checked using ApplyType
>> opcode before they are passed to the function. This means that the rules
>> for implicitly casting values ​​that were specified as arguments are
>> defined by this opcode.
>>
>> Closes #4159
>> ---
>>  src/box/sql/expr.c                          |    5 +
>>  src/box/sql/func.c                          |  360 +++-
>>  src/box/sql/select.c                        |   31 +
>>  src/box/sql/sqlInt.h                        |   32 +
>>  src/box/sql/vdbe.c                          |   12 +-
>>  test/sql-tap/cse.test.lua                   |    8 +-
>>  test/sql-tap/func.test.lua                  |   48 +-
>>  test/sql-tap/orderby1.test.lua              |    2 +-
>>  test/sql-tap/position.test.lua              |    6 +-
>>  test/sql/boolean.result                     |   32 +-
>>  test/sql/gh-4159-function-argumens.result   | 2131 +++++++++++++++++--
>>  test/sql/gh-4159-function-argumens.test.sql |  272 +++
>>  test/sql/types.result                       |   76 +-
>>  test/sql/types.test.lua                     |    2 +-
>>  14 files changed, 2584 insertions(+), 433 deletions(-)
>>
>> diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
>> index 7aee240a3..aa5477c6a 100644
>> --- a/src/box/sql/expr.c
>> +++ b/src/box/sql/expr.c
>> @@ -4104,6 +4104,11 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
>>  			} else {
>>  				r1 = 0;
>>  			}
>> +			if (func->def->language == FUNC_LANGUAGE_SQL_BUILTIN) {
>> +				struct func_sql_builtin *f =
>> +					(struct func_sql_builtin *)func;
>> +				sql_emit_func_types(v, &f->args, r1, nFarg);
>> +			}
>>  			if (sql_func_flag_is_set(func, SQL_FUNC_NEEDCOLL)) {
>>  				sqlVdbeAddOp4(v, OP_CollSeq, 0, 0, 0,
>>  						  (char *)coll, P4_COLLSEQ);
>> diff --git a/src/box/sql/func.c b/src/box/sql/func.c
>> index 9d4c26081..66edc3792 100644
>> --- a/src/box/sql/func.c
>> +++ b/src/box/sql/func.c
>> @@ -459,17 +459,10 @@ static void
>>  lengthFunc(sql_context * context, int argc, sql_value ** argv)
>>  {
>>  	int len;
>> -
>>  	assert(argc == 1);
>>  	UNUSED_PARAMETER(argc);
>>  	switch (sql_value_type(argv[0])) {
>> -	case MP_BIN:
>> -	case MP_ARRAY:
>> -	case MP_MAP:
>> -	case MP_INT:
>> -	case MP_UINT:
>> -	case MP_BOOL:
>> -	case MP_DOUBLE:{
>> +	case MP_BIN: {
>
> Let's get rid of switch-cases, they are really redundant now.
> If you are afraid that diff will become big enough, you can
> refactor each function in a separate patch.
>
Done, in next patches.

>> @@ -1550,6 +1514,15 @@ replaceFunc(sql_context * context, int argc, sql_value ** argv)
>>  
>>  	assert(argc == 3);
>>  	UNUSED_PARAMETER(argc);
>> +	assert(sql_value_type(argv[0]) == MP_NIL ||
>> +	       sql_value_type(argv[0]) == MP_STR ||
>> +	       sql_value_type(argv[0]) == MP_BIN);
>
> Let's evaluate each type of argv only once.
>
Fixed, in next patches.

>> +	assert(sql_value_type(argv[1]) == MP_NIL ||
>> +	       sql_value_type(argv[1]) == MP_STR ||
>> +	       sql_value_type(argv[1]) == MP_BIN);
>> +	assert(sql_value_type(argv[2]) == MP_NIL ||
>> +	       sql_value_type(argv[2]) == MP_STR ||
>> +	       sql_value_type(argv[2]) == MP_BIN);
>>  	zStr = sql_value_text(argv[0]);
>>  	if (zStr == 0)
>>  		return;
>> @@ -1858,13 +1831,9 @@ soundexFunc(sql_context * context, int argc, sql_value ** argv)
>>  		1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
>>  	};
>>  	assert(argc == 1);
>> -	enum mp_type mp_type = sql_value_type(argv[0]);
>> -	if (mp_type_is_bloblike(mp_type)) {
>> -		diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
>> -			 sql_value_to_diag_str(argv[0]), "text");
>> -		context->is_aborted = true;
>> -		return;
>> -	}
>> +	assert(sql_value_type(argv[0]) == MP_NIL ||
>> +	       sql_value_type(argv[0]) == MP_STR ||
>> +	       sql_value_type(argv[0]) == MP_BIN);
>
> Ditto
>
>>  	zIn = (u8 *) sql_value_text(argv[0]);
>>  	if (zIn == 0)
>>  		zIn = (u8 *) "";
>>  	int param_count;
>>  	uint32_t min_count;
>>  	uint32_t max_count;
>> +	enum field_type *types;
>> +	enum field_type recurrent_type;
>> +	bool is_blob_like_str;
>
> What are these members supposed to mean?
>
Added comments.
>>  	enum field_type returns;
>>  	enum func_aggregate aggregate;
>>  	bool export_to_sql;
>> diff --git a/src/box/sql/select.c b/src/box/sql/select.c
>> index 4b069addb..fe56ede1b 100644
>> --- a/src/box/sql/select.c
>> +++ b/src/box/sql/select.c
>> @@ -124,6 +124,34 @@ clearSelect(sql * db, Select * p, int bFree)
>>  	}
>>  }
>>  
>> +void
>> +sql_emit_func_types(struct Vdbe *vdbe, struct sql_builtin_func_args *args,
>> +		    int reg, uint32_t argc)
>
> -> sql_emit_func_arg_type_check()
>
Thanks, fixed.

>> +{
>> +	assert(argc <= args->max_count);
>> +	enum field_type recurrent_type = args->recurrent_type;
>> +	assert(args->max_count > 0 || recurrent_type == FIELD_TYPE_ANY);
>> +	/*
>> +	 * It makes no sense to check types of the MEMs if all
>> +	 * arguments should be of type ANY.
>> +	 */
>> +	if (recurrent_type == FIELD_TYPE_ANY)
>> +		return;
>> +	size_t size = (argc + 1) * sizeof(enum field_type);
>> +	enum field_type *types = sqlDbMallocZero(sql_get(), size);
>> +	for (uint32_t i = 0; i < argc; ++i) {
>> +		if (args->types == NULL)
>> +			types[i] = args->recurrent_type;
>> +		else
>> +			types[i] = args->types[i];
>> +	}
>
> I don't understand what's going on here.
>
Changed this part of the function. Added comments.

>> +	types[argc] = field_type_MAX;
>> +	sqlVdbeAddOp4(vdbe, OP_ApplyType, reg, argc, 0, (char *)types,
>> +		      P4_DYNAMIC);
>> +	if (args->is_blob_like_str)
>> +		sqlVdbeChangeP5(vdbe, OPFLAG_BLOB_LIKE_STRING);
>> +}
>> +
>>  /*
>>   * Initialize a SelectDest structure.
>>   */
>>  void
>>  sql_emit_table_types(struct Vdbe *v, struct space_def *def, int reg);
>>  
>> +/**
>> + * Code an OP_ApplyType opcode that will force types for given
>
> Not force, but try to cast implicitly. Force cast is implemented as CAST
> operator.
>
Thanks, fixed.

>> + * range of register starting from @a reg. These values then will
>> + * be used as arguments of a function.
>> + *
>> + * @param vdbe VDBE.
>> + * @param args Information about arguments of the function.
>> + * @param reg Register where types will be placed.
>> + * @param argc Number of arguments.
>> + */
>> +void
>> +sql_emit_func_types(struct Vdbe *vdbe, struct sql_builtin_func_args *args,
>> +		    int reg, uint32_t argc);
>> +
>>  enum field_type
>>  sql_type_result(enum field_type lhs, enum field_type rhs);
>>  
>> @@ -4406,6 +4424,20 @@ struct sql_builtin_func_args {
>>  	uint32_t min_count;
>>  	/** Max number of arguments. */
>>  	uint32_t max_count;
>> +	/**
>> +	 * If function arguments may not be of the same type, all
>> +	 * argument types are described here.
>> +	 */
>> +	enum field_type *types;
>> +	/**
>> +	 * Contains the type of arguments if all arguments to the
>> +	 * function are of the same type.
>> +	 */
>> +	enum field_type recurrent_type;
>
> Recurrent is quite unsuitable name. Why not always use array
> of type? Is it big deal to fill and store it?
>
Fixed.

>> +	/**
>> +	 * TRUE if the function should treat the BLOB as STRING.
>> +	 */
>> +	bool is_blob_like_str;
>
> Why do you need this attribute?
>
>>  };
>>  
>>  struct func_sql_builtin {
>> diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
>> index 863f38f5d..a4bf84bcc 100644
>> --- a/src/box/sql/vdbe.c
>> +++ b/src/box/sql/vdbe.c
>> @@ -2882,7 +2882,7 @@ case OP_Fetch: {
>>  	break;
>>  }
>>  
>> -/* Opcode: ApplyType P1 P2 * P4 *
>> +/* Opcode: ApplyType P1 P2 * P4 P5
>>   * Synopsis: type(r[P1@P2])
>>   *
>>   * Check that types of P2 registers starting from register P1 are
>> @@ -2890,6 +2890,9 @@ case OP_Fetch: {
>>   * value and the given type are incompatible according to
>>   * field_mp_plain_type_is_compatible(), but both are numeric,
>>   * this opcode attempts to convert the value to the type.
>> + *
>> + * If P5 contains the OPFLAG_BLOB_LIKE_STRING flag, the BLOB
>> + * values ​​are processed as if they had the field type STRING.
>
> I see this unprintable symbols for the third time. Did you review
> your own patch?
>
I look at them in 'less', which is the default for 'git diff'.
Also in Sublime Text sometimes. But these characters are not shown
there. I will try to fix this issue in general.

>
>>  case OP_ApplyType: {
>>  	enum field_type *types = pOp->p4.types;
>> @@ -2904,6 +2907,13 @@ case OP_ApplyType: {
>>  			pIn1++;
>>  			continue;
>>  		}
>
> Need more info for this chunk.
>
Added a comment.

>> +		if ((pOp->p5 & OPFLAG_BLOB_LIKE_STRING) != 0) {
>> +			if (type == FIELD_TYPE_STRING &&
>> +			    mem_mp_type(pIn1) == MP_BIN) {
>> +				pIn1++;
>> +				continue;
>> +			}
>> +		}
>>  		if (!mp_type_is_numeric(mem_mp_type(pIn1)) ||
>>  		    !sql_type_is_numeric(type) ||
>>  		    mem_convert_to_numeric(pIn1, type, false) != 0) {
>> diff --git a/test/sql-tap/cse.test.lua b/test/sql-tap/cse.test.lua
>> index 341b6de01..3c2076a1d 100755
>> --- a/test/sql-tap/cse.test.lua
>> +++ b/test/sql-tap/cse.test.lua
>> @@ -195,23 +195,23 @@ test:do_execsql_test(
>>  
>>  
>>  
>> -test:do_execsql_test(
>> +test:do_catchsql_test(
>>      "cse-1.13",
>>      [[
>>          SELECT upper(b), typeof(b), b FROM t1
>>      ]], {
>>          -- <cse-1.13>
>> -        "11", "integer", 11, "21", "integer", 21
>> +        1, "Type mismatch: can not convert 11 to string"
>>          -- </cse-1.13>
>>      })
>
> DId not look at test changes yet. Please, elaborate on notes above
> firstly.
>
>>  



New patch:

From dab7a97dbf0a9e498b24e8baeb5ff6c1338a5e43 Mon Sep 17 00:00:00 2001
From: Mergen Imeev <imeevma@gmail.com>
Date: Mon, 13 Jul 2020 19:50:34 +0300
Subject: [PATCH] sql: use ApplyType to check function arguments

This patch allows us to use the ApplyType opcode to check the type of
function arguments. This allows us not to fix the implicit cast inside
functions every time the implicit cast rules change, for example, due to
the addition of a new type.

Part of #4159

diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index bc2182446..0c810b73b 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -4120,6 +4120,8 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 			} else {
 				r1 = 0;
 			}
+			if (func->def->language == FUNC_LANGUAGE_SQL_BUILTIN)
+				sql_emit_func_arg_type_check(v, func, r1, nFarg);
 			if (sql_func_flag_is_set(func, SQL_FUNC_NEEDCOLL)) {
 				sqlVdbeAddOp4(v, OP_CollSeq, 0, 0, 0,
 						  (char *)coll, P4_COLLSEQ);
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 487cdafe1..511061b50 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -2230,12 +2230,21 @@ static struct {
 	/** Members below are related to struct func_def. */
 	bool is_deterministic;
 	int param_count;
+	/** Field type of the first argument. */
+	enum field_type first_arg;
+	/** Field type of all arguments except the first. */
+	enum field_type args;
+	/** TRUE if the function treats the BLOB as STRING. */
+	bool is_blob_like_str;
 	enum field_type returns;
 	enum func_aggregate aggregate;
 	bool export_to_sql;
 } sql_builtins[] = {
 	{.name = "ABS",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_NUMBER,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2246,6 +2255,9 @@ static struct {
 	}, {
 	 .name = "AVG",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_NUMBER,
 	 .is_deterministic = false,
 	 .aggregate = FUNC_AGGREGATE_GROUP,
@@ -2258,6 +2270,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2268,6 +2283,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2276,6 +2294,9 @@ static struct {
 	}, {
 	 .name = "CHAR",
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
 	 .is_deterministic = true,
 	 .aggregate = FUNC_AGGREGATE_NONE,
@@ -2286,6 +2307,9 @@ static struct {
 	 }, {
 	 .name = "CHARACTER_LENGTH",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_INTEGER,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2296,6 +2320,9 @@ static struct {
 	}, {
 	 .name = "CHAR_LENGTH",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_INTEGER,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2306,6 +2333,9 @@ static struct {
 	}, {
 	 .name = "COALESCE",
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_SCALAR,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2316,6 +2346,9 @@ static struct {
 	}, {
 	 .name = "COUNT",
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_INTEGER,
 	 .aggregate = FUNC_AGGREGATE_GROUP,
 	 .is_deterministic = false,
@@ -2328,6 +2361,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2338,6 +2374,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2348,6 +2387,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2358,6 +2400,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2368,6 +2413,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2378,6 +2426,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2388,6 +2439,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2398,6 +2452,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2408,6 +2465,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2418,6 +2478,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2428,6 +2491,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2436,6 +2502,9 @@ static struct {
 	}, {
 	 .name = "GREATEST",
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_SCALAR,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2446,6 +2515,9 @@ static struct {
 	}, {
 	 .name = "GROUP_CONCAT",
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
 	 .aggregate = FUNC_AGGREGATE_GROUP,
 	 .is_deterministic = false,
@@ -2456,6 +2528,9 @@ static struct {
 	}, {
 	 .name = "HEX",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2466,6 +2541,9 @@ static struct {
 	}, {
 	 .name = "IFNULL",
 	 .param_count = 2,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_INTEGER,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2478,6 +2556,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2486,6 +2567,9 @@ static struct {
 	}, {
 	 .name = "LEAST",
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_SCALAR,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2496,6 +2580,9 @@ static struct {
 	}, {
 	 .name = "LENGTH",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_INTEGER,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2508,6 +2595,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2516,6 +2606,9 @@ static struct {
 	}, {
 	 .name = "LIKE",
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_INTEGER,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2526,6 +2619,9 @@ static struct {
 	}, {
 	 .name = "LIKELIHOOD",
 	 .param_count = 2,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_BOOLEAN,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2536,6 +2632,9 @@ static struct {
 	}, {
 	 .name = "LIKELY",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_BOOLEAN,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2548,6 +2647,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2556,6 +2658,9 @@ static struct {
 	}, {
 	 .name = "LOWER",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2566,6 +2671,9 @@ static struct {
 	}, {
 	 .name = "MAX",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_SCALAR,
 	 .aggregate = FUNC_AGGREGATE_GROUP,
 	 .is_deterministic = false,
@@ -2576,6 +2684,9 @@ static struct {
 	}, {
 	 .name = "MIN",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_SCALAR,
 	 .aggregate = FUNC_AGGREGATE_GROUP,
 	 .is_deterministic = false,
@@ -2588,6 +2699,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2596,6 +2710,9 @@ static struct {
 	}, {
 	 .name = "NULLIF",
 	 .param_count = 2,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_SCALAR,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2608,6 +2725,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2616,6 +2736,9 @@ static struct {
 	}, {
 	 .name = "POSITION",
 	 .param_count = 2,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_INTEGER,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2628,6 +2751,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2636,6 +2762,9 @@ static struct {
 	}, {
 	 .name = "PRINTF",
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2646,6 +2775,9 @@ static struct {
 	}, {
 	 .name = "QUOTE",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2656,6 +2788,9 @@ static struct {
 	}, {
 	 .name = "RANDOM",
 	 .param_count = 0,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_INTEGER,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2666,6 +2801,9 @@ static struct {
 	}, {
 	 .name = "RANDOMBLOB",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_VARBINARY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2676,6 +2814,9 @@ static struct {
 	}, {
 	 .name = "REPLACE",
 	 .param_count = 3,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2686,6 +2827,9 @@ static struct {
 	}, {
 	 .name = "ROUND",
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_INTEGER,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2696,6 +2840,9 @@ static struct {
 	}, {
 	 .name = "ROW_COUNT",
 	 .param_count = 0,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_INTEGER,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2708,6 +2855,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2716,6 +2866,9 @@ static struct {
 	}, {
 	 .name = "SOUNDEX",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2728,6 +2881,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2738,6 +2894,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2746,6 +2905,9 @@ static struct {
 	}, {
 	 .name = "SUBSTR",
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2756,6 +2918,9 @@ static struct {
 	}, {
 	 .name = "SUM",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_NUMBER,
 	 .aggregate = FUNC_AGGREGATE_GROUP,
 	 .is_deterministic = false,
@@ -2768,6 +2933,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2776,6 +2944,9 @@ static struct {
 	}, {
 	 .name = "TOTAL",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_NUMBER,
 	 .aggregate = FUNC_AGGREGATE_GROUP,
 	 .is_deterministic = false,
@@ -2786,6 +2957,9 @@ static struct {
 	}, {
 	 .name = "TRIM",
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2796,6 +2970,9 @@ static struct {
 	}, {
 	 .name = "TYPEOF",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2806,6 +2983,9 @@ static struct {
 	}, {
 	 .name = "UNICODE",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2816,6 +2996,9 @@ static struct {
 	}, {
 	 .name = "UNLIKELY",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_BOOLEAN,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2826,6 +3009,9 @@ static struct {
 	}, {
 	 .name = "UPPER",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2836,6 +3022,9 @@ static struct {
 	}, {
 	 .name = "VERSION",
 	 .param_count = 0,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2846,6 +3035,9 @@ static struct {
 	}, {
 	 .name = "ZEROBLOB",
 	 .param_count = 1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_VARBINARY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2858,6 +3050,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2868,6 +3063,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2878,6 +3076,9 @@ static struct {
 	 .call = sql_builtin_stub,
 	 .export_to_sql = false,
 	 .param_count = -1,
+	 .first_arg = FIELD_TYPE_ANY,
+	 .args = FIELD_TYPE_ANY,
+	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_ANY,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = false,
@@ -2929,6 +3130,9 @@ func_sql_builtin_new(struct func_def *def)
 	func->flags = sql_builtins[idx].flags;
 	func->call = sql_builtins[idx].call;
 	func->finalize = sql_builtins[idx].finalize;
+	func->first_arg = sql_builtins[idx].first_arg;
+	func->args = sql_builtins[idx].args;
+	func->is_blob_like_str = sql_builtins[idx].is_blob_like_str;
 	def->param_count = sql_builtins[idx].param_count;
 	def->is_deterministic = sql_builtins[idx].is_deterministic;
 	def->returns = sql_builtins[idx].returns;
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 4b069addb..426247bd7 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -124,6 +124,40 @@ clearSelect(sql * db, Select * p, int bFree)
 	}
 }
 
+void
+sql_emit_func_arg_type_check(struct Vdbe *vdbe, struct func *func,
+			     int reg, uint32_t argc)
+{
+	if (argc == 0)
+		return;
+	struct func_sql_builtin *f = (struct func_sql_builtin *)func;
+	/*
+	 * There is no need to check types of the MEMs if all
+	 * arguments should be of type ANY.
+	 */
+	if (f->first_arg == FIELD_TYPE_ANY && f->args  == FIELD_TYPE_ANY)
+		return;
+	size_t size = (argc + 1) * sizeof(enum field_type);
+	enum field_type *types = sqlDbMallocZero(sql_get(), size);
+	/* Field type of the first argument of the function. */
+	types[0] = f->first_arg;
+	/*
+	 * The field types of all arguments except the first are
+	 * the same.
+	 */
+	for (uint32_t i = 1; i < argc; ++i)
+		types[i] = f->args;
+	types[argc] = field_type_MAX;
+	sqlVdbeAddOp4(vdbe, OP_ApplyType, reg, argc, 0, (char *)types,
+		      P4_DYNAMIC);
+	/*
+	 * If a function treats a BLOB as a STRING, we should
+	 * allow it to get a BLOB in place of a STRING.
+	 */
+	if (f->is_blob_like_str)
+		sqlVdbeChangeP5(vdbe, OPFLAG_BLOB_LIKE_STRING);
+}
+
 /*
  * Initialize a SelectDest structure.
  */
@@ -5414,6 +5448,7 @@ updateAccumulator(Parse * pParse, AggInfo * pAggInfo)
 			sqlVdbeAddOp4(v, OP_CollSeq, regHit, 0, 0,
 					  (char *)coll, P4_COLLSEQ);
 		}
+		sql_emit_func_arg_type_check(v, pF->func, regAgg, nArg);
 		sqlVdbeAddOp3(v, OP_AggStep0, 0, regAgg, pF->iMem);
 		sqlVdbeAppendP4(v, pF->func, P4_FUNC);
 		sqlVdbeChangeP5(v, (u8) nArg);
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 37283e506..54f1594d0 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -2307,6 +2307,8 @@ struct Parse {
 #define OPFLAG_SYSTEMSP      0x20	/* OP_Open**: set if space pointer
 					 * points to system space.
 					 */
+/** OP_ApplyType: Treat BLOB as STRING. */
+#define OPFLAG_BLOB_LIKE_STRING		0x01
 
 /**
  * Prepare vdbe P5 flags for OP_{IdxInsert, IdxReplace, Update}
@@ -3881,6 +3883,20 @@ sql_index_type_str(struct sql *db, const struct index_def *idx_def);
 void
 sql_emit_table_types(struct Vdbe *v, struct space_def *def, int reg);
 
+/**
+ * Code an OP_ApplyType opcode that try to cast implicitly types
+ * for given range of register starting from @a reg. These values
+ * then will be used as arguments of a function.
+ *
+ * @param vdbe VDBE.
+ * @param args Information about arguments of the function.
+ * @param reg Register where types will be placed.
+ * @param argc Number of arguments.
+ */
+void
+sql_emit_func_arg_type_check(struct Vdbe *vdbe, struct func *func,
+			     int reg, uint32_t argc);
+
 enum field_type
 sql_type_result(enum field_type lhs, enum field_type rhs);
 
@@ -4402,6 +4418,25 @@ struct func_sql_builtin {
 	struct func base;
 	/** A bitmask of SQL flags. */
 	uint16_t flags;
+	/**
+	 * In built-in functions, all arguments except the first
+	 * have the same field type. The first argument may have a
+	 * different field type.
+	 *
+	 * Field type of the first argument.
+	 */
+	enum field_type first_arg;
+	/** Field type of all arguments except the first. */
+	enum field_type args;
+	/**
+	 * Some built-in functions work with BLOB arguments in the
+	 * same way as with STRING arguments. This flag allows us
+	 * to pass BLOB arguments instead of STRING arguments in
+	 * this case.
+	 *
+	 * TRUE if the function treats the BLOB as STRING.
+	 */
+	bool is_blob_like_str;
 	/**
 	 * A VDBE-memory-compatible call method.
 	 * SQL built-ins don't use func base class "call"
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 41a4750da..9d25d10b0 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -2882,7 +2882,7 @@ case OP_Fetch: {
 	break;
 }
 
-/* Opcode: ApplyType P1 P2 * P4 *
+/* Opcode: ApplyType P1 P2 * P4 P5
  * Synopsis: type(r[P1@P2])
  *
  * Check that types of P2 registers starting from register P1 are
@@ -2890,6 +2890,9 @@ case OP_Fetch: {
  * value and the given type are incompatible according to
  * field_mp_plain_type_is_compatible(), but both are numeric,
  * this opcode attempts to convert the value to the type.
+ *
+ * If P5 contains the OPFLAG_BLOB_LIKE_STRING flag, the BLOB
+ * values are processed as if they had the field type STRING.
  */
 case OP_ApplyType: {
 	enum field_type *types = pOp->p4.types;
@@ -2901,6 +2904,19 @@ case OP_ApplyType: {
 		assert(pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)]);
 		assert(memIsValid(pIn1));
 		if (!mem_is_type_compatible(pIn1, type)) {
+			/*
+			 * If function works with BLOB argument
+			 * the same way it works with STRING
+			 * arguments, we should allow BLOB
+			 * arguments in place of STRING arguments.
+			 */
+			if ((pOp->p5 & OPFLAG_BLOB_LIKE_STRING) != 0) {
+				if (type == FIELD_TYPE_STRING &&
+				    mem_mp_type(pIn1) == MP_BIN) {
+					pIn1++;
+					continue;
+				}
+			}
 			/* Implicit cast is allowed only to numeric type. */
 			if (!sql_type_is_numeric(type))
 				goto type_mismatch;

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

* [Tarantool-patches] [PATCH v5 04/17] sql: check args of abs()
  2020-07-14 15:48 [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment imeevma
                   ` (2 preceding siblings ...)
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 03/17] sql: use ApplyType to check function arguments imeevma
@ 2020-07-14 15:48 ` imeevma
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 05/17] sql: check args of avg(), sum() and total() imeevma
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: imeevma @ 2020-07-14 15:48 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

After this patch, the argument types of the abs() function will be
checked properly.

Part of #4159
---
 src/box/sql/func.c          | 52 ++++++++++-------------------------
 test/sql-tap/func.test.lua  |  4 +--
 test/sql-tap/func5.test.lua | 55 ++++++++++++++++++++++++++++++++++++-
 test/sql/boolean.result     |  2 +-
 test/sql/types.result       |  2 +-
 5 files changed, 73 insertions(+), 42 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 511061b50..329554731 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -504,44 +504,22 @@ absFunc(sql_context * context, int argc, sql_value ** argv)
 {
 	assert(argc == 1);
 	UNUSED_PARAMETER(argc);
-	switch (sql_value_type(argv[0])) {
-	case MP_UINT: {
-		sql_result_uint(context, sql_value_uint64(argv[0]));
-		break;
-	}
-	case MP_INT: {
+	enum mp_type mp_type = sql_value_type(argv[0]);
+	if (mp_type == MP_NIL)
+		return sql_result_null(context);
+	if (mp_type == MP_UINT)
+		return sql_result_uint(context, sql_value_uint64(argv[0]));
+	if (mp_type == MP_INT) {
 		int64_t value = sql_value_int64(argv[0]);
 		assert(value < 0);
-		sql_result_uint(context, -value);
-		break;
-	}
-	case MP_NIL:{
-			/* IMP: R-37434-19929 Abs(X) returns NULL if X is NULL. */
-			sql_result_null(context);
-			break;
-		}
-	case MP_BOOL:
-	case MP_BIN:
-	case MP_ARRAY:
-	case MP_MAP: {
-		diag_set(ClientError, ER_INCONSISTENT_TYPES, "number",
-			 mem_type_to_str(argv[0]));
-		context->is_aborted = true;
-		return;
-	}
-	default:{
-			/* Because sql_value_double() returns 0.0 if the argument is not
-			 * something that can be converted into a number, we have:
-			 * IMP: R-01992-00519 Abs(X) returns 0.0 if X is a string or blob
-			 * that cannot be converted to a numeric value.
-			 */
-			double rVal = sql_value_double(argv[0]);
-			if (rVal < 0)
-				rVal = -rVal;
-			sql_result_double(context, rVal);
-			break;
-		}
-	}
+		return sql_result_uint(context, -value);
+	}
+	assert(mp_type == MP_DOUBLE);
+	double value = sql_value_double(argv[0]);
+	if (value < 0)
+		value = -value;
+	sql_result_double(context, value);
+	return;
 }
 
 /**
@@ -2242,7 +2220,7 @@ static struct {
 } sql_builtins[] = {
 	{.name = "ABS",
 	 .param_count = 1,
-	 .first_arg = FIELD_TYPE_ANY,
+	 .first_arg = FIELD_TYPE_NUMBER,
 	 .args = FIELD_TYPE_ANY,
 	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_NUMBER,
diff --git a/test/sql-tap/func.test.lua b/test/sql-tap/func.test.lua
index 3c088920f..422c8ce58 100755
--- a/test/sql-tap/func.test.lua
+++ b/test/sql-tap/func.test.lua
@@ -412,13 +412,13 @@ test:do_execsql_test(
         -- </func-4.4.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "func-4.4.2",
     [[
         SELECT abs(t1) FROM tbl1
     ]], {
         -- <func-4.4.2>
-        0.0, 0.0, 0.0, 0.0, 0.0
+        1, "Type mismatch: can not convert this to number"
         -- </func-4.4.2>
     })
 
diff --git a/test/sql-tap/func5.test.lua b/test/sql-tap/func5.test.lua
index 8329e1735..d6d5d4df6 100755
--- a/test/sql-tap/func5.test.lua
+++ b/test/sql-tap/func5.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(22)
+test:plan(29)
 
 --!./tcltestrunner.lua
 -- 2010 August 27
@@ -293,4 +293,57 @@ test:do_catchsql_test(
 box.func.COUNTER1:drop()
 box.func.COUNTER2:drop()
 
+--
+-- gh-4159: Make sure function argument types are validated
+-- correctly.
+--
+test:do_execsql_test(
+    "func-5-6.1.1", [[
+        SELECT abs(NULL);
+    ]],{
+        ""
+    })
+
+test:do_execsql_test(
+    "func-5-6.1.2", [[
+        SELECT abs(123);
+    ]], {
+        123
+    })
+
+test:do_execsql_test(
+    "func-5-6.1.3", [[
+        SELECT abs(-123);
+    ]], {
+        123
+    })
+
+test:do_execsql_test(
+    "func-5-6.1.4", [[
+        SELECT abs(-5.5);
+    ]], {
+        5.5
+    })
+
+test:do_catchsql_test(
+    "func-5-6.1.5", [[
+        SELECT abs('-123');
+    ]], {
+        1, "Type mismatch: can not convert -123 to number"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.1.6", [[
+        SELECT abs(false);
+    ]], {
+        1, "Type mismatch: can not convert FALSE to number"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.1.7", [[
+        SELECT abs(X'3334');
+    ]], {
+        1, "Type mismatch: can not convert varbinary to number"
+    })
+
 test:finish_test()
diff --git a/test/sql/boolean.result b/test/sql/boolean.result
index 112e41a12..c470ebd40 100644
--- a/test/sql/boolean.result
+++ b/test/sql/boolean.result
@@ -276,7 +276,7 @@ SELECT is_boolean('true');
 SELECT abs(a) FROM t0;
  | ---
  | - null
- | - 'Inconsistent types: expected number got boolean'
+ | - 'Type mismatch: can not convert FALSE to number'
  | ...
 SELECT lower(a) FROM t0;
  | ---
diff --git a/test/sql/types.result b/test/sql/types.result
index 70fbbc5a2..f5c059ef0 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -1326,7 +1326,7 @@ box.execute("SELECT upper(v) FROM t;")
 box.execute("SELECT abs(v) FROM t;")
 ---
 - null
-- 'Inconsistent types: expected number got varbinary'
+- 'Type mismatch: can not convert varbinary to number'
 ...
 box.execute("SELECT typeof(v) FROM t;")
 ---
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v5 05/17] sql: check args of avg(), sum() and total()
  2020-07-14 15:48 [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment imeevma
                   ` (3 preceding siblings ...)
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 04/17] sql: check args of abs() imeevma
@ 2020-07-14 15:48 ` imeevma
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 06/17] sql: check args of char() imeevma
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: imeevma @ 2020-07-14 15:48 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

After this patch, the argument types of the avg(), sum() and total()
functions will be checked properly.

Part of #4159
---
 src/box/sql/func.c          |  18 ++---
 test/sql-tap/func.test.lua  |   8 +-
 test/sql-tap/func5.test.lua | 149 +++++++++++++++++++++++++++++++++++-
 3 files changed, 157 insertions(+), 18 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 329554731..ed972fdab 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -1927,18 +1927,10 @@ sum_step(struct sql_context *context, int argc, sql_value **argv)
 	assert(argc == 1);
 	UNUSED_PARAMETER(argc);
 	struct SumCtx *p = sql_aggregate_context(context, sizeof(*p));
-	int type = sql_value_type(argv[0]);
+	enum mp_type type = sql_value_type(argv[0]);
 	if (type == MP_NIL || p == NULL)
 		return;
-	if (type != MP_DOUBLE && type != MP_INT && type != MP_UINT) {
-		if (mem_apply_numeric_type(argv[0]) != 0) {
-			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
-				 sql_value_to_diag_str(argv[0]), "number");
-			context->is_aborted = true;
-			return;
-		}
-		type = sql_value_type(argv[0]);
-	}
+	assert(type == MP_DOUBLE || type == MP_INT || type == MP_UINT);
 	p->cnt++;
 	if (type == MP_INT || type == MP_UINT) {
 		int64_t v = sql_value_int64(argv[0]);
@@ -2233,7 +2225,7 @@ static struct {
 	}, {
 	 .name = "AVG",
 	 .param_count = 1,
-	 .first_arg = FIELD_TYPE_ANY,
+	 .first_arg = FIELD_TYPE_NUMBER,
 	 .args = FIELD_TYPE_ANY,
 	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_NUMBER,
@@ -2896,7 +2888,7 @@ static struct {
 	}, {
 	 .name = "SUM",
 	 .param_count = 1,
-	 .first_arg = FIELD_TYPE_ANY,
+	 .first_arg = FIELD_TYPE_NUMBER,
 	 .args = FIELD_TYPE_ANY,
 	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_NUMBER,
@@ -2922,7 +2914,7 @@ static struct {
 	}, {
 	 .name = "TOTAL",
 	 .param_count = 1,
-	 .first_arg = FIELD_TYPE_ANY,
+	 .first_arg = FIELD_TYPE_NUMBER,
 	 .args = FIELD_TYPE_ANY,
 	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_NUMBER,
diff --git a/test/sql-tap/func.test.lua b/test/sql-tap/func.test.lua
index 422c8ce58..ffee8f1c5 100755
--- a/test/sql-tap/func.test.lua
+++ b/test/sql-tap/func.test.lua
@@ -893,7 +893,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "func-8.5",
     [[
-        SELECT sum(x) FROM (SELECT '9223372036' || '854775807' AS x
+        SELECT sum(x) FROM (SELECT CAST('9223372036' || '854775807' AS INTEGER) AS x
                             UNION ALL SELECT -9223372036854775807)
     ]], {
         -- <func-8.5>
@@ -904,7 +904,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "func-8.6",
     [[
-        SELECT typeof(sum(x)) FROM (SELECT '9223372036' || '854775807' AS x
+        SELECT typeof(sum(x)) FROM (SELECT CAST('9223372036' || '854775807' AS INTEGER) AS x
                             UNION ALL SELECT -9223372036854775807)
     ]], {
         -- <func-8.6>
@@ -915,7 +915,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "func-8.7",
     [[
-        SELECT typeof(sum(x)) FROM (SELECT '9223372036' || '854775808' AS x
+        SELECT typeof(sum(x)) FROM (SELECT CAST('9223372036' || '854775808' AS INTEGER) AS x
                             UNION ALL SELECT -9223372036854775807)
     ]], {
         -- <func-8.7>
@@ -926,7 +926,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "func-8.8",
     [[
-        SELECT sum(x)>0.0 FROM (SELECT '9223372036' || '854775808' AS x
+        SELECT sum(x)>0.0 FROM (SELECT CAST('9223372036' || '854775808' AS INTEGER) AS x
                             UNION ALL SELECT -9223372036850000000)
     ]], {
         -- <func-8.8>
diff --git a/test/sql-tap/func5.test.lua b/test/sql-tap/func5.test.lua
index d6d5d4df6..467ba7292 100755
--- a/test/sql-tap/func5.test.lua
+++ b/test/sql-tap/func5.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(29)
+test:plan(50)
 
 --!./tcltestrunner.lua
 -- 2010 August 27
@@ -346,4 +346,151 @@ test:do_catchsql_test(
         1, "Type mismatch: can not convert varbinary to number"
     })
 
+test:do_execsql_test(
+    "func-5-6.2.1", [[
+        SELECT sum("_auto_field_") from (values (NULL), (NULL), (NULL));
+    ]],{
+        ""
+    })
+
+test:do_execsql_test(
+    "func-5-6.2.2", [[
+        SELECT sum("_auto_field_") from (values (123), (123), (123));
+    ]], {
+        369
+    })
+
+test:do_execsql_test(
+    "func-5-6.2.3", [[
+        SELECT sum("_auto_field_") from (values (-123), (-123), (-123));
+    ]], {
+        -369
+    })
+
+test:do_execsql_test(
+    "func-5-6.2.4", [[
+        SELECT sum("_auto_field_") from (values (-5.5), (-5.5), (-5.5));
+    ]], {
+        -16.5
+    })
+
+test:do_catchsql_test(
+    "func-5-6.2.5", [[
+        SELECT sum("_auto_field_") from (values ('-123'), ('-123'), ('-123'));
+    ]], {
+        1, "Type mismatch: can not convert -123 to number"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.2.6", [[
+        SELECT sum("_auto_field_") from (values (false), (false), (false));
+    ]], {
+        1, "Type mismatch: can not convert FALSE to number"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.2.7", [[
+        SELECT sum("_auto_field_") from (values (X'3334'), (X'3334'), (X'3334'));
+    ]], {
+        1, "Type mismatch: can not convert varbinary to number"
+    })
+
+test:do_execsql_test(
+    "func-5-6.3.1", [[
+        SELECT avg("_auto_field_") from (values (NULL), (NULL), (NULL));
+    ]],{
+        ""
+    })
+
+test:do_execsql_test(
+    "func-5-6.3.2", [[
+        SELECT avg("_auto_field_") from (values (123), (123), (123));
+    ]], {
+        123
+    })
+
+test:do_execsql_test(
+    "func-5-6.3.3", [[
+        SELECT avg("_auto_field_") from (values (-123), (-123), (-123));
+    ]], {
+        -123
+    })
+
+test:do_execsql_test(
+    "func-5-6.3.4", [[
+        SELECT avg("_auto_field_") from (values (-5.5), (-5.5), (-5.5));
+    ]], {
+        -5.5
+    })
+
+test:do_catchsql_test(
+    "func-5-6.3.5", [[
+        SELECT avg("_auto_field_") from (values ('-123'), ('-123'), ('-123'));
+    ]], {
+        1, "Type mismatch: can not convert -123 to number"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.3.6", [[
+        SELECT avg("_auto_field_") from (values (false), (false), (false));
+    ]], {
+        1, "Type mismatch: can not convert FALSE to number"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.3.7", [[
+        SELECT avg("_auto_field_") from (values (X'3334'), (X'3334'), (X'3334'));
+    ]], {
+        1, "Type mismatch: can not convert varbinary to number"
+    })
+
+test:do_execsql_test(
+    "func-5-6.4.1", [[
+        SELECT total("_auto_field_") from (values (NULL), (NULL), (NULL));
+    ]],{
+        0
+    })
+
+test:do_execsql_test(
+    "func-5-6.4.2", [[
+        SELECT total("_auto_field_") from (values (123), (123), (123));
+    ]], {
+        369
+    })
+
+test:do_execsql_test(
+    "func-5-6.4.3", [[
+        SELECT total("_auto_field_") from (values (-123), (-123), (-123));
+    ]], {
+        -369
+    })
+
+test:do_execsql_test(
+    "func-5-6.4.4", [[
+        SELECT total("_auto_field_") from (values (-5.5), (-5.5), (-5.5));
+    ]], {
+        -16.5
+    })
+
+test:do_catchsql_test(
+    "func-5-6.4.5", [[
+        SELECT total("_auto_field_") from (values ('-123'), ('-123'), ('-123'));
+    ]], {
+        1, "Type mismatch: can not convert -123 to number"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.4.6", [[
+        SELECT total("_auto_field_") from (values (false), (false), (false));
+    ]], {
+        1, "Type mismatch: can not convert FALSE to number"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.4.7", [[
+        SELECT total("_auto_field_") from (values (X'3334'), (X'3334'), (X'3334'));
+    ]], {
+        1, "Type mismatch: can not convert varbinary to number"
+    })
+
 test:finish_test()
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v5 06/17] sql: check args of char()
  2020-07-14 15:48 [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment imeevma
                   ` (4 preceding siblings ...)
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 05/17] sql: check args of avg(), sum() and total() imeevma
@ 2020-07-14 15:48 ` imeevma
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 07/17] sql: check args of length() imeevma
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: imeevma @ 2020-07-14 15:48 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

After this patch, the argument types of the char() function will
be checked properly.

Part of #4159
---
 src/box/sql/func.c          | 13 +++++-----
 test/sql-tap/func5.test.lua | 51 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 57 insertions(+), 7 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index ed972fdab..2d0aea801 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -1454,10 +1454,11 @@ charFunc(sql_context * context, int argc, sql_value ** argv)
 	for (i = 0; i < argc; i++) {
 		uint64_t x;
 		unsigned c;
-		if (sql_value_type(argv[i]) == MP_INT)
-			x = 0xfffd;
-		else
-			x = sql_value_uint64(argv[i]);
+		enum mp_type mp_type = sql_value_type(argv[i]);
+		if (mp_type == MP_NIL)
+			continue;
+		assert(mp_type == MP_UINT);
+		x = sql_value_uint64(argv[i]);
 		if (x > 0x10ffff)
 			x = 0xfffd;
 		c = (unsigned)(x & 0x1fffff);
@@ -2264,8 +2265,8 @@ static struct {
 	}, {
 	 .name = "CHAR",
 	 .param_count = -1,
-	 .first_arg = FIELD_TYPE_ANY,
-	 .args = FIELD_TYPE_ANY,
+	 .first_arg = FIELD_TYPE_UNSIGNED,
+	 .args = FIELD_TYPE_UNSIGNED,
 	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
 	 .is_deterministic = true,
diff --git a/test/sql-tap/func5.test.lua b/test/sql-tap/func5.test.lua
index 467ba7292..6e65b98ac 100755
--- a/test/sql-tap/func5.test.lua
+++ b/test/sql-tap/func5.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(50)
+test:plan(57)
 
 --!./tcltestrunner.lua
 -- 2010 August 27
@@ -493,4 +493,53 @@ test:do_catchsql_test(
         1, "Type mismatch: can not convert varbinary to number"
     })
 
+test:do_execsql_test(
+    "func-5-6.5.1", [[
+        SELECT char(NULL);
+    ]],{
+        ""
+    })
+
+test:do_execsql_test(
+    "func-5-6.5.2", [[
+        SELECT char(0x33);
+    ]], {
+        "3"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.5.3", [[
+        SELECT char(-123);
+    ]], {
+        1, "Type mismatch: can not convert -123 to unsigned"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.5.4", [[
+        SELECT char(-5.5);
+    ]], {
+        1, "Type mismatch: can not convert -5.5 to unsigned"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.5.5", [[
+        SELECT char('-123');
+    ]], {
+        1, "Type mismatch: can not convert -123 to unsigned"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.5.6", [[
+        SELECT char(false);
+    ]], {
+        1, "Type mismatch: can not convert FALSE to unsigned"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.5.7", [[
+        SELECT char(X'3334');
+    ]], {
+        1, "Type mismatch: can not convert varbinary to unsigned"
+    })
+
 test:finish_test()
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v5 07/17] sql: check args of length()
  2020-07-14 15:48 [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment imeevma
                   ` (5 preceding siblings ...)
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 06/17] sql: check args of char() imeevma
@ 2020-07-14 15:48 ` imeevma
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 08/17] sql: check operands of LIKE imeevma
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: imeevma @ 2020-07-14 15:48 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

After this patch, the argument types of the length(), char_length() and
character_length() functions will be checked properly.

Part of #4159
---
 src/box/sql/func.c             |  48 ++++-------
 test/sql-tap/func.test.lua     |   2 +-
 test/sql-tap/func5.test.lua    | 149 ++++++++++++++++++++++++++++++++-
 test/sql-tap/orderby1.test.lua |   2 +-
 test/sql/boolean.result        |  10 +--
 5 files changed, 170 insertions(+), 41 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 2d0aea801..a22ba38e2 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -467,30 +467,18 @@ lengthFunc(sql_context * context, int argc, sql_value ** argv)
 
 	assert(argc == 1);
 	UNUSED_PARAMETER(argc);
-	switch (sql_value_type(argv[0])) {
-	case MP_BIN:
-	case MP_ARRAY:
-	case MP_MAP:
-	case MP_INT:
-	case MP_UINT:
-	case MP_BOOL:
-	case MP_DOUBLE:{
-			sql_result_uint(context, sql_value_bytes(argv[0]));
-			break;
-		}
-	case MP_STR:{
-			const unsigned char *z = sql_value_text(argv[0]);
-			if (z == 0)
-				return;
-			len = sql_utf8_char_count(z, sql_value_bytes(argv[0]));
-			sql_result_uint(context, len);
-			break;
-		}
-	default:{
-			sql_result_null(context);
-			break;
-		}
-	}
+	enum mp_type mp_type = sql_value_type(argv[0]);
+	if (mp_type == MP_NIL)
+		return sql_result_null(context);
+	if (mp_type == MP_BIN)
+		return sql_result_uint(context, sql_value_bytes(argv[0]));
+	assert(mp_type == MP_STR);
+	const unsigned char *z = sql_value_text(argv[0]);
+	if (z == NULL)
+		return;
+	len = sql_utf8_char_count(z, sql_value_bytes(argv[0]));
+	sql_result_uint(context, len);
+	return;
 }
 
 /*
@@ -2278,9 +2266,9 @@ static struct {
 	 }, {
 	 .name = "CHARACTER_LENGTH",
 	 .param_count = 1,
-	 .first_arg = FIELD_TYPE_ANY,
+	 .first_arg = FIELD_TYPE_STRING,
 	 .args = FIELD_TYPE_ANY,
-	 .is_blob_like_str = false,
+	 .is_blob_like_str = true,
 	 .returns = FIELD_TYPE_INTEGER,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2291,9 +2279,9 @@ static struct {
 	}, {
 	 .name = "CHAR_LENGTH",
 	 .param_count = 1,
-	 .first_arg = FIELD_TYPE_ANY,
+	 .first_arg = FIELD_TYPE_STRING,
 	 .args = FIELD_TYPE_ANY,
-	 .is_blob_like_str = false,
+	 .is_blob_like_str = true,
 	 .returns = FIELD_TYPE_INTEGER,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
@@ -2551,9 +2539,9 @@ static struct {
 	}, {
 	 .name = "LENGTH",
 	 .param_count = 1,
-	 .first_arg = FIELD_TYPE_ANY,
+	 .first_arg = FIELD_TYPE_STRING,
 	 .args = FIELD_TYPE_ANY,
-	 .is_blob_like_str = false,
+	 .is_blob_like_str = true,
 	 .returns = FIELD_TYPE_INTEGER,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
diff --git a/test/sql-tap/func.test.lua b/test/sql-tap/func.test.lua
index ffee8f1c5..69d175e16 100755
--- a/test/sql-tap/func.test.lua
+++ b/test/sql-tap/func.test.lua
@@ -95,7 +95,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "func-1.4",
     [[
-        SELECT coalesce(length(a),-1) FROM t2
+        SELECT coalesce(length(CAST(a AS STRING)),-1) FROM t2
     ]], {
         -- <func-1.4>
         1, -1, 3, -1, 5
diff --git a/test/sql-tap/func5.test.lua b/test/sql-tap/func5.test.lua
index 6e65b98ac..0398d8a9d 100755
--- a/test/sql-tap/func5.test.lua
+++ b/test/sql-tap/func5.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(57)
+test:plan(78)
 
 --!./tcltestrunner.lua
 -- 2010 August 27
@@ -542,4 +542,151 @@ test:do_catchsql_test(
         1, "Type mismatch: can not convert varbinary to unsigned"
     })
 
+test:do_execsql_test(
+    "func-5-6.6.1", [[
+        SELECT length(NULL);
+    ]],{
+        ""
+    })
+
+test:do_catchsql_test(
+    "func-5-6.6.2", [[
+        SELECT length(123);
+    ]], {
+        1, "Type mismatch: can not convert 123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.6.3", [[
+        SELECT length(-123);
+    ]], {
+        1, "Type mismatch: can not convert -123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.6.4", [[
+        SELECT length(-5.5);
+    ]], {
+        1, "Type mismatch: can not convert -5.5 to string"
+    })
+
+test:do_execsql_test(
+    "func-5-6.6.5", [[
+        SELECT length('-123');
+    ]], {
+        4
+    })
+
+test:do_catchsql_test(
+    "func-5-6.6.6", [[
+        SELECT length(false);
+    ]], {
+        1, "Type mismatch: can not convert FALSE to string"
+    })
+
+test:do_execsql_test(
+    "func-5-6.6.7", [[
+        SELECT length(X'3334');
+    ]], {
+        2
+    })
+
+test:do_execsql_test(
+    "func-5-6.7.1", [[
+        SELECT char_length(NULL);
+    ]],{
+        ""
+    })
+
+test:do_catchsql_test(
+    "func-5-6.7.2", [[
+        SELECT char_length(123);
+    ]], {
+        1, "Type mismatch: can not convert 123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.7.3", [[
+        SELECT char_length(-123);
+    ]], {
+        1, "Type mismatch: can not convert -123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.7.4", [[
+        SELECT char_length(-5.5);
+    ]], {
+        1, "Type mismatch: can not convert -5.5 to string"
+    })
+
+test:do_execsql_test(
+    "func-5-6.7.5", [[
+        SELECT char_length('-123');
+    ]], {
+        4
+    })
+
+test:do_catchsql_test(
+    "func-5-6.7.6", [[
+        SELECT char_length(false);
+    ]], {
+        1, "Type mismatch: can not convert FALSE to string"
+    })
+
+test:do_execsql_test(
+    "func-5-6.7.7", [[
+        SELECT char_length(X'3334');
+    ]], {
+        2
+    })
+
+test:do_execsql_test(
+    "func-5-6.8.1", [[
+        SELECT character_length(NULL);
+    ]],{
+        ""
+    })
+
+test:do_catchsql_test(
+    "func-5-6.8.2", [[
+        SELECT character_length(123);
+    ]], {
+        1, "Type mismatch: can not convert 123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.8.3", [[
+        SELECT character_length(-123);
+    ]], {
+        1, "Type mismatch: can not convert -123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.8.4", [[
+        SELECT character_length(-5.5);
+    ]], {
+        1, "Type mismatch: can not convert -5.5 to string"
+    })
+
+test:do_execsql_test(
+    "func-5-6.8.5", [[
+        SELECT character_length('-123');
+    ]], {
+        4
+    })
+
+test:do_catchsql_test(
+    "func-5-6.8.6", [[
+        SELECT character_length(false);
+    ]], {
+        1, "Type mismatch: can not convert FALSE to string"
+    })
+
+test:do_execsql_test(
+    "func-5-6.8.7", [[
+        SELECT character_length(X'3334');
+    ]], {
+        2
+    })
+
 test:finish_test()
diff --git a/test/sql-tap/orderby1.test.lua b/test/sql-tap/orderby1.test.lua
index 51e8d301f..95a8de487 100755
--- a/test/sql-tap/orderby1.test.lua
+++ b/test/sql-tap/orderby1.test.lua
@@ -735,7 +735,7 @@ test:do_execsql_test(
         SELECT (
           SELECT 'hardware' FROM ( 
             SELECT 'software' ORDER BY 'firmware' ASC, 'sportswear' DESC
-          ) GROUP BY 1 HAVING length(b) <> 0
+          ) GROUP BY 1 HAVING length(CAST(b AS STRING)) <> 0
         )
         FROM abc;
     ]], {
diff --git a/test/sql/boolean.result b/test/sql/boolean.result
index c470ebd40..39098b1f4 100644
--- a/test/sql/boolean.result
+++ b/test/sql/boolean.result
@@ -314,14 +314,8 @@ SELECT quote(a) FROM t0;
 -- gh-4462: LENGTH didn't take BOOLEAN arguments.
 SELECT length(a) FROM t0;
  | ---
- | - metadata:
- |   - name: length(a)
- |     type: integer
- |   rows:
- |   - [5]
- |   - [4]
- |   - [null]
- |   - [null]
+ | - null
+ | - 'Type mismatch: can not convert FALSE to string'
  | ...
 SELECT typeof(a) FROM t0;
  | ---
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v5 08/17] sql: check operands of LIKE
  2020-07-14 15:48 [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment imeevma
                   ` (6 preceding siblings ...)
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 07/17] sql: check args of length() imeevma
@ 2020-07-14 15:48 ` imeevma
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 09/17] sql: check args of lower() and upper() imeevma
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: imeevma @ 2020-07-14 15:48 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

After this patch, the operand types of LIKE will be checked
properly.

Part of #4159
---
 src/box/sql/func.c          | 17 +++----------
 test/sql-tap/func5.test.lua | 51 ++++++++++++++++++++++++++++++++++++-
 test/sql/types.result       | 24 +++++++----------
 3 files changed, 63 insertions(+), 29 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index a22ba38e2..e03d7d2e2 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -1203,18 +1203,9 @@ likeFunc(sql_context *context, int argc, sql_value **argv)
 	sql *db = sql_context_db_handle(context);
 	int rhs_type = sql_value_type(argv[0]);
 	int lhs_type = sql_value_type(argv[1]);
-
-	if (lhs_type != MP_STR || rhs_type != MP_STR) {
-		if (lhs_type == MP_NIL || rhs_type == MP_NIL)
-			return;
-		char *inconsistent_type = rhs_type != MP_STR ?
-					  mem_type_to_str(argv[0]) :
-					  mem_type_to_str(argv[1]);
-		diag_set(ClientError, ER_INCONSISTENT_TYPES, "text",
-			 inconsistent_type);
-		context->is_aborted = true;
+	if (lhs_type == MP_NIL || rhs_type == MP_NIL)
 		return;
-	}
+	assert(lhs_type == MP_STR && rhs_type == MP_STR);
 	const char *zB = (const char *) sql_value_text(argv[0]);
 	const char *zA = (const char *) sql_value_text(argv[1]);
 	const char *zB_end = zB + sql_value_bytes(argv[0]);
@@ -2565,8 +2556,8 @@ static struct {
 	}, {
 	 .name = "LIKE",
 	 .param_count = -1,
-	 .first_arg = FIELD_TYPE_ANY,
-	 .args = FIELD_TYPE_ANY,
+	 .first_arg = FIELD_TYPE_STRING,
+	 .args = FIELD_TYPE_STRING,
 	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_INTEGER,
 	 .aggregate = FUNC_AGGREGATE_NONE,
diff --git a/test/sql-tap/func5.test.lua b/test/sql-tap/func5.test.lua
index 0398d8a9d..84877a919 100755
--- a/test/sql-tap/func5.test.lua
+++ b/test/sql-tap/func5.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(78)
+test:plan(85)
 
 --!./tcltestrunner.lua
 -- 2010 August 27
@@ -689,4 +689,53 @@ test:do_execsql_test(
         2
     })
 
+test:do_execsql_test(
+    "func-5-6.9.1", [[
+        SELECT NULL like NULL;
+    ]],{
+        ""
+    })
+
+test:do_catchsql_test(
+    "func-5-6.9.2", [[
+        SELECT 123 like 123;
+    ]], {
+        1, "Type mismatch: can not convert 123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.9.3", [[
+        SELECT -123 like -123;
+    ]], {
+        1, "Type mismatch: can not convert -123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.9.4", [[
+        SELECT -5.5 like -5.5;
+    ]], {
+        1, "Type mismatch: can not convert -5.5 to string"
+    })
+
+test:do_execsql_test(
+    "func-5-6.9.5", [[
+        SELECT '-123' like '-123';
+    ]], {
+        true
+    })
+
+test:do_catchsql_test(
+    "func-5-6.9.6", [[
+        SELECT false like false;
+    ]], {
+        1, "Type mismatch: can not convert FALSE to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.9.7", [[
+        SELECT X'3334' like X'3334';
+    ]], {
+        1, "Type mismatch: can not convert varbinary to string"
+    })
+
 test:finish_test()
diff --git a/test/sql/types.result b/test/sql/types.result
index f5c059ef0..04633ba8f 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -215,25 +215,22 @@ box.execute("INSERT INTO t1 VALUES (randomblob(5));")
 box.execute("SELECT * FROM t1 WHERE s LIKE 'blob';")
 ---
 - null
-- 'Inconsistent types: expected text got varbinary'
+- 'Type mismatch: can not convert varbinary to string'
 ...
 box.execute("SELECT * FROM t1 WHERE 'blob' LIKE s;")
 ---
 - null
-- 'Inconsistent types: expected text got varbinary'
+- 'Type mismatch: can not convert varbinary to string'
 ...
 box.execute("SELECT * FROM t1 WHERE 'blob' LIKE x'0000';")
 ---
 - null
-- 'Inconsistent types: expected text got varbinary'
+- 'Type mismatch: can not convert varbinary to string'
 ...
 box.execute("SELECT s LIKE NULL FROM t1;")
 ---
-- metadata:
-  - name: s LIKE NULL
-    type: integer
-  rows:
-  - [null]
+- null
+- 'Type mismatch: can not convert varbinary to string'
 ...
 box.execute("DELETE FROM t1;")
 ---
@@ -246,20 +243,17 @@ box.execute("INSERT INTO t1 VALUES (1);")
 box.execute("SELECT * FROM t1 WHERE s LIKE 'int';")
 ---
 - null
-- 'Inconsistent types: expected text got unsigned'
+- 'Type mismatch: can not convert 1 to string'
 ...
 box.execute("SELECT * FROM t1 WHERE 'int' LIKE 4;")
 ---
 - null
-- 'Inconsistent types: expected text got unsigned'
+- 'Type mismatch: can not convert 4 to string'
 ...
 box.execute("SELECT NULL LIKE s FROM t1;")
 ---
-- metadata:
-  - name: NULL LIKE s
-    type: integer
-  rows:
-  - [null]
+- null
+- 'Type mismatch: can not convert 1 to string'
 ...
 box.space.T1:drop()
 ---
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v5 09/17] sql: check args of lower() and upper()
  2020-07-14 15:48 [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment imeevma
                   ` (7 preceding siblings ...)
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 08/17] sql: check operands of LIKE imeevma
@ 2020-07-14 15:48 ` imeevma
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 10/17] sql: check args of position() imeevma
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: imeevma @ 2020-07-14 15:48 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

After this patch, the argument types of the lower() and upper()
functions will be checked properly.

Part of #4159
---
 src/box/sql/func.c          |  15 +++---
 test/sql-tap/cse.test.lua   |   8 +--
 test/sql-tap/func.test.lua  |   8 +--
 test/sql-tap/func5.test.lua | 100 +++++++++++++++++++++++++++++++++++-
 test/sql/boolean.result     |  20 ++------
 test/sql/types.result       |  38 ++++----------
 6 files changed, 127 insertions(+), 62 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index e03d7d2e2..2910f308f 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -872,13 +872,10 @@ case_type##ICUFunc(sql_context *context, int argc, sql_value **argv)   \
 	const char *z2;                                                        \
 	int n;                                                                 \
 	UNUSED_PARAMETER(argc);                                                \
-	int arg_type = sql_value_type(argv[0]);                                \
-	if (mp_type_is_bloblike(arg_type)) {                                   \
-		diag_set(ClientError, ER_INCONSISTENT_TYPES, "text",           \
-			 "varbinary");                                         \
-		context->is_aborted = true;                                    \
-		return;                                                        \
-	}                                                                      \
+	enum mp_type mp_type = sql_value_type(argv[0]);                        \
+	if (mp_type == MP_NIL)                                                 \
+		return sql_result_null(context);                               \
+	assert(mp_type == MP_STR);                                             \
 	z2 = (char *)sql_value_text(argv[0]);                              \
 	n = sql_value_bytes(argv[0]);                                      \
 	/*                                                                     \
@@ -2608,7 +2605,7 @@ static struct {
 	}, {
 	 .name = "LOWER",
 	 .param_count = 1,
-	 .first_arg = FIELD_TYPE_ANY,
+	 .first_arg = FIELD_TYPE_STRING,
 	 .args = FIELD_TYPE_ANY,
 	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
@@ -2959,7 +2956,7 @@ static struct {
 	}, {
 	 .name = "UPPER",
 	 .param_count = 1,
-	 .first_arg = FIELD_TYPE_ANY,
+	 .first_arg = FIELD_TYPE_STRING,
 	 .args = FIELD_TYPE_ANY,
 	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
diff --git a/test/sql-tap/cse.test.lua b/test/sql-tap/cse.test.lua
index 341b6de01..3c2076a1d 100755
--- a/test/sql-tap/cse.test.lua
+++ b/test/sql-tap/cse.test.lua
@@ -195,23 +195,23 @@ test:do_execsql_test(
 
 
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "cse-1.13",
     [[
         SELECT upper(b), typeof(b), b FROM t1
     ]], {
         -- <cse-1.13>
-        "11", "integer", 11, "21", "integer", 21
+        1, "Type mismatch: can not convert 11 to string"
         -- </cse-1.13>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "cse-1.14",
     [[
         SELECT b, typeof(b), upper(b), typeof(b), b FROM t1
     ]], {
         -- <cse-1.14>
-        11, "integer", "11", "integer", 11, 21, "integer", "21", "integer", 21
+        1, "Type mismatch: can not convert 11 to string"
         -- </cse-1.14>
     })
 
diff --git a/test/sql-tap/func.test.lua b/test/sql-tap/func.test.lua
index 69d175e16..db267d0f5 100755
--- a/test/sql-tap/func.test.lua
+++ b/test/sql-tap/func.test.lua
@@ -760,13 +760,13 @@ test:do_execsql_test(
         -- </func-5.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "func-5.3",
     [[
         SELECT upper(a), lower(a) FROM t2
     ]], {
         -- <func-5.3>
-        "1","1","","","345","345","","","67890","67890"
+        1, "Type mismatch: can not convert 1 to string"
         -- </func-5.3>
     })
 
@@ -794,13 +794,13 @@ test:do_execsql_test(
         -- </func-6.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "func-6.2",
     [[
         SELECT coalesce(upper(a),'nil') FROM t2
     ]], {
         -- <func-6.2>
-        "1","nil","345","nil","67890"
+        1, "Type mismatch: can not convert 1 to string"
         -- </func-6.2>
     })
 
diff --git a/test/sql-tap/func5.test.lua b/test/sql-tap/func5.test.lua
index 84877a919..b704ed7d5 100755
--- a/test/sql-tap/func5.test.lua
+++ b/test/sql-tap/func5.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(85)
+test:plan(99)
 
 --!./tcltestrunner.lua
 -- 2010 August 27
@@ -738,4 +738,102 @@ test:do_catchsql_test(
         1, "Type mismatch: can not convert varbinary to string"
     })
 
+test:do_execsql_test(
+    "func-5-6.10.1", [[
+        SELECT upper(NULL);
+    ]],{
+        ""
+    })
+
+test:do_catchsql_test(
+    "func-5-6.10.2", [[
+        SELECT upper(123);
+    ]], {
+        1, "Type mismatch: can not convert 123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.10.3", [[
+        SELECT upper(-123);
+    ]], {
+        1, "Type mismatch: can not convert -123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.10.4", [[
+        SELECT upper(-5.5);
+    ]], {
+        1, "Type mismatch: can not convert -5.5 to string"
+    })
+
+test:do_execsql_test(
+    "func-5-6.10.5", [[
+        SELECT upper('-123');
+    ]], {
+        "-123"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.10.6", [[
+        SELECT upper(false);
+    ]], {
+        1, "Type mismatch: can not convert FALSE to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.10.7", [[
+        SELECT upper(X'3334');
+    ]], {
+        1, "Type mismatch: can not convert varbinary to string"
+    })
+
+test:do_execsql_test(
+    "func-5-6.11.1", [[
+        SELECT lower(NULL);
+    ]],{
+        ""
+    })
+
+test:do_catchsql_test(
+    "func-5-6.11.2", [[
+        SELECT lower(123);
+    ]], {
+        1, "Type mismatch: can not convert 123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.11.3", [[
+        SELECT lower(-123);
+    ]], {
+        1, "Type mismatch: can not convert -123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.11.4", [[
+        SELECT lower(-5.5);
+    ]], {
+        1, "Type mismatch: can not convert -5.5 to string"
+    })
+
+test:do_execsql_test(
+    "func-5-6.11.5", [[
+        SELECT lower('-123');
+    ]], {
+        "-123"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.11.6", [[
+        SELECT lower(false);
+    ]], {
+        1, "Type mismatch: can not convert FALSE to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.11.7", [[
+        SELECT lower(X'3334');
+    ]], {
+        1, "Type mismatch: can not convert varbinary to string"
+    })
+
 test:finish_test()
diff --git a/test/sql/boolean.result b/test/sql/boolean.result
index 39098b1f4..7e7f97284 100644
--- a/test/sql/boolean.result
+++ b/test/sql/boolean.result
@@ -280,25 +280,13 @@ SELECT abs(a) FROM t0;
  | ...
 SELECT lower(a) FROM t0;
  | ---
- | - metadata:
- |   - name: lower(a)
- |     type: string
- |   rows:
- |   - ['false']
- |   - ['true']
- |   - [null]
- |   - [null]
+ | - null
+ | - 'Type mismatch: can not convert FALSE to string'
  | ...
 SELECT upper(a) FROM t0;
  | ---
- | - metadata:
- |   - name: upper(a)
- |     type: string
- |   rows:
- |   - ['FALSE']
- |   - ['TRUE']
- |   - [null]
- |   - [null]
+ | - null
+ | - 'Type mismatch: can not convert FALSE to string'
  | ...
 SELECT quote(a) FROM t0;
  | ---
diff --git a/test/sql/types.result b/test/sql/types.result
index 04633ba8f..c217cfa14 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -824,19 +824,13 @@ box.execute("DELETE FROM t WHERE i < 18446744073709551613;")
 ...
 box.execute("SELECT lower(i) FROM t;")
 ---
-- metadata:
-  - name: lower(i)
-    type: string
-  rows:
-  - ['18446744073709551613']
+- null
+- 'Type mismatch: can not convert 18446744073709551613 to string'
 ...
 box.execute("SELECT upper(i) FROM t;")
 ---
-- metadata:
-  - name: upper(i)
-    type: string
-  rows:
-  - ['18446744073709551613']
+- null
+- 'Type mismatch: can not convert 18446744073709551613 to string'
 ...
 box.execute("SELECT abs(i) FROM t;")
 ---
@@ -1310,12 +1304,12 @@ box.execute("SELECT group_concat(v) FROM t;")
 box.execute("SELECT lower(v) FROM t;")
 ---
 - null
-- 'Inconsistent types: expected text got varbinary'
+- 'Type mismatch: can not convert varbinary to string'
 ...
 box.execute("SELECT upper(v) FROM t;")
 ---
 - null
-- 'Inconsistent types: expected text got varbinary'
+- 'Type mismatch: can not convert varbinary to string'
 ...
 box.execute("SELECT abs(v) FROM t;")
 ---
@@ -1877,25 +1871,13 @@ box.execute("SELECT group_concat(d) FROM t;")
 ...
 box.execute("SELECT lower(d) FROM t;")
 ---
-- metadata:
-  - name: lower(d)
-    type: string
-  rows:
-  - ['10.0']
-  - ['-2.0']
-  - ['3.3']
-  - ['1.8e+19']
+- null
+- 'Type mismatch: can not convert 10.0 to string'
 ...
 box.execute("SELECT upper(d) FROM t;")
 ---
-- metadata:
-  - name: upper(d)
-    type: string
-  rows:
-  - ['10.0']
-  - ['-2.0']
-  - ['3.3']
-  - ['1.8E+19']
+- null
+- 'Type mismatch: can not convert 10.0 to string'
 ...
 box.execute("SELECT abs(d) FROM t;")
 ---
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v5 10/17] sql: check args of position()
  2020-07-14 15:48 [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment imeevma
                   ` (8 preceding siblings ...)
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 09/17] sql: check args of lower() and upper() imeevma
@ 2020-07-14 15:48 ` imeevma
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 11/17] sql: check args of randomblob() imeevma
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: imeevma @ 2020-07-14 15:48 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

After this patch, the argument types of the position() function
will be checked properly.

Part of #4159
---
 src/box/sql/func.c             | 24 ++++------------
 test/sql-tap/func5.test.lua    | 51 +++++++++++++++++++++++++++++++++-
 test/sql-tap/position.test.lua |  6 ++--
 3 files changed, 58 insertions(+), 23 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 2910f308f..a1b284762 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -532,22 +532,8 @@ position_func(struct sql_context *context, int argc, struct Mem **argv)
 
 	if (haystack_type == MP_NIL || needle_type == MP_NIL)
 		return;
-	/*
-	 * Position function can be called only with string
-	 * or blob params.
-	 */
-	struct Mem *inconsistent_type_arg = NULL;
-	if (needle_type != MP_STR && needle_type != MP_BIN)
-		inconsistent_type_arg = needle;
-	if (haystack_type != MP_STR && haystack_type != MP_BIN)
-		inconsistent_type_arg = haystack;
-	if (inconsistent_type_arg != NULL) {
-		diag_set(ClientError, ER_INCONSISTENT_TYPES,
-			 "text or varbinary",
-			 mem_type_to_str(inconsistent_type_arg));
-		context->is_aborted = true;
-		return;
-	}
+	assert(needle_type == MP_STR || needle_type == MP_BIN);
+	assert(haystack_type == MP_STR || haystack_type == MP_BIN);
 	/*
 	 * Both params of Position function must be of the same
 	 * type.
@@ -2683,9 +2669,9 @@ static struct {
 	}, {
 	 .name = "POSITION",
 	 .param_count = 2,
-	 .first_arg = FIELD_TYPE_ANY,
-	 .args = FIELD_TYPE_ANY,
-	 .is_blob_like_str = false,
+	 .first_arg = FIELD_TYPE_STRING,
+	 .args = FIELD_TYPE_STRING,
+	 .is_blob_like_str = true,
 	 .returns = FIELD_TYPE_INTEGER,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
diff --git a/test/sql-tap/func5.test.lua b/test/sql-tap/func5.test.lua
index b704ed7d5..170dee9f9 100755
--- a/test/sql-tap/func5.test.lua
+++ b/test/sql-tap/func5.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(99)
+test:plan(106)
 
 --!./tcltestrunner.lua
 -- 2010 August 27
@@ -836,4 +836,53 @@ test:do_catchsql_test(
         1, "Type mismatch: can not convert varbinary to string"
     })
 
+test:do_execsql_test(
+    "func-5-6.12.1", [[
+        SELECT position(NULL, NULL);
+    ]],{
+        ""
+    })
+
+test:do_catchsql_test(
+    "func-5-6.12.2", [[
+        SELECT position(23, 123);
+    ]], {
+        1, "Type mismatch: can not convert 23 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.12.3", [[
+        SELECT position(-12, -123);
+    ]], {
+        1, "Type mismatch: can not convert -12 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.12.4", [[
+        SELECT position(-5.5, -5.5);
+    ]], {
+        1, "Type mismatch: can not convert -5.5 to string"
+    })
+
+test:do_execsql_test(
+    "func-5-6.12.5", [[
+        SELECT position('23', '-123');
+    ]], {
+        3
+    })
+
+test:do_catchsql_test(
+    "func-5-6.12.6", [[
+        SELECT position(false, true);
+    ]], {
+        1, "Type mismatch: can not convert FALSE to string"
+    })
+
+test:do_execsql_test(
+    "func-5-6.12.7", [[
+        SELECT position(X'34', X'3334');
+    ]], {
+        2
+    })
+
 test:finish_test()
diff --git a/test/sql-tap/position.test.lua b/test/sql-tap/position.test.lua
index e0455abc9..0d4f6f371 100755
--- a/test/sql-tap/position.test.lua
+++ b/test/sql-tap/position.test.lua
@@ -228,7 +228,7 @@ test:do_test(
         return test:catchsql "SELECT position(34, 12345);"
     end, {
         -- <position-1.23>
-        1, "Inconsistent types: expected text or varbinary got unsigned"
+        1, "Type mismatch: can not convert 34 to string"
         -- </position-1.23>
     })
 
@@ -238,7 +238,7 @@ test:do_test(
         return test:catchsql "SELECT position(34, 123456.78);"
     end, {
         -- <position-1.24>
-        1, "Inconsistent types: expected text or varbinary got real"
+        1, "Type mismatch: can not convert 34 to string"
         -- </position-1.24>
     })
 
@@ -248,7 +248,7 @@ test:do_test(
         return test:catchsql "SELECT position(x'3334', 123456.78);"
     end, {
         -- <position-1.25>
-        1, "Inconsistent types: expected text or varbinary got real"
+        1, "Type mismatch: can not convert 123456.78 to string"
         -- </position-1.25>
     })
 
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v5 11/17] sql: check args of randomblob()
  2020-07-14 15:48 [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment imeevma
                   ` (9 preceding siblings ...)
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 10/17] sql: check args of position() imeevma
@ 2020-07-14 15:48 ` imeevma
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 12/17] sql: check args of replace() imeevma
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: imeevma @ 2020-07-14 15:48 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

After this patch, the argument types of the randomblob() function
will be checked properly.

Part of #4159
---
 src/box/sql/func.c          | 12 ++++-----
 test/sql-tap/func.test.lua  |  6 ++---
 test/sql-tap/func5.test.lua | 51 ++++++++++++++++++++++++++++++++++++-
 3 files changed, 58 insertions(+), 11 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index a1b284762..ae9b6d138 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -937,12 +937,10 @@ randomBlob(sql_context * context, int argc, sql_value ** argv)
 	unsigned char *p;
 	assert(argc == 1);
 	UNUSED_PARAMETER(argc);
-	if (mp_type_is_bloblike(sql_value_type(argv[0]))) {
-		diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
-			 sql_value_to_diag_str(argv[0]), "numeric");
-		context->is_aborted = true;
-		return;
-	}
+	enum mp_type mp_type = sql_value_type(argv[0]);
+	if (mp_type == MP_NIL)
+		return sql_result_null(context);
+	assert(mp_type == MP_UINT);
 	n = sql_value_int(argv[0]);
 	if (n < 1)
 		return;
@@ -2734,7 +2732,7 @@ static struct {
 	}, {
 	 .name = "RANDOMBLOB",
 	 .param_count = 1,
-	 .first_arg = FIELD_TYPE_ANY,
+	 .first_arg = FIELD_TYPE_UNSIGNED,
 	 .args = FIELD_TYPE_ANY,
 	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_VARBINARY,
diff --git a/test/sql-tap/func.test.lua b/test/sql-tap/func.test.lua
index db267d0f5..2ae36fe64 100755
--- a/test/sql-tap/func.test.lua
+++ b/test/sql-tap/func.test.lua
@@ -982,14 +982,14 @@ test:do_execsql_test(
         -- </func-9.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "func-9.5",
     [[
         SELECT length(randomblob(32)), length(randomblob(-5)),
                length(randomblob(2000))
     ]], {
         -- <func-9.5>
-        32, "", 2000
+        1, "Type mismatch: can not convert -5 to unsigned"
         -- </func-9.5>
     })
 
@@ -2928,7 +2928,7 @@ test:do_catchsql_test(
         SELECT RANDOMBLOB(X'FF')
     ]], {
         -- <func-76.2>
-        1, "Type mismatch: can not convert varbinary to numeric"
+        1, "Type mismatch: can not convert varbinary to unsigned"
         -- </func-76.2>
     })
 
diff --git a/test/sql-tap/func5.test.lua b/test/sql-tap/func5.test.lua
index 170dee9f9..30653e9e1 100755
--- a/test/sql-tap/func5.test.lua
+++ b/test/sql-tap/func5.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(106)
+test:plan(113)
 
 --!./tcltestrunner.lua
 -- 2010 August 27
@@ -885,4 +885,53 @@ test:do_execsql_test(
         2
     })
 
+test:do_execsql_test(
+    "func-5-6.13.1", [[
+        SELECT randomblob(NULL);
+    ]],{
+        ""
+    })
+
+test:do_execsql_test(
+    "func-5-6.13.2", [[
+        SELECT typeof(randomblob(123));
+    ]], {
+        "varbinary"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.13.3", [[
+        SELECT randomblob(-123);
+    ]], {
+        1, "Type mismatch: can not convert -123 to unsigned"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.13.4", [[
+        SELECT randomblob(-5.5);
+    ]], {
+        1, "Type mismatch: can not convert -5.5 to unsigned"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.13.5", [[
+        SELECT randomblob('-123');
+    ]], {
+        1, "Type mismatch: can not convert -123 to unsigned"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.13.6", [[
+        SELECT randomblob(false);
+    ]], {
+        1, "Type mismatch: can not convert FALSE to unsigned"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.13.7", [[
+        SELECT randomblob(X'3334');
+    ]], {
+        1, "Type mismatch: can not convert varbinary to unsigned"
+    })
+
 test:finish_test()
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v5 12/17] sql: check args of replace()
  2020-07-14 15:48 [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment imeevma
                   ` (10 preceding siblings ...)
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 11/17] sql: check args of randomblob() imeevma
@ 2020-07-14 15:48 ` imeevma
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 13/17] sql: check args of round() imeevma
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: imeevma @ 2020-07-14 15:48 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

After this patch, the argument types of the replace() function
will be checked properly.

Part of #4159
---
 src/box/sql/func.c          | 21 +++++++++------
 test/sql-tap/func5.test.lua | 51 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 63 insertions(+), 9 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index ae9b6d138..a52b9a103 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -1509,20 +1509,25 @@ replaceFunc(sql_context * context, int argc, sql_value ** argv)
 
 	assert(argc == 3);
 	UNUSED_PARAMETER(argc);
+	enum mp_type str_type = sql_value_type(argv[0]);
+	enum mp_type pattern_type = sql_value_type(argv[1]);
+	enum mp_type rep_type = sql_value_type(argv[2]);
+	if (str_type == MP_NIL || pattern_type == MP_NIL || rep_type == MP_NIL)
+		return sql_result_null(context);
+	assert(str_type == MP_STR || str_type == MP_BIN);
+	assert(pattern_type == MP_STR || pattern_type == MP_BIN);
+	assert(rep_type == MP_STR || rep_type == MP_BIN);
+
 	zStr = sql_value_text(argv[0]);
 	if (zStr == 0)
 		return;
 	nStr = sql_value_bytes(argv[0]);
 	assert(zStr == sql_value_text(argv[0]));	/* No encoding change */
 	zPattern = sql_value_text(argv[1]);
-	if (zPattern == 0) {
-		assert(sql_value_is_null(argv[1])
-		       || sql_context_db_handle(context)->mallocFailed);
+	if (zPattern == 0)
 		return;
-	}
 	nPattern = sql_value_bytes(argv[1]);
 	if (nPattern == 0) {
-		assert(! sql_value_is_null(argv[1]));
 		sql_result_value(context, argv[0]);
 		return;
 	}
@@ -2745,9 +2750,9 @@ static struct {
 	}, {
 	 .name = "REPLACE",
 	 .param_count = 3,
-	 .first_arg = FIELD_TYPE_ANY,
-	 .args = FIELD_TYPE_ANY,
-	 .is_blob_like_str = false,
+	 .first_arg = FIELD_TYPE_STRING,
+	 .args = FIELD_TYPE_STRING,
+	 .is_blob_like_str = true,
 	 .returns = FIELD_TYPE_STRING,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
diff --git a/test/sql-tap/func5.test.lua b/test/sql-tap/func5.test.lua
index 30653e9e1..bf7a338a1 100755
--- a/test/sql-tap/func5.test.lua
+++ b/test/sql-tap/func5.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(113)
+test:plan(120)
 
 --!./tcltestrunner.lua
 -- 2010 August 27
@@ -934,4 +934,53 @@ test:do_catchsql_test(
         1, "Type mismatch: can not convert varbinary to unsigned"
     })
 
+test:do_execsql_test(
+    "func-5-6.14.1", [[
+        SELECT replace(NULL, NULL, NULL);
+    ]],{
+        ""
+    })
+
+test:do_catchsql_test(
+    "func-5-6.6.2", [[
+        SELECT replace(123, 123, 123);
+    ]], {
+        1, "Type mismatch: can not convert 123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.14.3", [[
+        SELECT replace(-123, -123, -123);
+    ]], {
+        1, "Type mismatch: can not convert -123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.14.4", [[
+        SELECT replace(-5.5,-5.5, -5.5);
+    ]], {
+        1, "Type mismatch: can not convert -5.5 to string"
+    })
+
+test:do_execsql_test(
+    "func-5-6.14.5", [[
+        SELECT replace('-123', '-123', '-123');
+    ]], {
+        "-123"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.14.6", [[
+        SELECT replace(false, false, false);
+    ]], {
+        1, "Type mismatch: can not convert FALSE to string"
+    })
+
+test:do_execsql_test(
+    "func-5-6.14.7", [[
+        SELECT replace(X'3334', X'3334', X'3334');
+    ]], {
+        "34"
+    })
+
 test:finish_test()
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v5 13/17] sql: check args of round()
  2020-07-14 15:48 [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment imeevma
                   ` (11 preceding siblings ...)
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 12/17] sql: check args of replace() imeevma
@ 2020-07-14 15:48 ` imeevma
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 14/17] sql: check args of soundex() imeevma
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: imeevma @ 2020-07-14 15:48 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

After this patch, the argument types of the round() function will be
checked properly.

Part of #4159
---
 src/box/sql/func.c          | 24 ++++++++---------
 test/sql-tap/func.test.lua  |  6 ++---
 test/sql-tap/func5.test.lua | 51 ++++++++++++++++++++++++++++++++++++-
 3 files changed, 63 insertions(+), 18 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index a52b9a103..d2b968702 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -789,21 +789,17 @@ roundFunc(sql_context * context, int argc, sql_value ** argv)
 		return;
 	}
 	if (argc == 2) {
-		if (sql_value_is_null(argv[1]))
-			return;
+		enum mp_type precision_type = sql_value_type(argv[1]);
+		if (precision_type == MP_NIL)
+			return sql_result_null(context);
+		assert(precision_type == MP_UINT);
 		n = sql_value_int(argv[1]);
-		if (n < 0)
-			n = 0;
+		assert(n >= 0);
 	}
-	if (sql_value_is_null(argv[0]))
-		return;
 	enum mp_type mp_type = sql_value_type(argv[0]);
-	if (mp_type_is_bloblike(mp_type)) {
-		diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
-			 sql_value_to_diag_str(argv[0]), "numeric");
-		context->is_aborted = true;
-		return;
-	}
+	if (mp_type == MP_NIL)
+		return sql_result_null(context);
+	assert(mp_type == MP_DOUBLE);
 	r = sql_value_double(argv[0]);
 	/* If Y==0 and X will fit in a 64-bit int,
 	 * handle the rounding directly,
@@ -2763,8 +2759,8 @@ static struct {
 	}, {
 	 .name = "ROUND",
 	 .param_count = -1,
-	 .first_arg = FIELD_TYPE_ANY,
-	 .args = FIELD_TYPE_ANY,
+	 .first_arg = FIELD_TYPE_DOUBLE,
+	 .args = FIELD_TYPE_UNSIGNED,
 	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_INTEGER,
 	 .aggregate = FUNC_AGGREGATE_NONE,
diff --git a/test/sql-tap/func.test.lua b/test/sql-tap/func.test.lua
index 2ae36fe64..9d8bf94ed 100755
--- a/test/sql-tap/func.test.lua
+++ b/test/sql-tap/func.test.lua
@@ -502,13 +502,13 @@ test:do_execsql_test(
         -- </func-4.12>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "func-4.13",
     [[
         SELECT round(t1,2) FROM tbl1
     ]], {
         -- <func-4.13>
-        0.0, 0.0, 0.0, 0.0, 0.0
+        1, "Type mismatch: can not convert this to double"
         -- </func-4.13>
     })
 
@@ -2918,7 +2918,7 @@ test:do_catchsql_test(
         SELECT ROUND(X'FF')
     ]], {
         -- <func-76.1>
-        1, "Type mismatch: can not convert varbinary to numeric"
+        1, "Type mismatch: can not convert varbinary to double"
         -- </func-76.1>
     })
 
diff --git a/test/sql-tap/func5.test.lua b/test/sql-tap/func5.test.lua
index bf7a338a1..3351e398b 100755
--- a/test/sql-tap/func5.test.lua
+++ b/test/sql-tap/func5.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(120)
+test:plan(127)
 
 --!./tcltestrunner.lua
 -- 2010 August 27
@@ -983,4 +983,53 @@ test:do_execsql_test(
         "34"
     })
 
+test:do_execsql_test(
+    "func-5-6.15.1", [[
+        SELECT round(NULL, NULL);
+    ]],{
+        ""
+    })
+
+test:do_execsql_test(
+    "func-5-6.15.2", [[
+        SELECT round(123, 3);
+    ]], {
+        123
+    })
+
+test:do_catchsql_test(
+    "func-5-6.15.3", [[
+        SELECT round(-123, -3);
+    ]], {
+        1, "Type mismatch: can not convert -3 to unsigned"
+    })
+
+test:do_execsql_test(
+    "func-5-6.15.4", [[
+        SELECT round(-5.5, 2.5);
+    ]], {
+        -5.5
+    })
+
+test:do_catchsql_test(
+    "func-5-6.15.5", [[
+        SELECT round('-123', '-123');
+    ]], {
+        1, "Type mismatch: can not convert -123 to double"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.15.6", [[
+        SELECT round(false, true);
+    ]], {
+        1, "Type mismatch: can not convert FALSE to double"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.15.7", [[
+        SELECT round(X'3334', X'35');
+    ]], {
+        1, "Type mismatch: can not convert varbinary to double"
+    })
+
 test:finish_test()
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v5 14/17] sql: check args of soundex()
  2020-07-14 15:48 [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment imeevma
                   ` (12 preceding siblings ...)
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 13/17] sql: check args of round() imeevma
@ 2020-07-14 15:48 ` imeevma
  2020-07-14 15:49 ` [Tarantool-patches] [PATCH v5 15/17] sql: check args of substr() imeevma
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 20+ messages in thread
From: imeevma @ 2020-07-14 15:48 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

After this patch, the argument types of the soundex() function will be
checked properly.

Part of #4159
---
 src/box/sql/func.c          | 11 +++-----
 test/sql-tap/func.test.lua  |  2 +-
 test/sql-tap/func5.test.lua | 51 ++++++++++++++++++++++++++++++++++++-
 3 files changed, 55 insertions(+), 9 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index d2b968702..120e37522 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -1820,12 +1820,9 @@ soundexFunc(sql_context * context, int argc, sql_value ** argv)
 	};
 	assert(argc == 1);
 	enum mp_type mp_type = sql_value_type(argv[0]);
-	if (mp_type_is_bloblike(mp_type)) {
-		diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
-			 sql_value_to_diag_str(argv[0]), "text");
-		context->is_aborted = true;
-		return;
-	}
+	if (mp_type == MP_NIL)
+		return sql_result_null(context);
+	assert(mp_type == MP_BIN || mp_type == MP_STR);
 	zIn = (u8 *) sql_value_text(argv[0]);
 	if (zIn == 0)
 		zIn = (u8 *) "";
@@ -2798,7 +2795,7 @@ static struct {
 	}, {
 	 .name = "SOUNDEX",
 	 .param_count = 1,
-	 .first_arg = FIELD_TYPE_ANY,
+	 .first_arg = FIELD_TYPE_STRING,
 	 .args = FIELD_TYPE_ANY,
 	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
diff --git a/test/sql-tap/func.test.lua b/test/sql-tap/func.test.lua
index 9d8bf94ed..35e7be562 100755
--- a/test/sql-tap/func.test.lua
+++ b/test/sql-tap/func.test.lua
@@ -2938,7 +2938,7 @@ test:do_catchsql_test(
         SELECT SOUNDEX(X'FF')
     ]], {
         -- <func-76.3>
-        1, "Type mismatch: can not convert varbinary to text"
+        1, "Type mismatch: can not convert varbinary to string"
         -- </func-76.3>
     })
 
diff --git a/test/sql-tap/func5.test.lua b/test/sql-tap/func5.test.lua
index 3351e398b..d2cddc56d 100755
--- a/test/sql-tap/func5.test.lua
+++ b/test/sql-tap/func5.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(127)
+test:plan(134)
 
 --!./tcltestrunner.lua
 -- 2010 August 27
@@ -1032,4 +1032,53 @@ test:do_catchsql_test(
         1, "Type mismatch: can not convert varbinary to double"
     })
 
+test:do_execsql_test(
+    "func-5-6.16.1", [[
+        SELECT soundex(NULL);
+    ]],{
+        ""
+    })
+
+test:do_catchsql_test(
+    "func-5-6.16.2", [[
+        SELECT soundex(123);
+    ]], {
+        1, "Type mismatch: can not convert 123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.16.3", [[
+        SELECT soundex(-123);
+    ]], {
+        1, "Type mismatch: can not convert -123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.16.4", [[
+        SELECT soundex(-5.5);
+    ]], {
+        1, "Type mismatch: can not convert -5.5 to string"
+    })
+
+test:do_execsql_test(
+    "func-5-6.16.5", [[
+        SELECT soundex('-123');
+    ]], {
+        "?000"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.16.6", [[
+        SELECT soundex(false);
+    ]], {
+        1, "Type mismatch: can not convert FALSE to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.16.7", [[
+        SELECT soundex(X'3334');
+    ]], {
+        1, "Type mismatch: can not convert varbinary to string"
+    })
+
 test:finish_test()
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v5 15/17] sql: check args of substr()
  2020-07-14 15:48 [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment imeevma
                   ` (13 preceding siblings ...)
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 14/17] sql: check args of soundex() imeevma
@ 2020-07-14 15:49 ` imeevma
  2020-07-14 15:49 ` [Tarantool-patches] [PATCH v5 16/17] sql: check args of unicode() imeevma
  2020-07-14 15:49 ` [Tarantool-patches] [PATCH v5 17/17] sql: check args of zeroblob() imeevma
  16 siblings, 0 replies; 20+ messages in thread
From: imeevma @ 2020-07-14 15:49 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

After this patch, the argument types of the substr() function will be
checked properly.

Part of #4159
---
 src/box/sql/func.c          | 25 ++++++++++--------
 test/sql-tap/func.test.lua  |  8 +++---
 test/sql-tap/func2.test.lua | 18 ++++++-------
 test/sql-tap/func5.test.lua | 51 ++++++++++++++++++++++++++++++++++++-
 test/sql/collation.result   |  2 +-
 5 files changed, 78 insertions(+), 26 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 120e37522..a22c50c79 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -677,22 +677,21 @@ substrFunc(sql_context * context, int argc, sql_value ** argv)
 	const unsigned char *z;
 	const unsigned char *z2;
 	int len;
-	int p0type;
 	i64 p1, p2;
 	int negP2 = 0;
 
 	if (argc != 2 && argc != 3) {
 		diag_set(ClientError, ER_FUNC_WRONG_ARG_COUNT, "SUBSTR",
-			 "1 or 2", argc);
+			 "2 or 3", argc);
 		context->is_aborted = true;
 		return;
 	}
-	if (sql_value_is_null(argv[1])
-	    || (argc == 3 && sql_value_is_null(argv[2]))
-	    ) {
-		return;
-	}
-	p0type = sql_value_type(argv[0]);
+	enum mp_type p0type = sql_value_type(argv[0]);
+	enum mp_type mp_type_pos = sql_value_type(argv[1]);
+	if (p0type == MP_NIL || mp_type_pos == MP_NIL)
+		return sql_result_null(context);
+	assert(p0type == MP_STR || p0type == MP_BIN);
+	assert(mp_type_pos == MP_INT || mp_type_pos == MP_UINT);
 	p1 = sql_value_int(argv[1]);
 	if (p0type == MP_BIN) {
 		len = sql_value_bytes(argv[0]);
@@ -709,6 +708,10 @@ substrFunc(sql_context * context, int argc, sql_value ** argv)
 			len = sql_utf8_char_count(z, sql_value_bytes(argv[0]));
 	}
 	if (argc == 3) {
+		enum mp_type mp_type_cnt = sql_value_type(argv[2]);
+		if (mp_type_cnt == MP_NIL)
+			return sql_result_null(context);
+		assert(mp_type_cnt == MP_INT || mp_type_cnt == MP_UINT);
 		p2 = sql_value_int(argv[2]);
 		if (p2 < 0) {
 			p2 = -p2;
@@ -2834,9 +2837,9 @@ static struct {
 	}, {
 	 .name = "SUBSTR",
 	 .param_count = -1,
-	 .first_arg = FIELD_TYPE_ANY,
-	 .args = FIELD_TYPE_ANY,
-	 .is_blob_like_str = false,
+	 .first_arg = FIELD_TYPE_STRING,
+	 .args = FIELD_TYPE_INTEGER,
+	 .is_blob_like_str = true,
 	 .returns = FIELD_TYPE_STRING,
 	 .aggregate = FUNC_AGGREGATE_NONE,
 	 .is_deterministic = true,
diff --git a/test/sql-tap/func.test.lua b/test/sql-tap/func.test.lua
index 35e7be562..c9df2a024 100755
--- a/test/sql-tap/func.test.lua
+++ b/test/sql-tap/func.test.lua
@@ -194,23 +194,23 @@ test:do_execsql_test(
         -- </func-2.8>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "func-2.9",
     [[
         SELECT substr(a,1,1) FROM t2
     ]], {
         -- <func-2.9>
-        "1", "", "3", "", "6"
+        1, "Type mismatch: can not convert 1 to string"
         -- </func-2.9>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "func-2.10",
     [[
         SELECT substr(a,2,2) FROM t2
     ]], {
         -- <func-2.10>
-        "", "", "45", "", "78"
+        1, "Type mismatch: can not convert 1 to string"
         -- </func-2.10>
     })
 
diff --git a/test/sql-tap/func2.test.lua b/test/sql-tap/func2.test.lua
index c9bd3665f..d2c83fcf2 100755
--- a/test/sql-tap/func2.test.lua
+++ b/test/sql-tap/func2.test.lua
@@ -50,7 +50,7 @@ test:do_catchsql_test(
         SELECT SUBSTR()
     ]], {
         -- <func2-1.2.1>
-        1, "Wrong number of arguments is passed to SUBSTR(): expected 1 or 2, got 0"
+        1, "Wrong number of arguments is passed to SUBSTR(): expected 2 or 3, got 0"
         -- </func2-1.2.1>
     })
 
@@ -60,7 +60,7 @@ test:do_catchsql_test(
         SELECT SUBSTR('Supercalifragilisticexpialidocious')
     ]], {
         -- <func2-1.2.2>
-        1, "Wrong number of arguments is passed to SUBSTR(): expected 1 or 2, got 1"
+        1, "Wrong number of arguments is passed to SUBSTR(): expected 2 or 3, got 1"
         -- </func2-1.2.2>
     })
 
@@ -70,7 +70,7 @@ test:do_catchsql_test(
         SELECT SUBSTR('Supercalifragilisticexpialidocious', 1,1,1)
     ]], {
         -- <func2-1.2.3>
-        1, "Wrong number of arguments is passed to SUBSTR(): expected 1 or 2, got 4"
+        1, "Wrong number of arguments is passed to SUBSTR(): expected 2 or 3, got 4"
         -- </func2-1.2.3>
     })
 
@@ -673,7 +673,7 @@ if ("ሴ" ~= "u1234")
             SELECT SUBSTR()
         ]], {
             -- <func2-2.1.2>
-            1, "Wrong number of arguments is passed to SUBSTR(): expected 1 or 2, got 0"
+            1, "Wrong number of arguments is passed to SUBSTR(): expected 2 or 3, got 0"
             -- </func2-2.1.2>
         })
 
@@ -683,7 +683,7 @@ if ("ሴ" ~= "u1234")
             SELECT SUBSTR('hiሴho')
         ]], {
             -- <func2-2.1.3>
-            1, "Wrong number of arguments is passed to SUBSTR(): expected 1 or 2, got 1"
+            1, "Wrong number of arguments is passed to SUBSTR(): expected 2 or 3, got 1"
             -- </func2-2.1.3>
         })
 
@@ -693,7 +693,7 @@ if ("ሴ" ~= "u1234")
             SELECT SUBSTR('hiሴho', 1,1,1)
         ]], {
             -- <func2-2.1.4>
-            1, "Wrong number of arguments is passed to SUBSTR(): expected 1 or 2, got 4"
+            1, "Wrong number of arguments is passed to SUBSTR(): expected 2 or 3, got 4"
             -- </func2-2.1.4>
         })
 
@@ -1038,7 +1038,7 @@ test:do_catchsql_test(
         SELECT SUBSTR()
     ]], {
         -- <func2-3.1.2>
-        1, "Wrong number of arguments is passed to SUBSTR(): expected 1 or 2, got 0"
+        1, "Wrong number of arguments is passed to SUBSTR(): expected 2 or 3, got 0"
         -- </func2-3.1.2>
     })
 
@@ -1048,7 +1048,7 @@ test:do_catchsql_test(
         SELECT SUBSTR(x'1234')
     ]], {
         -- <func2-3.1.3>
-        1, "Wrong number of arguments is passed to SUBSTR(): expected 1 or 2, got 1"
+        1, "Wrong number of arguments is passed to SUBSTR(): expected 2 or 3, got 1"
         -- </func2-3.1.3>
     })
 
@@ -1058,7 +1058,7 @@ test:do_catchsql_test(
         SELECT SUBSTR(x'1234', 1,1,1)
     ]], {
         -- <func2-3.1.4>
-        1, "Wrong number of arguments is passed to SUBSTR(): expected 1 or 2, got 4"
+        1, "Wrong number of arguments is passed to SUBSTR(): expected 2 or 3, got 4"
         -- </func2-3.1.4>
     })
 
diff --git a/test/sql-tap/func5.test.lua b/test/sql-tap/func5.test.lua
index d2cddc56d..78b98f2b1 100755
--- a/test/sql-tap/func5.test.lua
+++ b/test/sql-tap/func5.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(134)
+test:plan(141)
 
 --!./tcltestrunner.lua
 -- 2010 August 27
@@ -1081,4 +1081,53 @@ test:do_catchsql_test(
         1, "Type mismatch: can not convert varbinary to string"
     })
 
+test:do_execsql_test(
+    "func-5-6.17.1", [[
+        SELECT substr(NULL, NULL, NULL);
+    ]],{
+        ""
+    })
+
+test:do_catchsql_test(
+    "func-5-6.17.2", [[
+        SELECT substr(123, 123, 123);
+    ]], {
+        1, "Type mismatch: can not convert 123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.17.3", [[
+        SELECT substr(-123, -123, -123);
+    ]], {
+        1, "Type mismatch: can not convert -123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.17.4", [[
+        SELECT substr(-5.5, -5.5, -5.5);
+    ]], {
+        1, "Type mismatch: can not convert -5.5 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.17.5", [[
+        SELECT substr('-123', '-123', '-123');
+    ]], {
+        1, "Type mismatch: can not convert -123 to integer"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.17.6", [[
+        SELECT substr(false, false, false);
+    ]], {
+        1, "Type mismatch: can not convert FALSE to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.17.7", [[
+        SELECT substr(X'3334', X'3334', X'3334');
+    ]], {
+        1, "Type mismatch: can not convert varbinary to integer"
+    })
+
 test:finish_test()
diff --git a/test/sql/collation.result b/test/sql/collation.result
index 4e4c27ef0..857564607 100644
--- a/test/sql/collation.result
+++ b/test/sql/collation.result
@@ -298,7 +298,7 @@ box.execute("SELECT * FROM t WHERE a COLLATE \"binary\" = c COLLATE \"unicode\";
 box.execute("SELECT * FROM t WHERE a COLLATE \"binary\" = substr();")
 ---
 - null
-- 'Wrong number of arguments is passed to SUBSTR(): expected 1 or 2, got 0'
+- 'Wrong number of arguments is passed to SUBSTR(): expected 2 or 3, got 0'
 ...
 -- Compound queries perform implicit comparisons between values.
 -- Hence, rules for collations compatibilities are the same.
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v5 16/17] sql: check args of unicode()
  2020-07-14 15:48 [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment imeevma
                   ` (14 preceding siblings ...)
  2020-07-14 15:49 ` [Tarantool-patches] [PATCH v5 15/17] sql: check args of substr() imeevma
@ 2020-07-14 15:49 ` imeevma
  2020-07-14 15:49 ` [Tarantool-patches] [PATCH v5 17/17] sql: check args of zeroblob() imeevma
  16 siblings, 0 replies; 20+ messages in thread
From: imeevma @ 2020-07-14 15:49 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

After this patch, the argument types of the unicode() function will be
checked properly.

Part of #4159
---
 src/box/sql/func.c          |  6 ++++-
 test/sql-tap/func5.test.lua | 51 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index a22c50c79..00ba7c9c2 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -1389,6 +1389,10 @@ quoteFunc(sql_context * context, int argc, sql_value ** argv)
 static void
 unicodeFunc(sql_context * context, int argc, sql_value ** argv)
 {
+	enum mp_type mp_type = sql_value_type(argv[0]);
+	if (mp_type == MP_NIL)
+		return sql_result_null(context);
+	assert(mp_type == MP_STR);
 	const unsigned char *z = sql_value_text(argv[0]);
 	(void)argc;
 	if (z && z[0])
@@ -2915,7 +2919,7 @@ static struct {
 	}, {
 	 .name = "UNICODE",
 	 .param_count = 1,
-	 .first_arg = FIELD_TYPE_ANY,
+	 .first_arg = FIELD_TYPE_STRING,
 	 .args = FIELD_TYPE_ANY,
 	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_STRING,
diff --git a/test/sql-tap/func5.test.lua b/test/sql-tap/func5.test.lua
index 78b98f2b1..77105baf2 100755
--- a/test/sql-tap/func5.test.lua
+++ b/test/sql-tap/func5.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(141)
+test:plan(148)
 
 --!./tcltestrunner.lua
 -- 2010 August 27
@@ -1130,4 +1130,53 @@ test:do_catchsql_test(
         1, "Type mismatch: can not convert varbinary to integer"
     })
 
+test:do_execsql_test(
+    "func-5-6.18.1", [[
+        SELECT unicode(NULL);
+    ]],{
+        ""
+    })
+
+test:do_catchsql_test(
+    "func-5-6.18.2", [[
+        SELECT unicode(123);
+    ]], {
+        1, "Type mismatch: can not convert 123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.18.3", [[
+        SELECT unicode(-123);
+    ]], {
+        1, "Type mismatch: can not convert -123 to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.18.4", [[
+        SELECT unicode(-5.5);
+    ]], {
+        1, "Type mismatch: can not convert -5.5 to string"
+    })
+
+test:do_execsql_test(
+    "func-5-6.18.5", [[
+        SELECT unicode('-123');
+    ]], {
+        45
+    })
+
+test:do_catchsql_test(
+    "func-5-6.18.6", [[
+        SELECT unicode(false);
+    ]], {
+        1, "Type mismatch: can not convert FALSE to string"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.18.7", [[
+        SELECT unicode(X'3334');
+    ]], {
+        1, "Type mismatch: can not convert varbinary to string"
+    })
+
 test:finish_test()
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v5 17/17] sql: check args of zeroblob()
  2020-07-14 15:48 [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment imeevma
                   ` (15 preceding siblings ...)
  2020-07-14 15:49 ` [Tarantool-patches] [PATCH v5 16/17] sql: check args of unicode() imeevma
@ 2020-07-14 15:49 ` imeevma
  16 siblings, 0 replies; 20+ messages in thread
From: imeevma @ 2020-07-14 15:49 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

After this patch, the argument types of the zeroblob() function will be
checked properly.

Closes #4159
---
 src/box/sql/func.c          |  9 ++++---
 test/sql-tap/func5.test.lua | 50 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 55 insertions(+), 4 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 00ba7c9c2..5232f6745 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -1480,9 +1480,12 @@ zeroblobFunc(sql_context * context, int argc, sql_value ** argv)
 	i64 n;
 	assert(argc == 1);
 	UNUSED_PARAMETER(argc);
+	enum mp_type mp_type = sql_value_type(argv[0]);
+	if (mp_type == MP_NIL)
+		return sql_result_null(context);
+	assert(mp_type == MP_UINT);
 	n = sql_value_int64(argv[0]);
-	if (n < 0)
-		n = 0;
+	assert(n >= 0);
 	if (sql_result_zeroblob64(context, n) != 0) {
 		diag_set(ClientError, ER_SQL_EXECUTE, "string or binary string"\
 			 "is too big");
@@ -2971,7 +2974,7 @@ static struct {
 	}, {
 	 .name = "ZEROBLOB",
 	 .param_count = 1,
-	 .first_arg = FIELD_TYPE_ANY,
+	 .first_arg = FIELD_TYPE_UNSIGNED,
 	 .args = FIELD_TYPE_ANY,
 	 .is_blob_like_str = false,
 	 .returns = FIELD_TYPE_VARBINARY,
diff --git a/test/sql-tap/func5.test.lua b/test/sql-tap/func5.test.lua
index 77105baf2..582e7220a 100755
--- a/test/sql-tap/func5.test.lua
+++ b/test/sql-tap/func5.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(148)
+test:plan(155)
 
 --!./tcltestrunner.lua
 -- 2010 August 27
@@ -1178,5 +1178,53 @@ test:do_catchsql_test(
     ]], {
         1, "Type mismatch: can not convert varbinary to string"
     })
+test:do_execsql_test(
+    "func-5-6.19.1", [[
+        SELECT zeroblob(NULL);
+    ]],{
+        ""
+    })
+
+test:do_execsql_test(
+    "func-5-6.19.2", [[
+        SELECT zeroblob(3);
+    ]], {
+        '\0\0\0'
+    })
+
+test:do_catchsql_test(
+    "func-5-6.19.3", [[
+        SELECT zeroblob(-123);
+    ]], {
+        1, "Type mismatch: can not convert -123 to unsigned"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.19.4", [[
+        SELECT zeroblob(-5.5);
+    ]], {
+        1, "Type mismatch: can not convert -5.5 to unsigned"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.19.5", [[
+        SELECT zeroblob('-123');
+    ]], {
+        1, "Type mismatch: can not convert -123 to unsigned"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.19.6", [[
+        SELECT zeroblob(false);
+    ]], {
+        1, "Type mismatch: can not convert FALSE to unsigned"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.19.7", [[
+        SELECT zeroblob(X'3334');
+    ]], {
+        1, "Type mismatch: can not convert varbinary to unsigned"
+    })
 
 test:finish_test()
-- 
2.25.1

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

* Re: [Tarantool-patches] [PATCH v5 01/17] sql: set field_type in mem_set_*() functions
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 01/17] sql: set field_type in mem_set_*() functions imeevma
@ 2020-07-15 12:22   ` Nikita Pettik
  0 siblings, 0 replies; 20+ messages in thread
From: Nikita Pettik @ 2020-07-15 12:22 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches

On 14 Jul 18:48, imeevma@tarantool.org wrote:
> After this patch, the mem_set _*() functions will set the mem field type
> along with its MEM type flag. This will allow us to be sure that the MEM
> type and field type are set correctly, which is important when
> converting values from one type to another.
> 
> Needed for #3809
> ---
>  src/box/sql/vdbemem.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)

Pushed to master.
 

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

* Re: [Tarantool-patches] [PATCH v5 02/17] sql: change implicit cast for assignment
  2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 02/17] sql: change implicit cast for assignment imeevma
@ 2020-07-15 13:41   ` Mergen Imeev
  0 siblings, 0 replies; 20+ messages in thread
From: Mergen Imeev @ 2020-07-15 13:41 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

I removed unnecessary flag from convertion functions and rebased.

Diff and new patch below.

On Tue, Jul 14, 2020 at 06:48:13PM +0300, imeevma@tarantool.org wrote:
> This patch changes implicit cast for assignment.
> 
> Closes #3809
> Needed for #4159
> Part of #4230
> 
> @TarantoolBot document
> Title: change implicit cast for comparison
> 
> After this patch, these rules will apply during the implicit cast:
> 
> | | STRING | BINARY | BOOLEAN | INTEGER | UNSIGNED | DOUBLE |
> | :--- | :---: | :---: | :---: | :---: | :---: | :---: |
> | STRING | A | N | N | N | N | N |
> | BINARY | N | A | N | N | N | N |
> | BOOLEAN | N | N | A | N | N | N |
> | INTEGER | N | N | N | A | S | Aa |
> | UNSIGNED | N | N | N | A | A | Aa |
> | DOUBLE | N | N | N | Sa | Sa | A |
> 
> In this table, the types of the assigned value are on the left,
> and the types that should be after the assignment are at the top.
> 
> 'A' - the assignment will be completed.
> 'N' - the assignment won't be completed.
> 'S' - the appointment may be unsuccessful.
> 'a' - after assignment, the resulting value may be approximated.
> 
> Rules for numeric values are these:
> 1) Loss of significant digits (overflow) is an error.
> 2) Loss of insignificant digits is not an error.
> 
> Example:
> ```
> tarantool> box.execute([[CREATE TABLE t1(i INT PRIMARY KEY);]])
> tarantool> box.execute([[INSERT INTO t1 VALUES ('1');]])
> ---
> - null
> - 'Type mismatch: can not convert 1 to integer'
> ...
> 
> tarantool> box.execute('INSERT INTO t1 VALUES (1.2345);')
> tarantool> box.execute('SELECT * FROM t1;')
> ---
> - metadata:
>   - name: I
>     type: integer
>   rows:
>   - [1]
> ...
> 
> tarantool> box.execute([[CREATE TABLE t2(t text PRIMARY KEY);]])
> tarantool> box.execute([[INSERT INTO t2 VALUES (1);]])
> ---
> - null
> - 'Type mismatch: can not convert 1 to string'
> ...
> ```
> ---
>  src/box/sql/vdbe.c                   | 168 ++++-
>  src/box/sql/vdbeInt.h                |   4 +
>  test/sql-tap/autoinc.test.lua        |   2 +-
>  test/sql-tap/default.test.lua        |   6 +-
>  test/sql-tap/e_select1.test.lua      |  27 +-
>  test/sql-tap/in3.test.lua            |  14 +-
>  test/sql-tap/in4.test.lua            |  96 +--
>  test/sql-tap/index1.test.lua         |  24 +-
>  test/sql-tap/insert3.test.lua        |  10 +-
>  test/sql-tap/intpkey.test.lua        | 133 +---
>  test/sql-tap/limit.test.lua          |   2 +-
>  test/sql-tap/minmax2.test.lua        |   6 +-
>  test/sql-tap/misc1.test.lua          |  24 +-
>  test/sql-tap/numcast.test.lua        |   6 +-
>  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/subquery.test.lua       |  69 +-
>  test/sql-tap/tkt-3998683a16.test.lua |  26 +-
>  test/sql-tap/tkt-54844eea3f.test.lua |   8 +-
>  test/sql-tap/tkt-7bbfb7d442.test.lua |   4 +-
>  test/sql-tap/tkt-9a8b09f8e6.test.lua |  62 +-
>  test/sql-tap/tkt-f973c7ac31.test.lua |  18 +-
>  test/sql-tap/tkt-fc7bd6358f.test.lua | 111 ----
>  test/sql-tap/tkt1444.test.lua        |   4 +-
>  test/sql-tap/tkt3493.test.lua        |   6 +-
>  test/sql-tap/tkt3841.test.lua        |  12 +-
>  test/sql-tap/transitive1.test.lua    |   4 +-
>  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         | 908 ---------------------------
>  test/sql-tap/whereC.test.lua         |   8 +-
>  test/sql/types.result                | 620 ++++++++++++++++++
>  test/sql/types.test.lua              | 129 ++++
>  37 files changed, 1050 insertions(+), 1515 deletions(-)
>  delete mode 100755 test/sql-tap/tkt-fc7bd6358f.test.lua
>  delete mode 100755 test/sql-tap/whereB.test.lua
> 
> diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
> index 950f72ddd..41a4750da 100644
> --- a/src/box/sql/vdbe.c
> +++ b/src/box/sql/vdbe.c
> @@ -417,6 +417,144 @@ sql_value_apply_type(
>  	mem_apply_type((Mem *) pVal, type);
>  }
>  
> +/**
> + * Check that MEM_type of the mem is compatible with given type.
> + *
> + * @param mem The MEM that contains the value to check.
> + * @param type The type to check.
> + * @retval TRUE if the MEM_type of the value and the given type
> + *         are compatible, FALSE otherwise.
> + */
> +static bool
> +mem_is_type_compatible(struct Mem *mem, enum field_type type)
> +{
> +	enum mp_type mp_type = mem_mp_type(mem);
> +	assert(mp_type < MP_EXT);
> +	return field_mp_plain_type_is_compatible(type, mp_type, true);
> +}
> +
> +/**
> + * Convert the numeric value contained in MEM to double. If the
> + * is_precise flag is set, the conversion will succeed only if it
> + * is lossless.
> + *
> + * @param mem The MEM that contains the numeric value.
> + * @param is_precise Flag.
> + * @retval 0 if the conversion was successful, -1 otherwise.
> + */
> +static int
> +mem_convert_to_double(struct Mem *mem, bool is_precise)
> +{
> +	if ((mem->flags & MEM_Real) != 0)
> +		return 0;
> +	if ((mem->flags & (MEM_Int | MEM_UInt)) == 0)
> +		return -1;
> +	if ((mem->flags & MEM_Int) != 0) {
> +		int64_t i = mem->u.i;
> +		double d = (double)i;
> +		if (!is_precise || i == (int64_t)d)
> +			mem_set_double(mem, d);
> +		else
> +			return -1;
> +	} else {
> +		uint64_t u = mem->u.u;
> +		double d = (double)u;
> +		if (!is_precise || u == (uint64_t)d)
> +			mem_set_double(mem, d);
> +		else
> +			return -1;
> +	}
> +	return 0;
> +}
> +
> +/**
> + * Convert the numeric value contained in MEM to unsigned. If the
> + * is_precise flag is set, the conversion will succeed only if it
> + * is lossless.
> + *
> + * @param mem The MEM that contains the numeric value.
> + * @param is_precise Flag.
> + * @retval 0 if the conversion was successful, -1 otherwise.
> + */
> +static int
> +mem_convert_to_unsigned(struct Mem *mem, bool is_precise)
> +{
> +	if ((mem->flags & MEM_UInt) != 0)
> +		return 0;
> +	if ((mem->flags & MEM_Int) != 0)
> +		return -1;
> +	if ((mem->flags & MEM_Real) == 0)
> +		return -1;
> +	double d = mem->u.r;
> +	if (d < 0.0 || d >= (double)UINT64_MAX)
> +		return -1;
> +	uint64_t u = (uint64_t)d;
> +	if (!is_precise || d == (double)u)
> +		mem_set_u64(mem, (uint64_t) d);
> +	else
> +		return -1;
> +	return 0;
> +}
> +
> +/**
> + * Convert the numeric value contained in MEM to integer. If the
> + * is_precise flag is set, the conversion will succeed only if it
> + * is lossless.
> + *
> + * @param mem The MEM that contains the numeric value.
> + * @param is_precise Flag.
> + * @retval 0 if the conversion was successful, -1 otherwise.
> + */
> +static int
> +mem_convert_to_integer(struct Mem *mem, bool is_precise)
> +{
> +	if ((mem->flags & (MEM_UInt | MEM_Int)) != 0)
> +		return 0;
> +	if ((mem->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 (!is_precise || d == (double)i)
> +			mem_set_int(mem, (int64_t) d, d < 0);
> +		else
> +			return -1;
> +	} else {
> +		uint64_t u = (uint64_t)d;
> +		if (!is_precise || d == (double)u)
> +			mem_set_int(mem, (uint64_t) d, false);
> +		else
> +			return -1;
> +	}
> +	return 0;
> +}
> +
> +/**
> + * Convert the numeric value contained in MEM to another numeric
> + * type. If the is_precise flag is set, the conversion will
> + * succeed only if it is lossless.
> + *
> + * @param mem The MEM that contains the numeric value.
> + * @param type The type to convert to.
> + * @param is_precise Flag.
> + * @retval 0 if the conversion was successful, -1 otherwise.
> + */
> +static int
> +mem_convert_to_numeric(struct Mem *mem, enum field_type type, bool is_precise)
> +{
> +	assert(mp_type_is_numeric(mem_mp_type(mem)) &&
> +	       sql_type_is_numeric(type));
> +	assert(type != FIELD_TYPE_NUMBER);
> +	if (type == FIELD_TYPE_DOUBLE)
> +		return mem_convert_to_double(mem, is_precise);
> +	if (type == FIELD_TYPE_UNSIGNED)
> +		return mem_convert_to_unsigned(mem, is_precise);
> +	assert(type == FIELD_TYPE_INTEGER);
> +	return mem_convert_to_integer(mem, is_precise);
> +}
> +
>  /*
>   * 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
> @@ -2747,11 +2885,11 @@ case OP_Fetch: {
>  /* 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.
> + * Check that types of P2 registers starting from register P1 are
> + * compatible with given field types in P4. If the MEM_type of the
> + * value and the given type are incompatible according to
> + * field_mp_plain_type_is_compatible(), but both are numeric,
> + * this opcode attempts to convert the value to the type.
>   */
>  case OP_ApplyType: {
>  	enum field_type *types = pOp->p4.types;
> @@ -2762,13 +2900,23 @@ case OP_ApplyType: {
>  	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;
> +		if (!mem_is_type_compatible(pIn1, type)) {
> +			/* Implicit cast is allowed only to numeric type. */
> +			if (!sql_type_is_numeric(type))
> +				goto type_mismatch;
> +			/* Implicit cast is allowed only from numeric type. */
> +			if (!mp_type_is_numeric(mem_mp_type(pIn1)))
> +				goto type_mismatch;
> +			/* Try to convert numeric-to-numeric. */
> +			if (mem_convert_to_numeric(pIn1, type, false) != 0)
> +				goto type_mismatch;
>  		}
>  		pIn1++;
> +		continue;
> +type_mismatch:
> +		diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
> +			 sql_value_to_diag_str(pIn1), field_type_strs[type]);
> +		goto abort_due_to_error;
>  	}
>  	break;
>  }
> diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
> index 44c27bdb7..ad46ab129 100644
> --- a/src/box/sql/vdbeInt.h
> +++ b/src/box/sql/vdbeInt.h
> @@ -566,6 +566,10 @@ mem_mp_type(struct Mem *mem);
>   */
>  #define mp_type_is_bloblike(X) ((X) == MP_BIN || (X) == MP_ARRAY || (X) == MP_MAP)
>  
> +/** Return TRUE if MP_type of X is numeric, FALSE otherwise. */
> +#define mp_type_is_numeric(X) ((X) == MP_INT || (X) == MP_UINT ||\
> +			       (X) == MP_DOUBLE)
> +
>  /**
>   * Memory cell mem contains the context of an aggregate function.
>   * This routine calls the finalize method for that function. The
> diff --git a/test/sql-tap/autoinc.test.lua b/test/sql-tap/autoinc.test.lua
> index 37e65e541..07442b60a 100755
> --- a/test/sql-tap/autoinc.test.lua
> +++ b/test/sql-tap/autoinc.test.lua
> @@ -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..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
> @@ -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>
>  
> @@ -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/in3.test.lua b/test/sql-tap/in3.test.lua
> index e29db9d93..a6d842962 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/in4.test.lua b/test/sql-tap/in4.test.lua
> index 8c6917379..5c01ccdab 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"
> @@ -585,98 +585,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/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..684a24114 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(31)
>  
>  --!./tcltestrunner.lua
>  -- 2001 September 15
> @@ -770,142 +770,13 @@ 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",
> -    [[
> -        SELECT * FROM t1 WHERE a=1;
> -    ]], {
> -        -- <intpkey-13.1>
> -        
> -        -- </intpkey-13.1>
> -    })
> -
> -test:do_execsql_test(
> -    "intpkey-13.2",
> -    [[
> -        INSERT INTO t1 VALUES('1',2,3);
> -        SELECT * FROM t1 WHERE a=1;
> -    ]], {
> -        -- <intpkey-13.2>
> -        1, "2", "3"
> -        -- </intpkey-13.2>
> -    })
> -
> --- MUST_WORK_TEST
> -if (0 > 0) then
> -    -- Tarantool: issue submitted #2315
> -    test:do_catchsql_test(
> -        "intpkey-13.3",
> -        [[
> -            INSERT INTO t1 VALUES('1.5',3,4);
> -        ]], {
> -            -- <intpkey-13.3>
> -            1, "datatype mismatch"
> -            -- </intpkey-13.3>
> -        })
> -
> -    test:do_catchsql_test(
> -        "intpkey-13.4",
> -        [[
> -            INSERT INTO t1 VALUES(x'123456',3,4);
> -        ]], {
> -            -- <intpkey-13.4>
> -            1, "datatype mismatch"
> -            -- </intpkey-13.4>
> -        })
> -
> -
> -
> -end
> -test:do_catchsql_test(
> -    "intpkey-13.5",
> -    [[
> -        INSERT INTO t1 VALUES('+1234567890',3,4);
> -    ]], {
> -        -- <intpkey-13.5>
> -        0
> -        -- </intpkey-13.5>
> -    })
> -
> --- Compare an INTEGER PRIMARY KEY against a TEXT expression. The INTEGER
> --- affinity should be applied to the text value before the comparison
> --- takes place.
> ---
> -test:do_execsql_test(
> -    "intpkey-14.1",
> -    [[
> -        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);
> -    ]], {
> -        -- <intpkey-14.1>
> -        
> -        -- </intpkey-14.1>
> -    })
> -
> -test:do_execsql_test(
> -    "intpkey-14.2",
> -    [[
> -        SELECT * FROM t3 WHERE a>2;
> -    ]], {
> -        -- <intpkey-14.2>
> -        3, 3, "3"
> -        -- </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(
> -    "intpkey-14.4",
> -    [[
> -        SELECT * FROM t3 WHERE a<'2';
> -    ]], {
> -        -- <intpkey-14.4>
> -        1, 1, "one"
> -        -- </intpkey-14.4>
> -    })
> -
> -test:do_execsql_test(
> -    "intpkey-14.5",
> -    [[
> -        SELECT * FROM t3 WHERE a<c;
> -    ]], {
> -        -- <intpkey-14.5>
> -        1, 1, "one"
> -        -- </intpkey-14.5>
> -    })
> -
> -test:do_execsql_test(
> -    "intpkey-14.6",
> -    [[
> -        SELECT * FROM t3 WHERE a=c;
> -    ]], {
> -        -- <intpkey-14.6>
> -        2, 2, "2", 3, 3, "3"
> -        -- </intpkey-14.6>
> -    })
> -
>  -- Check for proper handling of primary keys greater than 2^31.
>  -- Ticket #1188
>  --
>  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/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/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..c0136d04c 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)
> @@ -176,7 +176,7 @@ test:do_test(
>      "misc1-2.1",
>      function()
>          test:execsql([[
> -            CREATE TABLE agger(one text primary key, two text, three text, four text);
> +            CREATE TABLE agger(one int 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');
> @@ -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..3161e48fa 100755
> --- a/test/sql-tap/numcast.test.lua
> +++ b/test/sql-tap/numcast.test.lua
> @@ -135,16 +135,16 @@ 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 2.0e+19 to integer"
>      })
>  
> -test:do_catchsql_test(
> +test:do_execsql_test(
>      "cast-2.9",
>      [[
>          INSERT INTO t VALUES(2.1);
>          SELECT * FROM t;
>      ]], {
> -        1,"Tuple field 1 type does not match one required by operation: expected integer"
> +        2, 9223372036854775808ULL, 18000000000000000000ULL
>      })
>  
>  --
> 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/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-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/tkt-9a8b09f8e6.test.lua b/test/sql-tap/tkt-9a8b09f8e6.test.lua
> index cb5348ab4..ca3a5427a 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
> @@ -193,16 +193,6 @@ test:do_execsql_test(
>          -- </3.3>
>      })
>  
> -test:do_execsql_test(
> -    3.4,
> -    [[
> -        SELECT x FROM t2 WHERE x IN ('1');
> -    ]], {
> -        -- <3.4>
> -        1
> -        -- </3.4>
> -    })
> -
>  test:do_execsql_test(
>      3.5,
>      [[
> @@ -233,16 +223,6 @@ test:do_execsql_test(
>          -- </3.7>
>      })
>  
> -test:do_execsql_test(
> -    3.8,
> -    [[
> -        SELECT x FROM t2 WHERE '1' IN (x);
> -    ]], {
> -        -- <3.8>
> -        1
> -        -- </3.8>
> -    })
> -
>  test:do_execsql_test(
>      4.1,
>      [[
> @@ -263,23 +243,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 1 to number"
>          -- </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 1.0 to number"
>          -- </4.4>
>      })
>  
> @@ -303,23 +283,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 1 to number"
>          -- </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 1.0 to number"
>          -- </4.8>
>      })
>  
> @@ -343,23 +323,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 1 to number"
>          -- </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 1.0 to number"
>          -- </5.4>
>      })
>  
> @@ -373,13 +353,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 1.11 to number"
>          -- </5.6>
>      })
>  
> @@ -403,23 +383,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 1 to number"
>          -- </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 1.0 to number"
>          -- </5.10>
>      })
>  
> @@ -433,13 +413,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 1.11 to number"
>          -- </5.12>
>      })
>  
> diff --git a/test/sql-tap/tkt-f973c7ac31.test.lua b/test/sql-tap/tkt-f973c7ac31.test.lua
> index 82bdb52f8..381f29c65 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/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/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/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/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
> deleted file mode 100755
> index d98645fdc..000000000
> --- a/test/sql-tap/whereB.test.lua
> +++ /dev/null
> @@ -1,908 +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>
> -    })
> -
> --- 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 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 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
> diff --git a/test/sql/types.result b/test/sql/types.result
> index 54aff460e..70fbbc5a2 100644
> --- a/test/sql/types.result
> +++ b/test/sql/types.result
> @@ -2155,3 +2155,623 @@ box.execute([[SELECT * FROM "s" WHERE "id" = ?;]])
>  s:drop()
>  ---
>  ...
> +--
> +-- gh-3809: Make sure there are no implicit casts during
> +-- assignment, except for the implicit cast between numeric
> +-- values.
> +--
> +-- Check INSERT.
> +box.execute([[CREATE TABLE ti (a INT PRIMARY KEY AUTOINCREMENT, i INTEGER);]])
> +---
> +- row_count: 1
> +...
> +box.execute([[CREATE TABLE td (a INT PRIMARY KEY AUTOINCREMENT, d DOUBLE);]])
> +---
> +- row_count: 1
> +...
> +box.execute([[CREATE TABLE tb (a INT PRIMARY KEY AUTOINCREMENT, b BOOLEAN);]])
> +---
> +- row_count: 1
> +...
> +box.execute([[CREATE TABLE tt (a INT PRIMARY KEY AUTOINCREMENT, t TEXT);]])
> +---
> +- row_count: 1
> +...
> +box.execute([[CREATE TABLE tv (a INT PRIMARY KEY AUTOINCREMENT, v VARBINARY);]])
> +---
> +- row_count: 1
> +...
> +box.execute([[CREATE TABLE ts (a INT PRIMARY KEY AUTOINCREMENT, s SCALAR);]])
> +---
> +- row_count: 1
> +...
> +box.execute([[INSERT INTO ti(i) VALUES (NULL);]])
> +---
> +- autoincrement_ids:
> +  - 1
> +  row_count: 1
> +...
> +box.execute([[INSERT INTO ti(i) VALUES (11);]])
> +---
> +- autoincrement_ids:
> +  - 2
> +  row_count: 1
> +...
> +box.execute([[INSERT INTO ti(i) VALUES (100000000000000000000000000000000.1);]])
> +---
> +- null
> +- 'Type mismatch: can not convert 1.0e+32 to integer'
> +...
> +box.execute([[INSERT INTO ti(i) VALUES (33.0);]])
> +---
> +- autoincrement_ids:
> +  - 3
> +  row_count: 1
> +...
> +box.execute([[INSERT INTO ti(i) VALUES (true);]])
> +---
> +- null
> +- 'Type mismatch: can not convert TRUE to integer'
> +...
> +box.execute([[INSERT INTO ti(i) VALUES ('33');]])
> +---
> +- null
> +- 'Type mismatch: can not convert 33 to integer'
> +...
> +box.execute([[INSERT INTO ti(i) VALUES (X'3434');]])
> +---
> +- null
> +- 'Type mismatch: can not convert varbinary to integer'
> +...
> +box.execute([[SELECT * FROM ti;]])
> +---
> +- metadata:
> +  - name: A
> +    type: integer
> +  - name: I
> +    type: integer
> +  rows:
> +  - [1, null]
> +  - [2, 11]
> +  - [3, 33]
> +...
> +box.execute([[INSERT INTO td(d) VALUES (NULL);]])
> +---
> +- autoincrement_ids:
> +  - 1
> +  row_count: 1
> +...
> +box.execute([[INSERT INTO td(d) VALUES (11);]])
> +---
> +- autoincrement_ids:
> +  - 2
> +  row_count: 1
> +...
> +box.execute([[INSERT INTO td(d) VALUES (100000000000000001);;]])
> +---
> +- null
> +- Syntax error at line 1 near ';'
> +...
> +box.execute([[INSERT INTO td(d) VALUES (22.2);]])
> +---
> +- autoincrement_ids:
> +  - 3
> +  row_count: 1
> +...
> +box.execute([[INSERT INTO td(d) VALUES (true);]])
> +---
> +- null
> +- 'Type mismatch: can not convert TRUE to double'
> +...
> +box.execute([[INSERT INTO td(d) VALUES ('33');]])
> +---
> +- null
> +- 'Type mismatch: can not convert 33 to double'
> +...
> +box.execute([[INSERT INTO td(d) VALUES (X'3434');]])
> +---
> +- null
> +- 'Type mismatch: can not convert varbinary to double'
> +...
> +box.execute([[SELECT * FROM td;]])
> +---
> +- metadata:
> +  - name: A
> +    type: integer
> +  - name: D
> +    type: double
> +  rows:
> +  - [1, null]
> +  - [2, 11]
> +  - [3, 22.2]
> +...
> +box.execute([[INSERT INTO tb(b) VALUES (NULL);]])
> +---
> +- autoincrement_ids:
> +  - 1
> +  row_count: 1
> +...
> +box.execute([[INSERT INTO tb(b) VALUES (11);]])
> +---
> +- null
> +- 'Type mismatch: can not convert 11 to boolean'
> +...
> +box.execute([[INSERT INTO tb(b) VALUES (22.2);]])
> +---
> +- null
> +- 'Type mismatch: can not convert 22.2 to boolean'
> +...
> +box.execute([[INSERT INTO tb(b) VALUES (true);]])
> +---
> +- autoincrement_ids:
> +  - 2
> +  row_count: 1
> +...
> +box.execute([[INSERT INTO tb(b) VALUES ('33');]])
> +---
> +- null
> +- 'Type mismatch: can not convert 33 to boolean'
> +...
> +box.execute([[INSERT INTO tb(b) VALUES (X'3434');]])
> +---
> +- null
> +- 'Type mismatch: can not convert varbinary to boolean'
> +...
> +box.execute([[SELECT * FROM tb;]])
> +---
> +- metadata:
> +  - name: A
> +    type: integer
> +  - name: B
> +    type: boolean
> +  rows:
> +  - [1, null]
> +  - [2, true]
> +...
> +box.execute([[INSERT INTO tt(t) VALUES (NULL);]])
> +---
> +- autoincrement_ids:
> +  - 1
> +  row_count: 1
> +...
> +box.execute([[INSERT INTO tt(t) VALUES (11);]])
> +---
> +- null
> +- 'Type mismatch: can not convert 11 to string'
> +...
> +box.execute([[INSERT INTO tt(t) VALUES (22.2);]])
> +---
> +- null
> +- 'Type mismatch: can not convert 22.2 to string'
> +...
> +box.execute([[INSERT INTO tt(t) VALUES (true);]])
> +---
> +- null
> +- 'Type mismatch: can not convert TRUE to string'
> +...
> +box.execute([[INSERT INTO tt(t) VALUES ('33');]])
> +---
> +- autoincrement_ids:
> +  - 2
> +  row_count: 1
> +...
> +box.execute([[INSERT INTO tt(t) VALUES (X'3434');]])
> +---
> +- null
> +- 'Type mismatch: can not convert varbinary to string'
> +...
> +box.execute([[SELECT * FROM tt;]])
> +---
> +- metadata:
> +  - name: A
> +    type: integer
> +  - name: T
> +    type: string
> +  rows:
> +  - [1, null]
> +  - [2, '33']
> +...
> +box.execute([[INSERT INTO tv(v) VALUES (NULL);]])
> +---
> +- autoincrement_ids:
> +  - 1
> +  row_count: 1
> +...
> +box.execute([[INSERT INTO tv(v) VALUES (11);]])
> +---
> +- null
> +- 'Type mismatch: can not convert 11 to varbinary'
> +...
> +box.execute([[INSERT INTO tv(v) VALUES (22.2);]])
> +---
> +- null
> +- 'Type mismatch: can not convert 22.2 to varbinary'
> +...
> +box.execute([[INSERT INTO tv(v) VALUES (true);]])
> +---
> +- null
> +- 'Type mismatch: can not convert TRUE to varbinary'
> +...
> +box.execute([[INSERT INTO tv(v) VALUES ('33');]])
> +---
> +- null
> +- 'Type mismatch: can not convert 33 to varbinary'
> +...
> +box.execute([[INSERT INTO tv(v) VALUES (X'3434');]])
> +---
> +- autoincrement_ids:
> +  - 2
> +  row_count: 1
> +...
> +box.execute([[SELECT * FROM tv;]])
> +---
> +- metadata:
> +  - name: A
> +    type: integer
> +  - name: V
> +    type: varbinary
> +  rows:
> +  - [1, null]
> +  - [2, '44']
> +...
> +box.execute([[INSERT INTO ts(s) VALUES (NULL);]])
> +---
> +- autoincrement_ids:
> +  - 1
> +  row_count: 1
> +...
> +box.execute([[INSERT INTO ts(s) VALUES (11);]])
> +---
> +- autoincrement_ids:
> +  - 2
> +  row_count: 1
> +...
> +box.execute([[INSERT INTO ts(s) VALUES (22.2);]])
> +---
> +- autoincrement_ids:
> +  - 3
> +  row_count: 1
> +...
> +box.execute([[INSERT INTO ts(s) VALUES (true);]])
> +---
> +- autoincrement_ids:
> +  - 4
> +  row_count: 1
> +...
> +box.execute([[INSERT INTO ts(s) VALUES ('33');]])
> +---
> +- autoincrement_ids:
> +  - 5
> +  row_count: 1
> +...
> +box.execute([[INSERT INTO ts(s) VALUES (X'3434');]])
> +---
> +- autoincrement_ids:
> +  - 6
> +  row_count: 1
> +...
> +box.execute([[SELECT * FROM ts;]])
> +---
> +- metadata:
> +  - name: A
> +    type: integer
> +  - name: S
> +    type: scalar
> +  rows:
> +  - [1, null]
> +  - [2, 11]
> +  - [3, 22.2]
> +  - [4, true]
> +  - [5, '33']
> +  - [6, '44']
> +...
> +-- Check for UPDATE.
> +box.execute([[DELETE FROM ti;]])
> +---
> +- row_count: 3
> +...
> +box.execute([[DELETE FROM td;]])
> +---
> +- row_count: 3
> +...
> +box.execute([[DELETE FROM tb;]])
> +---
> +- row_count: 2
> +...
> +box.execute([[DELETE FROM tt;]])
> +---
> +- row_count: 2
> +...
> +box.execute([[DELETE FROM tv;]])
> +---
> +- row_count: 2
> +...
> +box.execute([[DELETE FROM ts;]])
> +---
> +- row_count: 6
> +...
> +box.execute([[INSERT INTO ti VALUES(1, NULL);]])
> +---
> +- row_count: 1
> +...
> +box.execute([[INSERT INTO td VALUES(1, NULL);]])
> +---
> +- row_count: 1
> +...
> +box.execute([[INSERT INTO tb VALUES(1, NULL);]])
> +---
> +- row_count: 1
> +...
> +box.execute([[INSERT INTO tt VALUES(1, NULL);]])
> +---
> +- row_count: 1
> +...
> +box.execute([[INSERT INTO tv VALUES(1, NULL);]])
> +---
> +- row_count: 1
> +...
> +box.execute([[INSERT INTO ts VALUES(1, NULL);]])
> +---
> +- row_count: 1
> +...
> +box.execute([[SELECT * FROM ti, td, tb, tt, tv, ts;]])
> +---
> +- metadata:
> +  - name: A
> +    type: integer
> +  - name: I
> +    type: integer
> +  - name: A
> +    type: integer
> +  - name: D
> +    type: double
> +  - name: A
> +    type: integer
> +  - name: B
> +    type: boolean
> +  - name: A
> +    type: integer
> +  - name: T
> +    type: string
> +  - name: A
> +    type: integer
> +  - name: V
> +    type: varbinary
> +  - name: A
> +    type: integer
> +  - name: S
> +    type: scalar
> +  rows:
> +  - [1, null, 1, null, 1, null, 1, null, 1, null, 1, null]
> +...
> +box.execute([[UPDATE ti SET i = NULL WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[UPDATE ti SET i = 11 WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[UPDATE ti SET i = 100000000000000000000000000000000.1 WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert 1.0e+32 to integer'
> +...
> +box.execute([[UPDATE ti SET i = 33.0 WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[UPDATE ti SET i = true WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert TRUE to integer'
> +...
> +box.execute([[UPDATE ti SET i = '33' WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert 33 to integer'
> +...
> +box.execute([[UPDATE ti SET i = X'3434' WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert varbinary to integer'
> +...
> +box.execute([[SELECT * FROM ti;]])
> +---
> +- metadata:
> +  - name: A
> +    type: integer
> +  - name: I
> +    type: integer
> +  rows:
> +  - [1, 33]
> +...
> +box.execute([[UPDATE td SET d = NULL WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[UPDATE td SET d = 11 WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[UPDATE td SET d = 100000000000000001 WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[UPDATE td SET d = 22.2 WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[UPDATE td SET d = true WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert TRUE to double'
> +...
> +box.execute([[UPDATE td SET d = '33' WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert 33 to double'
> +...
> +box.execute([[UPDATE td SET d = X'3434' WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert varbinary to double'
> +...
> +box.execute([[SELECT * FROM td;]])
> +---
> +- metadata:
> +  - name: A
> +    type: integer
> +  - name: D
> +    type: double
> +  rows:
> +  - [1, 22.2]
> +...
> +box.execute([[UPDATE tb SET b = NULL WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[UPDATE tb SET b = 11 WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert 11 to boolean'
> +...
> +box.execute([[UPDATE tb SET b = 22.2 WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert 22.2 to boolean'
> +...
> +box.execute([[UPDATE tb SET b = true WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[UPDATE tb SET b = '33' WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert 33 to boolean'
> +...
> +box.execute([[UPDATE tb SET b = X'3434' WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert varbinary to boolean'
> +...
> +box.execute([[SELECT * FROM tb;]])
> +---
> +- metadata:
> +  - name: A
> +    type: integer
> +  - name: B
> +    type: boolean
> +  rows:
> +  - [1, true]
> +...
> +box.execute([[UPDATE tt SET t = NULL WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[UPDATE tt SET t = 11 WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert 11 to string'
> +...
> +box.execute([[UPDATE tt SET t = 22.2 WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert 22.2 to string'
> +...
> +box.execute([[UPDATE tt SET t = true WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert TRUE to string'
> +...
> +box.execute([[UPDATE tt SET t = '33' WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[UPDATE tt SET t = X'3434' WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert varbinary to string'
> +...
> +box.execute([[SELECT * FROM tt;]])
> +---
> +- metadata:
> +  - name: A
> +    type: integer
> +  - name: T
> +    type: string
> +  rows:
> +  - [1, '33']
> +...
> +box.execute([[UPDATE tv SET v = NULL WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[UPDATE tv SET v = 11 WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert 11 to varbinary'
> +...
> +box.execute([[UPDATE tv SET v = 22.2 WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert 22.2 to varbinary'
> +...
> +box.execute([[UPDATE tv SET v = true WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert TRUE to varbinary'
> +...
> +box.execute([[UPDATE tv SET v = '33' WHERE a = 1;]])
> +---
> +- null
> +- 'Type mismatch: can not convert 33 to varbinary'
> +...
> +box.execute([[UPDATE tv SET v = X'3434' WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[SELECT * FROM tv;]])
> +---
> +- metadata:
> +  - name: A
> +    type: integer
> +  - name: V
> +    type: varbinary
> +  rows:
> +  - [1, '44']
> +...
> +box.execute([[UPDATE ts SET s = NULL WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[UPDATE ts SET s = 11 WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[UPDATE ts SET s = 22.2 WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[UPDATE ts SET s = true WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[UPDATE ts SET s = '33' WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[UPDATE ts SET s = X'3434' WHERE a = 1;]])
> +---
> +- row_count: 1
> +...
> +box.execute([[SELECT * FROM ts;]])
> +---
> +- metadata:
> +  - name: A
> +    type: integer
> +  - name: S
> +    type: scalar
> +  rows:
> +  - [1, '44']
> +...
> diff --git a/test/sql/types.test.lua b/test/sql/types.test.lua
> index bd14b342d..2dc70f3c5 100644
> --- a/test/sql/types.test.lua
> +++ b/test/sql/types.test.lua
> @@ -487,3 +487,132 @@ s:format({ \
>  
>  box.execute([[SELECT * FROM "s" WHERE "id" = ?;]])
>  s:drop()
> +
> +--
> +-- gh-3809: Make sure there are no implicit casts during
> +-- assignment, except for the implicit cast between numeric
> +-- values.
> +--
> +
> +-- Check INSERT.
> +box.execute([[CREATE TABLE ti (a INT PRIMARY KEY AUTOINCREMENT, i INTEGER);]])
> +box.execute([[CREATE TABLE td (a INT PRIMARY KEY AUTOINCREMENT, d DOUBLE);]])
> +box.execute([[CREATE TABLE tb (a INT PRIMARY KEY AUTOINCREMENT, b BOOLEAN);]])
> +box.execute([[CREATE TABLE tt (a INT PRIMARY KEY AUTOINCREMENT, t TEXT);]])
> +box.execute([[CREATE TABLE tv (a INT PRIMARY KEY AUTOINCREMENT, v VARBINARY);]])
> +box.execute([[CREATE TABLE ts (a INT PRIMARY KEY AUTOINCREMENT, s SCALAR);]])
> +
> +box.execute([[INSERT INTO ti(i) VALUES (NULL);]])
> +box.execute([[INSERT INTO ti(i) VALUES (11);]])
> +box.execute([[INSERT INTO ti(i) VALUES (100000000000000000000000000000000.1);]])
> +box.execute([[INSERT INTO ti(i) VALUES (33.0);]])
> +box.execute([[INSERT INTO ti(i) VALUES (true);]])
> +box.execute([[INSERT INTO ti(i) VALUES ('33');]])
> +box.execute([[INSERT INTO ti(i) VALUES (X'3434');]])
> +box.execute([[SELECT * FROM ti;]])
> +
> +box.execute([[INSERT INTO td(d) VALUES (NULL);]])
> +box.execute([[INSERT INTO td(d) VALUES (11);]])
> +box.execute([[INSERT INTO td(d) VALUES (100000000000000001);;]])
> +box.execute([[INSERT INTO td(d) VALUES (22.2);]])
> +box.execute([[INSERT INTO td(d) VALUES (true);]])
> +box.execute([[INSERT INTO td(d) VALUES ('33');]])
> +box.execute([[INSERT INTO td(d) VALUES (X'3434');]])
> +box.execute([[SELECT * FROM td;]])
> +
> +box.execute([[INSERT INTO tb(b) VALUES (NULL);]])
> +box.execute([[INSERT INTO tb(b) VALUES (11);]])
> +box.execute([[INSERT INTO tb(b) VALUES (22.2);]])
> +box.execute([[INSERT INTO tb(b) VALUES (true);]])
> +box.execute([[INSERT INTO tb(b) VALUES ('33');]])
> +box.execute([[INSERT INTO tb(b) VALUES (X'3434');]])
> +box.execute([[SELECT * FROM tb;]])
> +
> +box.execute([[INSERT INTO tt(t) VALUES (NULL);]])
> +box.execute([[INSERT INTO tt(t) VALUES (11);]])
> +box.execute([[INSERT INTO tt(t) VALUES (22.2);]])
> +box.execute([[INSERT INTO tt(t) VALUES (true);]])
> +box.execute([[INSERT INTO tt(t) VALUES ('33');]])
> +box.execute([[INSERT INTO tt(t) VALUES (X'3434');]])
> +box.execute([[SELECT * FROM tt;]])
> +
> +box.execute([[INSERT INTO tv(v) VALUES (NULL);]])
> +box.execute([[INSERT INTO tv(v) VALUES (11);]])
> +box.execute([[INSERT INTO tv(v) VALUES (22.2);]])
> +box.execute([[INSERT INTO tv(v) VALUES (true);]])
> +box.execute([[INSERT INTO tv(v) VALUES ('33');]])
> +box.execute([[INSERT INTO tv(v) VALUES (X'3434');]])
> +box.execute([[SELECT * FROM tv;]])
> +
> +box.execute([[INSERT INTO ts(s) VALUES (NULL);]])
> +box.execute([[INSERT INTO ts(s) VALUES (11);]])
> +box.execute([[INSERT INTO ts(s) VALUES (22.2);]])
> +box.execute([[INSERT INTO ts(s) VALUES (true);]])
> +box.execute([[INSERT INTO ts(s) VALUES ('33');]])
> +box.execute([[INSERT INTO ts(s) VALUES (X'3434');]])
> +box.execute([[SELECT * FROM ts;]])
> +
> +-- Check for UPDATE.
> +box.execute([[DELETE FROM ti;]])
> +box.execute([[DELETE FROM td;]])
> +box.execute([[DELETE FROM tb;]])
> +box.execute([[DELETE FROM tt;]])
> +box.execute([[DELETE FROM tv;]])
> +box.execute([[DELETE FROM ts;]])
> +box.execute([[INSERT INTO ti VALUES(1, NULL);]])
> +box.execute([[INSERT INTO td VALUES(1, NULL);]])
> +box.execute([[INSERT INTO tb VALUES(1, NULL);]])
> +box.execute([[INSERT INTO tt VALUES(1, NULL);]])
> +box.execute([[INSERT INTO tv VALUES(1, NULL);]])
> +box.execute([[INSERT INTO ts VALUES(1, NULL);]])
> +box.execute([[SELECT * FROM ti, td, tb, tt, tv, ts;]])
> +
> +box.execute([[UPDATE ti SET i = NULL WHERE a = 1;]])
> +box.execute([[UPDATE ti SET i = 11 WHERE a = 1;]])
> +box.execute([[UPDATE ti SET i = 100000000000000000000000000000000.1 WHERE a = 1;]])
> +box.execute([[UPDATE ti SET i = 33.0 WHERE a = 1;]])
> +box.execute([[UPDATE ti SET i = true WHERE a = 1;]])
> +box.execute([[UPDATE ti SET i = '33' WHERE a = 1;]])
> +box.execute([[UPDATE ti SET i = X'3434' WHERE a = 1;]])
> +box.execute([[SELECT * FROM ti;]])
> +
> +box.execute([[UPDATE td SET d = NULL WHERE a = 1;]])
> +box.execute([[UPDATE td SET d = 11 WHERE a = 1;]])
> +box.execute([[UPDATE td SET d = 100000000000000001 WHERE a = 1;]])
> +box.execute([[UPDATE td SET d = 22.2 WHERE a = 1;]])
> +box.execute([[UPDATE td SET d = true WHERE a = 1;]])
> +box.execute([[UPDATE td SET d = '33' WHERE a = 1;]])
> +box.execute([[UPDATE td SET d = X'3434' WHERE a = 1;]])
> +box.execute([[SELECT * FROM td;]])
> +
> +box.execute([[UPDATE tb SET b = NULL WHERE a = 1;]])
> +box.execute([[UPDATE tb SET b = 11 WHERE a = 1;]])
> +box.execute([[UPDATE tb SET b = 22.2 WHERE a = 1;]])
> +box.execute([[UPDATE tb SET b = true WHERE a = 1;]])
> +box.execute([[UPDATE tb SET b = '33' WHERE a = 1;]])
> +box.execute([[UPDATE tb SET b = X'3434' WHERE a = 1;]])
> +box.execute([[SELECT * FROM tb;]])
> +
> +box.execute([[UPDATE tt SET t = NULL WHERE a = 1;]])
> +box.execute([[UPDATE tt SET t = 11 WHERE a = 1;]])
> +box.execute([[UPDATE tt SET t = 22.2 WHERE a = 1;]])
> +box.execute([[UPDATE tt SET t = true WHERE a = 1;]])
> +box.execute([[UPDATE tt SET t = '33' WHERE a = 1;]])
> +box.execute([[UPDATE tt SET t = X'3434' WHERE a = 1;]])
> +box.execute([[SELECT * FROM tt;]])
> +
> +box.execute([[UPDATE tv SET v = NULL WHERE a = 1;]])
> +box.execute([[UPDATE tv SET v = 11 WHERE a = 1;]])
> +box.execute([[UPDATE tv SET v = 22.2 WHERE a = 1;]])
> +box.execute([[UPDATE tv SET v = true WHERE a = 1;]])
> +box.execute([[UPDATE tv SET v = '33' WHERE a = 1;]])
> +box.execute([[UPDATE tv SET v = X'3434' WHERE a = 1;]])
> +box.execute([[SELECT * FROM tv;]])
> +
> +box.execute([[UPDATE ts SET s = NULL WHERE a = 1;]])
> +box.execute([[UPDATE ts SET s = 11 WHERE a = 1;]])
> +box.execute([[UPDATE ts SET s = 22.2 WHERE a = 1;]])
> +box.execute([[UPDATE ts SET s = true WHERE a = 1;]])
> +box.execute([[UPDATE ts SET s = '33' WHERE a = 1;]])
> +box.execute([[UPDATE ts SET s = X'3434' WHERE a = 1;]])
> +box.execute([[SELECT * FROM ts;]])
> -- 
> 2.25.1
> 



Diff:


diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 41a4750da..14ddb5160 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -434,50 +434,35 @@ mem_is_type_compatible(struct Mem *mem, enum field_type type)
 }
 
 /**
- * Convert the numeric value contained in MEM to double. If the
- * is_precise flag is set, the conversion will succeed only if it
- * is lossless.
+ * Convert the numeric value contained in MEM to double.
  *
  * @param mem The MEM that contains the numeric value.
- * @param is_precise Flag.
  * @retval 0 if the conversion was successful, -1 otherwise.
  */
 static int
-mem_convert_to_double(struct Mem *mem, bool is_precise)
+mem_convert_to_double(struct Mem *mem)
 {
 	if ((mem->flags & MEM_Real) != 0)
 		return 0;
 	if ((mem->flags & (MEM_Int | MEM_UInt)) == 0)
 		return -1;
-	if ((mem->flags & MEM_Int) != 0) {
-		int64_t i = mem->u.i;
-		double d = (double)i;
-		if (!is_precise || i == (int64_t)d)
-			mem_set_double(mem, d);
-		else
-			return -1;
-	} else {
-		uint64_t u = mem->u.u;
-		double d = (double)u;
-		if (!is_precise || u == (uint64_t)d)
-			mem_set_double(mem, d);
-		else
-			return -1;
-	}
+	double d;
+	if ((mem->flags & MEM_Int) != 0)
+		d = (double)mem->u.i;
+	else
+		d = (double)mem->u.u;
+	mem_set_double(mem, d);
 	return 0;
 }
 
 /**
- * Convert the numeric value contained in MEM to unsigned. If the
- * is_precise flag is set, the conversion will succeed only if it
- * is lossless.
+ * Convert the numeric value contained in MEM to unsigned.
  *
  * @param mem The MEM that contains the numeric value.
- * @param is_precise Flag.
  * @retval 0 if the conversion was successful, -1 otherwise.
  */
 static int
-mem_convert_to_unsigned(struct Mem *mem, bool is_precise)
+mem_convert_to_unsigned(struct Mem *mem)
 {
 	if ((mem->flags & MEM_UInt) != 0)
 		return 0;
@@ -488,25 +473,18 @@ mem_convert_to_unsigned(struct Mem *mem, bool is_precise)
 	double d = mem->u.r;
 	if (d < 0.0 || d >= (double)UINT64_MAX)
 		return -1;
-	uint64_t u = (uint64_t)d;
-	if (!is_precise || d == (double)u)
-		mem_set_u64(mem, (uint64_t) d);
-	else
-		return -1;
+	mem_set_u64(mem, (uint64_t) d);
 	return 0;
 }
 
 /**
- * Convert the numeric value contained in MEM to integer. If the
- * is_precise flag is set, the conversion will succeed only if it
- * is lossless.
+ * Convert the numeric value contained in MEM to integer.
  *
  * @param mem The MEM that contains the numeric value.
- * @param is_precise Flag.
  * @retval 0 if the conversion was successful, -1 otherwise.
  */
 static int
-mem_convert_to_integer(struct Mem *mem, bool is_precise)
+mem_convert_to_integer(struct Mem *mem)
 {
 	if ((mem->flags & (MEM_UInt | MEM_Int)) != 0)
 		return 0;
@@ -515,44 +493,33 @@ mem_convert_to_integer(struct Mem *mem, bool is_precise)
 	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 (!is_precise || d == (double)i)
-			mem_set_int(mem, (int64_t) d, d < 0);
-		else
-			return -1;
-	} else {
-		uint64_t u = (uint64_t)d;
-		if (!is_precise || d == (double)u)
-			mem_set_int(mem, (uint64_t) d, false);
-		else
-			return -1;
-	}
+	if (d < (double)INT64_MAX)
+		mem_set_int(mem, (int64_t) d, d < 0);
+	else
+		mem_set_int(mem, (uint64_t) d, false);
 	return 0;
 }
 
 /**
  * Convert the numeric value contained in MEM to another numeric
- * type. If the is_precise flag is set, the conversion will
- * succeed only if it is lossless.
+ * type.
  *
  * @param mem The MEM that contains the numeric value.
  * @param type The type to convert to.
- * @param is_precise Flag.
  * @retval 0 if the conversion was successful, -1 otherwise.
  */
 static int
-mem_convert_to_numeric(struct Mem *mem, enum field_type type, bool is_precise)
+mem_convert_to_numeric(struct Mem *mem, enum field_type type)
 {
 	assert(mp_type_is_numeric(mem_mp_type(mem)) &&
 	       sql_type_is_numeric(type));
 	assert(type != FIELD_TYPE_NUMBER);
 	if (type == FIELD_TYPE_DOUBLE)
-		return mem_convert_to_double(mem, is_precise);
+		return mem_convert_to_double(mem);
 	if (type == FIELD_TYPE_UNSIGNED)
-		return mem_convert_to_unsigned(mem, is_precise);
+		return mem_convert_to_unsigned(mem);
 	assert(type == FIELD_TYPE_INTEGER);
-	return mem_convert_to_integer(mem, is_precise);
+	return mem_convert_to_integer(mem);
 }
 
 /*
@@ -2908,7 +2875,7 @@ case OP_ApplyType: {
 			if (!mp_type_is_numeric(mem_mp_type(pIn1)))
 				goto type_mismatch;
 			/* Try to convert numeric-to-numeric. */
-			if (mem_convert_to_numeric(pIn1, type, false) != 0)
+			if (mem_convert_to_numeric(pIn1, type) != 0)
 				goto type_mismatch;
 		}
 		pIn1++;



New patch:

From 92e6b17ecc58833b37bf91bef6bd218e1c5cdc54 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: change implicit cast for assignment

This patch changes implicit cast for assignment.

Closes #3809
Needed for #4159
Part of #4230

@TarantoolBot document
Title: change implicit cast for comparison

After this patch, these rules will apply during the implicit cast:

| | STRING | BINARY | BOOLEAN | INTEGER | UNSIGNED | DOUBLE |
| :--- | :---: | :---: | :---: | :---: | :---: | :---: |
| STRING | A | N | N | N | N | N |
| BINARY | N | A | N | N | N | N |
| BOOLEAN | N | N | A | N | N | N |
| INTEGER | N | N | N | A | S | Aa |
| UNSIGNED | N | N | N | A | A | Aa |
| DOUBLE | N | N | N | Sa | Sa | A |

In this table, the types of the assigned value are on the left,
and the types that should be after the assignment are at the top.

'A' - the assignment will be completed.
'N' - the assignment won't be completed.
'S' - the appointment may be unsuccessful.
'a' - after assignment, the resulting value may be approximated.

Rules for numeric values are these:
1) Loss of significant digits (overflow) is an error.
2) Loss of insignificant digits is not an error.

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

tarantool> box.execute('INSERT INTO t1 VALUES (1.2345);')
tarantool> box.execute('SELECT * FROM t1;')
---
- metadata:
  - name: I
    type: integer
  rows:
  - [1]
...

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

diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 950f72ddd..14ddb5160 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -417,6 +417,111 @@ sql_value_apply_type(
 	mem_apply_type((Mem *) pVal, type);
 }
 
+/**
+ * Check that MEM_type of the mem is compatible with given type.
+ *
+ * @param mem The MEM that contains the value to check.
+ * @param type The type to check.
+ * @retval TRUE if the MEM_type of the value and the given type
+ *         are compatible, FALSE otherwise.
+ */
+static bool
+mem_is_type_compatible(struct Mem *mem, enum field_type type)
+{
+	enum mp_type mp_type = mem_mp_type(mem);
+	assert(mp_type < MP_EXT);
+	return field_mp_plain_type_is_compatible(type, mp_type, true);
+}
+
+/**
+ * Convert the numeric value contained in MEM to double.
+ *
+ * @param mem The MEM that contains the numeric value.
+ * @retval 0 if the conversion was successful, -1 otherwise.
+ */
+static int
+mem_convert_to_double(struct Mem *mem)
+{
+	if ((mem->flags & MEM_Real) != 0)
+		return 0;
+	if ((mem->flags & (MEM_Int | MEM_UInt)) == 0)
+		return -1;
+	double d;
+	if ((mem->flags & MEM_Int) != 0)
+		d = (double)mem->u.i;
+	else
+		d = (double)mem->u.u;
+	mem_set_double(mem, d);
+	return 0;
+}
+
+/**
+ * Convert the numeric value contained in MEM to unsigned.
+ *
+ * @param mem The MEM that contains the numeric value.
+ * @retval 0 if the conversion was successful, -1 otherwise.
+ */
+static int
+mem_convert_to_unsigned(struct Mem *mem)
+{
+	if ((mem->flags & MEM_UInt) != 0)
+		return 0;
+	if ((mem->flags & MEM_Int) != 0)
+		return -1;
+	if ((mem->flags & MEM_Real) == 0)
+		return -1;
+	double d = mem->u.r;
+	if (d < 0.0 || d >= (double)UINT64_MAX)
+		return -1;
+	mem_set_u64(mem, (uint64_t) d);
+	return 0;
+}
+
+/**
+ * Convert the numeric value contained in MEM to integer.
+ *
+ * @param mem The MEM that contains the numeric value.
+ * @retval 0 if the conversion was successful, -1 otherwise.
+ */
+static int
+mem_convert_to_integer(struct Mem *mem)
+{
+	if ((mem->flags & (MEM_UInt | MEM_Int)) != 0)
+		return 0;
+	if ((mem->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)
+		mem_set_int(mem, (int64_t) d, d < 0);
+	else
+		mem_set_int(mem, (uint64_t) d, false);
+	return 0;
+}
+
+/**
+ * Convert the numeric value contained in MEM to another numeric
+ * type.
+ *
+ * @param mem The MEM that contains the numeric value.
+ * @param type The type to convert to.
+ * @retval 0 if the conversion was successful, -1 otherwise.
+ */
+static int
+mem_convert_to_numeric(struct Mem *mem, enum field_type type)
+{
+	assert(mp_type_is_numeric(mem_mp_type(mem)) &&
+	       sql_type_is_numeric(type));
+	assert(type != FIELD_TYPE_NUMBER);
+	if (type == FIELD_TYPE_DOUBLE)
+		return mem_convert_to_double(mem);
+	if (type == FIELD_TYPE_UNSIGNED)
+		return mem_convert_to_unsigned(mem);
+	assert(type == FIELD_TYPE_INTEGER);
+	return mem_convert_to_integer(mem);
+}
+
 /*
  * 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
@@ -2747,11 +2852,11 @@ case OP_Fetch: {
 /* 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.
+ * Check that types of P2 registers starting from register P1 are
+ * compatible with given field types in P4. If the MEM_type of the
+ * value and the given type are incompatible according to
+ * field_mp_plain_type_is_compatible(), but both are numeric,
+ * this opcode attempts to convert the value to the type.
  */
 case OP_ApplyType: {
 	enum field_type *types = pOp->p4.types;
@@ -2762,13 +2867,23 @@ case OP_ApplyType: {
 	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;
+		if (!mem_is_type_compatible(pIn1, type)) {
+			/* Implicit cast is allowed only to numeric type. */
+			if (!sql_type_is_numeric(type))
+				goto type_mismatch;
+			/* Implicit cast is allowed only from numeric type. */
+			if (!mp_type_is_numeric(mem_mp_type(pIn1)))
+				goto type_mismatch;
+			/* Try to convert numeric-to-numeric. */
+			if (mem_convert_to_numeric(pIn1, type) != 0)
+				goto type_mismatch;
 		}
 		pIn1++;
+		continue;
+type_mismatch:
+		diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+			 sql_value_to_diag_str(pIn1), field_type_strs[type]);
+		goto abort_due_to_error;
 	}
 	break;
 }
diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index 44c27bdb7..ad46ab129 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -566,6 +566,10 @@ mem_mp_type(struct Mem *mem);
  */
 #define mp_type_is_bloblike(X) ((X) == MP_BIN || (X) == MP_ARRAY || (X) == MP_MAP)
 
+/** Return TRUE if MP_type of X is numeric, FALSE otherwise. */
+#define mp_type_is_numeric(X) ((X) == MP_INT || (X) == MP_UINT ||\
+			       (X) == MP_DOUBLE)
+
 /**
  * Memory cell mem contains the context of an aggregate function.
  * This routine calls the finalize method for that function. The
diff --git a/test/sql-tap/autoinc.test.lua b/test/sql-tap/autoinc.test.lua
index 37e65e541..07442b60a 100755
--- a/test/sql-tap/autoinc.test.lua
+++ b/test/sql-tap/autoinc.test.lua
@@ -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..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
@@ -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>
 
@@ -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/in3.test.lua b/test/sql-tap/in3.test.lua
index e29db9d93..a6d842962 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/in4.test.lua b/test/sql-tap/in4.test.lua
index 8c6917379..5c01ccdab 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"
@@ -585,98 +585,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/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..684a24114 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(31)
 
 --!./tcltestrunner.lua
 -- 2001 September 15
@@ -770,142 +770,13 @@ 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",
-    [[
-        SELECT * FROM t1 WHERE a=1;
-    ]], {
-        -- <intpkey-13.1>
-        
-        -- </intpkey-13.1>
-    })
-
-test:do_execsql_test(
-    "intpkey-13.2",
-    [[
-        INSERT INTO t1 VALUES('1',2,3);
-        SELECT * FROM t1 WHERE a=1;
-    ]], {
-        -- <intpkey-13.2>
-        1, "2", "3"
-        -- </intpkey-13.2>
-    })
-
--- MUST_WORK_TEST
-if (0 > 0) then
-    -- Tarantool: issue submitted #2315
-    test:do_catchsql_test(
-        "intpkey-13.3",
-        [[
-            INSERT INTO t1 VALUES('1.5',3,4);
-        ]], {
-            -- <intpkey-13.3>
-            1, "datatype mismatch"
-            -- </intpkey-13.3>
-        })
-
-    test:do_catchsql_test(
-        "intpkey-13.4",
-        [[
-            INSERT INTO t1 VALUES(x'123456',3,4);
-        ]], {
-            -- <intpkey-13.4>
-            1, "datatype mismatch"
-            -- </intpkey-13.4>
-        })
-
-
-
-end
-test:do_catchsql_test(
-    "intpkey-13.5",
-    [[
-        INSERT INTO t1 VALUES('+1234567890',3,4);
-    ]], {
-        -- <intpkey-13.5>
-        0
-        -- </intpkey-13.5>
-    })
-
--- Compare an INTEGER PRIMARY KEY against a TEXT expression. The INTEGER
--- affinity should be applied to the text value before the comparison
--- takes place.
---
-test:do_execsql_test(
-    "intpkey-14.1",
-    [[
-        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);
-    ]], {
-        -- <intpkey-14.1>
-        
-        -- </intpkey-14.1>
-    })
-
-test:do_execsql_test(
-    "intpkey-14.2",
-    [[
-        SELECT * FROM t3 WHERE a>2;
-    ]], {
-        -- <intpkey-14.2>
-        3, 3, "3"
-        -- </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(
-    "intpkey-14.4",
-    [[
-        SELECT * FROM t3 WHERE a<'2';
-    ]], {
-        -- <intpkey-14.4>
-        1, 1, "one"
-        -- </intpkey-14.4>
-    })
-
-test:do_execsql_test(
-    "intpkey-14.5",
-    [[
-        SELECT * FROM t3 WHERE a<c;
-    ]], {
-        -- <intpkey-14.5>
-        1, 1, "one"
-        -- </intpkey-14.5>
-    })
-
-test:do_execsql_test(
-    "intpkey-14.6",
-    [[
-        SELECT * FROM t3 WHERE a=c;
-    ]], {
-        -- <intpkey-14.6>
-        2, 2, "2", 3, 3, "3"
-        -- </intpkey-14.6>
-    })
-
 -- Check for proper handling of primary keys greater than 2^31.
 -- Ticket #1188
 --
 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/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/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..c0136d04c 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)
@@ -176,7 +176,7 @@ test:do_test(
     "misc1-2.1",
     function()
         test:execsql([[
-            CREATE TABLE agger(one text primary key, two text, three text, four text);
+            CREATE TABLE agger(one int 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');
@@ -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..3161e48fa 100755
--- a/test/sql-tap/numcast.test.lua
+++ b/test/sql-tap/numcast.test.lua
@@ -135,16 +135,16 @@ 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 2.0e+19 to integer"
     })
 
-test:do_catchsql_test(
+test:do_execsql_test(
     "cast-2.9",
     [[
         INSERT INTO t VALUES(2.1);
         SELECT * FROM t;
     ]], {
-        1,"Tuple field 1 type does not match one required by operation: expected integer"
+        2, 9223372036854775808ULL, 18000000000000000000ULL
     })
 
 --
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/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-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/tkt-9a8b09f8e6.test.lua b/test/sql-tap/tkt-9a8b09f8e6.test.lua
index cb5348ab4..ca3a5427a 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
@@ -193,16 +193,6 @@ test:do_execsql_test(
         -- </3.3>
     })
 
-test:do_execsql_test(
-    3.4,
-    [[
-        SELECT x FROM t2 WHERE x IN ('1');
-    ]], {
-        -- <3.4>
-        1
-        -- </3.4>
-    })
-
 test:do_execsql_test(
     3.5,
     [[
@@ -233,16 +223,6 @@ test:do_execsql_test(
         -- </3.7>
     })
 
-test:do_execsql_test(
-    3.8,
-    [[
-        SELECT x FROM t2 WHERE '1' IN (x);
-    ]], {
-        -- <3.8>
-        1
-        -- </3.8>
-    })
-
 test:do_execsql_test(
     4.1,
     [[
@@ -263,23 +243,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 1 to number"
         -- </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 1.0 to number"
         -- </4.4>
     })
 
@@ -303,23 +283,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 1 to number"
         -- </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 1.0 to number"
         -- </4.8>
     })
 
@@ -343,23 +323,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 1 to number"
         -- </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 1.0 to number"
         -- </5.4>
     })
 
@@ -373,13 +353,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 1.11 to number"
         -- </5.6>
     })
 
@@ -403,23 +383,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 1 to number"
         -- </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 1.0 to number"
         -- </5.10>
     })
 
@@ -433,13 +413,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 1.11 to number"
         -- </5.12>
     })
 
diff --git a/test/sql-tap/tkt-f973c7ac31.test.lua b/test/sql-tap/tkt-f973c7ac31.test.lua
index 82bdb52f8..381f29c65 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/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/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/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/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
deleted file mode 100755
index d98645fdc..000000000
--- a/test/sql-tap/whereB.test.lua
+++ /dev/null
@@ -1,908 +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>
-    })
-
--- 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 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 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
diff --git a/test/sql/types.result b/test/sql/types.result
index 54aff460e..70fbbc5a2 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -2155,3 +2155,623 @@ box.execute([[SELECT * FROM "s" WHERE "id" = ?;]])
 s:drop()
 ---
 ...
+--
+-- gh-3809: Make sure there are no implicit casts during
+-- assignment, except for the implicit cast between numeric
+-- values.
+--
+-- Check INSERT.
+box.execute([[CREATE TABLE ti (a INT PRIMARY KEY AUTOINCREMENT, i INTEGER);]])
+---
+- row_count: 1
+...
+box.execute([[CREATE TABLE td (a INT PRIMARY KEY AUTOINCREMENT, d DOUBLE);]])
+---
+- row_count: 1
+...
+box.execute([[CREATE TABLE tb (a INT PRIMARY KEY AUTOINCREMENT, b BOOLEAN);]])
+---
+- row_count: 1
+...
+box.execute([[CREATE TABLE tt (a INT PRIMARY KEY AUTOINCREMENT, t TEXT);]])
+---
+- row_count: 1
+...
+box.execute([[CREATE TABLE tv (a INT PRIMARY KEY AUTOINCREMENT, v VARBINARY);]])
+---
+- row_count: 1
+...
+box.execute([[CREATE TABLE ts (a INT PRIMARY KEY AUTOINCREMENT, s SCALAR);]])
+---
+- row_count: 1
+...
+box.execute([[INSERT INTO ti(i) VALUES (NULL);]])
+---
+- autoincrement_ids:
+  - 1
+  row_count: 1
+...
+box.execute([[INSERT INTO ti(i) VALUES (11);]])
+---
+- autoincrement_ids:
+  - 2
+  row_count: 1
+...
+box.execute([[INSERT INTO ti(i) VALUES (100000000000000000000000000000000.1);]])
+---
+- null
+- 'Type mismatch: can not convert 1.0e+32 to integer'
+...
+box.execute([[INSERT INTO ti(i) VALUES (33.0);]])
+---
+- autoincrement_ids:
+  - 3
+  row_count: 1
+...
+box.execute([[INSERT INTO ti(i) VALUES (true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to integer'
+...
+box.execute([[INSERT INTO ti(i) VALUES ('33');]])
+---
+- null
+- 'Type mismatch: can not convert 33 to integer'
+...
+box.execute([[INSERT INTO ti(i) VALUES (X'3434');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to integer'
+...
+box.execute([[SELECT * FROM ti;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: I
+    type: integer
+  rows:
+  - [1, null]
+  - [2, 11]
+  - [3, 33]
+...
+box.execute([[INSERT INTO td(d) VALUES (NULL);]])
+---
+- autoincrement_ids:
+  - 1
+  row_count: 1
+...
+box.execute([[INSERT INTO td(d) VALUES (11);]])
+---
+- autoincrement_ids:
+  - 2
+  row_count: 1
+...
+box.execute([[INSERT INTO td(d) VALUES (100000000000000001);;]])
+---
+- null
+- Syntax error at line 1 near ';'
+...
+box.execute([[INSERT INTO td(d) VALUES (22.2);]])
+---
+- autoincrement_ids:
+  - 3
+  row_count: 1
+...
+box.execute([[INSERT INTO td(d) VALUES (true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to double'
+...
+box.execute([[INSERT INTO td(d) VALUES ('33');]])
+---
+- null
+- 'Type mismatch: can not convert 33 to double'
+...
+box.execute([[INSERT INTO td(d) VALUES (X'3434');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to double'
+...
+box.execute([[SELECT * FROM td;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: D
+    type: double
+  rows:
+  - [1, null]
+  - [2, 11]
+  - [3, 22.2]
+...
+box.execute([[INSERT INTO tb(b) VALUES (NULL);]])
+---
+- autoincrement_ids:
+  - 1
+  row_count: 1
+...
+box.execute([[INSERT INTO tb(b) VALUES (11);]])
+---
+- null
+- 'Type mismatch: can not convert 11 to boolean'
+...
+box.execute([[INSERT INTO tb(b) VALUES (22.2);]])
+---
+- null
+- 'Type mismatch: can not convert 22.2 to boolean'
+...
+box.execute([[INSERT INTO tb(b) VALUES (true);]])
+---
+- autoincrement_ids:
+  - 2
+  row_count: 1
+...
+box.execute([[INSERT INTO tb(b) VALUES ('33');]])
+---
+- null
+- 'Type mismatch: can not convert 33 to boolean'
+...
+box.execute([[INSERT INTO tb(b) VALUES (X'3434');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to boolean'
+...
+box.execute([[SELECT * FROM tb;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: B
+    type: boolean
+  rows:
+  - [1, null]
+  - [2, true]
+...
+box.execute([[INSERT INTO tt(t) VALUES (NULL);]])
+---
+- autoincrement_ids:
+  - 1
+  row_count: 1
+...
+box.execute([[INSERT INTO tt(t) VALUES (11);]])
+---
+- null
+- 'Type mismatch: can not convert 11 to string'
+...
+box.execute([[INSERT INTO tt(t) VALUES (22.2);]])
+---
+- null
+- 'Type mismatch: can not convert 22.2 to string'
+...
+box.execute([[INSERT INTO tt(t) VALUES (true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string'
+...
+box.execute([[INSERT INTO tt(t) VALUES ('33');]])
+---
+- autoincrement_ids:
+  - 2
+  row_count: 1
+...
+box.execute([[INSERT INTO tt(t) VALUES (X'3434');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to string'
+...
+box.execute([[SELECT * FROM tt;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: T
+    type: string
+  rows:
+  - [1, null]
+  - [2, '33']
+...
+box.execute([[INSERT INTO tv(v) VALUES (NULL);]])
+---
+- autoincrement_ids:
+  - 1
+  row_count: 1
+...
+box.execute([[INSERT INTO tv(v) VALUES (11);]])
+---
+- null
+- 'Type mismatch: can not convert 11 to varbinary'
+...
+box.execute([[INSERT INTO tv(v) VALUES (22.2);]])
+---
+- null
+- 'Type mismatch: can not convert 22.2 to varbinary'
+...
+box.execute([[INSERT INTO tv(v) VALUES (true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to varbinary'
+...
+box.execute([[INSERT INTO tv(v) VALUES ('33');]])
+---
+- null
+- 'Type mismatch: can not convert 33 to varbinary'
+...
+box.execute([[INSERT INTO tv(v) VALUES (X'3434');]])
+---
+- autoincrement_ids:
+  - 2
+  row_count: 1
+...
+box.execute([[SELECT * FROM tv;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: V
+    type: varbinary
+  rows:
+  - [1, null]
+  - [2, '44']
+...
+box.execute([[INSERT INTO ts(s) VALUES (NULL);]])
+---
+- autoincrement_ids:
+  - 1
+  row_count: 1
+...
+box.execute([[INSERT INTO ts(s) VALUES (11);]])
+---
+- autoincrement_ids:
+  - 2
+  row_count: 1
+...
+box.execute([[INSERT INTO ts(s) VALUES (22.2);]])
+---
+- autoincrement_ids:
+  - 3
+  row_count: 1
+...
+box.execute([[INSERT INTO ts(s) VALUES (true);]])
+---
+- autoincrement_ids:
+  - 4
+  row_count: 1
+...
+box.execute([[INSERT INTO ts(s) VALUES ('33');]])
+---
+- autoincrement_ids:
+  - 5
+  row_count: 1
+...
+box.execute([[INSERT INTO ts(s) VALUES (X'3434');]])
+---
+- autoincrement_ids:
+  - 6
+  row_count: 1
+...
+box.execute([[SELECT * FROM ts;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: S
+    type: scalar
+  rows:
+  - [1, null]
+  - [2, 11]
+  - [3, 22.2]
+  - [4, true]
+  - [5, '33']
+  - [6, '44']
+...
+-- Check for UPDATE.
+box.execute([[DELETE FROM ti;]])
+---
+- row_count: 3
+...
+box.execute([[DELETE FROM td;]])
+---
+- row_count: 3
+...
+box.execute([[DELETE FROM tb;]])
+---
+- row_count: 2
+...
+box.execute([[DELETE FROM tt;]])
+---
+- row_count: 2
+...
+box.execute([[DELETE FROM tv;]])
+---
+- row_count: 2
+...
+box.execute([[DELETE FROM ts;]])
+---
+- row_count: 6
+...
+box.execute([[INSERT INTO ti VALUES(1, NULL);]])
+---
+- row_count: 1
+...
+box.execute([[INSERT INTO td VALUES(1, NULL);]])
+---
+- row_count: 1
+...
+box.execute([[INSERT INTO tb VALUES(1, NULL);]])
+---
+- row_count: 1
+...
+box.execute([[INSERT INTO tt VALUES(1, NULL);]])
+---
+- row_count: 1
+...
+box.execute([[INSERT INTO tv VALUES(1, NULL);]])
+---
+- row_count: 1
+...
+box.execute([[INSERT INTO ts VALUES(1, NULL);]])
+---
+- row_count: 1
+...
+box.execute([[SELECT * FROM ti, td, tb, tt, tv, ts;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: I
+    type: integer
+  - name: A
+    type: integer
+  - name: D
+    type: double
+  - name: A
+    type: integer
+  - name: B
+    type: boolean
+  - name: A
+    type: integer
+  - name: T
+    type: string
+  - name: A
+    type: integer
+  - name: V
+    type: varbinary
+  - name: A
+    type: integer
+  - name: S
+    type: scalar
+  rows:
+  - [1, null, 1, null, 1, null, 1, null, 1, null, 1, null]
+...
+box.execute([[UPDATE ti SET i = NULL WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE ti SET i = 11 WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE ti SET i = 100000000000000000000000000000000.1 WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 1.0e+32 to integer'
+...
+box.execute([[UPDATE ti SET i = 33.0 WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE ti SET i = true WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to integer'
+...
+box.execute([[UPDATE ti SET i = '33' WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 33 to integer'
+...
+box.execute([[UPDATE ti SET i = X'3434' WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to integer'
+...
+box.execute([[SELECT * FROM ti;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: I
+    type: integer
+  rows:
+  - [1, 33]
+...
+box.execute([[UPDATE td SET d = NULL WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE td SET d = 11 WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE td SET d = 100000000000000001 WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE td SET d = 22.2 WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE td SET d = true WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to double'
+...
+box.execute([[UPDATE td SET d = '33' WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 33 to double'
+...
+box.execute([[UPDATE td SET d = X'3434' WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to double'
+...
+box.execute([[SELECT * FROM td;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: D
+    type: double
+  rows:
+  - [1, 22.2]
+...
+box.execute([[UPDATE tb SET b = NULL WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE tb SET b = 11 WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 11 to boolean'
+...
+box.execute([[UPDATE tb SET b = 22.2 WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 22.2 to boolean'
+...
+box.execute([[UPDATE tb SET b = true WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE tb SET b = '33' WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 33 to boolean'
+...
+box.execute([[UPDATE tb SET b = X'3434' WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to boolean'
+...
+box.execute([[SELECT * FROM tb;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: B
+    type: boolean
+  rows:
+  - [1, true]
+...
+box.execute([[UPDATE tt SET t = NULL WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE tt SET t = 11 WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 11 to string'
+...
+box.execute([[UPDATE tt SET t = 22.2 WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 22.2 to string'
+...
+box.execute([[UPDATE tt SET t = true WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string'
+...
+box.execute([[UPDATE tt SET t = '33' WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE tt SET t = X'3434' WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to string'
+...
+box.execute([[SELECT * FROM tt;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: T
+    type: string
+  rows:
+  - [1, '33']
+...
+box.execute([[UPDATE tv SET v = NULL WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE tv SET v = 11 WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 11 to varbinary'
+...
+box.execute([[UPDATE tv SET v = 22.2 WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 22.2 to varbinary'
+...
+box.execute([[UPDATE tv SET v = true WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to varbinary'
+...
+box.execute([[UPDATE tv SET v = '33' WHERE a = 1;]])
+---
+- null
+- 'Type mismatch: can not convert 33 to varbinary'
+...
+box.execute([[UPDATE tv SET v = X'3434' WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[SELECT * FROM tv;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: V
+    type: varbinary
+  rows:
+  - [1, '44']
+...
+box.execute([[UPDATE ts SET s = NULL WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE ts SET s = 11 WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE ts SET s = 22.2 WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE ts SET s = true WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE ts SET s = '33' WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[UPDATE ts SET s = X'3434' WHERE a = 1;]])
+---
+- row_count: 1
+...
+box.execute([[SELECT * FROM ts;]])
+---
+- metadata:
+  - name: A
+    type: integer
+  - name: S
+    type: scalar
+  rows:
+  - [1, '44']
+...
diff --git a/test/sql/types.test.lua b/test/sql/types.test.lua
index bd14b342d..2dc70f3c5 100644
--- a/test/sql/types.test.lua
+++ b/test/sql/types.test.lua
@@ -487,3 +487,132 @@ s:format({ \
 
 box.execute([[SELECT * FROM "s" WHERE "id" = ?;]])
 s:drop()
+
+--
+-- gh-3809: Make sure there are no implicit casts during
+-- assignment, except for the implicit cast between numeric
+-- values.
+--
+
+-- Check INSERT.
+box.execute([[CREATE TABLE ti (a INT PRIMARY KEY AUTOINCREMENT, i INTEGER);]])
+box.execute([[CREATE TABLE td (a INT PRIMARY KEY AUTOINCREMENT, d DOUBLE);]])
+box.execute([[CREATE TABLE tb (a INT PRIMARY KEY AUTOINCREMENT, b BOOLEAN);]])
+box.execute([[CREATE TABLE tt (a INT PRIMARY KEY AUTOINCREMENT, t TEXT);]])
+box.execute([[CREATE TABLE tv (a INT PRIMARY KEY AUTOINCREMENT, v VARBINARY);]])
+box.execute([[CREATE TABLE ts (a INT PRIMARY KEY AUTOINCREMENT, s SCALAR);]])
+
+box.execute([[INSERT INTO ti(i) VALUES (NULL);]])
+box.execute([[INSERT INTO ti(i) VALUES (11);]])
+box.execute([[INSERT INTO ti(i) VALUES (100000000000000000000000000000000.1);]])
+box.execute([[INSERT INTO ti(i) VALUES (33.0);]])
+box.execute([[INSERT INTO ti(i) VALUES (true);]])
+box.execute([[INSERT INTO ti(i) VALUES ('33');]])
+box.execute([[INSERT INTO ti(i) VALUES (X'3434');]])
+box.execute([[SELECT * FROM ti;]])
+
+box.execute([[INSERT INTO td(d) VALUES (NULL);]])
+box.execute([[INSERT INTO td(d) VALUES (11);]])
+box.execute([[INSERT INTO td(d) VALUES (100000000000000001);;]])
+box.execute([[INSERT INTO td(d) VALUES (22.2);]])
+box.execute([[INSERT INTO td(d) VALUES (true);]])
+box.execute([[INSERT INTO td(d) VALUES ('33');]])
+box.execute([[INSERT INTO td(d) VALUES (X'3434');]])
+box.execute([[SELECT * FROM td;]])
+
+box.execute([[INSERT INTO tb(b) VALUES (NULL);]])
+box.execute([[INSERT INTO tb(b) VALUES (11);]])
+box.execute([[INSERT INTO tb(b) VALUES (22.2);]])
+box.execute([[INSERT INTO tb(b) VALUES (true);]])
+box.execute([[INSERT INTO tb(b) VALUES ('33');]])
+box.execute([[INSERT INTO tb(b) VALUES (X'3434');]])
+box.execute([[SELECT * FROM tb;]])
+
+box.execute([[INSERT INTO tt(t) VALUES (NULL);]])
+box.execute([[INSERT INTO tt(t) VALUES (11);]])
+box.execute([[INSERT INTO tt(t) VALUES (22.2);]])
+box.execute([[INSERT INTO tt(t) VALUES (true);]])
+box.execute([[INSERT INTO tt(t) VALUES ('33');]])
+box.execute([[INSERT INTO tt(t) VALUES (X'3434');]])
+box.execute([[SELECT * FROM tt;]])
+
+box.execute([[INSERT INTO tv(v) VALUES (NULL);]])
+box.execute([[INSERT INTO tv(v) VALUES (11);]])
+box.execute([[INSERT INTO tv(v) VALUES (22.2);]])
+box.execute([[INSERT INTO tv(v) VALUES (true);]])
+box.execute([[INSERT INTO tv(v) VALUES ('33');]])
+box.execute([[INSERT INTO tv(v) VALUES (X'3434');]])
+box.execute([[SELECT * FROM tv;]])
+
+box.execute([[INSERT INTO ts(s) VALUES (NULL);]])
+box.execute([[INSERT INTO ts(s) VALUES (11);]])
+box.execute([[INSERT INTO ts(s) VALUES (22.2);]])
+box.execute([[INSERT INTO ts(s) VALUES (true);]])
+box.execute([[INSERT INTO ts(s) VALUES ('33');]])
+box.execute([[INSERT INTO ts(s) VALUES (X'3434');]])
+box.execute([[SELECT * FROM ts;]])
+
+-- Check for UPDATE.
+box.execute([[DELETE FROM ti;]])
+box.execute([[DELETE FROM td;]])
+box.execute([[DELETE FROM tb;]])
+box.execute([[DELETE FROM tt;]])
+box.execute([[DELETE FROM tv;]])
+box.execute([[DELETE FROM ts;]])
+box.execute([[INSERT INTO ti VALUES(1, NULL);]])
+box.execute([[INSERT INTO td VALUES(1, NULL);]])
+box.execute([[INSERT INTO tb VALUES(1, NULL);]])
+box.execute([[INSERT INTO tt VALUES(1, NULL);]])
+box.execute([[INSERT INTO tv VALUES(1, NULL);]])
+box.execute([[INSERT INTO ts VALUES(1, NULL);]])
+box.execute([[SELECT * FROM ti, td, tb, tt, tv, ts;]])
+
+box.execute([[UPDATE ti SET i = NULL WHERE a = 1;]])
+box.execute([[UPDATE ti SET i = 11 WHERE a = 1;]])
+box.execute([[UPDATE ti SET i = 100000000000000000000000000000000.1 WHERE a = 1;]])
+box.execute([[UPDATE ti SET i = 33.0 WHERE a = 1;]])
+box.execute([[UPDATE ti SET i = true WHERE a = 1;]])
+box.execute([[UPDATE ti SET i = '33' WHERE a = 1;]])
+box.execute([[UPDATE ti SET i = X'3434' WHERE a = 1;]])
+box.execute([[SELECT * FROM ti;]])
+
+box.execute([[UPDATE td SET d = NULL WHERE a = 1;]])
+box.execute([[UPDATE td SET d = 11 WHERE a = 1;]])
+box.execute([[UPDATE td SET d = 100000000000000001 WHERE a = 1;]])
+box.execute([[UPDATE td SET d = 22.2 WHERE a = 1;]])
+box.execute([[UPDATE td SET d = true WHERE a = 1;]])
+box.execute([[UPDATE td SET d = '33' WHERE a = 1;]])
+box.execute([[UPDATE td SET d = X'3434' WHERE a = 1;]])
+box.execute([[SELECT * FROM td;]])
+
+box.execute([[UPDATE tb SET b = NULL WHERE a = 1;]])
+box.execute([[UPDATE tb SET b = 11 WHERE a = 1;]])
+box.execute([[UPDATE tb SET b = 22.2 WHERE a = 1;]])
+box.execute([[UPDATE tb SET b = true WHERE a = 1;]])
+box.execute([[UPDATE tb SET b = '33' WHERE a = 1;]])
+box.execute([[UPDATE tb SET b = X'3434' WHERE a = 1;]])
+box.execute([[SELECT * FROM tb;]])
+
+box.execute([[UPDATE tt SET t = NULL WHERE a = 1;]])
+box.execute([[UPDATE tt SET t = 11 WHERE a = 1;]])
+box.execute([[UPDATE tt SET t = 22.2 WHERE a = 1;]])
+box.execute([[UPDATE tt SET t = true WHERE a = 1;]])
+box.execute([[UPDATE tt SET t = '33' WHERE a = 1;]])
+box.execute([[UPDATE tt SET t = X'3434' WHERE a = 1;]])
+box.execute([[SELECT * FROM tt;]])
+
+box.execute([[UPDATE tv SET v = NULL WHERE a = 1;]])
+box.execute([[UPDATE tv SET v = 11 WHERE a = 1;]])
+box.execute([[UPDATE tv SET v = 22.2 WHERE a = 1;]])
+box.execute([[UPDATE tv SET v = true WHERE a = 1;]])
+box.execute([[UPDATE tv SET v = '33' WHERE a = 1;]])
+box.execute([[UPDATE tv SET v = X'3434' WHERE a = 1;]])
+box.execute([[SELECT * FROM tv;]])
+
+box.execute([[UPDATE ts SET s = NULL WHERE a = 1;]])
+box.execute([[UPDATE ts SET s = 11 WHERE a = 1;]])
+box.execute([[UPDATE ts SET s = 22.2 WHERE a = 1;]])
+box.execute([[UPDATE ts SET s = true WHERE a = 1;]])
+box.execute([[UPDATE ts SET s = '33' WHERE a = 1;]])
+box.execute([[UPDATE ts SET s = X'3434' WHERE a = 1;]])
+box.execute([[SELECT * FROM ts;]])

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

end of thread, other threads:[~2020-07-15 13:41 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-14 15:48 [Tarantool-patches] [PATCH v5 00/17] sql: change implicit cast for assignment imeevma
2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 01/17] sql: set field_type in mem_set_*() functions imeevma
2020-07-15 12:22   ` Nikita Pettik
2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 02/17] sql: change implicit cast for assignment imeevma
2020-07-15 13:41   ` Mergen Imeev
2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 03/17] sql: use ApplyType to check function arguments imeevma
2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 04/17] sql: check args of abs() imeevma
2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 05/17] sql: check args of avg(), sum() and total() imeevma
2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 06/17] sql: check args of char() imeevma
2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 07/17] sql: check args of length() imeevma
2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 08/17] sql: check operands of LIKE imeevma
2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 09/17] sql: check args of lower() and upper() imeevma
2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 10/17] sql: check args of position() imeevma
2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 11/17] sql: check args of randomblob() imeevma
2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 12/17] sql: check args of replace() imeevma
2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 13/17] sql: check args of round() imeevma
2020-07-14 15:48 ` [Tarantool-patches] [PATCH v5 14/17] sql: check args of soundex() imeevma
2020-07-14 15:49 ` [Tarantool-patches] [PATCH v5 15/17] sql: check args of substr() imeevma
2020-07-14 15:49 ` [Tarantool-patches] [PATCH v5 16/17] sql: check args of unicode() imeevma
2020-07-14 15:49 ` [Tarantool-patches] [PATCH v5 17/17] sql: check args of zeroblob() imeevma

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