[Tarantool-patches] [PATCH v2 09/10] sql: check built-in functions argument types

imeevma at tarantool.org imeevma at tarantool.org
Fri Aug 14 18:05:11 MSK 2020


This patch creates a uniform way to check the argument types of SQL
built-in functions. Prior to this patch, argument types were checked
inside functions. They are now checked in the ApplyType opcode.

Closes #4159
---
 src/box/sql/expr.c             |    4 +
 src/box/sql/select.c           |   26 +
 src/box/sql/sqlInt.h           |   14 +
 test/sql-tap/cse.test.lua      |   24 +-
 test/sql-tap/func.test.lua     |   46 +-
 test/sql-tap/orderby1.test.lua |    2 +-
 test/sql-tap/position.test.lua |   16 +-
 test/sql-tap/substr.test.lua   |    2 +-
 test/sql/boolean.result        |   32 +-
 test/sql/checks.result         |    8 -
 test/sql/checks.test.lua       |    2 -
 test/sql/types.result          | 1535 +++++++++++++++++++++++++++++++-
 test/sql/types.test.lua        |  258 ++++++
 13 files changed, 1828 insertions(+), 141 deletions(-)

diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index 99ca91bba..68b55f0e4 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -4134,6 +4134,10 @@ 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/select.c b/src/box/sql/select.c
index b0554a172..49f01eb0d 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -124,6 +124,31 @@ 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 || func->def->param_list == NULL)
+		return;
+	assert(func->def->param_count > 0);
+	uint32_t len = (uint32_t)func->def->param_count;
+	assert(len > 0);
+	size_t size = (argc + 1) * sizeof(enum field_type);
+	enum field_type *types = sqlDbMallocZero(sql_get(), size);
+	if (argc <= len) {
+		for (uint32_t i = 0; i < argc; ++i)
+			types[i] = func->def->param_list[i];
+	} else {
+		for (uint32_t i = 0; i < len; ++i)
+			types[i] = func->def->param_list[i];
+		for (uint32_t i = len; i < argc; ++i)
+			types[i] = func->def->param_list[len - 1];
+	}
+	types[argc] = field_type_MAX;
+	sqlVdbeAddOp4(vdbe, OP_ApplyType, reg, argc, 0, (char *)types,
+		      P4_DYNAMIC);
+}
+
 /*
  * Initialize a SelectDest structure.
  */
@@ -5420,6 +5445,7 @@ updateAccumulator(Parse * pParse, AggInfo * pAggInfo)
 			vdbe_insert_distinct(pParse, pF->iDistinct, pF->reg_eph,
 					     addrNext, 1, regAgg);
 		}
+		sql_emit_func_arg_type_check(v, pF->func, regAgg, nArg);
 		if (sql_func_flag_is_set(pF->func, SQL_FUNC_NEEDCOLL)) {
 			struct coll *coll = NULL;
 			struct ExprList_item *pItem;
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 9ff1dd3ff..38fa83df0 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -3883,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 func Definition 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);
 
diff --git a/test/sql-tap/cse.test.lua b/test/sql-tap/cse.test.lua
index 341b6de01..18ddbf47c 100755
--- a/test/sql-tap/cse.test.lua
+++ b/test/sql-tap/cse.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(118)
+test:plan(116)
 
 --!./tcltestrunner.lua
 -- 2008 April 1
@@ -193,28 +193,6 @@ test:do_execsql_test(
         -- </cse-1.12>
     })
 
-
-
-test:do_execsql_test(
-    "cse-1.13",
-    [[
-        SELECT upper(b), typeof(b), b FROM t1
-    ]], {
-        -- <cse-1.13>
-        "11", "integer", 11, "21", "integer", 21
-        -- </cse-1.13>
-    })
-
-test:do_execsql_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
-        -- </cse-1.14>
-    })
-
 -- Overflow the column cache.  Create queries involving more and more
 -- columns until the cache overflows.  Verify correct operation throughout.
 --
diff --git a/test/sql-tap/func.test.lua b/test/sql-tap/func.test.lua
index 3c088920f..575a21007 100755
--- a/test/sql-tap/func.test.lua
+++ b/test/sql-tap/func.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(14694)
+test:plan(14693)
 
 --!./tcltestrunner.lua
 -- 2001 September 15
@@ -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
@@ -197,7 +197,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "func-2.9",
     [[
-        SELECT substr(a,1,1) FROM t2
+        SELECT substr(CAST(a AS STRING),1,1) FROM t2
     ]], {
         -- <func-2.9>
         "1", "", "3", "", "6"
@@ -207,7 +207,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "func-2.10",
     [[
-        SELECT substr(a,2,2) FROM t2
+        SELECT substr(CAST(a AS STRING),2,2) FROM t2
     ]], {
         -- <func-2.10>
         "", "", "45", "", "78"
@@ -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>
     })
 
@@ -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>
     })
 
@@ -760,18 +760,6 @@ test:do_execsql_test(
         -- </func-5.2>
     })
 
-test:do_execsql_test(
-    "func-5.3",
-    [[
-        SELECT upper(a), lower(a) FROM t2
-    ]], {
-        -- <func-5.3>
-        "1","1","","","345","345","","","67890","67890"
-        -- </func-5.3>
-    })
-
-
-
 test:do_catchsql_test(
     "func-5.5",
     [[
@@ -797,7 +785,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "func-6.2",
     [[
-        SELECT coalesce(upper(a),'nil') FROM t2
+        SELECT coalesce(upper(CAST(a AS STRING)),'nil') FROM t2
     ]], {
         -- <func-6.2>
         "1","nil","345","nil","67890"
@@ -893,7 +881,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 +892,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 +903,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 +914,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>
@@ -985,7 +973,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "func-9.5",
     [[
-        SELECT length(randomblob(32)), length(randomblob(-5)),
+        SELECT length(randomblob(32)), length(randomblob(0)),
                length(randomblob(2000))
     ]], {
         -- <func-9.5>
@@ -2918,7 +2906,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>
     })
 
@@ -2928,7 +2916,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>
     })
 
@@ -2938,7 +2926,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/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-tap/position.test.lua b/test/sql-tap/position.test.lua
index e0455abc9..08fee3796 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 varbinary"
         -- </position-1.25>
     })
 
@@ -554,7 +554,7 @@ test:do_test(
         return test:catchsql("SELECT position('x', x'78c3a4e282ac79');")
     end, {
         -- <position-1.54>
-        1, "Inconsistent types: expected text got varbinary"
+        1, "Type mismatch: can not convert varbinary to string"
         -- </position-1.54>
     })
 
@@ -564,7 +564,7 @@ test:do_test(
         return test:catchsql "SELECT position('y', x'78c3a4e282ac79');"
     end, {
         -- <position-1.55>
-        1, "Inconsistent types: expected text got varbinary"
+        1, "Type mismatch: can not convert varbinary to string"
         -- </position-1.55>
     })
 
@@ -614,7 +614,7 @@ test:do_test(
         return test:catchsql "SELECT position(x'79', 'xä€y');"
     end, {
         -- <position-1.57.1>
-        1, "Inconsistent types: expected varbinary got text"
+        1, "Type mismatch: can not convert xä€y to varbinary"
         -- </position-1.57.1>
     })
 
@@ -624,7 +624,7 @@ test:do_test(
         return test:catchsql "SELECT position(x'a4', 'xä€y');"
     end, {
         -- <position-1.57.2>
-        1, "Inconsistent types: expected varbinary got text"
+        1, "Type mismatch: can not convert xä€y to varbinary"
         -- </position-1.57.2>
     })
 
@@ -634,7 +634,7 @@ test:do_test(
         return test:catchsql "SELECT position('y', x'78c3a4e282ac79');"
     end, {
         -- <position-1.57.3>
-        1, "Inconsistent types: expected text got varbinary"
+        1, "Type mismatch: can not convert varbinary to string"
         -- </position-1.57.3>
     })
 
diff --git a/test/sql-tap/substr.test.lua b/test/sql-tap/substr.test.lua
index a9e656e6d..a970f9e93 100755
--- a/test/sql-tap/substr.test.lua
+++ b/test/sql-tap/substr.test.lua
@@ -25,7 +25,7 @@ test:plan(93)
 --
 test:execsql [[
     CREATE TABLE t1(id integer primary key --autoincrement
-    , t text, b SCALAR)
+    , t text, b VARBINARY)
 ]]
 
 local function substr_test(id, string, i1, i2, result)
diff --git a/test/sql/boolean.result b/test/sql/boolean.result
index 51ec5820b..b525e908c 100644
--- a/test/sql/boolean.result
+++ b/test/sql/boolean.result
@@ -276,29 +276,17 @@ 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;
  | ---
- | - metadata:
- |   - name: COLUMN_1
- |     type: string
- |   rows:
- |   - ['false']
- |   - ['true']
- |   - [null]
- |   - [null]
+ | - null
+ | - 'Type mismatch: can not convert FALSE to string'
  | ...
 SELECT upper(a) FROM t0;
  | ---
- | - metadata:
- |   - name: COLUMN_1
- |     type: string
- |   rows:
- |   - ['FALSE']
- |   - ['TRUE']
- |   - [null]
- |   - [null]
+ | - null
+ | - 'Type mismatch: can not convert FALSE to string'
  | ...
 SELECT quote(a) FROM t0;
  | ---
@@ -314,14 +302,8 @@ SELECT quote(a) FROM t0;
 -- gh-4462: LENGTH didn't take BOOLEAN arguments.
 SELECT length(a) FROM t0;
  | ---
- | - metadata:
- |   - name: COLUMN_1
- |     type: integer
- |   rows:
- |   - [5]
- |   - [4]
- |   - [null]
- |   - [null]
+ | - null
+ | - 'Type mismatch: can not convert FALSE to string'
  | ...
 SELECT typeof(a) FROM t0;
  | ---
diff --git a/test/sql/checks.result b/test/sql/checks.result
index 7b18e5d6b..3c942fb23 100644
--- a/test/sql/checks.result
+++ b/test/sql/checks.result
@@ -519,14 +519,6 @@ s:insert({1, 'string'})
 ---
 - error: 'Check constraint failed ''complex2'': typeof(coalesce(z,0))==''integer'''
 ...
-s:insert({1, {map=true}})
----
-- error: 'Check constraint failed ''complex2'': typeof(coalesce(z,0))==''integer'''
-...
-s:insert({1, {'a', 'r','r','a','y'}})
----
-- error: 'Check constraint failed ''complex2'': typeof(coalesce(z,0))==''integer'''
-...
 s:insert({1, 3.14})
 ---
 - error: 'Check constraint failed ''complex2'': typeof(coalesce(z,0))==''integer'''
diff --git a/test/sql/checks.test.lua b/test/sql/checks.test.lua
index 301f8ea69..b55abe955 100644
--- a/test/sql/checks.test.lua
+++ b/test/sql/checks.test.lua
@@ -173,8 +173,6 @@ s:format({{name='X', type='integer'}, {name='Z', type='any'}})
 _ = s:create_index('pk', {parts = {1, 'integer'}})
 _ = box.space._ck_constraint:insert({s.id, 'complex2', false, 'SQL', 'typeof(coalesce(z,0))==\'integer\'', true})
 s:insert({1, 'string'})
-s:insert({1, {map=true}})
-s:insert({1, {'a', 'r','r','a','y'}})
 s:insert({1, 3.14})
 s:insert({1, 666})
 s:drop()
diff --git a/test/sql/types.result b/test/sql/types.result
index 2498f3a48..bd503c700 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: COLUMN_1
-    type: boolean
-  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: COLUMN_1
-    type: boolean
-  rows:
-  - [null]
+- null
+- 'Type mismatch: can not convert 1 to string'
 ...
 box.space.T1:drop()
 ---
@@ -830,19 +824,13 @@ box.execute("DELETE FROM t WHERE i < 18446744073709551613;")
 ...
 box.execute("SELECT lower(i) FROM t;")
 ---
-- metadata:
-  - name: COLUMN_1
-    type: string
-  rows:
-  - ['18446744073709551613']
+- null
+- 'Type mismatch: can not convert 18446744073709551613 to string'
 ...
 box.execute("SELECT upper(i) FROM t;")
 ---
-- metadata:
-  - name: COLUMN_1
-    type: string
-  rows:
-  - ['18446744073709551613']
+- null
+- 'Type mismatch: can not convert 18446744073709551613 to string'
 ...
 box.execute("SELECT abs(i) FROM t;")
 ---
@@ -1312,17 +1300,17 @@ 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;")
 ---
 - null
-- 'Inconsistent types: expected number got varbinary'
+- 'Type mismatch: can not convert varbinary to number'
 ...
 box.execute("SELECT typeof(v) FROM t;")
 ---
@@ -1879,25 +1867,13 @@ box.execute("SELECT group_concat(d) FROM t;")
 ...
 box.execute("SELECT lower(d) FROM t;")
 ---
-- metadata:
-  - name: COLUMN_1
-    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: COLUMN_1
-    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;")
 ---
@@ -2807,3 +2783,1474 @@ box.execute([[SELECT typeof(length('abc'));]])
   rows:
   - ['integer']
 ...
+-- Make sure the function argument types are checked.
+box.execute([[SELECT abs(-1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: number
+  rows:
+  - [1]
+...
+box.execute([[SELECT abs(1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: number
+  rows:
+  - [1]
+...
+box.execute([[SELECT abs(1.5);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: number
+  rows:
+  - [1.5]
+...
+box.execute([[SELECT abs(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to number'
+...
+box.execute([[SELECT abs('a');]])
+---
+- null
+- 'Type mismatch: can not convert a to number'
+...
+box.execute([[SELECT abs(X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to number'
+...
+box.execute([[SELECT char(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to unsigned'
+...
+box.execute([[SELECT char(1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ["\x01"]
+...
+box.execute([[SELECT char(1.5);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ["\x01"]
+...
+box.execute([[SELECT char(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to unsigned'
+...
+box.execute([[SELECT char('a');]])
+---
+- null
+- 'Type mismatch: can not convert a to unsigned'
+...
+box.execute([[SELECT char(X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to unsigned'
+...
+box.execute([[SELECT character_length(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string'
+...
+box.execute([[SELECT character_length(1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string'
+...
+box.execute([[SELECT character_length(1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string'
+...
+box.execute([[SELECT character_length(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string'
+...
+box.execute([[SELECT character_length('a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT character_length(X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to string'
+...
+box.execute([[SELECT char_length(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string'
+...
+box.execute([[SELECT char_length(1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string'
+...
+box.execute([[SELECT char_length(1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string'
+...
+box.execute([[SELECT char_length(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string'
+...
+box.execute([[SELECT char_length('a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT char_length(X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to string'
+...
+box.execute([[SELECT coalesce(-1, -1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [-1]
+...
+box.execute([[SELECT coalesce(1, 1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [1]
+...
+box.execute([[SELECT coalesce(1.5, 1.5);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [1.5]
+...
+box.execute([[SELECT coalesce(true, true);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [true]
+...
+box.execute([[SELECT coalesce('a', 'a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - ['a']
+...
+box.execute([[SELECT coalesce(X'33', X'33');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - ['3']
+...
+box.execute([[SELECT greatest(-1, -1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [-1]
+...
+box.execute([[SELECT greatest(1, 1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [1]
+...
+box.execute([[SELECT greatest(1.5, 1.5);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [1.5]
+...
+box.execute([[SELECT greatest(true, true);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [true]
+...
+box.execute([[SELECT greatest('a', 'a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - ['a']
+...
+box.execute([[SELECT greatest(X'33', X'33');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - ['3']
+...
+box.execute([[SELECT hex(-1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['2D31']
+...
+box.execute([[SELECT hex(1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['31']
+...
+box.execute([[SELECT hex(1.5);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['312E35']
+...
+box.execute([[SELECT hex(true);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['54525545']
+...
+box.execute([[SELECT hex('a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['61']
+...
+box.execute([[SELECT hex(X'33');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['33']
+...
+box.execute([[SELECT ifnull(-1, -1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [-1]
+...
+box.execute([[SELECT ifnull(1, 1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [1]
+...
+box.execute([[SELECT ifnull(1.5, 1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [1.5]
+...
+box.execute([[SELECT ifnull(true, true);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [true]
+...
+box.execute([[SELECT ifnull('a', 'a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - ['a']
+...
+box.execute([[SELECT ifnull(X'33', X'33');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - ['3']
+...
+box.execute([[SELECT least(-1, -1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [-1]
+...
+box.execute([[SELECT least(1, 1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [1]
+...
+box.execute([[SELECT least(1.5, 1.5);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [1.5]
+...
+box.execute([[SELECT least(true, true);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [true]
+...
+box.execute([[SELECT least('a', 'a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - ['a']
+...
+box.execute([[SELECT least(X'33', X'33');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - ['3']
+...
+box.execute([[SELECT length(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string'
+...
+box.execute([[SELECT length(1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string'
+...
+box.execute([[SELECT length(1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string'
+...
+box.execute([[SELECT length(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string'
+...
+box.execute([[SELECT length('a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT length(X'33');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT likelihood(-1, -1);]])
+---
+- null
+- Illegal parameters, second argument to likelihood() must be a constant between 0.0
+  and 1.0
+...
+box.execute([[SELECT likelihood(1, 1);]])
+---
+- null
+- Illegal parameters, second argument to likelihood() must be a constant between 0.0
+  and 1.0
+...
+box.execute([[SELECT likelihood(1.5, 1.5);]])
+---
+- null
+- Illegal parameters, second argument to likelihood() must be a constant between 0.0
+  and 1.0
+...
+box.execute([[SELECT likelihood(true, true);]])
+---
+- null
+- Illegal parameters, second argument to likelihood() must be a constant between 0.0
+  and 1.0
+...
+box.execute([[SELECT likelihood('a', 'a');]])
+---
+- null
+- Illegal parameters, second argument to likelihood() must be a constant between 0.0
+  and 1.0
+...
+box.execute([[SELECT likelihood(X'33', X'33');]])
+---
+- null
+- Illegal parameters, second argument to likelihood() must be a constant between 0.0
+  and 1.0
+...
+box.execute([[SELECT likely(-1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: integer
+  rows:
+  - [-1]
+...
+box.execute([[SELECT likely(1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT likely(1.5);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: double
+  rows:
+  - [1.5]
+...
+box.execute([[SELECT likely(true);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: boolean
+  rows:
+  - [true]
+...
+box.execute([[SELECT likely('a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['a']
+...
+box.execute([[SELECT likely(X'33');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: varbinary
+  rows:
+  - ['3']
+...
+box.execute([[SELECT lower(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string'
+...
+box.execute([[SELECT lower(1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string'
+...
+box.execute([[SELECT lower(1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string'
+...
+box.execute([[SELECT lower(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string'
+...
+box.execute([[SELECT lower('a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['a']
+...
+box.execute([[SELECT lower(X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to string'
+...
+box.execute([[SELECT nullif(-1, -1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [null]
+...
+box.execute([[SELECT nullif(1, 1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [null]
+...
+box.execute([[SELECT nullif(1.5, 1.5);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [null]
+...
+box.execute([[SELECT nullif(true, true);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [null]
+...
+box.execute([[SELECT nullif('a', 'a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [null]
+...
+box.execute([[SELECT nullif(X'33', X'33');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [null]
+...
+box.execute([[SELECT position(-1, -1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string'
+...
+box.execute([[SELECT position(1, 1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string'
+...
+box.execute([[SELECT position(1.5, 1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string'
+...
+box.execute([[SELECT position(true, true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string'
+...
+box.execute([[SELECT position('a', 'a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT position(X'33', X'33');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT printf(-1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['-1']
+...
+box.execute([[SELECT printf(1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['1']
+...
+box.execute([[SELECT printf(1.5);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['1.5']
+...
+box.execute([[SELECT printf(true);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['TRUE']
+...
+box.execute([[SELECT printf('a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['a']
+...
+box.execute([[SELECT printf(X'33');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['3']
+...
+box.execute([[SELECT quote(-1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - [-1]
+...
+box.execute([[SELECT quote(1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - [1]
+...
+box.execute([[SELECT quote(1.5);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['1.5']
+...
+box.execute([[SELECT quote(true);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['TRUE']
+...
+box.execute([[SELECT quote('a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['''a''']
+...
+box.execute([[SELECT quote(X'33');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['X''33''']
+...
+box.execute([[SELECT randomblob(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to unsigned'
+...
+box.execute([[SELECT randomblob(0);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: varbinary
+  rows:
+  - [null]
+...
+box.execute([[SELECT randomblob(0.5);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: varbinary
+  rows:
+  - [null]
+...
+box.execute([[SELECT randomblob(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to unsigned'
+...
+box.execute([[SELECT randomblob('a');]])
+---
+- null
+- 'Type mismatch: can not convert a to unsigned'
+...
+box.execute([[SELECT randomblob(X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to unsigned'
+...
+box.execute([[SELECT replace(-1, -1, -1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string'
+...
+box.execute([[SELECT replace(1, 1, 1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string'
+...
+box.execute([[SELECT replace(1.5, 1.5, 1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string'
+...
+box.execute([[SELECT replace(true, true, true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string'
+...
+box.execute([[SELECT replace('a', 'a', 'a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['a']
+...
+box.execute([[SELECT replace(X'33', X'33', X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to string'
+...
+box.execute([[SELECT round(-1, -1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to unsigned'
+...
+box.execute([[SELECT round(1, 1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: double
+  rows:
+  - [1]
+...
+box.execute([[SELECT round(1.5, 1.5);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: double
+  rows:
+  - [1.5]
+...
+box.execute([[SELECT round(true, true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to double'
+...
+box.execute([[SELECT round('a', 'a');]])
+---
+- null
+- 'Type mismatch: can not convert a to double'
+...
+box.execute([[SELECT round(X'33', X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to double'
+...
+box.execute([[SELECT soundex(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string'
+...
+box.execute([[SELECT soundex(1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string'
+...
+box.execute([[SELECT soundex(1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string'
+...
+box.execute([[SELECT soundex(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string'
+...
+box.execute([[SELECT soundex('a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['A000']
+...
+box.execute([[SELECT soundex(X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to string'
+...
+box.execute([[SELECT substr(-1, -1, -1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string'
+...
+box.execute([[SELECT substr(1, 1, 1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string'
+...
+box.execute([[SELECT substr(1.5, 1.5, 1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string'
+...
+box.execute([[SELECT substr(true, true, true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string'
+...
+box.execute([[SELECT substr('a', 'a', 'a');]])
+---
+- null
+- 'Type mismatch: can not convert a to integer'
+...
+box.execute([[SELECT substr(X'33', X'33', X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to integer'
+...
+box.execute([[SELECT typeof(-1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['integer']
+...
+box.execute([[SELECT typeof(1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['integer']
+...
+box.execute([[SELECT typeof(1.5);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['double']
+...
+box.execute([[SELECT typeof(true);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['boolean']
+...
+box.execute([[SELECT typeof('a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['string']
+...
+box.execute([[SELECT typeof(X'33');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['varbinary']
+...
+box.execute([[SELECT unicode(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string'
+...
+box.execute([[SELECT unicode(1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string'
+...
+box.execute([[SELECT unicode(1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string'
+...
+box.execute([[SELECT unicode(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string'
+...
+box.execute([[SELECT unicode('a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - [97]
+...
+box.execute([[SELECT unicode(X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to string'
+...
+box.execute([[SELECT unlikely(-1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: integer
+  rows:
+  - [-1]
+...
+box.execute([[SELECT unlikely(1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT unlikely(1.5);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: double
+  rows:
+  - [1.5]
+...
+box.execute([[SELECT unlikely(true);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: boolean
+  rows:
+  - [true]
+...
+box.execute([[SELECT unlikely('a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['a']
+...
+box.execute([[SELECT unlikely(X'33');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: varbinary
+  rows:
+  - ['3']
+...
+box.execute([[SELECT upper(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string'
+...
+box.execute([[SELECT upper(1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string'
+...
+box.execute([[SELECT upper(1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string'
+...
+box.execute([[SELECT upper(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string'
+...
+box.execute([[SELECT upper('a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['A']
+...
+box.execute([[SELECT upper(X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to string'
+...
+box.execute([[SELECT zeroblob(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to unsigned'
+...
+box.execute([[SELECT zeroblob(1);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: varbinary
+  rows:
+  - ["\0"]
+...
+box.execute([[SELECT zeroblob(1.5);]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: varbinary
+  rows:
+  - ["\0"]
+...
+box.execute([[SELECT zeroblob(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to unsigned'
+...
+box.execute([[SELECT zeroblob('a');]])
+---
+- null
+- 'Type mismatch: can not convert a to unsigned'
+...
+box.execute([[SELECT zeroblob(X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to unsigned'
+...
+box.execute([[SELECT trim(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string'
+...
+box.execute([[SELECT trim(1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string'
+...
+box.execute([[SELECT trim(1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string'
+...
+box.execute([[SELECT trim(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string'
+...
+box.execute([[SELECT trim('a');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['a']
+...
+box.execute([[SELECT trim(X'33');]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['3']
+...
+box.execute([[SELECT -1 like -1;]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string'
+...
+box.execute([[SELECT 1 like 1;]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string'
+...
+box.execute([[SELECT 1.5 like 1.5;]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string'
+...
+box.execute([[SELECT true like true;]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string'
+...
+box.execute([[SELECT 'a' like 'a';]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: boolean
+  rows:
+  - [true]
+...
+box.execute([[SELECT X'33' like X'33';]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to string'
+...
+box.execute([[CREATE TABLE t (i INTEGER PRIMARY KEY, u UNSIGNED, d DOUBLE, b BOOLEAN, s STRING, v VARBINARY);]])
+---
+- row_count: 1
+...
+box.execute([[INSERT INTO t VALUES (-1, 1, 1.5, true, 'a', X'33');]])
+---
+- row_count: 1
+...
+box.execute([[SELECT avg(i) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: number
+  rows:
+  - [-1]
+...
+box.execute([[SELECT avg(u) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: number
+  rows:
+  - [1]
+...
+box.execute([[SELECT avg(d) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: number
+  rows:
+  - [1.5]
+...
+box.execute([[SELECT avg(b) FROM t;]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to number'
+...
+box.execute([[SELECT avg(s) FROM t;]])
+---
+- null
+- 'Type mismatch: can not convert a to number'
+...
+box.execute([[SELECT avg(v) FROM t;]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to number'
+...
+box.execute([[SELECT count(i) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT count(u) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT count(d) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT count(b) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT count(s) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT count(v) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: integer
+  rows:
+  - [1]
+...
+box.execute([[SELECT group_concat(i) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['-1']
+...
+box.execute([[SELECT group_concat(u) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['1']
+...
+box.execute([[SELECT group_concat(d) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['1.5']
+...
+box.execute([[SELECT group_concat(b) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['TRUE']
+...
+box.execute([[SELECT group_concat(s) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['a']
+...
+box.execute([[SELECT group_concat(v) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: string
+  rows:
+  - ['3']
+...
+box.execute([[SELECT max(i) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [-1]
+...
+box.execute([[SELECT max(u) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [1]
+...
+box.execute([[SELECT max(d) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [1.5]
+...
+box.execute([[SELECT max(b) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [true]
+...
+box.execute([[SELECT max(s) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - ['a']
+...
+box.execute([[SELECT max(v) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - ['3']
+...
+box.execute([[SELECT min(i) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [-1]
+...
+box.execute([[SELECT min(u) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [1]
+...
+box.execute([[SELECT min(d) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [1.5]
+...
+box.execute([[SELECT min(b) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - [true]
+...
+box.execute([[SELECT min(s) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - ['a']
+...
+box.execute([[SELECT min(v) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: scalar
+  rows:
+  - ['3']
+...
+box.execute([[SELECT sum(i) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: number
+  rows:
+  - [-1]
+...
+box.execute([[SELECT sum(u) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: number
+  rows:
+  - [1]
+...
+box.execute([[SELECT sum(d) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: number
+  rows:
+  - [1.5]
+...
+box.execute([[SELECT sum(b) FROM t;]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to number'
+...
+box.execute([[SELECT sum(s) FROM t;]])
+---
+- null
+- 'Type mismatch: can not convert a to number'
+...
+box.execute([[SELECT sum(v) FROM t;]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to number'
+...
+box.execute([[SELECT total(i) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: number
+  rows:
+  - [-1]
+...
+box.execute([[SELECT total(u) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: number
+  rows:
+  - [1]
+...
+box.execute([[SELECT total(d) FROM t;]])
+---
+- metadata:
+  - name: COLUMN_1
+    type: number
+  rows:
+  - [1.5]
+...
+box.execute([[SELECT total(b) FROM t;]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to number'
+...
+box.execute([[SELECT total(s) FROM t;]])
+---
+- null
+- 'Type mismatch: can not convert a to number'
+...
+box.execute([[SELECT total(v) FROM t;]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to number'
+...
+box.execute([[DROP TABLE t;]])
+---
+- row_count: 1
+...
diff --git a/test/sql/types.test.lua b/test/sql/types.test.lua
index fff0057bd..61483e7e9 100644
--- a/test/sql/types.test.lua
+++ b/test/sql/types.test.lua
@@ -629,3 +629,261 @@ box.execute([[DROP TABLE ts;]])
 -- instead of values of type UNSIGNED.
 --
 box.execute([[SELECT typeof(length('abc'));]])
+
+-- Make sure the function argument types are checked.
+box.execute([[SELECT abs(-1);]])
+box.execute([[SELECT abs(1);]])
+box.execute([[SELECT abs(1.5);]])
+box.execute([[SELECT abs(true);]])
+box.execute([[SELECT abs('a');]])
+box.execute([[SELECT abs(X'33');]])
+
+box.execute([[SELECT char(-1);]])
+box.execute([[SELECT char(1);]])
+box.execute([[SELECT char(1.5);]])
+box.execute([[SELECT char(true);]])
+box.execute([[SELECT char('a');]])
+box.execute([[SELECT char(X'33');]])
+
+box.execute([[SELECT character_length(-1);]])
+box.execute([[SELECT character_length(1);]])
+box.execute([[SELECT character_length(1.5);]])
+box.execute([[SELECT character_length(true);]])
+box.execute([[SELECT character_length('a');]])
+box.execute([[SELECT character_length(X'33');]])
+
+box.execute([[SELECT char_length(-1);]])
+box.execute([[SELECT char_length(1);]])
+box.execute([[SELECT char_length(1.5);]])
+box.execute([[SELECT char_length(true);]])
+box.execute([[SELECT char_length('a');]])
+box.execute([[SELECT char_length(X'33');]])
+
+box.execute([[SELECT coalesce(-1, -1);]])
+box.execute([[SELECT coalesce(1, 1);]])
+box.execute([[SELECT coalesce(1.5, 1.5);]])
+box.execute([[SELECT coalesce(true, true);]])
+box.execute([[SELECT coalesce('a', 'a');]])
+box.execute([[SELECT coalesce(X'33', X'33');]])
+
+box.execute([[SELECT greatest(-1, -1);]])
+box.execute([[SELECT greatest(1, 1);]])
+box.execute([[SELECT greatest(1.5, 1.5);]])
+box.execute([[SELECT greatest(true, true);]])
+box.execute([[SELECT greatest('a', 'a');]])
+box.execute([[SELECT greatest(X'33', X'33');]])
+
+box.execute([[SELECT hex(-1);]])
+box.execute([[SELECT hex(1);]])
+box.execute([[SELECT hex(1.5);]])
+box.execute([[SELECT hex(true);]])
+box.execute([[SELECT hex('a');]])
+box.execute([[SELECT hex(X'33');]])
+
+box.execute([[SELECT ifnull(-1, -1);]])
+box.execute([[SELECT ifnull(1, 1);]])
+box.execute([[SELECT ifnull(1.5, 1);]])
+box.execute([[SELECT ifnull(true, true);]])
+box.execute([[SELECT ifnull('a', 'a');]])
+box.execute([[SELECT ifnull(X'33', X'33');]])
+
+box.execute([[SELECT least(-1, -1);]])
+box.execute([[SELECT least(1, 1);]])
+box.execute([[SELECT least(1.5, 1.5);]])
+box.execute([[SELECT least(true, true);]])
+box.execute([[SELECT least('a', 'a');]])
+box.execute([[SELECT least(X'33', X'33');]])
+
+box.execute([[SELECT length(-1);]])
+box.execute([[SELECT length(1);]])
+box.execute([[SELECT length(1.5);]])
+box.execute([[SELECT length(true);]])
+box.execute([[SELECT length('a');]])
+box.execute([[SELECT length(X'33');]])
+
+box.execute([[SELECT likelihood(-1, -1);]])
+box.execute([[SELECT likelihood(1, 1);]])
+box.execute([[SELECT likelihood(1.5, 1.5);]])
+box.execute([[SELECT likelihood(true, true);]])
+box.execute([[SELECT likelihood('a', 'a');]])
+box.execute([[SELECT likelihood(X'33', X'33');]])
+
+box.execute([[SELECT likely(-1);]])
+box.execute([[SELECT likely(1);]])
+box.execute([[SELECT likely(1.5);]])
+box.execute([[SELECT likely(true);]])
+box.execute([[SELECT likely('a');]])
+box.execute([[SELECT likely(X'33');]])
+
+box.execute([[SELECT lower(-1);]])
+box.execute([[SELECT lower(1);]])
+box.execute([[SELECT lower(1.5);]])
+box.execute([[SELECT lower(true);]])
+box.execute([[SELECT lower('a');]])
+box.execute([[SELECT lower(X'33');]])
+
+box.execute([[SELECT nullif(-1, -1);]])
+box.execute([[SELECT nullif(1, 1);]])
+box.execute([[SELECT nullif(1.5, 1.5);]])
+box.execute([[SELECT nullif(true, true);]])
+box.execute([[SELECT nullif('a', 'a');]])
+box.execute([[SELECT nullif(X'33', X'33');]])
+
+box.execute([[SELECT position(-1, -1);]])
+box.execute([[SELECT position(1, 1);]])
+box.execute([[SELECT position(1.5, 1.5);]])
+box.execute([[SELECT position(true, true);]])
+box.execute([[SELECT position('a', 'a');]])
+box.execute([[SELECT position(X'33', X'33');]])
+
+box.execute([[SELECT printf(-1);]])
+box.execute([[SELECT printf(1);]])
+box.execute([[SELECT printf(1.5);]])
+box.execute([[SELECT printf(true);]])
+box.execute([[SELECT printf('a');]])
+box.execute([[SELECT printf(X'33');]])
+
+box.execute([[SELECT quote(-1);]])
+box.execute([[SELECT quote(1);]])
+box.execute([[SELECT quote(1.5);]])
+box.execute([[SELECT quote(true);]])
+box.execute([[SELECT quote('a');]])
+box.execute([[SELECT quote(X'33');]])
+
+box.execute([[SELECT randomblob(-1);]])
+box.execute([[SELECT randomblob(0);]])
+box.execute([[SELECT randomblob(0.5);]])
+box.execute([[SELECT randomblob(true);]])
+box.execute([[SELECT randomblob('a');]])
+box.execute([[SELECT randomblob(X'33');]])
+
+box.execute([[SELECT replace(-1, -1, -1);]])
+box.execute([[SELECT replace(1, 1, 1);]])
+box.execute([[SELECT replace(1.5, 1.5, 1.5);]])
+box.execute([[SELECT replace(true, true, true);]])
+box.execute([[SELECT replace('a', 'a', 'a');]])
+box.execute([[SELECT replace(X'33', X'33', X'33');]])
+
+box.execute([[SELECT round(-1, -1);]])
+box.execute([[SELECT round(1, 1);]])
+box.execute([[SELECT round(1.5, 1.5);]])
+box.execute([[SELECT round(true, true);]])
+box.execute([[SELECT round('a', 'a');]])
+box.execute([[SELECT round(X'33', X'33');]])
+
+box.execute([[SELECT soundex(-1);]])
+box.execute([[SELECT soundex(1);]])
+box.execute([[SELECT soundex(1.5);]])
+box.execute([[SELECT soundex(true);]])
+box.execute([[SELECT soundex('a');]])
+box.execute([[SELECT soundex(X'33');]])
+
+box.execute([[SELECT substr(-1, -1, -1);]])
+box.execute([[SELECT substr(1, 1, 1);]])
+box.execute([[SELECT substr(1.5, 1.5, 1.5);]])
+box.execute([[SELECT substr(true, true, true);]])
+box.execute([[SELECT substr('a', 'a', 'a');]])
+box.execute([[SELECT substr(X'33', X'33', X'33');]])
+
+box.execute([[SELECT typeof(-1);]])
+box.execute([[SELECT typeof(1);]])
+box.execute([[SELECT typeof(1.5);]])
+box.execute([[SELECT typeof(true);]])
+box.execute([[SELECT typeof('a');]])
+box.execute([[SELECT typeof(X'33');]])
+
+box.execute([[SELECT unicode(-1);]])
+box.execute([[SELECT unicode(1);]])
+box.execute([[SELECT unicode(1.5);]])
+box.execute([[SELECT unicode(true);]])
+box.execute([[SELECT unicode('a');]])
+box.execute([[SELECT unicode(X'33');]])
+
+box.execute([[SELECT unlikely(-1);]])
+box.execute([[SELECT unlikely(1);]])
+box.execute([[SELECT unlikely(1.5);]])
+box.execute([[SELECT unlikely(true);]])
+box.execute([[SELECT unlikely('a');]])
+box.execute([[SELECT unlikely(X'33');]])
+
+box.execute([[SELECT upper(-1);]])
+box.execute([[SELECT upper(1);]])
+box.execute([[SELECT upper(1.5);]])
+box.execute([[SELECT upper(true);]])
+box.execute([[SELECT upper('a');]])
+box.execute([[SELECT upper(X'33');]])
+
+box.execute([[SELECT zeroblob(-1);]])
+box.execute([[SELECT zeroblob(1);]])
+box.execute([[SELECT zeroblob(1.5);]])
+box.execute([[SELECT zeroblob(true);]])
+box.execute([[SELECT zeroblob('a');]])
+box.execute([[SELECT zeroblob(X'33');]])
+
+box.execute([[SELECT trim(-1);]])
+box.execute([[SELECT trim(1);]])
+box.execute([[SELECT trim(1.5);]])
+box.execute([[SELECT trim(true);]])
+box.execute([[SELECT trim('a');]])
+box.execute([[SELECT trim(X'33');]])
+
+box.execute([[SELECT -1 like -1;]])
+box.execute([[SELECT 1 like 1;]])
+box.execute([[SELECT 1.5 like 1.5;]])
+box.execute([[SELECT true like true;]])
+box.execute([[SELECT 'a' like 'a';]])
+box.execute([[SELECT X'33' like X'33';]])
+
+box.execute([[CREATE TABLE t (i INTEGER PRIMARY KEY, u UNSIGNED, d DOUBLE, b BOOLEAN, s STRING, v VARBINARY);]])
+box.execute([[INSERT INTO t VALUES (-1, 1, 1.5, true, 'a', X'33');]])
+
+box.execute([[SELECT avg(i) FROM t;]])
+box.execute([[SELECT avg(u) FROM t;]])
+box.execute([[SELECT avg(d) FROM t;]])
+box.execute([[SELECT avg(b) FROM t;]])
+box.execute([[SELECT avg(s) FROM t;]])
+box.execute([[SELECT avg(v) FROM t;]])
+
+box.execute([[SELECT count(i) FROM t;]])
+box.execute([[SELECT count(u) FROM t;]])
+box.execute([[SELECT count(d) FROM t;]])
+box.execute([[SELECT count(b) FROM t;]])
+box.execute([[SELECT count(s) FROM t;]])
+box.execute([[SELECT count(v) FROM t;]])
+
+box.execute([[SELECT group_concat(i) FROM t;]])
+box.execute([[SELECT group_concat(u) FROM t;]])
+box.execute([[SELECT group_concat(d) FROM t;]])
+box.execute([[SELECT group_concat(b) FROM t;]])
+box.execute([[SELECT group_concat(s) FROM t;]])
+box.execute([[SELECT group_concat(v) FROM t;]])
+
+box.execute([[SELECT max(i) FROM t;]])
+box.execute([[SELECT max(u) FROM t;]])
+box.execute([[SELECT max(d) FROM t;]])
+box.execute([[SELECT max(b) FROM t;]])
+box.execute([[SELECT max(s) FROM t;]])
+box.execute([[SELECT max(v) FROM t;]])
+
+box.execute([[SELECT min(i) FROM t;]])
+box.execute([[SELECT min(u) FROM t;]])
+box.execute([[SELECT min(d) FROM t;]])
+box.execute([[SELECT min(b) FROM t;]])
+box.execute([[SELECT min(s) FROM t;]])
+box.execute([[SELECT min(v) FROM t;]])
+
+box.execute([[SELECT sum(i) FROM t;]])
+box.execute([[SELECT sum(u) FROM t;]])
+box.execute([[SELECT sum(d) FROM t;]])
+box.execute([[SELECT sum(b) FROM t;]])
+box.execute([[SELECT sum(s) FROM t;]])
+box.execute([[SELECT sum(v) FROM t;]])
+
+box.execute([[SELECT total(i) FROM t;]])
+box.execute([[SELECT total(u) FROM t;]])
+box.execute([[SELECT total(d) FROM t;]])
+box.execute([[SELECT total(b) FROM t;]])
+box.execute([[SELECT total(s) FROM t;]])
+box.execute([[SELECT total(v) FROM t;]])
+
+box.execute([[DROP TABLE t;]])
\ No newline at end of file
-- 
2.25.1



More information about the Tarantool-patches mailing list