Tarantool development patches archive
 help / color / mirror / Atom feed
From: imeevma@tarantool.org
To: korablev@tarantool.org, tsafin@tarantool.org,
	tarantool-patches@dev.tarantool.org
Subject: [Tarantool-patches] [PATCH v6 02/22] sql: use ApplyType to check function arguments
Date: Thu, 16 Jul 2020 17:45:46 +0300	[thread overview]
Message-ID: <5e4e0edcbdb06a33f6769215df0b0df825ee7a2d.1594909974.git.imeevma@gmail.com> (raw)
In-Reply-To: <cover.1594909974.git.imeevma@gmail.com>

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

  parent reply	other threads:[~2020-07-16 14:45 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5e4e0edcbdb06a33f6769215df0b0df825ee7a2d.1594909974.git.imeevma@gmail.com \
    --to=imeevma@tarantool.org \
    --cc=korablev@tarantool.org \
    --cc=tarantool-patches@dev.tarantool.org \
    --cc=tsafin@tarantool.org \
    --subject='Re: [Tarantool-patches] [PATCH v6 02/22] sql: use ApplyType to check function arguments' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

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