Tarantool development patches archive
 help / color / mirror / Atom feed
* [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast
@ 2020-07-16 14:45 imeevma
  2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 01/22] sql: change implicit cast for assignment imeevma
                   ` (21 more replies)
  0 siblings, 22 replies; 31+ messages in thread
From: imeevma @ 2020-07-16 14:45 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

This patch-set changes implicit cast for assignment and removes implicit
cast for comparison.

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

@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.

v6:
 - Removal of implicit cast for comparison returned in patch-set.

Mergen Imeev (22):
  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()
  sql: remove unused DOUBLE to INTEGER conversion
  sql: add implicit cast between numbers in OP_Seek*
  sql: change comparison between numbers using index
  sql: remove implicit cast from comparison opcodes
  sql: fix implicit cast in opcode MustBeInt
  sql: remove implicit cast from MakeRecord opcode

 src/box/sql/analyze.c                 |   6 +-
 src/box/sql/delete.c                  |  15 +-
 src/box/sql/expr.c                    |  19 +-
 src/box/sql/fk_constraint.c           |  12 +-
 src/box/sql/func.c                    | 437 +++++++----
 src/box/sql/select.c                  |  61 +-
 src/box/sql/sqlInt.h                  |  36 +
 src/box/sql/update.c                  |  23 +-
 src/box/sql/vdbe.c                    | 682 +++++++++++++-----
 src/box/sql/vdbeInt.h                 |   4 +
 src/box/sql/wherecode.c               | 103 +--
 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/identifier_case.test.lua |   6 +-
 test/sql-tap/in1.test.lua             |   4 +-
 test/sql-tap/in3.test.lua             |  38 +-
 test/sql-tap/in4.test.lua             | 100 +--
 test/sql-tap/index1.test.lua          |  24 +-
 test/sql-tap/insert3.test.lua         |  12 +-
 test/sql-tap/intpkey.test.lua         | 133 +---
 test/sql-tap/join.test.lua            |   8 +-
 test/sql-tap/limit.test.lua           |   2 +-
 test/sql-tap/minmax2.test.lua         |   6 +-
 test/sql-tap/misc1.test.lua           |  56 +-
 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         |  12 +-
 test/sql-tap/select4.test.lua         |  12 +-
 test/sql-tap/select7.test.lua         |   4 +-
 test/sql-tap/sort.test.lua            |   8 +-
 test/sql-tap/subquery.test.lua        |  73 +-
 test/sql-tap/tkt-3998683a16.test.lua  |  26 +-
 test/sql-tap/tkt-54844eea3f.test.lua  |   8 +-
 test/sql-tap/tkt-7bbfb7d442.test.lua  |   4 +-
 test/sql-tap/tkt-9a8b09f8e6.test.lua  | 528 --------------
 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         |  46 +-
 test/sql-tap/tkt3841.test.lua         |  12 +-
 test/sql-tap/transitive1.test.lua     |  16 +-
 test/sql-tap/triggerA.test.lua        |   4 +-
 test/sql-tap/unique.test.lua          |   8 +-
 test/sql-tap/view.test.lua            |   2 +-
 test/sql-tap/where2.test.lua          | 183 +----
 test/sql-tap/where5.test.lua          |  22 +-
 test/sql-tap/whereB.test.lua          | 908 -----------------------
 test/sql-tap/whereC.test.lua          |   8 +-
 test/sql/boolean.result               | 108 +--
 test/sql/collation.result             |   2 +-
 test/sql/types.result                 | 994 ++++++++++++++++++++++++--
 test/sql/types.test.lua               | 199 ++++++
 58 files changed, 3276 insertions(+), 2886 deletions(-)
 delete mode 100755 test/sql-tap/tkt-9a8b09f8e6.test.lua
 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] 31+ messages in thread

* [Tarantool-patches] [PATCH v6 01/22] sql: change implicit cast for assignment
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
@ 2020-07-16 14:45 ` imeevma
  2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 02/22] sql: use ApplyType to check function arguments imeevma
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: imeevma @ 2020-07-16 14:45 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                   | 135 +++-
 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                | 644 +++++++++++++++++++
 test/sql/types.test.lua              | 136 ++++
 37 files changed, 1048 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..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..438ac44ab 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -2155,3 +2155,647 @@ 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']
+...
+box.execute([[DROP TABLE ti;]])
+---
+- row_count: 1
+...
+box.execute([[DROP TABLE td;]])
+---
+- row_count: 1
+...
+box.execute([[DROP TABLE tb;]])
+---
+- row_count: 1
+...
+box.execute([[DROP TABLE tt;]])
+---
+- row_count: 1
+...
+box.execute([[DROP TABLE tv;]])
+---
+- row_count: 1
+...
+box.execute([[DROP TABLE ts;]])
+---
+- row_count: 1
+...
diff --git a/test/sql/types.test.lua b/test/sql/types.test.lua
index bd14b342d..0270d9f8a 100644
--- a/test/sql/types.test.lua
+++ b/test/sql/types.test.lua
@@ -487,3 +487,139 @@ 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;]])
+
+box.execute([[DROP TABLE ti;]])
+box.execute([[DROP TABLE td;]])
+box.execute([[DROP TABLE tb;]])
+box.execute([[DROP TABLE tt;]])
+box.execute([[DROP TABLE tv;]])
+box.execute([[DROP TABLE ts;]])
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v6 02/22] sql: use ApplyType to check function arguments
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
  2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 01/22] sql: change implicit cast for assignment imeevma
@ 2020-07-16 14:45 ` imeevma
  2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 03/22] sql: check args of abs() imeevma
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: imeevma @ 2020-07-16 14:45 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

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
---
 src/box/sql/expr.c   |   2 +
 src/box/sql/func.c   | 204 +++++++++++++++++++++++++++++++++++++++++++
 src/box/sql/select.c |  35 ++++++++
 src/box/sql/sqlInt.h |  34 ++++++++
 src/box/sql/vdbe.c   |  18 +++-
 5 files changed, 292 insertions(+), 1 deletion(-)

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..cd94616ca 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,24 @@ 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 works with BLOB arguments the
+	 * same way that works with STRING arguments. This flag
+	 * allows us to reflect on this.
+	 *
+	 * 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 14ddb5160..97e09cac4 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -2849,7 +2849,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
@@ -2857,6 +2857,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;
@@ -2868,6 +2871,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;
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v6 03/22] sql: check args of abs()
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
  2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 01/22] sql: change implicit cast for assignment imeevma
  2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 02/22] sql: use ApplyType to check function arguments imeevma
@ 2020-07-16 14:45 ` imeevma
  2020-07-16 16:12   ` Nikita Pettik
  2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 04/22] sql: check args of avg(), sum() and total() imeevma
                   ` (18 subsequent siblings)
  21 siblings, 1 reply; 31+ messages in thread
From: imeevma @ 2020-07-16 14:45 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 438ac44ab..9cb0818e6 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] 31+ messages in thread

* [Tarantool-patches] [PATCH v6 04/22] sql: check args of avg(), sum() and total()
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (2 preceding siblings ...)
  2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 03/22] sql: check args of abs() imeevma
@ 2020-07-16 14:45 ` imeevma
  2020-07-16 16:21   ` Nikita Pettik
  2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 05/22] sql: check args of char() imeevma
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 31+ messages in thread
From: imeevma @ 2020-07-16 14:45 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] 31+ messages in thread

* [Tarantool-patches] [PATCH v6 05/22] sql: check args of char()
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (3 preceding siblings ...)
  2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 04/22] sql: check args of avg(), sum() and total() imeevma
@ 2020-07-16 14:45 ` imeevma
  2020-07-16 16:27   ` Nikita Pettik
  2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 06/22] sql: check args of length() imeevma
                   ` (16 subsequent siblings)
  21 siblings, 1 reply; 31+ messages in thread
From: imeevma @ 2020-07-16 14:45 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] 31+ messages in thread

* [Tarantool-patches] [PATCH v6 06/22] sql: check args of length()
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (4 preceding siblings ...)
  2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 05/22] sql: check args of char() imeevma
@ 2020-07-16 14:45 ` imeevma
  2020-07-16 16:31   ` Nikita Pettik
  2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 07/22] sql: check operands of LIKE imeevma
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 31+ messages in thread
From: imeevma @ 2020-07-16 14:45 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] 31+ messages in thread

* [Tarantool-patches] [PATCH v6 07/22] sql: check operands of LIKE
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (5 preceding siblings ...)
  2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 06/22] sql: check args of length() imeevma
@ 2020-07-16 14:46 ` imeevma
  2020-07-16 17:03   ` Nikita Pettik
  2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 08/22] sql: check args of lower() and upper() imeevma
                   ` (14 subsequent siblings)
  21 siblings, 1 reply; 31+ messages in thread
From: imeevma @ 2020-07-16 14:46 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 9cb0818e6..e0cf2d7d9 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] 31+ messages in thread

* [Tarantool-patches] [PATCH v6 08/22] sql: check args of lower() and upper()
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (6 preceding siblings ...)
  2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 07/22] sql: check operands of LIKE imeevma
@ 2020-07-16 14:46 ` imeevma
  2020-07-16 17:09   ` Nikita Pettik
  2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 09/22] sql: check args of position() imeevma
                   ` (13 subsequent siblings)
  21 siblings, 1 reply; 31+ messages in thread
From: imeevma @ 2020-07-16 14:46 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 e0cf2d7d9..43cdffad0 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] 31+ messages in thread

* [Tarantool-patches] [PATCH v6 09/22] sql: check args of position()
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (7 preceding siblings ...)
  2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 08/22] sql: check args of lower() and upper() imeevma
@ 2020-07-16 14:46 ` imeevma
  2020-07-16 17:28   ` Nikita Pettik
  2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 10/22] sql: check args of randomblob() imeevma
                   ` (12 subsequent siblings)
  21 siblings, 1 reply; 31+ messages in thread
From: imeevma @ 2020-07-16 14:46 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] 31+ messages in thread

* [Tarantool-patches] [PATCH v6 10/22] sql: check args of randomblob()
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (8 preceding siblings ...)
  2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 09/22] sql: check args of position() imeevma
@ 2020-07-16 14:46 ` imeevma
  2020-07-16 17:28   ` Nikita Pettik
  2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 11/22] sql: check args of replace() imeevma
                   ` (11 subsequent siblings)
  21 siblings, 1 reply; 31+ messages in thread
From: imeevma @ 2020-07-16 14:46 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] 31+ messages in thread

* [Tarantool-patches] [PATCH v6 11/22] sql: check args of replace()
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (9 preceding siblings ...)
  2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 10/22] sql: check args of randomblob() imeevma
@ 2020-07-16 14:46 ` imeevma
  2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 12/22] sql: check args of round() imeevma
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: imeevma @ 2020-07-16 14:46 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] 31+ messages in thread

* [Tarantool-patches] [PATCH v6 12/22] sql: check args of round()
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (10 preceding siblings ...)
  2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 11/22] sql: check args of replace() imeevma
@ 2020-07-16 14:46 ` imeevma
  2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 13/22] sql: check args of soundex() imeevma
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: imeevma @ 2020-07-16 14:46 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] 31+ messages in thread

* [Tarantool-patches] [PATCH v6 13/22] sql: check args of soundex()
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (11 preceding siblings ...)
  2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 12/22] sql: check args of round() imeevma
@ 2020-07-16 14:46 ` imeevma
  2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 14/22] sql: check args of substr() imeevma
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: imeevma @ 2020-07-16 14:46 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] 31+ messages in thread

* [Tarantool-patches] [PATCH v6 14/22] sql: check args of substr()
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (12 preceding siblings ...)
  2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 13/22] sql: check args of soundex() imeevma
@ 2020-07-16 14:47 ` imeevma
  2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 15/22] sql: check args of unicode() imeevma
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: imeevma @ 2020-07-16 14:47 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] 31+ messages in thread

* [Tarantool-patches] [PATCH v6 15/22] sql: check args of unicode()
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (13 preceding siblings ...)
  2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 14/22] sql: check args of substr() imeevma
@ 2020-07-16 14:47 ` imeevma
  2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 16/22] sql: check args of zeroblob() imeevma
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: imeevma @ 2020-07-16 14:47 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] 31+ messages in thread

* [Tarantool-patches] [PATCH v6 16/22] sql: check args of zeroblob()
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (14 preceding siblings ...)
  2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 15/22] sql: check args of unicode() imeevma
@ 2020-07-16 14:47 ` imeevma
  2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 17/22] sql: remove unused DOUBLE to INTEGER conversion imeevma
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: imeevma @ 2020-07-16 14:47 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..66ee6782a 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.13.1", [[
+        SELECT zeroblob(NULL);
+    ]],{
+        ""
+    })
+
+test:do_execsql_test(
+    "func-5-6.13.2", [[
+        SELECT zeroblob(3);
+    ]], {
+        '\0\0\0'
+    })
+
+test:do_catchsql_test(
+    "func-5-6.13.3", [[
+        SELECT zeroblob(-123);
+    ]], {
+        1, "Type mismatch: can not convert -123 to unsigned"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.13.4", [[
+        SELECT zeroblob(-5.5);
+    ]], {
+        1, "Type mismatch: can not convert -5.5 to unsigned"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.13.5", [[
+        SELECT zeroblob('-123');
+    ]], {
+        1, "Type mismatch: can not convert -123 to unsigned"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.13.6", [[
+        SELECT zeroblob(false);
+    ]], {
+        1, "Type mismatch: can not convert FALSE to unsigned"
+    })
+
+test:do_catchsql_test(
+    "func-5-6.13.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] 31+ messages in thread

* [Tarantool-patches] [PATCH v6 17/22] sql: remove unused DOUBLE to INTEGER conversion
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (15 preceding siblings ...)
  2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 16/22] sql: check args of zeroblob() imeevma
@ 2020-07-16 14:47 ` imeevma
  2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 18/22] sql: add implicit cast between numbers in OP_Seek* imeevma
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: imeevma @ 2020-07-16 14:47 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

This patch removes the unused DOUBLE to INTEGER conversion from OP_Seek*
opcodes. This transformation is not used due to changes in the ApplyType
opcode. The next few patches will introduce new rules for converting
numbers (not just DOUBLE to INTEGER), and the implicit conversion within
the ApplyType opcode will be disabled for this case.

Part of #4230
---
 src/box/sql/vdbe.c      | 106 ++--------------------------------------
 src/box/sql/wherecode.c |  27 ----------
 2 files changed, 5 insertions(+), 128 deletions(-)

diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 97e09cac4..d853a0edb 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -3366,7 +3366,7 @@ case OP_Close: {
 	break;
 }
 
-/* Opcode: SeekGE P1 P2 P3 P4 P5
+/* Opcode: SeekGE P1 P2 P3 P4 *
  * Synopsis: key=r[P3@P4]
  *
  * If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
@@ -3389,14 +3389,9 @@ case OP_Close: {
  * from the beginning toward the end.  In other words, the cursor is
  * configured to use Next, not Prev.
  *
- * If P5 is not zero, than it is offset of integer fields in input
- * vector. Force corresponding value to be INTEGER, in case it
- * is floating point value. Alongside with that, type of
- * iterator may be changed: a > 1.5 -> a >= 2.
- *
  * See also: Found, NotFound, SeekLt, SeekGt, SeekLe
  */
-/* Opcode: SeekGT P1 P2 P3 P4 P5
+/* Opcode: SeekGT P1 P2 P3 P4 *
  * Synopsis: key=r[P3@P4]
  *
  * If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
@@ -3412,12 +3407,9 @@ case OP_Close: {
  * from the beginning toward the end.  In other words, the cursor is
  * configured to use Next, not Prev.
  *
- * If P5 is not zero, than it is offset of integer fields in input
- * vector. Force corresponding value to be INTEGER.
- *
- * P5 has the same meaning as for SeekGE.
+ * See also: Found, NotFound, SeekLt, SeekGe, SeekLe
  */
-/* Opcode: SeekLT P1 P2 P3 P4 P5
+/* Opcode: SeekLT P1 P2 P3 P4 *
  * Synopsis: key=r[P3@P4]
  *
  * If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
@@ -3433,11 +3425,9 @@ case OP_Close: {
  * from the end toward the beginning.  In other words, the cursor is
  * configured to use Prev, not Next.
  *
- * P5 has the same meaning as for SeekGE.
- *
  * See also: Found, NotFound, SeekGt, SeekGe, SeekLe
  */
-/* Opcode: SeekLE P1 P2 P3 P4 P5
+/* Opcode: SeekLE P1 P2 P3 P4 *
  * Synopsis: key=r[P3@P4]
  *
  * If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
@@ -3460,8 +3450,6 @@ case OP_Close: {
  * The IdxGE opcode will be skipped if this opcode succeeds, but the
  * IdxGE opcode will be used on subsequent loop iterations.
  *
- * P5 has the same meaning as for SeekGE.
- *
  * See also: Found, NotFound, SeekGt, SeekGe, SeekLt
  */
 case OP_SeekLT:         /* jump, in3 */
@@ -3473,7 +3461,6 @@ case OP_SeekGT: {       /* jump, in3 */
 	VdbeCursor *pC;    /* The cursor to seek */
 	UnpackedRecord r;  /* The key to seek for */
 	int nField;        /* Number of columns or fields in the key */
-	i64 iKey;          /* The id we are to seek to */
 	int eqOnly;        /* Only interested in == results */
 
 	assert(pOp->p1>=0 && pOp->p1<p->nCursor);
@@ -3491,86 +3478,6 @@ case OP_SeekGT: {       /* jump, in3 */
 #ifdef SQL_DEBUG
 	pC->seekOp = pOp->opcode;
 #endif
-	iKey = 0;
-	/*
-	 * In case floating value is intended to be passed to
-	 * iterator over integer field, we must truncate it to
-	 * integer value and change type of iterator:
-	 * a > 1.5 -> a >= 2
-	 */
-	int int_field = pOp->p5;
-	bool is_neg = false;
-
-	if (int_field > 0) {
-		/* The input value in P3 might be of any type: integer, real, string,
-		 * blob, or NULL.  But it needs to be an integer before we can do
-		 * the seek, so convert it.
-		 */
-		pIn3 = &aMem[int_field];
-		if ((pIn3->flags & MEM_Null) != 0)
-			goto skip_truncate;
-		if ((pIn3->flags & MEM_Str) != 0)
-			mem_apply_numeric_type(pIn3);
-		int64_t i;
-		if ((pIn3->flags & MEM_Int) == MEM_Int) {
-			i = pIn3->u.i;
-			is_neg = true;
-		} else if ((pIn3->flags & MEM_UInt) == MEM_UInt) {
-			i = pIn3->u.u;
-			is_neg = false;
-		} else if ((pIn3->flags & MEM_Real) == MEM_Real) {
-			if (pIn3->u.r > INT64_MAX)
-				i = INT64_MAX;
-			else if (pIn3->u.r < INT64_MIN)
-				i = INT64_MIN;
-			else
-				i = pIn3->u.r;
-			is_neg = i < 0;
-		} else {
-			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
-				 sql_value_to_diag_str(pIn3), "integer");
-			goto abort_due_to_error;
-		}
-		iKey = i;
-
-		/* If the P3 value could not be converted into an integer without
-		 * loss of information, then special processing is required...
-		 */
-		if ((pIn3->flags & (MEM_Int | MEM_UInt)) == 0) {
-			if ((pIn3->flags & MEM_Real)==0) {
-				/* If the P3 value cannot be converted into any kind of a number,
-				 * then the seek is not possible, so jump to P2
-				 */
-				VdbeBranchTaken(1,2); goto jump_to_p2;
-				break;
-			}
-
-			/* If the approximation iKey is larger than the actual real search
-			 * term, substitute >= for > and < for <=. e.g. if the search term
-			 * is 4.9 and the integer approximation 5:
-			 *
-			 *        (x >  4.9)    ->     (x >= 5)
-			 *        (x <= 4.9)    ->     (x <  5)
-			 */
-			if (pIn3->u.r<(double)iKey) {
-				assert(OP_SeekGE==(OP_SeekGT-1));
-				assert(OP_SeekLT==(OP_SeekLE-1));
-				assert((OP_SeekLE & 0x0001)==(OP_SeekGT & 0x0001));
-				if ((oc & 0x0001)==(OP_SeekGT & 0x0001)) oc--;
-			}
-
-			/* If the approximation iKey is smaller than the actual real search
-			 * term, substitute <= for < and > for >=.
-			 */
-			else if (pIn3->u.r>(double)iKey) {
-				assert(OP_SeekLE==(OP_SeekLT+1));
-				assert(OP_SeekGT==(OP_SeekGE+1));
-				assert((OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001));
-				if ((oc & 0x0001)==(OP_SeekLT & 0x0001)) oc++;
-			}
-		}
-	}
-skip_truncate:
 	/*
 	 * For a cursor with the OPFLAG_SEEKEQ hint, only the
 	 * OP_SeekGE and OP_SeekLE opcodes are allowed, and these
@@ -3593,9 +3500,6 @@ skip_truncate:
 	r.key_def = pC->key_def;
 	r.nField = (u16)nField;
 
-	if (int_field > 0)
-		mem_set_int(&aMem[int_field], iKey, is_neg);
-
 	r.default_rc = ((1 & (oc - OP_SeekLT)) ? -1 : +1);
 	assert(oc!=OP_SeekGT || r.default_rc==-1);
 	assert(oc!=OP_SeekLE || r.default_rc==-1);
diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
index 6d8768865..97ba59151 100644
--- a/src/box/sql/wherecode.c
+++ b/src/box/sql/wherecode.c
@@ -910,10 +910,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 		enum field_type *end_types = NULL;
 		u8 bSeekPastNull = 0;	/* True to seek past initial nulls */
 		u8 bStopAtNull = 0;	/* Add condition to terminate at NULLs */
-		int force_integer_reg = -1;  /* If non-negative: number of
-					      * column which must be converted
-					      * to integer type, used for IPK.
-					      */
 
 		struct index_def *idx_def = pLoop->index_def;
 		assert(idx_def != NULL);
@@ -1120,21 +1116,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 							   1);
 			}
 		}
-		/* Inequality constraint comes always at the end of list. */
-		part_count = idx_def->key_def->part_count;
-		if (pRangeStart != NULL) {
-			/*
-			 * nEq == 0 means that filter condition
-			 * contains only inequality.
-			 */
-			uint32_t ineq_idx = nEq == 0 ? 0 : nEq - 1;
-			assert(ineq_idx < part_count);
-			enum field_type ineq_type =
-				idx_def->key_def->parts[ineq_idx].type;
-			if (ineq_type == FIELD_TYPE_INTEGER ||
-			    ineq_type == FIELD_TYPE_UNSIGNED)
-				force_integer_reg = regBase + nEq;
-		}
 		emit_apply_type(pParse, regBase, nConstraint - bSeekPastNull,
 				start_types);
 		if (pLoop->nSkip > 0 && nConstraint == pLoop->nSkip) {
@@ -1152,14 +1133,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 			}
 			sqlVdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase,
 					     nConstraint);
-			/* If this is Seek* opcode, and IPK is detected in the
-			 * constraints vector: force it to be integer.
-			 */
-			if ((op == OP_SeekGE || op == OP_SeekGT
-			    || op == OP_SeekLE || op == OP_SeekLT)
-			    && force_integer_reg > 0) {
-				sqlVdbeChangeP5(v, force_integer_reg);
-			}
 			VdbeCoverage(v);
 			VdbeCoverageIf(v, op == OP_Rewind);
 			testcase(op == OP_Rewind);
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v6 18/22] sql: add implicit cast between numbers in OP_Seek*
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (16 preceding siblings ...)
  2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 17/22] sql: remove unused DOUBLE to INTEGER conversion imeevma
@ 2020-07-16 14:47 ` imeevma
  2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 19/22] sql: change comparison between numbers using index imeevma
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: imeevma @ 2020-07-16 14:47 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

This patch adds new rules for implicit casting between numbers in
OP_Seek * opcodes. They are still not used because the ApplyType
opcode is converting numbers, but this will be changed in the next
patch. Conversion within the ApplyType opcode can affect the
result of comparison operations.

Part of #4230
---
 src/box/sql/vdbe.c | 329 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 329 insertions(+)

diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index d853a0edb..dd1ce97b7 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -522,6 +522,265 @@ mem_convert_to_numeric(struct Mem *mem, enum field_type type)
 	return mem_convert_to_integer(mem);
 }
 
+/**
+ * Convert the numeric value contained in the MEM to UNSIGNED.
+ * @see mem_prepare_for_cmp() for more info.
+ *
+ * @param mem The MEM that contains the numeric value.
+ * @param[in][out] oc Operation code.
+ * @retval 0 if the conversion was successful, -1 otherwise.
+ */
+static int
+mem_prepare_for_cmp_to_uint(struct Mem *mem, int *oc, int eqOnly)
+{
+	if ((mem->flags & MEM_Int) != 0) {
+		if (eqOnly == 1)
+			return 0;
+		if (*oc == OP_SeekGT) {
+			mem_set_u64(mem, 0);
+			*oc = OP_SeekGE;
+			return 0;
+		}
+		if (*oc == OP_SeekGE) {
+			mem_set_u64(mem, 0);
+			return 0;
+		}
+		if (*oc == OP_SeekLT)
+			return 0;
+		assert(*oc == OP_SeekLE);
+		return 0;
+	}
+	assert((mem->flags & MEM_Real) != 0);
+	double d = mem->u.r;
+	if (d == (double)(uint64_t)d)
+		return mem_convert_to_unsigned(mem);
+	if (eqOnly == 1)
+		return 0;
+	if (*oc == OP_SeekGT) {
+		if (d >= (double)UINT64_MAX)
+			return 0;
+		if (d < 0) {
+			mem_set_u64(mem, 0);
+			*oc = OP_SeekGE;
+			return 0;
+		}
+		assert((double)(uint64_t)d < d);
+		return mem_convert_to_unsigned(mem);
+	}
+	if (*oc == OP_SeekGE) {
+		if (d >= (double)UINT64_MAX)
+			return 0;
+		if (d < 0) {
+			mem_set_u64(mem, 0);
+			return 0;
+		}
+		assert((double)(uint64_t)d < d);
+		*oc = OP_SeekGT;
+		return mem_convert_to_unsigned(mem);
+	}
+	if (*oc == OP_SeekLT) {
+		if (d >= (double)UINT64_MAX) {
+			*oc = OP_SeekLE;
+			mem_set_u64(mem, UINT64_MAX);
+			return 0;
+		}
+		if (d < 0)
+			return 0;
+		assert((double)(uint64_t)d < d);
+		*oc = OP_SeekLE;
+		return mem_convert_to_unsigned(mem);
+	}
+	assert(*oc == OP_SeekLE);
+	if (d >= (double)UINT64_MAX) {
+		mem_set_u64(mem, UINT64_MAX);
+		return 0;
+	}
+	if (d < 0)
+		return 0;
+	assert((double)(uint64_t)d < d);
+	return mem_convert_to_unsigned(mem);
+}
+
+/**
+ * Convert the numeric value contained in the MEM to INTEGER.
+ * @see mem_prepare_for_cmp() for more info.
+ *
+ * @param mem The MEM that contains the numeric value.
+ * @param[in][out] oc Operation code.
+ * @retval 0 if the conversion was successful, -1 otherwise.
+ */
+static int
+mem_prepare_for_cmp_to_int(struct Mem *mem, int *oc, int eqOnly)
+{
+	assert((mem->flags & MEM_Real) != 0);
+	double d = mem->u.r;
+	if (d == (double)(uint64_t)d || d == (double)(int64_t)d)
+		return mem_convert_to_integer(mem);
+	if (eqOnly == 1)
+		return 0;
+	if (*oc == OP_SeekGT) {
+		if (d >= (double)UINT64_MAX)
+			return 0;
+		if (d < (double)INT64_MIN) {
+			mem_set_i64(mem, INT64_MIN);
+			*oc = OP_SeekGE;
+			return 0;
+		}
+		if (d > 0 || (double)(int64_t)d < d)
+			return mem_convert_to_integer(mem);
+		*oc = OP_SeekGE;
+		return mem_convert_to_integer(mem);
+	}
+	if (*oc == OP_SeekGE) {
+		if (d >= (double)UINT64_MAX)
+			return 0;
+		if (d < (double)INT64_MIN) {
+			mem_set_i64(mem, INT64_MIN);
+			return 0;
+		}
+		if (d > 0 || (double)(int64_t)d < d) {
+			*oc = OP_SeekGT;
+			return mem_convert_to_integer(mem);
+		}
+		return mem_convert_to_integer(mem);
+	}
+	if (*oc == OP_SeekLT) {
+		if (d >= (double)UINT64_MAX) {
+			*oc = OP_SeekLE;
+			mem_set_int(mem, UINT64_MAX, false);
+			return 0;
+		}
+		if (d < (double)INT64_MIN)
+			return 0;
+		if (d > 0 || (double)(int64_t)d < d) {
+			*oc = OP_SeekLE;
+			return mem_convert_to_integer(mem);
+		}
+		return mem_convert_to_integer(mem);
+	}
+	assert(*oc == OP_SeekLE);
+	if (d >= (double)UINT64_MAX) {
+		mem_set_int(mem, UINT64_MAX, false);
+		return 0;
+	}
+	if (d > 0 || (double)(int64_t)d < d)
+		return mem_convert_to_integer(mem);
+	*oc = OP_SeekLT;
+	return mem_convert_to_integer(mem);
+}
+
+/**
+ * Convert the numeric value contained in the MEM to DOUBLE.
+ * @see mem_prepare_for_cmp() for more info.
+ *
+ * @param mem The MEM that contains the numeric value.
+ * @param[in][out] oc Operation code.
+ * @retval 0 if the conversion was successful, -1 otherwise.
+ */
+static int
+mem_prepare_for_cmp_to_double(struct Mem *mem, int *oc, int eqOnly)
+{
+	if ((mem->flags & MEM_Int) != 0) {
+		int64_t i = mem->u.i;
+		if (i == (int64_t)(double)i)
+			return mem_convert_to_double(mem);
+		if (eqOnly == 1)
+			return 0;
+		double d = (double)i;
+		if (*oc == OP_SeekGT) {
+			if (d == (double)INT64_MAX || i < (int64_t)d)
+				*oc = OP_SeekGE;
+			return mem_convert_to_double(mem);
+		}
+		if (*oc == OP_SeekGE) {
+			if (d != (double)INT64_MAX && i > (int64_t)d)
+				*oc = OP_SeekGT;
+			return mem_convert_to_double(mem);
+		}
+		if (*oc == OP_SeekLT) {
+			if (d != (double)INT64_MAX && i > (int64_t)d)
+				*oc = OP_SeekLE;
+			return mem_convert_to_double(mem);
+		}
+		assert(*oc == OP_SeekLE);
+		if (d == (double)INT64_MAX || i < (int64_t)d)
+			*oc = OP_SeekLT;
+		return mem_convert_to_double(mem);
+	}
+	assert((mem->flags & MEM_UInt) != 0);
+	uint64_t u = mem->u.u;
+	if (u == (uint64_t)(double)u)
+		return mem_convert_to_double(mem);
+	if (eqOnly == 1)
+		return 0;
+	double d = (double)u;
+	if (*oc == OP_SeekGT) {
+		if (d == (double)UINT64_MAX || u < (uint64_t)d)
+			*oc = OP_SeekGE;
+		return mem_convert_to_double(mem);
+	}
+	if (*oc == OP_SeekGE) {
+		if (d != (double)UINT64_MAX && u > (uint64_t)d)
+			*oc = OP_SeekGT;
+		return mem_convert_to_double(mem);
+	}
+	if (*oc == OP_SeekLT) {
+		if (d != (double)UINT64_MAX && u > (uint64_t)d)
+			*oc = OP_SeekLE;
+		return mem_convert_to_double(mem);
+	}
+	assert(*oc == OP_SeekLE);
+	if (d == (double)UINT64_MAX || u < (uint64_t)d)
+		*oc = OP_SeekLT;
+	return mem_convert_to_double(mem);
+}
+
+/**
+ * Convert the numeric value contained in the MEM to another
+ * numeric type according to the specified operation. If the
+ * conversion is successful, we will get the converted MEM. If the
+ * conversion fails, the MEM will not be changed.
+ *
+ * There are two reasons why the MEM might not convert.
+ * 1) MEM conversion affects the result of the operation.
+ * For example:
+ * CREATE TABLE t (i INT PRIMARY KEY);
+ * ...
+ * SELECT * FROM t WHERE i = 1.5;
+ *
+ * 2) After conversion, nothing will be found as a result of the
+ * operation.
+ * For example:
+ * CREATE TABLE t (i INT PRIMARY KEY);
+ * ...
+ * SELECT * FROM t WHERE i > 2^100;
+ *
+ *
+ * If the conversion is successful, the operation can also change.
+ * For example:
+ * CREATE TABLE t (i INT PRIMARY KEY);
+ * ...
+ * SELECT * FROM t WHERE i > -(2^100);
+ *
+ * The value becomes INT64_MIN after conversion and the operation
+ * becomes '> ='.
+ *
+ * @param mem The MEM that contains the numeric value.
+ * @param type The type to convert to.
+ * @param[in][out] oc Operation code.
+ * @retval 0 if the conversion was successful, -1 otherwise.
+ */
+static int
+mem_prepare_for_cmp(struct Mem *mem, enum field_type type, int *oc, int eqOnly)
+{
+	if (type == FIELD_TYPE_UNSIGNED)
+		return mem_prepare_for_cmp_to_uint(mem, oc, eqOnly);
+	if (type == FIELD_TYPE_INTEGER)
+		return mem_prepare_for_cmp_to_int(mem, oc, eqOnly);
+	assert(type == FIELD_TYPE_DOUBLE);
+	return mem_prepare_for_cmp_to_double(mem, oc, eqOnly);
+}
+
 /*
  * 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
@@ -3507,6 +3766,74 @@ case OP_SeekGT: {       /* jump, in3 */
 	assert(oc!=OP_SeekLT || r.default_rc==+1);
 
 	r.aMem = &aMem[pOp->p3];
+	bool is_on_region = false;
+	struct region *region = &fiber()->gc;
+	size_t region_svp = 0;
+	for (int i = 0; i < r.nField; ++i) {
+		struct Mem *mem = &r.aMem[i];
+		enum field_type type = r.key_def->parts[i].type;
+		/*
+		 * We already know that MEM_type and field type
+		 * are comparable. If they are not compatible, we
+		 * should try to convert MEM to field type.
+		 */
+		if (!mem_is_type_compatible(mem, type)) {
+			/*
+			 * We cannot make changes to original MEMs
+			 * since they will be used in OP_Idx*. So
+			 * we should copy them and make changes to
+			 * the copies.
+			 */
+			if (!is_on_region) {
+				region_svp = region_used(region);
+				uint32_t size = sizeof(struct Mem) * r.nField;
+				r.aMem = region_aligned_alloc(region, size,
+							      alignof(struct Mem));
+				if (r.aMem == NULL) {
+					diag_set(OutOfMemory, size,
+						 "region_aligned_alloc",
+						 "r.aMem");
+					goto abort_due_to_error;
+				}
+				memcpy(r.aMem, &aMem[pOp->p3], size);
+				is_on_region = true;
+				mem = &r.aMem[i];
+			}
+			/*
+			 * In cases where we can change the MEM
+			 * according to the field type and opcode,
+			 * we will get the converted MEM after
+			 * this function.
+			 *
+			 * There are two cases where MEM does not
+			 * change:
+			 * 1) any resultof conversion can affect
+			 * the result of the operation;
+			 * 2) after conversion nothing will be
+			 * found as a result of the operation.
+			 *
+			 * Examples can be found in description of
+			 * the function.
+			 */
+			if (mem_prepare_for_cmp(mem, type, &oc, eqOnly) != 0) {
+				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+					 sql_value_to_diag_str(mem),
+					 field_type_strs[type]);
+				goto abort_due_to_error;
+			}
+			/*
+			 * if the MEM type and the field type are
+			 * still not compatible, then the
+			 * conversion failed and we won't find
+			 * anything.
+			 */
+			if (!mem_is_type_compatible(mem, type)) {
+				res = 1;
+				goto seek_not_found;
+			}
+		}
+	}
+
 #ifdef SQL_DEBUG
 	{ int i; for(i=0; i<r.nField; i++) assert(memIsValid(&r.aMem[i])); }
 #endif
@@ -3544,6 +3871,8 @@ case OP_SeekGT: {       /* jump, in3 */
 		}
 	}
 			seek_not_found:
+	if (is_on_region)
+		region_truncate(region, region_svp);
 	assert(pOp->p2>0);
 	VdbeBranchTaken(res!=0,2);
 	if (res) {
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v6 19/22] sql: change comparison between numbers using index
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (17 preceding siblings ...)
  2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 18/22] sql: add implicit cast between numbers in OP_Seek* imeevma
@ 2020-07-16 14:47 ` imeevma
  2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 20/22] sql: remove implicit cast from comparison opcodes imeevma
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 31+ messages in thread
From: imeevma @ 2020-07-16 14:47 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

This patch disables number conversions in ApplyType in wherecode.c. This
allows conversions between numbers introduced in previous commit to be
used.

Part of #4230
---
 src/box/sql/sqlInt.h                 |  2 +
 src/box/sql/vdbe.c                   |  3 +-
 src/box/sql/wherecode.c              | 76 +---------------------------
 test/sql-tap/in4.test.lua            |  4 +-
 test/sql-tap/join.test.lua           |  4 +-
 test/sql-tap/tkt-9a8b09f8e6.test.lua |  8 +--
 test/sql/types.result                | 54 ++++++++++++++++++++
 test/sql/types.test.lua              | 12 +++++
 8 files changed, 79 insertions(+), 84 deletions(-)

diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index cd94616ca..7d6119904 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -2309,6 +2309,8 @@ struct Parse {
 					 */
 /** OP_ApplyType: Treat BLOB as STRING. */
 #define OPFLAG_BLOB_LIKE_STRING		0x01
+/** OP_ApplyType: Do not convert numbers. */
+#define OPFLAG_DO_NOT_CONVERT_NUMBERS	0x02
 
 /**
  * Prepare vdbe P5 flags for OP_{IdxInsert, IdxReplace, Update}
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index dd1ce97b7..96f02717c 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -3150,7 +3150,8 @@ 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) != 0)
+			if ((pOp->p5 & OPFLAG_DO_NOT_CONVERT_NUMBERS) == 0 &&
+			    mem_convert_to_numeric(pIn1, type) != 0)
 				goto type_mismatch;
 		}
 		pIn1++;
diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
index 97ba59151..78d580801 100644
--- a/src/box/sql/wherecode.c
+++ b/src/box/sql/wherecode.c
@@ -374,6 +374,7 @@ emit_apply_type(Parse *pParse, int base, int n, enum field_type *types)
 								     types, n);
 		sqlVdbeAddOp4(v, OP_ApplyType, base, n, 0,
 				  (char *) types_dup, P4_DYNAMIC);
+		sqlVdbeChangeP5(v, OPFLAG_DO_NOT_CONVERT_NUMBERS);
 		sql_expr_type_cache_change(pParse, base, n);
 	}
 }
@@ -1045,77 +1046,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 		}
 		struct index_def *idx_pk = space->index[0]->def;
 		uint32_t pk_part_count = idx_pk->key_def->part_count;
-		/*
-		 * Tarantool's iterator over integer fields doesn't
-		 * tolerate floating point values. Hence, if term
-		 * is equality comparison and value of operand is
-		 * not integer, we can skip it since it always
-		 * results in false: INT a == 0.5 -> false;
-		 * It is done using OP_MustBeInt facilities.
-		 * In case term is greater comparison (a > ?), we
-		 * should notify OP_SeekGT to process truncation of
-		 * floating point value: a > 0.5 -> a >= 1;
-		 * It is done by setting P5 flag for OP_Seek*.
-		 * It is worth mentioning that we do not need
-		 * this step when it comes for less (<) comparison
-		 * of nullable field. Key is NULL in this case:
-		 * values are ordered as  NULL, ... NULL, min_value,
-		 * so to fetch min value we pass NULL to GT iterator.
-		 * The only exception is less comparison in
-		 * conjunction with ORDER BY DESC clause:
-		 * in such situation we use LE iterator and
-		 * truncated value to compare. But then
-		 * pRangeStart == NULL.
-		 * This procedure is correct for compound index:
-		 * only one comparison of less/greater type can be
-		 * used at the same time. For instance,
-		 * a < 1.5 AND b > 0.5 is handled by SeekGT using
-		 * column a and fetching column b from tuple and
-		 * OP_Le comparison.
-		 *
-		 * Note that OP_ApplyType, which is emitted before
-		 * OP_Seek** doesn't truncate floating point to
-		 * integer. That's why we need this routine.
-		 * Also, note that terms are separated by OR
-		 * predicates, so we consider term as sequence
-		 * of AND'ed predicates.
-		 */
-		size_t addrs_sz;
-		int *seek_addrs = region_alloc_array(&pParse->region,
-						     typeof(seek_addrs[0]), nEq,
-						     &addrs_sz);
-		if (seek_addrs == NULL) {
-			diag_set(OutOfMemory, addrs_sz, "region_alloc_array",
-				 "seek_addrs");
-			pParse->is_aborted = true;
-			return 0;
-		}
-		memset(seek_addrs, 0, addrs_sz);
-		for (int i = 0; i < nEq; i++) {
-			enum field_type type = idx_def->key_def->parts[i].type;
-			if (type == FIELD_TYPE_INTEGER ||
-			    type == FIELD_TYPE_UNSIGNED) {
-				/*
-				 * OP_MustBeInt consider NULLs as
-				 * non-integer values, so firstly
-				 * check whether value is NULL or not.
-				 */
-				seek_addrs[i] = sqlVdbeAddOp1(v, OP_IsNull,
-							      regBase);
-				sqlVdbeAddOp2(v, OP_MustBeInt, regBase + i,
-					      addrNxt);
-				start_types[i] = FIELD_TYPE_SCALAR;
-				/*
-				 * We need to notify column cache
-				 * that type of value may change
-				 * so we should fetch value from
-				 * tuple again rather then copy
-				 * from register.
-				 */
-				sql_expr_type_cache_change(pParse, regBase + i,
-							   1);
-			}
-		}
 		emit_apply_type(pParse, regBase, nConstraint - bSeekPastNull,
 				start_types);
 		if (pLoop->nSkip > 0 && nConstraint == pLoop->nSkip) {
@@ -1127,10 +1057,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 			op = aStartOp[(start_constraints << 2) +
 				      (startEq << 1) + bRev];
 			assert(op != 0);
-			for (uint32_t i = 0; i < nEq; ++i) {
-				if (seek_addrs[i] != 0)
-					sqlVdbeJumpHere(v, seek_addrs[i]);
-			}
 			sqlVdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase,
 					     nConstraint);
 			VdbeCoverage(v);
diff --git a/test/sql-tap/in4.test.lua b/test/sql-tap/in4.test.lua
index 5c01ccdab..e0bf671d9 100755
--- a/test/sql-tap/in4.test.lua
+++ b/test/sql-tap/in4.test.lua
@@ -147,13 +147,13 @@ test:do_execsql_test(
         -- </in4-2.7>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "in4-2.8",
     [[
         SELECT b FROM t2 WHERE a IN ('', '0.0.0', '2') 
     ]], {
         -- <in4-2.8>
-        "two"
+        1, "Type mismatch: can not convert  to integer"
         -- </in4-2.8>
     })
 
diff --git a/test/sql-tap/join.test.lua b/test/sql-tap/join.test.lua
index 840b780a3..7a1346094 100755
--- a/test/sql-tap/join.test.lua
+++ b/test/sql-tap/join.test.lua
@@ -1028,13 +1028,13 @@ test:do_test(
         -- </join-11.8>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "join-11.9",
     [[
         SELECT * FROM t1 NATURAL JOIN t2 
     ]], {
         -- <join-11.9>
-        "one", "1", "two", "2"
+        1, "Type mismatch: can not convert 1 to integer"
         -- </join-11.9>
     })
 
diff --git a/test/sql-tap/tkt-9a8b09f8e6.test.lua b/test/sql-tap/tkt-9a8b09f8e6.test.lua
index ca3a5427a..1314d0aad 100755
--- a/test/sql-tap/tkt-9a8b09f8e6.test.lua
+++ b/test/sql-tap/tkt-9a8b09f8e6.test.lua
@@ -183,13 +183,13 @@ test:do_execsql_test(
         -- </3.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     3.3,
     [[
         SELECT x FROM t2 WHERE x IN ('1');
     ]], {
         -- <3.3>
-        1
+        1, "Type mismatch: can not convert 1 to integer"
         -- </3.3>
     })
 
@@ -213,13 +213,13 @@ test:do_execsql_test(
         -- </3.6>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     3.7,
     [[
         SELECT x FROM t2 WHERE '1' IN (x);
     ]], {
         -- <3.7>
-        1
+        1, "Type mismatch: can not convert 1 to integer"
         -- </3.7>
     })
 
diff --git a/test/sql/types.result b/test/sql/types.result
index 43cdffad0..7a4e9bca3 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -2775,3 +2775,57 @@ box.execute([[DROP TABLE ts;]])
 ---
 - row_count: 1
 ...
+--
+-- gh-4230: Make sure the comparison between numbers that use
+-- index is working correctly.
+--
+box.execute([[CREATE TABLE t (i INTEGER PRIMARY KEY, a DOUBLE);]])
+---
+- row_count: 1
+...
+box.execute([[INSERT INTO t VALUES (1, ?);]], {2^60})
+---
+- row_count: 1
+...
+box.execute([[SELECT * FROM t WHERE i > ?]], {2^70})
+---
+- metadata:
+  - name: I
+    type: integer
+  - name: A
+    type: double
+  rows: []
+...
+box.execute([[SELECT * FROM t WHERE i > ?]], {-2^70})
+---
+- metadata:
+  - name: I
+    type: integer
+  - name: A
+    type: double
+  rows:
+  - [1, 1152921504606846976]
+...
+box.execute([[SELECT * FROM t WHERE a = ?]], {2ULL^60ULL - 1ULL})
+---
+- metadata:
+  - name: I
+    type: integer
+  - name: A
+    type: double
+  rows: []
+...
+box.execute([[SELECT * FROM t WHERE a > ?]], {2ULL^60ULL - 1ULL})
+---
+- metadata:
+  - name: I
+    type: integer
+  - name: A
+    type: double
+  rows:
+  - [1, 1152921504606846976]
+...
+box.execute([[DROP TABLE t;]])
+---
+- row_count: 1
+...
diff --git a/test/sql/types.test.lua b/test/sql/types.test.lua
index 0270d9f8a..a23b12801 100644
--- a/test/sql/types.test.lua
+++ b/test/sql/types.test.lua
@@ -623,3 +623,15 @@ box.execute([[DROP TABLE tb;]])
 box.execute([[DROP TABLE tt;]])
 box.execute([[DROP TABLE tv;]])
 box.execute([[DROP TABLE ts;]])
+
+--
+-- gh-4230: Make sure the comparison between numbers that use
+-- index is working correctly.
+--
+box.execute([[CREATE TABLE t (i INTEGER PRIMARY KEY, a DOUBLE);]])
+box.execute([[INSERT INTO t VALUES (1, ?);]], {2^60})
+box.execute([[SELECT * FROM t WHERE i > ?]], {2^70})
+box.execute([[SELECT * FROM t WHERE i > ?]], {-2^70})
+box.execute([[SELECT * FROM t WHERE a = ?]], {2ULL^60ULL - 1ULL})
+box.execute([[SELECT * FROM t WHERE a > ?]], {2ULL^60ULL - 1ULL})
+box.execute([[DROP TABLE t;]])
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v6 20/22] sql: remove implicit cast from comparison opcodes
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (18 preceding siblings ...)
  2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 19/22] sql: change comparison between numbers using index imeevma
@ 2020-07-16 14:47 ` imeevma
  2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 21/22] sql: fix implicit cast in opcode MustBeInt imeevma
  2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 22/22] sql: remove implicit cast from MakeRecord opcode imeevma
  21 siblings, 0 replies; 31+ messages in thread
From: imeevma @ 2020-07-16 14:47 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

This patch removes implicit casting from STRING to number and vice
versa from comparison opcodes.

Part of #4230
---
 src/box/sql/vdbe.c                    |  52 ++-
 test/sql-tap/identifier_case.test.lua |   6 +-
 test/sql-tap/in1.test.lua             |   4 +-
 test/sql-tap/insert3.test.lua         |   2 +-
 test/sql-tap/join.test.lua            |   4 +-
 test/sql-tap/misc1.test.lua           |  32 +-
 test/sql-tap/select1.test.lua         |   4 +-
 test/sql-tap/select7.test.lua         |   2 +-
 test/sql-tap/subquery.test.lua        |   4 +-
 test/sql-tap/tkt-9a8b09f8e6.test.lua  | 508 --------------------------
 test/sql-tap/tkt3493.test.lua         |  40 +-
 test/sql-tap/transitive1.test.lua     |  12 +-
 test/sql-tap/where2.test.lua          | 183 +---------
 test/sql-tap/where5.test.lua          |  12 +-
 test/sql/types.result                 |   7 +-
 15 files changed, 86 insertions(+), 786 deletions(-)
 delete mode 100755 test/sql-tap/tkt-9a8b09f8e6.test.lua

diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 96f02717c..73b25fecf 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -2574,22 +2574,17 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
 	} else {
 		enum field_type type = pOp->p5 & FIELD_TYPE_MASK;
 		if (sql_type_is_numeric(type)) {
-			if ((flags1 | flags3)&MEM_Str) {
-				if ((flags1 & MEM_Str) == MEM_Str) {
-					mem_apply_numeric_type(pIn1);
-					testcase( flags3!=pIn3->flags); /* Possible if pIn1==pIn3 */
-					flags3 = pIn3->flags;
-				}
-				if ((flags3 & MEM_Str) == MEM_Str) {
-					if (mem_apply_numeric_type(pIn3) != 0) {
-						diag_set(ClientError,
-							 ER_SQL_TYPE_MISMATCH,
-							 sql_value_to_diag_str(pIn3),
-							 "numeric");
-						goto abort_due_to_error;
-					}
-
-				}
+			if ((flags1 & MEM_Str) == MEM_Str) {
+				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+					 sql_value_to_diag_str(pIn1),
+					 "numeric");
+				goto abort_due_to_error;
+			}
+			if ((flags3 & MEM_Str) == MEM_Str) {
+				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+					 sql_value_to_diag_str(pIn3),
+					 "numeric");
+				goto abort_due_to_error;
 			}
 			/* Handle the common case of integer comparison here, as an
 			 * optimization, to avoid a call to sqlMemCompare()
@@ -2622,22 +2617,17 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
 				goto compare_op;
 			}
 		} else if (type == FIELD_TYPE_STRING) {
-			if ((flags1 & MEM_Str) == 0 &&
-			    (flags1 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
-				testcase( pIn1->flags & MEM_Int);
-				testcase( pIn1->flags & MEM_Real);
-				sqlVdbeMemStringify(pIn1);
-				testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn));
-				flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
-				assert(pIn1!=pIn3);
+			if ((flags1 & MEM_Str) == 0) {
+				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+					 mem_type_to_str(pIn3),
+					 mem_type_to_str(pIn1));
+				goto abort_due_to_error;
 			}
-			if ((flags3 & MEM_Str) == 0 &&
-			    (flags3 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
-				testcase( pIn3->flags & MEM_Int);
-				testcase( pIn3->flags & MEM_Real);
-				sqlVdbeMemStringify(pIn3);
-				testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn));
-				flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask);
+			if ((flags3 & MEM_Str) == 0) {
+				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+					 mem_type_to_str(pIn1),
+					 mem_type_to_str(pIn3));
+				goto abort_due_to_error;
 			}
 		}
 		assert(pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0);
diff --git a/test/sql-tap/identifier_case.test.lua b/test/sql-tap/identifier_case.test.lua
index 2a00626fc..1d56ffb44 100755
--- a/test/sql-tap/identifier_case.test.lua
+++ b/test/sql-tap/identifier_case.test.lua
@@ -242,11 +242,11 @@ data = {
     { 2,  [[ 'a' < 'b' collate "binary" ]], {0, {true}}},
     { 3,  [[ 'a' < 'b' collate 'binary' ]], {1, [[Syntax error at line 1 near ''binary'']]}},
     { 4,  [[ 'a' < 'b' collate "unicode" ]], {0, {true}}},
-    { 5,  [[ 5 < 'b' collate "unicode" ]], {0, {true}}},
+    { 5,  [[ 5 < 'b' collate "unicode" ]], {1, "Type mismatch: can not convert b to numeric"}},
     { 6,  [[ 5 < 'b' collate unicode ]], {1,"Collation 'UNICODE' does not exist"}},
-    { 7,  [[ 5 < 'b' collate "unicode_ci" ]], {0, {true}}},
+    { 7,  [[ 5 < 'b' collate "unicode_ci" ]], {1, "Type mismatch: can not convert b to numeric"}},
     { 8,  [[ 5 < 'b' collate NONE ]], {1, "Collation 'NONE' does not exist"}},
-    { 9,  [[ 5 < 'b' collate "none" ]], {0, {true}}},
+    { 9,  [[ 5 < 'b' collate "none" ]], {1, "Type mismatch: can not convert b to numeric"}},
 }
 
 for _, row in ipairs(data) do
diff --git a/test/sql-tap/in1.test.lua b/test/sql-tap/in1.test.lua
index 570cc1779..e2f498889 100755
--- a/test/sql-tap/in1.test.lua
+++ b/test/sql-tap/in1.test.lua
@@ -637,12 +637,12 @@ test:do_test(
     "in-11.2",
     function()
         -- The '2' should be coerced into 2 because t6.b is NUMERIC
-        return test:execsql [[
+        return test:catchsql [[
             SELECT * FROM t6 WHERE b IN ('2');
         ]]
     end, {
         -- <in-11.2>
-        1, 2
+        1, "Type mismatch: can not convert 2 to numeric"
         -- </in-11.2>
     })
 
diff --git a/test/sql-tap/insert3.test.lua b/test/sql-tap/insert3.test.lua
index b92bc508e..3276f0db2 100755
--- a/test/sql-tap/insert3.test.lua
+++ b/test/sql-tap/insert3.test.lua
@@ -59,7 +59,7 @@ test:do_execsql_test(
     [[
             CREATE TABLE log2(rowid INTEGER PRIMARY KEY AUTOINCREMENT, x TEXT UNIQUE,y INT );
             CREATE TRIGGER r2 BEFORE INSERT ON t1 FOR EACH ROW BEGIN
-              UPDATE log2 SET y=y+1 WHERE x=new.b;
+              UPDATE log2 SET y=y+1 WHERE x=CAST(new.b AS STRING);
               INSERT OR IGNORE INTO log2(x, y) VALUES(CAST(new.b AS STRING),1);
             END;
             INSERT INTO t1(a, b) VALUES('hi', 453);
diff --git a/test/sql-tap/join.test.lua b/test/sql-tap/join.test.lua
index 7a1346094..a78913836 100755
--- a/test/sql-tap/join.test.lua
+++ b/test/sql-tap/join.test.lua
@@ -1038,13 +1038,13 @@ test:do_catchsql_test(
         -- </join-11.9>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "join-11.10",
     [[
         SELECT * FROM t2 NATURAL JOIN t1 
     ]], {
         -- <join-11.10>
-        1, "one", 2, "two"
+        1, "Type mismatch: can not convert 1 to numeric"
         -- </join-11.10>
     })
 
diff --git a/test/sql-tap/misc1.test.lua b/test/sql-tap/misc1.test.lua
index c0136d04c..66666878e 100755
--- a/test/sql-tap/misc1.test.lua
+++ b/test/sql-tap/misc1.test.lua
@@ -88,7 +88,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-1.4",
     [[
-        SELECT x75 FROM manycol WHERE x50=350
+        SELECT x75 FROM manycol WHERE x50='350'
     ]], {
         -- <misc1-1.4>
         "375"
@@ -98,7 +98,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-1.5",
     [[
-        SELECT x50 FROM manycol WHERE x99=599
+        SELECT x50 FROM manycol WHERE x99='599'
     ]], {
         -- <misc1-1.5>
         "550"
@@ -109,7 +109,7 @@ test:do_test(
     "misc1-1.6",
     function()
         test:execsql("CREATE INDEX manycol_idx1 ON manycol(x99)")
-        return test:execsql("SELECT x50 FROM manycol WHERE x99=899")
+        return test:execsql("SELECT x50 FROM manycol WHERE x99='899'")
     end, {
         -- <misc1-1.6>
         "850"
@@ -129,7 +129,7 @@ test:do_execsql_test(
 test:do_test(
     "misc1-1.8",
     function()
-        test:execsql("DELETE FROM manycol WHERE x98=1234")
+        test:execsql("DELETE FROM manycol WHERE x98='1234'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.8>
@@ -140,7 +140,7 @@ test:do_test(
 test:do_test(
     "misc1-1.9",
     function()
-        test:execsql("DELETE FROM manycol WHERE x98=998")
+        test:execsql("DELETE FROM manycol WHERE x98='998'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.9>
@@ -151,7 +151,7 @@ test:do_test(
 test:do_test(
     "misc1-1.10",
     function()
-        test:execsql("DELETE FROM manycol WHERE x99=500")
+        test:execsql("DELETE FROM manycol WHERE x99='500'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.10>
@@ -162,7 +162,7 @@ test:do_test(
 test:do_test(
     "misc1-1.11",
     function()
-        test:execsql("DELETE FROM manycol WHERE x99=599")
+        test:execsql("DELETE FROM manycol WHERE x99='599'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.11>
@@ -479,9 +479,9 @@ local where = ""
 test:do_test(
     "misc1-10.1",
     function()
-        where = "WHERE x0>=0"
+        where = "WHERE x0>='0'"
         for i = 1, 99, 1 do
-            where = where .. " AND x"..i.."<>0"
+            where = where .. " AND x"..i.."<>'0'"
         end
         return test:catchsql("SELECT count(*) FROM manycol "..where.."")
     end, {
@@ -496,7 +496,7 @@ test:do_test(
 test:do_test(
     "misc1-10.3",
     function()
-        where = string.gsub(where,"x0>=0", "x0=0")
+        where = string.gsub(where,"x0>='0'", "x0='0'")
         return test:catchsql("DELETE FROM manycol "..where.."")
     end, {
         -- <misc1-10.3>
@@ -520,7 +520,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-10.6",
     [[
-        SELECT x1 FROM manycol WHERE x0=100
+        SELECT x1 FROM manycol WHERE x0='100'
     ]], {
         -- <misc1-10.6>
         "101"
@@ -530,7 +530,7 @@ test:do_execsql_test(
 test:do_test(
     "misc1-10.7",
     function()
-        where = string.gsub(where, "x0=0", "x0=100")
+        where = string.gsub(where, "x0='0'", "x0='100'")
         return test:catchsql("UPDATE manycol SET x1=CAST(x1+1 AS STRING) "..where.."")
     end, {
         -- <misc1-10.7>
@@ -541,7 +541,7 @@ test:do_test(
 test:do_execsql_test(
     "misc1-10.8",
     [[
-        SELECT x1 FROM manycol WHERE x0=100
+        SELECT x1 FROM manycol WHERE x0='100'
     ]], {
         -- <misc1-10.8>
         "102"
@@ -563,7 +563,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-10.10",
     [[
-        SELECT x1 FROM manycol WHERE x0=100
+        SELECT x1 FROM manycol WHERE x0='100'
     ]], {
         -- <misc1-10.10>
         "103"
@@ -619,13 +619,13 @@ test:do_execsql_test(
         -- </misc1-12.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "misc1-12.2",
     [[
         SELECT '0'==0.0
     ]], {
         -- <misc1-12.2>
-        true
+        1, "Type mismatch: can not convert 0 to numeric"
         -- </misc1-12.2>
     })
 
diff --git a/test/sql-tap/select1.test.lua b/test/sql-tap/select1.test.lua
index 9a969bf3c..f5a9b63fe 100755
--- a/test/sql-tap/select1.test.lua
+++ b/test/sql-tap/select1.test.lua
@@ -1912,7 +1912,7 @@ test:do_execsql_test(
 test:do_execsql_test(
         "select1-12.7",
         [[
-            SELECT * FROM t3 WHERE a=(SELECT 1);
+            SELECT * FROM t3 WHERE a=(SELECT '1');
         ]], {
             -- <select1-12.7>
             0, "1", "2"
@@ -1922,7 +1922,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "select1-12.8",
     [[
-        SELECT * FROM t3 WHERE a=(SELECT 2);
+        SELECT * FROM t3 WHERE a=(SELECT '2');
     ]], {
         -- <select1-12.8>
 
diff --git a/test/sql-tap/select7.test.lua b/test/sql-tap/select7.test.lua
index e1e43c557..0d1390fd6 100755
--- a/test/sql-tap/select7.test.lua
+++ b/test/sql-tap/select7.test.lua
@@ -256,7 +256,7 @@ test:do_execsql_test(
         DROP TABLE IF EXISTS t5;
         CREATE TABLE t5(a TEXT primary key, b INT);
         INSERT INTO t5 VALUES('123', 456);
-        SELECT typeof(a), a FROM t5 GROUP BY a HAVING a<b;
+        SELECT typeof(a), a FROM t5 GROUP BY a HAVING CAST(a AS INTEGER)<b;
     ]], {
         -- <select7-7.7>
         "string", "123"
diff --git a/test/sql-tap/subquery.test.lua b/test/sql-tap/subquery.test.lua
index e0771825e..bad702de9 100755
--- a/test/sql-tap/subquery.test.lua
+++ b/test/sql-tap/subquery.test.lua
@@ -284,13 +284,13 @@ test:do_execsql_test(
         -- </subquery-2.3.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "subquery-2.3.2",
     [[
         SELECT a IN (10.0, 20) FROM t3;
     ]], {
         -- <subquery-2.3.2>
-        false
+        1, "Type mismatch: can not convert text to real"
         -- </subquery-2.3.2>
     })
 
diff --git a/test/sql-tap/tkt-9a8b09f8e6.test.lua b/test/sql-tap/tkt-9a8b09f8e6.test.lua
deleted file mode 100755
index 1314d0aad..000000000
--- a/test/sql-tap/tkt-9a8b09f8e6.test.lua
+++ /dev/null
@@ -1,508 +0,0 @@
-#!/usr/bin/env tarantool
-test = require("sqltester")
-test:plan(47)
-
---!./tcltestrunner.lua
--- 2014 June 26
---
--- 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.
---
--- This file implements tests to verify that ticket [9a8b09f8e6] has been
--- fixed.
---
--- ["set","testdir",[["file","dirname",["argv0"]]]]
--- ["source",[["testdir"],"\/tester.tcl"]]
-testprefix = "tkt-9a8b09f8e6"
--- MUST_WORK_TEST
-if (0 > 0)
- then
-end
-test:do_execsql_test(
-    1.1,
-    [[
-        CREATE TABLE t1(x TEXT primary key);
-        INSERT INTO t1 VALUES('1');
-    ]], {
-        -- <1.1>
-        
-        -- </1.1>
-    })
-
-test:do_execsql_test(
-    1.2,
-    [[
-        CREATE TABLE t2(x INTEGER primary key);
-        INSERT INTO t2 VALUES(1);
-    ]], {
-        -- <1.2>
-        
-        -- </1.2>
-    })
-
-test:do_execsql_test(
-    1.3,
-    [[
-        CREATE TABLE t3(x NUMBER primary key);
-        INSERT INTO t3 VALUES(1.0);
-    ]], {
-        -- <1.3>
-        
-        -- </1.3>
-    })
-
-test:do_execsql_test(
-    1.4,
-    [[
-        CREATE TABLE t4(x NUMBER primary key);
-        INSERT INTO t4 VALUES(1.11);
-    ]], {
-        -- <1.4>
-        
-        -- </1.4>
-    })
-
-test:do_execsql_test(
-    1.5,
-    [[
-        CREATE TABLE t5(id  INT primary key, x INT , y TEXT);
-        INSERT INTO t5 VALUES(1, 1, 'one');
-        INSERT INTO t5 VALUES(2, 1, 'two');
-        INSERT INTO t5 VALUES(3, 1.0, 'three');
-        INSERT INTO t5 VALUES(4, 1.0, 'four');
-    ]], {
-        -- <1.5>
-        
-        -- </1.5>
-    })
-
-test:do_execsql_test(
-    2.1,
-    [[
-        SELECT x FROM t1 WHERE x IN (1);
-    ]], {
-        -- <2.1>
-        "1"
-        -- </2.1>
-    })
-
-test:do_execsql_test(
-    2.2,
-    [[
-        SELECT x FROM t1 WHERE x IN (1.0);
-    ]], {
-        -- <2.2>
-        "1"
-        -- </2.2>
-    })
-
-test:do_execsql_test(
-    2.3,
-    [[
-        SELECT x FROM t1 WHERE x IN ('1');
-    ]], {
-        -- <2.3>
-        "1"
-        -- </2.3>
-    })
-
-test:do_execsql_test(
-    2.4,
-    [[
-        SELECT x FROM t1 WHERE x IN ('1.0');
-    ]], {
-        -- <2.4>
-        
-        -- </2.4>
-    })
-
-test:do_execsql_test(
-    2.5,
-    [[
-        SELECT x FROM t1 WHERE 1 IN (x);
-    ]], {
-        -- <2.5>
-        "1"
-        -- </2.5>
-    })
-
-test:do_execsql_test(
-    2.6,
-    [[
-        SELECT x FROM t1 WHERE 1.0 IN (x);
-    ]], {
-        -- <2.6>
-        "1"
-        -- </2.6>
-    })
-
-test:do_execsql_test(
-    2.7,
-    [[
-        SELECT x FROM t1 WHERE '1' IN (x);
-    ]], {
-        -- <2.7>
-        "1"
-        -- </2.7>
-    })
-
-test:do_execsql_test(
-    2.8,
-    [[
-        SELECT x FROM t1 WHERE '1.0' IN (x);
-    ]], {
-        -- <2.8>
-        
-        -- </2.8>
-    })
-
-test:do_execsql_test(
-    3.1,
-    [[
-        SELECT x FROM t2 WHERE x IN (1);
-    ]], {
-        -- <3.1>
-        1
-        -- </3.1>
-    })
-
-test:do_execsql_test(
-    3.2,
-    [[
-        SELECT x FROM t2 WHERE x IN (1.0);
-    ]], {
-        -- <3.2>
-        1
-        -- </3.2>
-    })
-
-test:do_catchsql_test(
-    3.3,
-    [[
-        SELECT x FROM t2 WHERE x IN ('1');
-    ]], {
-        -- <3.3>
-        1, "Type mismatch: can not convert 1 to integer"
-        -- </3.3>
-    })
-
-test:do_execsql_test(
-    3.5,
-    [[
-        SELECT x FROM t2 WHERE 1 IN (x);
-    ]], {
-        -- <3.5>
-        1
-        -- </3.5>
-    })
-
-test:do_execsql_test(
-    3.6,
-    [[
-        SELECT x FROM t2 WHERE 1.0 IN (x);
-    ]], {
-        -- <3.6>
-        1
-        -- </3.6>
-    })
-
-test:do_catchsql_test(
-    3.7,
-    [[
-        SELECT x FROM t2 WHERE '1' IN (x);
-    ]], {
-        -- <3.7>
-        1, "Type mismatch: can not convert 1 to integer"
-        -- </3.7>
-    })
-
-test:do_execsql_test(
-    4.1,
-    [[
-        SELECT x FROM t3 WHERE x IN (1);
-    ]], {
-        -- <4.1>
-        1.0
-        -- </4.1>
-    })
-
-test:do_execsql_test(
-    4.2,
-    [[
-        SELECT x FROM t3 WHERE x IN (1.0);
-    ]], {
-        -- <4.2>
-        1.0
-        -- </4.2>
-    })
-
-test:do_catchsql_test(
-    4.3,
-    [[
-        SELECT x FROM t3 WHERE x IN ('1');
-    ]], {
-        -- <4.3>
-        1, "Type mismatch: can not convert 1 to number"
-        -- </4.3>
-    })
-
-test:do_catchsql_test(
-    4.4,
-    [[
-        SELECT x FROM t3 WHERE x IN ('1.0');
-    ]], {
-        -- <4.4>
-        1, "Type mismatch: can not convert 1.0 to number"
-        -- </4.4>
-    })
-
-test:do_execsql_test(
-    4.5,
-    [[
-        SELECT x FROM t3 WHERE 1 IN (x);
-    ]], {
-        -- <4.5>
-        1.0
-        -- </4.5>
-    })
-
-test:do_execsql_test(
-    4.6,
-    [[
-        SELECT x FROM t3 WHERE 1.0 IN (x);
-    ]], {
-        -- <4.6>
-        1.0
-        -- </4.6>
-    })
-
-test:do_catchsql_test(
-    4.7,
-    [[
-        SELECT x FROM t3 WHERE '1' IN (x);
-    ]], {
-        -- <4.7>
-        1, "Type mismatch: can not convert 1 to number"
-        -- </4.7>
-    })
-
-test:do_catchsql_test(
-    4.8,
-    [[
-        SELECT x FROM t3 WHERE '1.0' IN (x);
-    ]], {
-        -- <4.8>
-        1, "Type mismatch: can not convert 1.0 to number"
-        -- </4.8>
-    })
-
-test:do_execsql_test(
-    5.1,
-    [[
-        SELECT x FROM t4 WHERE x IN (1);
-    ]], {
-        -- <5.1>
-        
-        -- </5.1>
-    })
-
-test:do_execsql_test(
-    5.2,
-    [[
-        SELECT x FROM t4 WHERE x IN (1.0);
-    ]], {
-        -- <5.2>
-        
-        -- </5.2>
-    })
-
-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_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>
-    })
-
-test:do_execsql_test(
-    5.5,
-    [[
-        SELECT x FROM t4 WHERE x IN (1.11);
-    ]], {
-        -- <5.5>
-        1.11
-        -- </5.5>
-    })
-
-test:do_catchsql_test(
-    5.6,
-    [[
-        SELECT x FROM t4 WHERE x IN ('1.11');
-    ]], {
-        -- <5.6>
-        1, "Type mismatch: can not convert 1.11 to number"
-        -- </5.6>
-    })
-
-test:do_execsql_test(
-    5.7,
-    [[
-        SELECT x FROM t4 WHERE 1 IN (x);
-    ]], {
-        -- <5.7>
-        
-        -- </5.7>
-    })
-
-test:do_execsql_test(
-    5.8,
-    [[
-        SELECT x FROM t4 WHERE 1.0 IN (x);
-    ]], {
-        -- <5.8>
-        
-        -- </5.8>
-    })
-
-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_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>
-    })
-
-test:do_execsql_test(
-    5.11,
-    [[
-        SELECT x FROM t4 WHERE 1.11 IN (x);
-    ]], {
-        -- <5.11>
-        1.11
-        -- </5.11>
-    })
-
-test:do_catchsql_test(
-    5.12,
-    [[
-        SELECT x FROM t4 WHERE '1.11' IN (x);
-    ]], {
-        -- <5.12>
-        1, "Type mismatch: can not convert 1.11 to number"
-        -- </5.12>
-    })
-
-test:do_execsql_test(
-    6.1,
-    [[
-        SELECT x, y FROM t5 WHERE x IN (1);
-    ]], {
-        -- <6.1>
-        1, "one", 1, "two", 1, "three", 1.0, "four"
-        -- </6.1>
-    })
-
-test:do_execsql_test(
-    6.2,
-    [[
-        SELECT x, y FROM t5 WHERE x IN (1.0);
-    ]], {
-        -- <6.2>
-        1, "one", 1, "two", 1, "three", 1.0, "four"
-        -- </6.2>
-    })
-
-test:do_execsql_test(
-    6.3,
-    [[
-        SELECT x, y FROM t5 WHERE x IN ('1');
-    ]], {
-        -- <6.3>
-        1, "one", 1, "two", 1, "three", 1.0, "four"
-        -- </6.3>
-    })
-
-test:do_execsql_test(
-    6.4,
-    [[
-        SELECT x, y FROM t5 WHERE x IN ('1.0');
-    ]], {
-        -- <6.4>
-        1, "one", 1, "two", 1, "three", 1.0, "four"
-        -- </6.4>
-    })
-
-test:do_execsql_test(
-    6.5,
-    [[
-        SELECT x, y FROM t5 WHERE 1 IN (x);
-    ]], {
-        -- <6.5>
-        1, "one", 1, "two", 1, "three", 1.0, "four"
-        -- </6.5>
-    })
-
-test:do_execsql_test(
-    6.6,
-    [[
-        SELECT x, y FROM t5 WHERE 1.0 IN (x);
-    ]], {
-        -- <6.6>
-        1, "one", 1, "two", 1, "three", 1.0, "four"
-        -- </6.6>
-    })
-
-test:do_execsql_test(
-    6.7,
-    [[
-        SELECT x, y FROM t5 WHERE '1' IN (x);
-    ]], {
-        -- <6.7>
-        1, "one", 1, "two", 1, "three", 1.0, "four"
-        -- </6.7>
-    })
-
-test:do_execsql_test(
-    6.8,
-    [[
-        SELECT x, y FROM t5 WHERE '1.0' IN (x);
-    ]], {
-        -- <6.8>
-        1, "one", 1, "two", 1, "three", 1, "four"
-        -- </6.8>
-    })
-
-
-
-test:finish_test()
diff --git a/test/sql-tap/tkt3493.test.lua b/test/sql-tap/tkt3493.test.lua
index de77e61e9..82ba828d0 100755
--- a/test/sql-tap/tkt3493.test.lua
+++ b/test/sql-tap/tkt3493.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(26)
+test:plan(25)
 
 --!./tcltestrunner.lua
 -- 2008 October 13
@@ -45,7 +45,7 @@ test:do_execsql_test(
     [[
         SELECT 
           CASE 
-             WHEN B.val = 1 THEN 'XYZ' 
+             WHEN B.val = '1' THEN 'XYZ'
              ELSE A.val 
           END AS Col1
         FROM B  
@@ -63,7 +63,7 @@ test:do_execsql_test(
     [[
         SELECT DISTINCT
           CASE 
-             WHEN B.val = 1 THEN 'XYZ' 
+             WHEN B.val = '1' THEN 'XYZ'
              ELSE A.val 
           END AS Col1
         FROM B  
@@ -79,7 +79,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-1.4",
     [[
-        SELECT b.val, CASE WHEN b.val = 1 THEN 'xyz' ELSE b.val END AS col1 FROM b;
+        SELECT b.val, CASE WHEN b.val = '1' THEN 'xyz' ELSE b.val END AS col1 FROM b;
     ]], {
         -- <tkt3493-1.4>
         "1", "xyz", "2", "2"
@@ -91,7 +91,7 @@ test:do_execsql_test(
     [[
         SELECT DISTINCT 
           b.val, 
-          CASE WHEN b.val = 1 THEN 'xyz' ELSE b.val END AS col1 
+          CASE WHEN b.val = '1' THEN 'xyz' ELSE b.val END AS col1
         FROM b;
     ]], {
         -- <tkt3493-1.5>
@@ -126,23 +126,13 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.2.1",
     [[
-        SELECT a=123 FROM t1 GROUP BY a 
+        SELECT a='123' FROM t1 GROUP BY a
     ]], {
         -- <tkt3493-2.2.1>
         true
         -- </tkt3493-2.2.1>
     })
 
-test:do_execsql_test(
-    "tkt3493-2.2.2",
-    [[
-        SELECT a=123 FROM t1 
-    ]], {
-        -- <tkt3493-2.2.2>
-        true
-        -- </tkt3493-2.2.2>
-    })
-
 test:do_execsql_test(
     "tkt3493-2.2.3",
     [[
@@ -156,7 +146,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.2.4",
     [[
-        SELECT count(*), a=123 FROM t1 
+        SELECT count(*), a='123' FROM t1
     ]], {
         -- <tkt3493-2.2.4>
         1, true
@@ -166,7 +156,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.2.5",
     [[
-        SELECT count(*), +a=123 FROM t1 
+        SELECT count(*), +a='123' FROM t1
     ]], {
         -- <tkt3493-2.2.5>
         1, true
@@ -176,7 +166,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.3.3",
     [[
-        SELECT b='456' FROM t1 GROUP BY a 
+        SELECT b = 456 FROM t1 GROUP BY a
     ]], {
         -- <tkt3493-2.3.3>
         true
@@ -186,7 +176,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.3.1",
     [[
-        SELECT b='456' FROM t1 GROUP BY b 
+        SELECT b = 456 FROM t1 GROUP BY b
     ]], {
         -- <tkt3493-2.3.1>
         true
@@ -196,7 +186,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.3.2",
     [[
-        SELECT b='456' FROM t1 
+        SELECT b = 456 FROM t1
     ]], {
         -- <tkt3493-2.3.2>
         true
@@ -206,7 +196,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.4.1",
     [[
-        SELECT typeof(a), a FROM t1 GROUP BY a HAVING a=123 
+        SELECT typeof(a), a FROM t1 GROUP BY a HAVING a='123'
     ]], {
         -- <tkt3493-2.4.1>
         "string", "123"
@@ -216,7 +206,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.4.2",
     [[
-        SELECT typeof(a), a FROM t1 GROUP BY b HAVING a=123 
+        SELECT typeof(a), a FROM t1 GROUP BY b HAVING a='123'
     ]], {
         -- <tkt3493-2.4.2>
         "string", "123"
@@ -226,7 +216,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.5.1",
     [[
-        SELECT typeof(b), b FROM t1 GROUP BY a HAVING b='456' 
+        SELECT typeof(b), b FROM t1 GROUP BY a HAVING b=456
     ]], {
         -- <tkt3493-2.5.1>
         "integer", 456
@@ -236,7 +226,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.5.2",
     [[
-        SELECT typeof(b), b FROM t1 GROUP BY b HAVING b='456' 
+        SELECT typeof(b), b FROM t1 GROUP BY b HAVING b=456
     ]], {
         -- <tkt3493-2.5.2>
         "integer", 456
diff --git a/test/sql-tap/transitive1.test.lua b/test/sql-tap/transitive1.test.lua
index 96895b4a7..cc7e066bf 100755
--- a/test/sql-tap/transitive1.test.lua
+++ b/test/sql-tap/transitive1.test.lua
@@ -63,7 +63,7 @@ test:do_execsql_test(
         INSERT INTO t2 VALUES(2, 20,20,'20');
         INSERT INTO t2 VALUES(3, 3,3,'3');
 
-        SELECT a,b,c FROM t2 WHERE a=b AND c=b AND c=20;
+        SELECT a,b,c FROM t2 WHERE a=b AND c=CAST(b AS STRING) AND c='20';
     ]], {
         -- <transitive1-200>
         20, 20, "20"
@@ -73,7 +73,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "transitive1-210",
     [[
-        SELECT a,b,c FROM t2 WHERE a=b AND c=b AND c>='20' ORDER BY +a;
+        SELECT a,b,c FROM t2 WHERE a=b AND c=CAST(b AS STRING) AND c>='20' ORDER BY +a;
     ]], {
         -- <transitive1-210>
         3, 3, "3", 20, 20, "20"
@@ -83,7 +83,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "transitive1-220",
     [[
-        SELECT a,b,c FROM t2 WHERE a=b AND c=b AND c<='20' ORDER BY +a;
+        SELECT a,b,c FROM t2 WHERE a=b AND c=CAST(b AS STRING) AND c<='20' ORDER BY +a;
     ]], {
         -- <transitive1-220>
         20, 20, "20", 100, 100, "100"
@@ -402,7 +402,7 @@ test:do_execsql_test(
     [[
         CREATE TABLE x(i INTEGER PRIMARY KEY, y TEXT);
         INSERT INTO x VALUES(10, '10');
-        SELECT * FROM x WHERE x.y>='1' AND x.y<'2' AND x.i=x.y;
+        SELECT * FROM x WHERE x.y>='1' AND x.y<'2' AND CAST(x.i AS STRING)=x.y;
     ]], {
         -- <transitive1-500>
         10, "10"
@@ -430,7 +430,7 @@ test:do_execsql_test(
     [[
         CREATE TABLE t3(i INTEGER PRIMARY KEY, t TEXT);
         INSERT INTO t3 VALUES(10, '10');
-        SELECT * FROM t3 WHERE i=t AND t = '10 ';
+        SELECT * FROM t3 WHERE CAST(i AS STRING)=t AND t = '10 ';
     ]], {
         -- <transitive1-520>
 
@@ -443,7 +443,7 @@ test:do_execsql_test(
         CREATE TABLE u1(x TEXT PRIMARY KEY, y INTEGER, z TEXT);
         CREATE INDEX i1 ON u1(x);
         INSERT INTO u1 VALUES('00013', 13, '013');
-        SELECT * FROM u1 WHERE x=y AND y=z AND z='013';
+        SELECT * FROM u1 WHERE CAST(x AS INTEGER)=y AND y=CAST(z AS INTEGER) AND z='013';
     ]], {
         -- <transitive1-530>
         "00013",13,"013"
diff --git a/test/sql-tap/where2.test.lua b/test/sql-tap/where2.test.lua
index f267be8e6..7348a855a 100755
--- a/test/sql-tap/where2.test.lua
+++ b/test/sql-tap/where2.test.lua
@@ -4,7 +4,7 @@ yaml = require("yaml")
 fio = require("fio")
 
 ffi = require("ffi")
-test:plan(74)
+test:plan(62)
 
 ffi.cdef[[
        int dup(int oldfd);
@@ -622,181 +622,12 @@ test:do_test(
         -- </where2-6.6>
     })
 
--- if X(356, "X!cmd", [=[["expr","[permutation] != \"no_optimization\""]]=])
--- then
-    -- Ticket #2249.  Make sure the OR optimization is not attempted if
-    -- comparisons between columns of different affinities are needed.
-    --
-    test:do_test(
-        "where2-6.7",
-        function()
-            test:execsql [[
-                CREATE TABLE t2249a(a TEXT PRIMARY KEY, x VARCHAR(100));
-                CREATE TABLE t2249b(b INTEGER PRIMARY KEY);
-                INSERT INTO t2249a(a) VALUES('0123');
-                INSERT INTO t2249b VALUES(123);
-            ]]
-            return queryplan([[
-    -- Because a is type TEXT and b is type INTEGER, both a and b
-    -- will attempt to convert to NUMERIC before the comparison.
-    -- They will thus compare equal.
-    --
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=b;
-  ]])
-        end, {
-            -- <where2-6.7>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.7>
-        })
-
-    test:do_test(
-        "where2-6.9",
-        function()
-            return queryplan([[
-    -- The + operator doesn't affect RHS.
-    --
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b;
-  ]])
-        end, {
-            -- <where2-6.9>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.9>
-        })
-
-    test:do_test(
-        "where2-6.9.2",
-        function()
-            -- The same thing but with the expression flipped around.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=a
-  ]])
-        end, {
-            -- <where2-6.9.2>
-            123, "0123","nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.9.2>
-        })
-
-    test:do_test(
-        "where2-6.10",
-        function()
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +a=+b;
-  ]])
-        end, {
-            -- <where2-6.10>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.10>
-        })
-
-    test:do_test(
-        "where2-6.11",
-        function()
-            -- This will not attempt the OR optimization because of the a=b
-            -- comparison.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=b OR a='hello';
-  ]])
-        end, {
-            -- <where2-6.11>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.11>
-        })
-
-    test:do_test(
-        "where2-6.11.2",
-        function()
-            -- Permutations of the expression terms.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE b=a OR a='hello';
-  ]])
-        end, {
-            -- <where2-6.11.2>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.11.2>
-        })
-
-    test:do_test(
-        "where2-6.11.3",
-        function()
-            -- Permutations of the expression terms.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE 'hello'=a OR b=a;
-  ]])
-        end, {
-            -- <where2-6.11.3>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.11.3>
-        })
-
-    test:do_test(
-        "where2-6.11.4",
-        function()
-            -- Permutations of the expression terms.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR b=a;
-  ]])
-        end, {
-            -- <where2-6.11.4>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.11.4>
-        })
-
-    -- These tests are not run if subquery support is not included in the
-    -- build. This is because these tests test the "a = 1 OR a = 2" to
-    -- "a IN (1, 2)" optimisation transformation, which is not enabled if
-    -- subqueries and the IN operator is not available.
-    --
-    test:do_test(
-        "where2-6.12",
-        function()
-            return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b OR a='hello';
-    ]])
-        end, {
-            -- <where2-6.12>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.12>
-        })
-
-    test:do_test(
-        "where2-6.12.2",
-        function()
-            return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR +b=a;
-    ]])
-        end, {
-            -- <where2-6.12.2>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.12.2>
-        })
-
-    test:do_test(
-        "where2-6.12.3",
-        function()
-            return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=a OR a='hello';
-    ]])
-        end, {
-            -- <where2-6.12.3>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.12.3>
-        })
-
-    test:do_test(
-        "where2-6.13",
-        function()
-            -- The addition of +a on the second term disabled the OR optimization.
-            -- But we should still get the same empty-set result as in where2-6.9.
-            return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b OR +a='hello';
-    ]])
-        end, {
-            -- <where2-6.13>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.13>
-        })
-
-
+    test:execsql [[
+        CREATE TABLE t2249a(a TEXT PRIMARY KEY, x VARCHAR(100));
+        CREATE TABLE t2249b(b INTEGER PRIMARY KEY);
+        INSERT INTO t2249a(a) VALUES('0123');
+        INSERT INTO t2249b VALUES(123);
+    ]]
 
     -- Variations on the order of terms in a WHERE clause in order
     -- to make sure the OR optimizer can recognize them all.
diff --git a/test/sql-tap/where5.test.lua b/test/sql-tap/where5.test.lua
index 3aefcaca5..4a197aac2 100755
--- a/test/sql-tap/where5.test.lua
+++ b/test/sql-tap/where5.test.lua
@@ -34,7 +34,7 @@ test:do_test("where5-1.0", function()
         INSERT INTO t3 SELECT CAST(x AS INTEGER) FROM t1;
     ]]
     return test:execsql [[
-        SELECT * FROM t1 WHERE x<0
+        SELECT * FROM t1 WHERE x<'0'
     ]]
 end, {
     -- <where5-1.0>
@@ -43,7 +43,7 @@ end, {
 })
 
 test:do_execsql_test("where5-1.1", [[
-    SELECT * FROM t1 WHERE x<=0
+    SELECT * FROM t1 WHERE x<='0'
 ]], {
     -- <where5-1.1>
     '-1', '0'
@@ -51,7 +51,7 @@ test:do_execsql_test("where5-1.1", [[
 })
 
 test:do_execsql_test("where5-1.2", [[
-    SELECT * FROM t1 WHERE x=0
+    SELECT * FROM t1 WHERE x='0'
 ]], {
     -- <where5-1.2>
     '0'
@@ -59,7 +59,7 @@ test:do_execsql_test("where5-1.2", [[
 })
 
 test:do_execsql_test("where5-1.3", [[
-    SELECT * FROM t1 WHERE x>=0
+    SELECT * FROM t1 WHERE x>='0'
 ]], {
     -- <where5-1.3>
     '0', '1'
@@ -67,7 +67,7 @@ test:do_execsql_test("where5-1.3", [[
 })
 
 test:do_execsql_test("where5-1.4", [[
-    SELECT * FROM t1 WHERE x>0
+    SELECT * FROM t1 WHERE x>'0'
 ]], {
     -- <where5-1.4>
     '1'
@@ -75,7 +75,7 @@ test:do_execsql_test("where5-1.4", [[
 })
 
 test:do_execsql_test("where5-1.5", [[
-    SELECT * FROM t1 WHERE x<>0
+    SELECT * FROM t1 WHERE x<>'0'
 ]], {
     -- <where5-1.5>
     '-1', '1'
diff --git a/test/sql/types.result b/test/sql/types.result
index 7a4e9bca3..f9b6cdcf7 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -602,11 +602,8 @@ box.execute("SELECT 18446744073709551615.0 > 18446744073709551615")
 ...
 box.execute("SELECT 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0)")
 ---
-- metadata:
-  - name: 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0)
-    type: boolean
-  rows:
-  - [true]
+- null
+- 'Type mismatch: can not convert 18446744073709551615 to numeric'
 ...
 box.execute("SELECT 1 LIMIT 18446744073709551615;")
 ---
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v6 21/22] sql: fix implicit cast in opcode MustBeInt
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (19 preceding siblings ...)
  2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 20/22] sql: remove implicit cast from comparison opcodes imeevma
@ 2020-07-16 14:47 ` imeevma
  2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 22/22] sql: remove implicit cast from MakeRecord opcode imeevma
  21 siblings, 0 replies; 31+ messages in thread
From: imeevma @ 2020-07-16 14:47 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

This patch removes implicit casting from STRING to number and vice
versa from MustBeInt opcode.

Part of #4230
---
 src/box/sql/vdbe.c | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 73b25fecf..9b2b18a9a 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -2349,16 +2349,20 @@ case OP_AddImm: {            /* in1 */
  */
 case OP_MustBeInt: {            /* jump, in1 */
 	pIn1 = &aMem[pOp->p1];
-	if ((pIn1->flags & (MEM_Int | MEM_UInt)) == 0) {
-		mem_apply_type(pIn1, FIELD_TYPE_INTEGER);
-		if ((pIn1->flags & (MEM_Int | MEM_UInt)) == 0) {
-			if (pOp->p2==0) {
-				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
-					 sql_value_to_diag_str(pIn1), "integer");
-				goto abort_due_to_error;
-			} else {
-				goto jump_to_p2;
-			}
+	if (mem_is_type_compatible(pIn1, FIELD_TYPE_INTEGER))
+		break;
+	if ((pIn1->flags & MEM_Real) != 0) {
+		double d = pIn1->u.r;
+		if (d == (double)(int64_t)d || d == (double)(uint64_t)d)
+			mem_convert_to_integer(pIn1);
+	}
+	if (!mem_is_type_compatible(pIn1, FIELD_TYPE_INTEGER)) {
+		if (pOp->p2==0) {
+			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+				 sql_value_to_diag_str(pIn1), "integer");
+			goto abort_due_to_error;
+		} else {
+			goto jump_to_p2;
 		}
 	}
 	break;
-- 
2.25.1

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

* [Tarantool-patches] [PATCH v6 22/22] sql: remove implicit cast from MakeRecord opcode
  2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
                   ` (20 preceding siblings ...)
  2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 21/22] sql: fix implicit cast in opcode MustBeInt imeevma
@ 2020-07-16 14:47 ` imeevma
  21 siblings, 0 replies; 31+ messages in thread
From: imeevma @ 2020-07-16 14:47 UTC (permalink / raw)
  To: korablev, tsafin, tarantool-patches

This patch removes implicit casting from MakeRecord opcode.

Closes #4230

@TarantoolBot document
Title: remove implicit cast for comparison

After this patch-set, there will be no implicit casts for comparison.
This means that the values of the field types STRING, BOOLEAN and
VARBINARY can be compared with the values of the same field type.
Any numerical value can be compared with any other numerical value.

Example:

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

tarantool> box.execute([[SELECT true > X'33';]])
---
- null
- 'Type mismatch: can not convert boolean to varbinary'
...

tarantool> box.execute([[SELECT 1.23 > 123;]])
---
- metadata:
  - name: 1.23 > 123
    type: boolean
  rows:
  - [false]
...
```
---
 src/box/sql/analyze.c       |   6 +-
 src/box/sql/delete.c        |  15 ++-
 src/box/sql/expr.c          |  17 ++-
 src/box/sql/fk_constraint.c |  12 +-
 src/box/sql/select.c        |  26 +++--
 src/box/sql/update.c        |  23 ++--
 src/box/sql/vdbe.c          |  19 +--
 test/sql-tap/in3.test.lua   |  26 +----
 test/sql/boolean.result     |  76 ++++--------
 test/sql/types.result       | 225 ++++++++++++++++++++++++++++++++++++
 test/sql/types.test.lua     |  51 ++++++++
 11 files changed, 363 insertions(+), 133 deletions(-)

diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
index f74f9b358..3efcd041a 100644
--- a/src/box/sql/analyze.c
+++ b/src/box/sql/analyze.c
@@ -969,8 +969,10 @@ vdbe_emit_analyze_space(struct Parse *parse, struct space *space)
 					     FIELD_TYPE_STRING,
 					     FIELD_TYPE_STRING,
 					     field_type_MAX };
-		sqlVdbeAddOp4(v, OP_MakeRecord, tab_name_reg, 4, tmp_reg,
-				  (char *)types, sizeof(types));
+		sqlVdbeAddOp4(v, OP_ApplyType, tab_name_reg, 4, 0,
+			      (char *)types, P4_STATIC);
+		sqlVdbeChangeP5(v, OPFLAG_DO_NOT_CONVERT_NUMBERS);
+		sqlVdbeAddOp3(v, OP_MakeRecord, tab_name_reg, 4, tmp_reg);
 		sqlVdbeAddOp4(v, OP_IdxInsert, tmp_reg, 0, 0,
 				  (char *)stat1, P4_SPACEPTR);
 		/* Add the entries to the stat4 table. */
diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
index 68abd1f58..40a52aadc 100644
--- a/src/box/sql/delete.c
+++ b/src/box/sql/delete.c
@@ -329,11 +329,16 @@ sql_table_delete_from(struct Parse *parse, struct SrcList *tab_list,
 			 */
 			key_len = 0;
 			struct index *pk = space_index(space, 0);
-			enum field_type *types = is_view ? NULL :
-						 sql_index_type_str(parse->db,
-								    pk->def);
-			sqlVdbeAddOp4(v, OP_MakeRecord, reg_pk, pk_len,
-					  reg_key, (char *)types, P4_DYNAMIC);
+			if (!is_view) {
+				enum field_type *types =
+					sql_index_type_str(parse->db, pk->def);
+				sqlVdbeAddOp4(v, OP_ApplyType, reg_pk, pk_len,
+					      0, (char *)types, P4_DYNAMIC);
+				sqlVdbeChangeP5(v,
+						OPFLAG_DO_NOT_CONVERT_NUMBERS);
+			}
+			sqlVdbeAddOp3(v, OP_MakeRecord, reg_pk, pk_len,
+				      reg_key);
 			/* Set flag to save memory allocating one
 			 * by malloc.
 			 */
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index 0c810b73b..18d8ce4b0 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -2886,11 +2886,18 @@ sqlCodeSubselect(Parse * pParse,	/* Parsing context */
 						jmpIfDynamic = -1;
 					}
 					r3 = sqlExprCodeTarget(pParse, pE2, r1);
-					enum field_type types[2] =
-						{ lhs_type, field_type_MAX };
-	 				sqlVdbeAddOp4(v, OP_MakeRecord, r3,
-							  1, r2, (char *)types,
-							  sizeof(types));
+					uint32_t size =
+						2 * sizeof(enum field_type);
+					enum field_type *types=
+						sqlDbMallocZero(pParse->db,
+								size);
+					types[0] = lhs_type;
+					types[1] = field_type_MAX;
+					sqlVdbeAddOp4(v, OP_ApplyType, r3, 1, 0,
+						      (char *)types, P4_DYNAMIC);
+					sqlVdbeChangeP5(v, OPFLAG_DO_NOT_CONVERT_NUMBERS);
+					sqlVdbeAddOp3(v, OP_MakeRecord, r3, 1,
+						      r2);
 					sql_expr_type_cache_change(pParse,
 								   r3, 1);
 					sqlVdbeAddOp2(v, OP_IdxInsert, r2,
diff --git a/src/box/sql/fk_constraint.c b/src/box/sql/fk_constraint.c
index 482220a95..50f9ebf74 100644
--- a/src/box/sql/fk_constraint.c
+++ b/src/box/sql/fk_constraint.c
@@ -264,11 +264,13 @@ fk_constraint_lookup_parent(struct Parse *parse_context, struct space *parent,
 		}
 		struct index *idx = space_index(parent, referenced_idx);
 		assert(idx != NULL);
-		sqlVdbeAddOp4(v, OP_MakeRecord, temp_regs, field_count,
-				  rec_reg,
-				  (char *) sql_index_type_str(parse_context->db,
-							      idx->def),
-				  P4_DYNAMIC);
+		sqlVdbeAddOp4(v, OP_ApplyType, temp_regs, field_count, 0,
+			      (char *) sql_index_type_str(parse_context->db,
+							  idx->def),
+			      P4_DYNAMIC);
+		sqlVdbeChangeP5(v, OPFLAG_DO_NOT_CONVERT_NUMBERS);
+		sqlVdbeAddOp3(v, OP_MakeRecord, temp_regs, field_count,
+			      rec_reg);
 		sqlVdbeAddOp4Int(v, OP_Found, cursor, ok_label, rec_reg, 0);
 		sqlReleaseTempReg(parse_context, rec_reg);
 		sqlReleaseTempRange(parse_context, temp_regs, field_count);
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 426247bd7..0de6486b5 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -1308,9 +1308,13 @@ selectInnerLoop(Parse * pParse,		/* The parser context */
 					field_type_sequence_dup(pParse,
 								pDest->dest_type,
 								nResultCol);
-				sqlVdbeAddOp4(v, OP_MakeRecord, regResult,
-						  nResultCol, r1, (char *)types,
-						  P4_DYNAMIC);
+				sqlVdbeAddOp4(v, OP_ApplyType, regResult,
+					      nResultCol, 0, (char *)types,
+					      P4_DYNAMIC);
+				sqlVdbeChangeP5(v,
+						OPFLAG_DO_NOT_CONVERT_NUMBERS);
+				sqlVdbeAddOp3(v, OP_MakeRecord, regResult,
+						  nResultCol, r1);
 				sql_expr_type_cache_change(pParse,
 							   regResult,
 							   nResultCol);
@@ -1730,9 +1734,11 @@ generateSortTail(Parse * pParse,	/* Parsing context */
 			enum field_type *types =
 				field_type_sequence_dup(pParse, pDest->dest_type,
 							nColumn);
-			sqlVdbeAddOp4(v, OP_MakeRecord, regRow, nColumn,
-					  regTupleid, (char *)types,
-					  P4_DYNAMIC);
+			sqlVdbeAddOp4(v, OP_ApplyType, regRow, nColumn, 0,
+				      (char *)types, P4_DYNAMIC);
+			sqlVdbeChangeP5(v, OPFLAG_DO_NOT_CONVERT_NUMBERS);
+			sqlVdbeAddOp3(v, OP_MakeRecord, regRow, nColumn,
+				      regTupleid);
 			sql_expr_type_cache_change(pParse, regRow, nColumn);
 			sqlVdbeAddOp2(v, OP_IdxInsert, regTupleid, pDest->reg_eph);
 			break;
@@ -3174,9 +3180,11 @@ generateOutputSubroutine(struct Parse *parse, struct Select *p,
 			enum field_type *types =
 				field_type_sequence_dup(parse, dest->dest_type,
 							in->nSdst);
-			sqlVdbeAddOp4(v, OP_MakeRecord, in->iSdst,
-					  in->nSdst, r1, (char *)types,
-					  P4_DYNAMIC);
+			sqlVdbeAddOp4(v, OP_ApplyType, in->iSdst, in->nSdst, 0,
+				      (char *)types, P4_DYNAMIC);
+			sqlVdbeChangeP5(v, OPFLAG_DO_NOT_CONVERT_NUMBERS);
+			sqlVdbeAddOp3(v, OP_MakeRecord, in->iSdst, in->nSdst,
+				      r1);
 			sql_expr_type_cache_change(parse, in->iSdst,
 						   in->nSdst);
 			sqlVdbeAddOp2(v, OP_IdxInsert, r1, dest->reg_eph);
diff --git a/src/box/sql/update.c b/src/box/sql/update.c
index 24c7cfa27..7c80dcc4e 100644
--- a/src/box/sql/update.c
+++ b/src/box/sql/update.c
@@ -251,11 +251,14 @@ sqlUpdate(Parse * pParse,		/* The parser context */
 		nKey = pk_part_count;
 		regKey = iPk;
 	} else {
-		enum field_type *types = is_view ? NULL :
-					 sql_index_type_str(pParse->db,
-							    pPk->def);
-		sqlVdbeAddOp4(v, OP_MakeRecord, iPk, pk_part_count,
-				  regKey, (char *) types, P4_DYNAMIC);
+		if (!is_view) {
+			enum field_type *types =
+				sql_index_type_str(pParse->db, pPk->def);
+			sqlVdbeAddOp4(v, OP_ApplyType, iPk, pk_part_count, 0,
+				      (char *)types, P4_DYNAMIC);
+			sqlVdbeChangeP5(v, OPFLAG_DO_NOT_CONVERT_NUMBERS);
+		}
+		sqlVdbeAddOp3(v, OP_MakeRecord, iPk, pk_part_count, regKey);
 		/*
 		 * Set flag to save memory allocating one by
 		 * malloc.
@@ -423,9 +426,13 @@ sqlUpdate(Parse * pParse,		/* The parser context */
 				enum field_type *types =
 					sql_index_type_str(pParse->db,
 							   pPk->def);
-				sqlVdbeAddOp4(v, OP_MakeRecord, iPk,
-						  pk_part_count, key_reg,
-						  (char *) types, P4_DYNAMIC);
+				sqlVdbeAddOp4(v, OP_ApplyType, iPk,
+					      pk_part_count, 0, (char *)types,
+					      P4_DYNAMIC);
+				sqlVdbeChangeP5(v,
+						OPFLAG_DO_NOT_CONVERT_NUMBERS);
+				sqlVdbeAddOp3(v, OP_MakeRecord, iPk,
+					      pk_part_count, key_reg);
 			} else {
 				assert(nKey == 0);
 				key_reg = regKey;
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 9b2b18a9a..e8b02a2ac 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -3158,24 +3158,17 @@ type_mismatch:
 	break;
 }
 
-/* Opcode: MakeRecord P1 P2 P3 P4 P5
+/* Opcode: MakeRecord P1 P2 P3 * P5
  * Synopsis: r[P3]=mkrec(r[P1@P2])
  *
  * Convert P2 registers beginning with P1 into the [record format]
  * use as a data record in a database table or as a key
  * in an index.  The OP_Column opcode can decode the record later.
  *
- * P4 may be a string that is P2 characters long.  The nth character of the
- * string indicates the column type that should be used for the nth
- * field of the index key.
- *
- * If P4 is NULL then all index fields have type SCALAR.
- *
  * If P5 is not NULL then record under construction is intended to be inserted
  * into ephemeral space. Thus, sort of memory optimization can be performed.
  */
 case OP_MakeRecord: {
-	Mem *pRec;             /* The new record */
 	Mem *pData0;           /* First field to be combined into the record */
 	Mem MAYBE_UNUSED *pLast;  /* Last field of the record */
 	int nField;            /* Number of fields in the record */
@@ -3197,7 +3190,6 @@ case OP_MakeRecord: {
 	 * of the record to data0.
 	 */
 	nField = pOp->p1;
-	enum field_type *types = pOp->p4.types;
 	bIsEphemeral = pOp->p5;
 	assert(nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem+1 - p->nCursor)+1);
 	pData0 = &aMem[nField];
@@ -3208,15 +3200,6 @@ case OP_MakeRecord: {
 	assert(pOp->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2);
 	pOut = vdbe_prepare_null_out(p, pOp->p3);
 
-	/* Apply the requested types to all inputs */
-	assert(pData0<=pLast);
-	if (types != NULL) {
-		pRec = pData0;
-		do {
-			mem_apply_type(pRec++, *(types++));
-		} while(types[0] != field_type_MAX);
-	}
-
 	struct region *region = &fiber()->gc;
 	size_t used = region_used(region);
 	uint32_t tuple_size;
diff --git a/test/sql-tap/in3.test.lua b/test/sql-tap/in3.test.lua
index a6d842962..7f3abbae0 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(28)
+test:plan(26)
 
 --!./tcltestrunner.lua
 -- 2007 November 29
@@ -334,18 +334,6 @@ test:do_test(
         -- </in3-3.4>
     })
 
-test:do_test(
-    "in3-3.5",
-    function()
-        -- Numeric affinity should be applied to each side before the comparison
-        -- takes place. Therefore we cannot use index t1_i1, which has no affinity.
-        return exec_neph(" SELECT y IN (SELECT a FROM t1) FROM t2 ")
-    end, {
-        -- <in3-3.5>
-        1, true
-        -- </in3-3.5>
-    })
-
 test:do_test(
     "in3-3.6",
     function()
@@ -358,18 +346,6 @@ test:do_test(
         -- </in3-3.6>
     })
 
-test:do_test(
-    "in3-3.7",
-    function()
-        -- Numeric affinity is applied before the comparison takes place. 
-        -- Making it impossible to use index t1_i3.
-        return exec_neph(" SELECT y IN (SELECT c FROM t1) FROM t2 ")
-    end, {
-        -- <in3-3.7>
-        1, true
-        -- </in3-3.7>
-    })
-
 -----------------------------------------------------------------------
 --
 -- Test using a multi-column index.
diff --git a/test/sql/boolean.result b/test/sql/boolean.result
index 7e7f97284..11c479b74 100644
--- a/test/sql/boolean.result
+++ b/test/sql/boolean.result
@@ -2238,19 +2238,13 @@ SELECT false IN (SELECT a1 FROM t6 LIMIT 1);
  | ...
 SELECT true IN (1, 1.2, 'true', false);
  | ---
- | - metadata:
- |   - name: true IN (1, 1.2, 'true', false)
- |     type: boolean
- |   rows:
- |   - [false]
+ | - null
+ | - 'Type mismatch: can not convert 1 to boolean'
  | ...
 SELECT false IN (1, 1.2, 'true', false);
  | ---
- | - metadata:
- |   - name: false IN (1, 1.2, 'true', false)
- |     type: boolean
- |   rows:
- |   - [true]
+ | - null
+ | - 'Type mismatch: can not convert 1 to boolean'
  | ...
 
 SELECT a, a IN (true) FROM t;
@@ -2310,14 +2304,8 @@ SELECT a, a IN (SELECT a1 FROM t6) FROM t;
  | ...
 SELECT a, a IN (1, 1.2, 'true', false) FROM t;
  | ---
- | - metadata:
- |   - name: A
- |     type: boolean
- |   - name: a IN (1, 1.2, 'true', false)
- |     type: boolean
- |   rows:
- |   - [false, true]
- |   - [true, false]
+ | - null
+ | - 'Type mismatch: can not convert 1 to boolean'
  | ...
 
 SELECT true BETWEEN true AND true;
@@ -3842,19 +3830,13 @@ SELECT a2, b, b != a2 FROM t6, t7;
 
 SELECT true IN (0, 1, 2, 3);
  | ---
- | - metadata:
- |   - name: true IN (0, 1, 2, 3)
- |     type: boolean
- |   rows:
- |   - [false]
+ | - null
+ | - 'Type mismatch: can not convert 0 to boolean'
  | ...
 SELECT false IN (0, 1, 2, 3);
  | ---
- | - metadata:
- |   - name: false IN (0, 1, 2, 3)
- |     type: boolean
- |   rows:
- |   - [false]
+ | - null
+ | - 'Type mismatch: can not convert 0 to boolean'
  | ...
 SELECT true IN (SELECT b FROM t7);
  | ---
@@ -3868,14 +3850,8 @@ SELECT false IN (SELECT b FROM t7);
  | ...
 SELECT a1, a1 IN (0, 1, 2, 3) FROM t6
  | ---
- | - metadata:
- |   - name: A1
- |     type: boolean
- |   - name: a1 IN (0, 1, 2, 3)
- |     type: boolean
- |   rows:
- |   - [false, false]
- |   - [true, false]
+ | - null
+ | - 'Type mismatch: can not convert 0 to boolean'
  | ...
 
 SELECT true BETWEEN 0 and 10;
@@ -4987,35 +4963,23 @@ SELECT a2, c, c != a2 FROM t6, t8;
 
 SELECT true IN (0.1, 1.2, 2.3, 3.4);
  | ---
- | - metadata:
- |   - name: true IN (0.1, 1.2, 2.3, 3.4)
- |     type: boolean
- |   rows:
- |   - [false]
+ | - null
+ | - 'Type mismatch: can not convert 0.1 to boolean'
  | ...
 SELECT false IN (0.1, 1.2, 2.3, 3.4);
  | ---
- | - metadata:
- |   - name: false IN (0.1, 1.2, 2.3, 3.4)
- |     type: boolean
- |   rows:
- |   - [false]
+ | - null
+ | - 'Type mismatch: can not convert 0.1 to boolean'
  | ...
 SELECT a1 IN (0.1, 1.2, 2.3, 3.4) FROM t6 LIMIT 1;
  | ---
- | - metadata:
- |   - name: a1 IN (0.1, 1.2, 2.3, 3.4)
- |     type: boolean
- |   rows:
- |   - [false]
+ | - null
+ | - 'Type mismatch: can not convert 0.1 to boolean'
  | ...
 SELECT a2 IN (0.1, 1.2, 2.3, 3.4) FROM t6 LIMIT 1;
  | ---
- | - metadata:
- |   - name: a2 IN (0.1, 1.2, 2.3, 3.4)
- |     type: boolean
- |   rows:
- |   - [false]
+ | - null
+ | - 'Type mismatch: can not convert 0.1 to boolean'
  | ...
 SELECT true IN (SELECT c FROM t8);
  | ---
diff --git a/test/sql/types.result b/test/sql/types.result
index f9b6cdcf7..866579b86 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -2826,3 +2826,228 @@ box.execute([[DROP TABLE t;]])
 ---
 - row_count: 1
 ...
+--
+-- Make sure that there is no implicit cast between string and
+-- number.
+--
+box.execute([[SELECT '1' > 0;]]);
+---
+- null
+- 'Type mismatch: can not convert 1 to numeric'
+...
+box.execute([[SELECT 1 > '0';]]);
+---
+- null
+- 'Type mismatch: can not convert 0 to numeric'
+...
+box.execute([[CREATE TABLE t (i INT PRIMARY KEY, d DOUBLE, n NUMBER, s STRING);]])
+---
+- row_count: 1
+...
+box.execute([[INSERT INTO t VALUES (1, 1.0, 1, '2'), (2, 2.0, 2.0, '2');]])
+---
+- row_count: 2
+...
+box.execute([[SELECT * from t WHERE i > s;]])
+---
+- null
+- 'Type mismatch: can not convert 2 to numeric'
+...
+box.execute([[SELECT * from t WHERE s > i;]])
+---
+- null
+- 'Type mismatch: can not convert 2 to numeric'
+...
+box.execute([[SELECT * from t WHERE d > s;]])
+---
+- null
+- 'Type mismatch: can not convert 2 to numeric'
+...
+box.execute([[SELECT * from t WHERE s > d;]])
+---
+- null
+- 'Type mismatch: can not convert 2 to numeric'
+...
+box.execute([[SELECT * from t WHERE i = 1 and n > s;]])
+---
+- null
+- 'Type mismatch: can not convert 2 to numeric'
+...
+box.execute([[SELECT * from t WHERE i = 2 and s > n;]])
+---
+- null
+- 'Type mismatch: can not convert 2 to numeric'
+...
+box.execute([[SELECT i FROM t WHERE i in (1);]])
+---
+- metadata:
+  - name: I
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT i FROM t WHERE d in (1);]])
+---
+- metadata:
+  - name: I
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT i FROM t WHERE n in (1);]])
+---
+- metadata:
+  - name: I
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT i FROM t WHERE s in (1);]])
+---
+- null
+- 'Type mismatch: can not convert 2 to numeric'
+...
+box.execute([[SELECT i FROM t WHERE i in (1.0);]])
+---
+- metadata:
+  - name: I
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT i FROM t WHERE d in (1.0);]])
+---
+- metadata:
+  - name: I
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT i FROM t WHERE n in (1.0);]])
+---
+- metadata:
+  - name: I
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT i FROM t WHERE s in (1.0);]])
+---
+- null
+- 'Type mismatch: can not convert 2 to numeric'
+...
+box.execute([[SELECT i FROM t WHERE i in ('1');]])
+---
+- null
+- 'Type mismatch: can not convert 1 to integer'
+...
+box.execute([[SELECT i FROM t WHERE d in ('1');]])
+---
+- null
+- 'Type mismatch: can not convert 1 to numeric'
+...
+box.execute([[SELECT i FROM t WHERE n in ('1');]])
+---
+- null
+- 'Type mismatch: can not convert 1 to numeric'
+...
+box.execute([[SELECT i FROM t WHERE s in ('1');]])
+---
+- metadata:
+  - name: I
+    type: integer
+  rows: []
+...
+box.execute([[SELECT i FROM t WHERE i in ('1.0');]])
+---
+- null
+- 'Type mismatch: can not convert 1.0 to integer'
+...
+box.execute([[SELECT i FROM t WHERE d in ('1.0');]])
+---
+- null
+- 'Type mismatch: can not convert 1.0 to numeric'
+...
+box.execute([[SELECT i FROM t WHERE n in ('1.0');]])
+---
+- null
+- 'Type mismatch: can not convert 1.0 to numeric'
+...
+box.execute([[SELECT i FROM t WHERE s in ('1.0');]])
+---
+- metadata:
+  - name: I
+    type: integer
+  rows: []
+...
+box.execute([[DROP TABLE t;]])
+---
+- row_count: 1
+...
+-- Comparison with SCALAR.
+box.execute([[CREATE TABLE t(a SCALAR PRIMARY KEY);]])
+---
+- row_count: 1
+...
+box.execute([[INSERT INTO t VALUES (1), (2.2), ('3');]]);
+---
+- row_count: 3
+...
+box.execute([[SELECT a FROM t WHERE a > 1]]);
+---
+- null
+- 'Type mismatch: can not convert 3 to numeric'
+...
+box.execute([[SELECT a FROM t WHERE a > 1.0]]);
+---
+- null
+- 'Type mismatch: can not convert 3 to numeric'
+...
+box.execute([[SELECT a FROM t WHERE a > '1']]);
+---
+- metadata:
+  - name: A
+    type: scalar
+  rows:
+  - ['3']
+...
+box.execute([[SELECT a FROM t WHERE a < 1]]);
+---
+- null
+- 'Type mismatch: can not convert 3 to numeric'
+...
+box.execute([[SELECT a FROM t WHERE a < 1.0]]);
+---
+- null
+- 'Type mismatch: can not convert 3 to numeric'
+...
+box.execute([[SELECT a FROM t WHERE a < '1']]);
+---
+- metadata:
+  - name: A
+    type: scalar
+  rows:
+  - [1]
+  - [2.2]
+...
+box.execute([[SELECT a FROM t WHERE a = 1]]);
+---
+- null
+- 'Type mismatch: can not convert 3 to numeric'
+...
+box.execute([[SELECT a FROM t WHERE a = 1.0]]);
+---
+- null
+- 'Type mismatch: can not convert 3 to numeric'
+...
+box.execute([[SELECT a FROM t WHERE a = '1']]);
+---
+- metadata:
+  - name: A
+    type: scalar
+  rows: []
+...
+box.execute([[DROP TABLE t;]])
+---
+- row_count: 1
+...
diff --git a/test/sql/types.test.lua b/test/sql/types.test.lua
index a23b12801..09619653b 100644
--- a/test/sql/types.test.lua
+++ b/test/sql/types.test.lua
@@ -635,3 +635,54 @@ box.execute([[SELECT * FROM t WHERE i > ?]], {-2^70})
 box.execute([[SELECT * FROM t WHERE a = ?]], {2ULL^60ULL - 1ULL})
 box.execute([[SELECT * FROM t WHERE a > ?]], {2ULL^60ULL - 1ULL})
 box.execute([[DROP TABLE t;]])
+
+--
+-- Make sure that there is no implicit cast between string and
+-- number.
+--
+box.execute([[SELECT '1' > 0;]]);
+box.execute([[SELECT 1 > '0';]]);
+box.execute([[CREATE TABLE t (i INT PRIMARY KEY, d DOUBLE, n NUMBER, s STRING);]])
+box.execute([[INSERT INTO t VALUES (1, 1.0, 1, '2'), (2, 2.0, 2.0, '2');]])
+box.execute([[SELECT * from t WHERE i > s;]])
+box.execute([[SELECT * from t WHERE s > i;]])
+box.execute([[SELECT * from t WHERE d > s;]])
+box.execute([[SELECT * from t WHERE s > d;]])
+box.execute([[SELECT * from t WHERE i = 1 and n > s;]])
+box.execute([[SELECT * from t WHERE i = 2 and s > n;]])
+
+box.execute([[SELECT i FROM t WHERE i in (1);]])
+box.execute([[SELECT i FROM t WHERE d in (1);]])
+box.execute([[SELECT i FROM t WHERE n in (1);]])
+box.execute([[SELECT i FROM t WHERE s in (1);]])
+
+box.execute([[SELECT i FROM t WHERE i in (1.0);]])
+box.execute([[SELECT i FROM t WHERE d in (1.0);]])
+box.execute([[SELECT i FROM t WHERE n in (1.0);]])
+box.execute([[SELECT i FROM t WHERE s in (1.0);]])
+
+box.execute([[SELECT i FROM t WHERE i in ('1');]])
+box.execute([[SELECT i FROM t WHERE d in ('1');]])
+box.execute([[SELECT i FROM t WHERE n in ('1');]])
+box.execute([[SELECT i FROM t WHERE s in ('1');]])
+
+box.execute([[SELECT i FROM t WHERE i in ('1.0');]])
+box.execute([[SELECT i FROM t WHERE d in ('1.0');]])
+box.execute([[SELECT i FROM t WHERE n in ('1.0');]])
+box.execute([[SELECT i FROM t WHERE s in ('1.0');]])
+
+box.execute([[DROP TABLE t;]])
+
+-- Comparison with SCALAR.
+box.execute([[CREATE TABLE t(a SCALAR PRIMARY KEY);]])
+box.execute([[INSERT INTO t VALUES (1), (2.2), ('3');]]);
+box.execute([[SELECT a FROM t WHERE a > 1]]);
+box.execute([[SELECT a FROM t WHERE a > 1.0]]);
+box.execute([[SELECT a FROM t WHERE a > '1']]);
+box.execute([[SELECT a FROM t WHERE a < 1]]);
+box.execute([[SELECT a FROM t WHERE a < 1.0]]);
+box.execute([[SELECT a FROM t WHERE a < '1']]);
+box.execute([[SELECT a FROM t WHERE a = 1]]);
+box.execute([[SELECT a FROM t WHERE a = 1.0]]);
+box.execute([[SELECT a FROM t WHERE a = '1']]);
+box.execute([[DROP TABLE t;]])
-- 
2.25.1

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

* Re: [Tarantool-patches] [PATCH v6 03/22] sql: check args of abs()
  2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 03/22] sql: check args of abs() imeevma
@ 2020-07-16 16:12   ` Nikita Pettik
  0 siblings, 0 replies; 31+ messages in thread
From: Nikita Pettik @ 2020-07-16 16:12 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches

On 16 Jul 17:45, imeevma@tarantool.org wrote:
> 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(-)

LGTM

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

* Re: [Tarantool-patches] [PATCH v6 04/22] sql: check args of avg(), sum() and total()
  2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 04/22] sql: check args of avg(), sum() and total() imeevma
@ 2020-07-16 16:21   ` Nikita Pettik
  0 siblings, 0 replies; 31+ messages in thread
From: Nikita Pettik @ 2020-07-16 16:21 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches

On 16 Jul 17:45, imeevma@tarantool.org wrote:
> 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(-)
> 
> +
> +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"
> +    })
> 

Why don't you use arguemnts of different types? Like numb+numb+bool?

+
>  test:finish_test()
> -- 
> 2.25.1
> 

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

* Re: [Tarantool-patches] [PATCH v6 05/22] sql: check args of char()
  2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 05/22] sql: check args of char() imeevma
@ 2020-07-16 16:27   ` Nikita Pettik
  0 siblings, 0 replies; 31+ messages in thread
From: Nikita Pettik @ 2020-07-16 16:27 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches

On 16 Jul 17:45, imeevma@tarantool.org wrote:
> 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(-)


LGTM 

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

* Re: [Tarantool-patches] [PATCH v6 06/22] sql: check args of length()
  2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 06/22] sql: check args of length() imeevma
@ 2020-07-16 16:31   ` Nikita Pettik
  0 siblings, 0 replies; 31+ messages in thread
From: Nikita Pettik @ 2020-07-16 16:31 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches

On 16 Jul 17:45, imeevma@tarantool.org wrote:
> 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(-)


LGTM

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

* Re: [Tarantool-patches] [PATCH v6 07/22] sql: check operands of LIKE
  2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 07/22] sql: check operands of LIKE imeevma
@ 2020-07-16 17:03   ` Nikita Pettik
  0 siblings, 0 replies; 31+ messages in thread
From: Nikita Pettik @ 2020-07-16 17:03 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches

On 16 Jul 17:46, imeevma@tarantool.org wrote:
> 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(-)

LGTM
 

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

* Re: [Tarantool-patches] [PATCH v6 08/22] sql: check args of lower() and upper()
  2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 08/22] sql: check args of lower() and upper() imeevma
@ 2020-07-16 17:09   ` Nikita Pettik
  0 siblings, 0 replies; 31+ messages in thread
From: Nikita Pettik @ 2020-07-16 17:09 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches

On 16 Jul 17:46, imeevma@tarantool.org wrote:
> 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(-)
>

LGTM
 

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

* Re: [Tarantool-patches] [PATCH v6 09/22] sql: check args of position()
  2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 09/22] sql: check args of position() imeevma
@ 2020-07-16 17:28   ` Nikita Pettik
  0 siblings, 0 replies; 31+ messages in thread
From: Nikita Pettik @ 2020-07-16 17:28 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches

On 16 Jul 17:46, imeevma@tarantool.org wrote:
> 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(-)
>

LGTM 

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

* Re: [Tarantool-patches] [PATCH v6 10/22] sql: check args of randomblob()
  2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 10/22] sql: check args of randomblob() imeevma
@ 2020-07-16 17:28   ` Nikita Pettik
  0 siblings, 0 replies; 31+ messages in thread
From: Nikita Pettik @ 2020-07-16 17:28 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches

On 16 Jul 17:46, imeevma@tarantool.org wrote:
> 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(-)

LGTM 

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

end of thread, other threads:[~2020-07-16 17:28 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-16 14:45 [Tarantool-patches] [PATCH v6 00/22] sql: change implicit cast imeevma
2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 01/22] sql: change implicit cast for assignment imeevma
2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 02/22] sql: use ApplyType to check function arguments imeevma
2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 03/22] sql: check args of abs() imeevma
2020-07-16 16:12   ` Nikita Pettik
2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 04/22] sql: check args of avg(), sum() and total() imeevma
2020-07-16 16:21   ` Nikita Pettik
2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 05/22] sql: check args of char() imeevma
2020-07-16 16:27   ` Nikita Pettik
2020-07-16 14:45 ` [Tarantool-patches] [PATCH v6 06/22] sql: check args of length() imeevma
2020-07-16 16:31   ` Nikita Pettik
2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 07/22] sql: check operands of LIKE imeevma
2020-07-16 17:03   ` Nikita Pettik
2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 08/22] sql: check args of lower() and upper() imeevma
2020-07-16 17:09   ` Nikita Pettik
2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 09/22] sql: check args of position() imeevma
2020-07-16 17:28   ` Nikita Pettik
2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 10/22] sql: check args of randomblob() imeevma
2020-07-16 17:28   ` Nikita Pettik
2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 11/22] sql: check args of replace() imeevma
2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 12/22] sql: check args of round() imeevma
2020-07-16 14:46 ` [Tarantool-patches] [PATCH v6 13/22] sql: check args of soundex() imeevma
2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 14/22] sql: check args of substr() imeevma
2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 15/22] sql: check args of unicode() imeevma
2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 16/22] sql: check args of zeroblob() imeevma
2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 17/22] sql: remove unused DOUBLE to INTEGER conversion imeevma
2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 18/22] sql: add implicit cast between numbers in OP_Seek* imeevma
2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 19/22] sql: change comparison between numbers using index imeevma
2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 20/22] sql: remove implicit cast from comparison opcodes imeevma
2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 21/22] sql: fix implicit cast in opcode MustBeInt imeevma
2020-07-16 14:47 ` [Tarantool-patches] [PATCH v6 22/22] sql: remove implicit cast from MakeRecord opcode imeevma

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