Tarantool development patches archive
 help / color / mirror / Atom feed
* [Tarantool-patches] [PATCH v2 0/6] Remove SQL built-in functions from _func
@ 2021-08-09  7:18 Mergen Imeev via Tarantool-patches
  2021-08-09  7:18 ` [Tarantool-patches] [PATCH v2 1/6] sql: introduce sql_func_flags() Mergen Imeev via Tarantool-patches
                   ` (7 more replies)
  0 siblings, 8 replies; 12+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-08-09  7:18 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

This patch-set removes SQL built-in functions from _func and prohibits functions
with SQL_BUILTIN language to be decribed in _func system space.

https://github.com/tarantool/tarantool/issues/6106
https://github.com/tarantool/tarantool/tree/imeevma/gh-6106-remove-sql-builtins-from-_func

Changes in v2:
 - Added some functions that simplifies work with SQL built-in functions.
 - Removed some code that become unused due to removal of SQL built-in functions
   from _func.
 - Prohibited to insert tuples with "language" = 'SQL_BUILTIN' to _func.

Mergen Imeev (5):
  sql: introduce sql_func_flags()
  sql: introduce sql_func_find()
  sql: remove SQL built-in functions from _func
  alter: disallow creation of SQL built-in function
  sql: remove unnecessary function initialization

Vladislav Shpilevoy (1):
  alter: parse data dictionary version

 ...gh-6106-remove-sql-built-ins-from-_func.md |   7 +
 src/box/alter.cc                              |  63 +++++-
 src/box/bootstrap.snap                        | Bin 6016 -> 4891 bytes
 src/box/box.cc                                |   1 +
 src/box/func.c                                |   7 -
 src/box/func_def.c                            |   8 -
 src/box/lua/upgrade.lua                       |  16 +-
 src/box/schema.cc                             |   3 +
 src/box/schema.h                              |   1 +
 src/box/sql.c                                 |   1 +
 src/box/sql.h                                 |   9 +
 src/box/sql/analyze.c                         |  12 ++
 src/box/sql/expr.c                            |  23 +--
 src/box/sql/func.c                            | 189 +++++++++++++-----
 src/box/sql/resolve.c                         |  22 +-
 src/box/sql/sqlInt.h                          |  20 +-
 src/box/sql/vdbemem.c                         |   2 +-
 test/box-py/bootstrap.result                  |  66 ------
 test/box/access_bin.result                    |   4 +-
 test/box/access_bin.test.lua                  |   4 +-
 test/box/access_sysview.result                |   8 +-
 test/box/function1.result                     |  39 ++--
 test/box/function1.test.lua                   |  16 +-
 test/sql-tap/func5.test.lua                   |  57 +++++-
 test/wal_off/func_max.result                  |   8 +-
 25 files changed, 338 insertions(+), 248 deletions(-)
 create mode 100644 changelogs/unreleased/gh-6106-remove-sql-built-ins-from-_func.md

-- 
2.25.1


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

* [Tarantool-patches] [PATCH v2 1/6] sql: introduce sql_func_flags()
  2021-08-09  7:18 [Tarantool-patches] [PATCH v2 0/6] Remove SQL built-in functions from _func Mergen Imeev via Tarantool-patches
@ 2021-08-09  7:18 ` Mergen Imeev via Tarantool-patches
  2021-08-09  7:18 ` [Tarantool-patches] [PATCH v2 2/6] sql: introduce sql_func_find() Mergen Imeev via Tarantool-patches
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-08-09  7:18 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

This function returns a set of parameters for the function with the
given name. This function is used when we do not need to call a
function, but we need its parameters.

In addition, this function will allow us to split the parameters
between those that are the same for all implementations, and the
parameters, the value of which is implementation-dependent.

Needed for #6105
Part of #6106
---
 src/box/sql/expr.c   |  9 +++------
 src/box/sql/func.c   | 12 ++++++++++++
 src/box/sql/sqlInt.h | 10 ++++++++++
 3 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index d2624516c..80f2d349a 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -328,11 +328,8 @@ sql_expr_coll(Parse *parse, Expr *p, bool *is_explicit_coll, uint32_t *coll_id,
 		if (op == TK_FUNCTION) {
 			uint32_t arg_count = p->x.pList == NULL ? 0 :
 					     p->x.pList->nExpr;
-			struct func *func =
-				sql_func_by_signature(p->u.zToken, arg_count);
-			if (func == NULL)
-				break;
-			if (sql_func_flag_is_set(func, SQL_FUNC_DERIVEDCOLL) &&
+			uint32_t flags = sql_func_flags(p->u.zToken);
+			if (((flags & SQL_FUNC_DERIVEDCOLL) != 0) &&
 			    arg_count > 0) {
 				/*
 				 * Now we use quite straightforward
@@ -342,7 +339,7 @@ sql_expr_coll(Parse *parse, Expr *p, bool *is_explicit_coll, uint32_t *coll_id,
 				 * built-in functions: trim, upper,
 				 * lower, replace, substr.
 				 */
-				assert(func->def->returns == FIELD_TYPE_STRING);
+				assert(p->type == FIELD_TYPE_STRING);
 				p = p->x.pList->a->pExpr;
 				continue;
 			}
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 6ca852dec..28d383293 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -2655,6 +2655,18 @@ static struct {
 	},
 };
 
+uint32_t
+sql_func_flags(const char *name)
+{
+	struct func *func = func_by_name(name, strlen(name));
+	if (func == NULL || func->def->language != FUNC_LANGUAGE_SQL_BUILTIN)
+		return 0;
+	uint32_t flags = ((struct func_sql_builtin *)func)->flags;
+	if (func->def->aggregate == FUNC_AGGREGATE_GROUP)
+		flags |= SQL_FUNC_AGG;
+	return flags;
+}
+
 static struct func_vtab func_sql_builtin_vtab;
 
 struct func *
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 115c52f96..a92de0a2f 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -1186,6 +1186,8 @@ struct type_def {
  *     SQL_FUNC_LENGTH    ==  OPFLAG_LENGTHARG
  *     SQL_FUNC_TYPEOF    ==  OPFLAG_TYPEOFARG
  */
+/** Function is one of aggregate functions. */
+#define SQL_FUNC_AGG      0x0001
 #define SQL_FUNC_LIKE     0x0004	/* Candidate for the LIKE optimization */
 #define SQL_FUNC_NEEDCOLL 0x0020	/* sqlGetFuncCollSeq() might be called.
 					 * The flag is set when the collation
@@ -4372,6 +4374,14 @@ sql_func_flag_is_set(struct func *func, uint16_t flag)
 struct func *
 sql_func_by_signature(const char *name, int argc);
 
+/**
+ * Return the parameters of the function with the given name. If the function
+ * with the given name does not exist, or the function is not a built-in SQL
+ * function, 0 is returned, which means no parameters have been set.
+ */
+uint32_t
+sql_func_flags(const char *name);
+
 /**
  * Generate VDBE code to halt execution with correct error if
  * the object with specified key is already present (or doesn't
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v2 2/6] sql: introduce sql_func_find()
  2021-08-09  7:18 [Tarantool-patches] [PATCH v2 0/6] Remove SQL built-in functions from _func Mergen Imeev via Tarantool-patches
  2021-08-09  7:18 ` [Tarantool-patches] [PATCH v2 1/6] sql: introduce sql_func_flags() Mergen Imeev via Tarantool-patches
@ 2021-08-09  7:18 ` Mergen Imeev via Tarantool-patches
  2021-08-09  7:18 ` [Tarantool-patches] [PATCH v2 3/6] sql: remove SQL built-in functions from _func Mergen Imeev via Tarantool-patches
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-08-09  7:18 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

This patch introduces the sql_func_find() function. This function allows
us to centralize the look up of functions during parsing, which
simplifies code and fixes some incorrect error messages.

Part of #6106
---
 src/box/sql/analyze.c       | 12 ++++++++++++
 src/box/sql/expr.c          | 14 ++------------
 src/box/sql/func.c          | 38 ++++++++++++++++++++++++-------------
 src/box/sql/resolve.c       | 22 +--------------------
 src/box/sql/sqlInt.h        | 12 ++----------
 src/box/sql/vdbemem.c       |  2 +-
 test/sql-tap/func5.test.lua | 34 ++++++++++++++++++++++++++++++++-
 7 files changed, 76 insertions(+), 58 deletions(-)

diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
index b87f69512..afa2331a1 100644
--- a/src/box/sql/analyze.c
+++ b/src/box/sql/analyze.c
@@ -719,6 +719,10 @@ callStatGet(Vdbe * v, int regStat4, int iParam, int regOut)
 {
 	assert(regOut != regStat4 && regOut != regStat4 + 1);
 	sqlVdbeAddOp2(v, OP_Integer, iParam, regStat4 + 1);
+	/*
+	 * Function sql_func_by_signature() was removed, so after enabling this
+	 * part should be changed.
+	 */
 	struct func *func = sql_func_by_signature("_sql_stat_get", 2);
 	assert(func != NULL);
 	sqlVdbeAddOp4(v, OP_BuiltinFunction0, 0, regStat4, regOut,
@@ -858,6 +862,10 @@ vdbe_emit_analyze_space(struct Parse *parse, struct space *space)
 		sqlVdbeAddOp2(v, OP_Count, idx_cursor, stat4_reg + 3);
 		sqlVdbeAddOp2(v, OP_Integer, part_count, stat4_reg + 1);
 		sqlVdbeAddOp2(v, OP_Integer, part_count, stat4_reg + 2);
+		/*
+		 * Function sql_func_by_signature() was removed, so after
+		 * enabling this part should be changed.
+		 */
 		struct func *init_func =
 			sql_func_by_signature("_sql_stat_init", 3);
 		assert(init_func != NULL);
@@ -959,6 +967,10 @@ vdbe_emit_analyze_space(struct Parse *parse, struct space *space)
 		sqlVdbeAddOp3(v, OP_MakeRecord, stat_key_reg,
 				  pk_part_count, key_reg);
 		assert(chng_reg == (stat4_reg + 1));
+		/*
+		 * Function sql_func_by_signature() was removed, so after
+		 * enabling this part should be changed.
+		 */
 		struct func *push_func =
 			sql_func_by_signature("_sql_stat_push", 3);
 		assert(push_func != NULL);
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index 80f2d349a..20d22455c 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -3957,7 +3957,6 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 	case TK_FUNCTION:{
 			ExprList *pFarg;	/* List of function arguments */
 			int nFarg;	/* Number of function arguments */
-			const char *zId;	/* The function name */
 			u32 constMask = 0;	/* Mask of function arguments that are constant */
 			int i;	/* Loop counter */
 			struct coll *coll = NULL;
@@ -3970,11 +3969,8 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 			}
 			nFarg = pFarg ? pFarg->nExpr : 0;
 			assert(!ExprHasProperty(pExpr, EP_IntValue));
-			zId = pExpr->u.zToken;
-			struct func *func = sql_func_by_signature(zId, nFarg);
+			struct func *func = sql_func_find(pExpr);
 			if (func == NULL) {
-				diag_set(ClientError, ER_NO_SUCH_FUNCTION,
-					 zId);
 				pParse->is_aborted = true;
 				break;
 			}
@@ -5431,14 +5427,8 @@ analyzeAggregate(Walker * pWalker, Expr * pExpr)
 						pItem->iMem = ++pParse->nMem;
 						assert(!ExprHasProperty
 						       (pExpr, EP_IntValue));
-						const char *name =
-							pExpr->u.zToken;
-						uint32_t argc =
-							pExpr->x.pList != NULL ?
-							pExpr->x.pList->nExpr : 0;
 						pItem->func =
-							sql_func_by_signature(
-								name, argc);
+							sql_func_find(pExpr);
 						assert(pItem->func != NULL);
 						assert(pItem->func->def->
 						       language ==
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 28d383293..7cdcce6bc 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -1934,24 +1934,12 @@ sql_is_like_func(struct Expr *expr)
 	    expr->x.pList->nExpr != 2)
 		return 0;
 	assert(!ExprHasProperty(expr, EP_xIsSelect));
-	struct func *func = sql_func_by_signature(expr->u.zToken, 2);
+	struct func *func = sql_func_find(expr);
 	if (func == NULL || !sql_func_flag_is_set(func, SQL_FUNC_LIKE))
 		return 0;
 	return 1;
 }
 
-struct func *
-sql_func_by_signature(const char *name, int argc)
-{
-	struct func *base = func_by_name(name, strlen(name));
-	if (base == NULL || !base->def->exports.sql)
-		return NULL;
-
-	if (base->def->param_count != -1 && base->def->param_count != argc)
-		return NULL;
-	return base;
-}
-
 static int
 func_sql_builtin_call_stub(struct func *func, struct port *args,
 			   struct port *ret)
@@ -2655,6 +2643,30 @@ static struct {
 	},
 };
 
+struct func *
+sql_func_find(struct Expr *expr)
+{
+	const char *name = expr->u.zToken;
+	struct func *func = func_by_name(name, strlen(name));
+	if (func == NULL) {
+		diag_set(ClientError, ER_NO_SUCH_FUNCTION, name);
+		return NULL;
+	}
+	if (!func->def->exports.sql) {
+		diag_set(ClientError, ER_SQL_PARSER_GENERIC,
+			 tt_sprintf("function %s() is not available in SQL",
+				     name));
+		return NULL;
+	}
+	int n = expr->x.pList != NULL ? expr->x.pList->nExpr : 0;
+	if (func->def->param_count != -1 && func->def->param_count != n) {
+		diag_set(ClientError, ER_FUNC_WRONG_ARG_COUNT, name,
+			 tt_sprintf("%d", func->def->param_count), n);
+		return NULL;
+	}
+	return func;
+}
+
 uint32_t
 sql_func_flags(const char *name)
 {
diff --git a/src/box/sql/resolve.c b/src/box/sql/resolve.c
index 11b6139e3..35faddab5 100644
--- a/src/box/sql/resolve.c
+++ b/src/box/sql/resolve.c
@@ -598,28 +598,8 @@ resolveExprStep(Walker * pWalker, Expr * pExpr)
 			assert(!ExprHasProperty(pExpr, EP_xIsSelect));
 			zId = pExpr->u.zToken;
 			nId = sqlStrlen30(zId);
-			struct func *func = func_by_name(zId, nId);
+			struct func *func = sql_func_find(pExpr);
 			if (func == NULL) {
-				diag_set(ClientError, ER_NO_SUCH_FUNCTION, zId);
-				pParse->is_aborted = true;
-				pNC->nErr++;
-				return WRC_Abort;
-			}
-			if (!func->def->exports.sql) {
-				diag_set(ClientError, ER_SQL_PARSER_GENERIC,
-					 tt_sprintf("function %.*s() is not "
-						    "available in SQL",
-						     nId, zId));
-				pParse->is_aborted = true;
-				pNC->nErr++;
-				return WRC_Abort;
-			}
-			if (func->def->param_count != -1 &&
-			    func->def->param_count != n) {
-				uint32_t argc = func->def->param_count;
-				const char *err = tt_sprintf("%d", argc);
-				diag_set(ClientError, ER_FUNC_WRONG_ARG_COUNT,
-					 func->def->name, err, n);
 				pParse->is_aborted = true;
 				pNC->nErr++;
 				return WRC_Abort;
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index a92de0a2f..c6927e1e4 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -4362,17 +4362,9 @@ sql_func_flag_is_set(struct func *func, uint16_t flag)
 	return (((struct func_sql_builtin *)func)->flags & flag) != 0;
 }
 
-/**
- * A SQL method to find a function in a hash by its name and
- * count of arguments. Only functions that have 'SQL' engine
- * export field set true and have exactly the same signature
- * are returned.
- *
- * Returns not NULL function pointer when a valid and exported
- * to SQL engine function is found and NULL otherwise.
- */
+/** Return a function that matches the parameters described in given expr. */
 struct func *
-sql_func_by_signature(const char *name, int argc);
+sql_func_find(struct Expr *expr);
 
 /**
  * Return the parameters of the function with the given name. If the function
diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c
index 2c5099616..499089c8d 100644
--- a/src/box/sql/vdbemem.c
+++ b/src/box/sql/vdbemem.c
@@ -148,7 +148,7 @@ valueFromFunction(sql * db,	/* The database connection */
 	pList = p->x.pList;
 	if (pList)
 		nVal = pList->nExpr;
-	struct func *func = sql_func_by_signature(p->u.zToken, nVal);
+	struct func *func = sql_func_find(p);
 	if (func == NULL || func->def->language != FUNC_LANGUAGE_SQL_BUILTIN ||
 	    !func->def->is_deterministic ||
 	    sql_func_flag_is_set(func, SQL_FUNC_NEEDCOLL))
diff --git a/test/sql-tap/func5.test.lua b/test/sql-tap/func5.test.lua
index 9b1526aaf..13698582b 100755
--- a/test/sql-tap/func5.test.lua
+++ b/test/sql-tap/func5.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 local test = require("sqltester")
-test:plan(25)
+test:plan(27)
 
 --!./tcltestrunner.lua
 -- 2010 August 27
@@ -314,4 +314,36 @@ test:do_execsql_test(
 box.func.COUNTER1:drop()
 box.func.COUNTER2:drop()
 
+--
+-- Make sure the correct error is displayed if the function throws an error when
+-- setting the default value.
+--
+local body = 'function(x) return 1 end'
+box.schema.func.create('F1', {language = 'Lua', returns = 'number', body = body,
+                       param_list = {}, exports = {'LUA'}});
+box.execute([[CREATE TABLE t01(i INT PRIMARY KEY, a INT DEFAULT(f1(1)));]])
+test:do_catchsql_test(
+    "func-7.1",
+    [[
+        INSERT INTO t01(i) VALUES(1);
+    ]], {
+        1, "function F1() is not available in SQL"
+    })
+
+box.schema.func.create('F2', {language = 'Lua', returns = 'number', body = body,
+                       exports = {'LUA', 'SQL'}});
+box.execute([[CREATE TABLE t02(i INT PRIMARY KEY, a INT DEFAULT(f2(1)));]])
+test:do_catchsql_test(
+    "func-7.2",
+    [[
+        INSERT INTO t02(i) VALUES(1);
+    ]], {
+        1, "Wrong number of arguments is passed to F2(): expected 0, got 1"
+    })
+
+box.func.F1:drop()
+box.func.F2:drop()
+box.space.T01:drop()
+box.space.T02:drop()
+
 test:finish_test()
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v2 3/6] sql: remove SQL built-in functions from _func
  2021-08-09  7:18 [Tarantool-patches] [PATCH v2 0/6] Remove SQL built-in functions from _func Mergen Imeev via Tarantool-patches
  2021-08-09  7:18 ` [Tarantool-patches] [PATCH v2 1/6] sql: introduce sql_func_flags() Mergen Imeev via Tarantool-patches
  2021-08-09  7:18 ` [Tarantool-patches] [PATCH v2 2/6] sql: introduce sql_func_find() Mergen Imeev via Tarantool-patches
@ 2021-08-09  7:18 ` Mergen Imeev via Tarantool-patches
  2021-08-09  7:19 ` [Tarantool-patches] [PATCH v2 4/6] alter: parse data dictionary version Mergen Imeev via Tarantool-patches
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-08-09  7:18 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

This patch removes SQL built-in functions from _func. These functions
could be called directly from Lua, however all they did was returned an
error. After this patch, no SQL built-in functions can be called
directly from LUA.

Part of #6106
---
 ...gh-6106-remove-sql-built-ins-from-_func.md |   7 ++
 src/box/alter.cc                              |   7 --
 src/box/bootstrap.snap                        | Bin 6016 -> 4891 bytes
 src/box/box.cc                                |   1 +
 src/box/lua/upgrade.lua                       |  16 +--
 src/box/sql.c                                 |   1 +
 src/box/sql.h                                 |   9 ++
 src/box/sql/func.c                            | 118 +++++++++++++++++-
 test/box-py/bootstrap.result                  |  66 ----------
 test/box/access_bin.result                    |   4 +-
 test/box/access_bin.test.lua                  |   4 +-
 test/box/access_sysview.result                |   8 +-
 test/box/function1.result                     |  32 +----
 test/box/function1.test.lua                   |  13 +-
 test/sql-tap/func5.test.lua                   |  25 +++-
 test/wal_off/func_max.result                  |   8 +-
 16 files changed, 184 insertions(+), 135 deletions(-)
 create mode 100644 changelogs/unreleased/gh-6106-remove-sql-built-ins-from-_func.md

diff --git a/changelogs/unreleased/gh-6106-remove-sql-built-ins-from-_func.md b/changelogs/unreleased/gh-6106-remove-sql-built-ins-from-_func.md
new file mode 100644
index 000000000..02f33dd50
--- /dev/null
+++ b/changelogs/unreleased/gh-6106-remove-sql-built-ins-from-_func.md
@@ -0,0 +1,7 @@
+## feature/sql
+
+* SQL built-in functions were removed from \_func system space (gh-6106).
+* Function are now looked up first in SQL built-in functions and then in
+  user-defined functions.
+* Fixed incorrect error message in case of misuse of the function used to set
+  the default value.
diff --git a/src/box/alter.cc b/src/box/alter.cc
index 390199298..935790df4 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -3548,13 +3548,6 @@ on_replace_dd_func(struct trigger * /* trigger */, void *event)
 				  "function has references");
 			return -1;
 		}
-		/* Can't' drop a builtin function. */
-		if (old_func->def->language == FUNC_LANGUAGE_SQL_BUILTIN) {
-			diag_set(ClientError, ER_DROP_FUNCTION,
-				  (unsigned) old_func->def->uid,
-				  "function is SQL built-in");
-			return -1;
-		}
 		struct trigger *on_commit =
 			txn_alter_trigger_new(on_drop_func_commit, old_func);
 		struct trigger *on_rollback =
diff --git a/src/box/bootstrap.snap b/src/box/bootstrap.snap
index 57374decc0f9de140772d9809a227e3ba4ce61eb..018670d2a6558e64ba691ce0002320b76ac1c97b 100644
GIT binary patch
literal 4891
zcmV+$6XfhuPC-x#FfK7O3RY!ub7^mGIv_GGIW90QF*!CZXEHH4GB;#2VlxU!ZgX^D
zZewLSATlyFFkv?`W-T@_GG#3^Fk@jYIWS>jEjeT|VP;`uIAJ$qW(rnAY;R+0Iv{&}
z3JTS_3%bn`p#aW#B#y(S0000004TLD{Qy|SlmPms=p;rEh}k&+0000005BMOz-BjK
zEcy1k{S!#N{Q$r==I?(gQ&N*D$;g(Zlu6_?<k+ozn>%r8?VM(P)P($NwZDINckgJ^
z4ow1F0tx~pzm0m|MzXw(x3Ni|V<yjWY&yqt6!SQS<2Yh*98)kH#}ALA4II<^VeEko
zV|y{~z=Il(154v=(81FkaZh*TX~4laqS;^^&uB1?X$ELc5rZ?QctHlIc#38)sL?5N
z0gVnBGr6TKwuf}alnFyIWWvybF=1MP7|jb~fzBb1f(mpFaXh9lUSKHr!j!`~v+U&s
zOb)wz$>9WEa+t%EOP4U*GC>$>;Sz>vmM#Bd(enRNmjBZ$SZaABSc>2Zc>DKQ&fPr!
z4Bq~&^*E0e2_T37;|Hu@Tm=G-l^)<YsS3v&JD`Md14$TDaRB3VN&_~}t5LCe9&L)v
zgE*V#&1$tgNHkg=24-cJW@VQ0NI|N3MPY#EwSW|ofA+Lnv{(#wk(}G`=A&sX_JR`S
zf(k5f!6PUayr7W+w*-!EHw27sw*wOJ1|Z;l0S9<bfC2YQWd+<XEh6B4SNBVw$ZB0g
zMYJv_Pj<TBvUD{e@&h>WUVtXv4-K$|1lT)(p}heR!Zs!WU|SFX*oJLOm_$V>35tqJ
zvLq@BNQw7Il6Zdv$a^D5dM|RMcOpi5A5x?&g%ByrAVbRXra*+$egpwG|FGAh`2Z5$
ztC_dqwP}wZw|;lF>3)2axtqKE*{xWQpBRkIt>64R{#oM}H}2nONyRaf#S5-tkbilf
zyJ{s1`uT~$*r<tfX3SC;FIaRHZ@#f$R<fX<7>rF765Blcj?tZ)`V)h(=~H`Pwotd!
zQOSTR48{j&%?fU8@x&G^Q!FLXBL-U&dC+)v;BlXD_lZ}>9UP^@4vx-I2S+(72OSxW
zV~&i%AxB0t`bHf6bOVllw(&+k`^knI=eb53=cxu8XPU+uwJtQ&pmm**#@Bfzo?T|3
z(SI3d^iPHv{r5jc8UKqx#{XfA@qY@282^6}#{a1oU|gkLd@+75ycqu$U5tPHT5$1y
z7F+y}g%<y(S7dR&6<FL~#TED8PlXk=J5y9ayCVe^sHX$svhxskYf*nEiYdH@LJIGn
zh{C5%KvC;z;t5(86He^@WwPCOEzv~xN-)tqpC!8QzNdtf|Kj81lju2lCy&IJ_eUh*
zy%9)wU&ImK6Jdn+LlogtA&98q*)s$Uj~*eu40<{J%b>N{;|XF<_CV;#{)Zs4&)x?h
zu<zjq?0N73d+c}U;rcv0T#sjm>#z69!}}dPyxZ~Oo%cF-w5fv~ZRSu%o7(Ks;hH$)
za7{X0*SzK&96IOG={%j&dFOI?CFe>@z9pyRCD-E0+S+M-`Hk~DUDnR+_Qulfjmz2g
z6_#z^fU|Aej&t>GxZ(dA;`~p84Sj|hdY6HQ-eZ_S!;wL27-G=+4IHwxf}!dSS(2q2
zD->;0g;Kde(Wy57zd)6`Fr}~37GBtz1sAqnp@prtR)K{SR-o}vP~nTzI8yUYNTFr|
z3SVSe!U<nwN`eWs5xz>Gu_57$lQ`a*5x#0tY`#b}Uu(Wd5v0CIG7Uk^*Cs&_VUwFo
z6M`l`06~*cX*8+H+Xo~G6-AQi(~Z0$Qxxhpolm#vqqpfc`P1kAeRlFb`)qbGb0;xx
zQ_Nxxf8Q?d(A-U%t4Rn{b?i^n>gw!(@t?P<V}IIQMKZw6x6cr@x_VSV$6sIj{nc{*
z#r@mivgF^6n^1VC_5G~Y=LRtpw}Jb5>$99Mf1h_QJN_87KGX5|`>xeae$Kxl?xJ|L
z{O;$+edn{b<?YwpvUulz@-F8FavPR-PjO$Jb$;xZz^?fA8QNSmBESl@yDF3QYvwY}
z3JQZeTU{+Gf`i(vO7!Gk(DJGiqJ6RE+@`-99>4qLe!t)6pzh8ku457Zop&bw9t+OK
zrxW&8t2S}+2DQ67)a2i?^H3*V9p?T%`Da0mbI7%`xUuey)m5PZo^VF}&F@glRhbB2
z-V*1($+7Oowa&c#j`tJKU0H3O|J9m*cB=*r?ZMi1wLZ7?nG2u#qPg3?I5sy-;>4Z%
z_qsJyYG6>m#AWW5c>KKGRiN6tz26+x=J|8mYaEETnEgJpuzCAfV7B<Xrq9CV-B@ed
zR4`lf<Xy~?f?>@^^1Irmg+JC9v>@&shZwZ_wliw&)LMIQWI_Q10kDM0IYuc7O0on<
z2_|{}9!Zi~og+ZBI!2J>+s<a4B1dXoM2yh9h7{q^W;L2k^b$g(W+%uH8j#wny)kOe
z9jS=fX6^h4GDi6TGDh|IF-DD1KR#-)+N(WUt-YVy4OV-#SL^d-B@3#(r>8UzSnWNf
zc=W09?g$koReL`b2oY?ACu!;jSAL>mUv5fJv!^3eb`t#|Uzzk+Q0?WMmdqNfRkEbo
z>(i$XpSp!$*msQPeP)$CVz62zOVS;ir_a?V<d?OHJ6HW_!kTxiFKgRr>T0Y?hE#hy
zm*CCSS|vjot%%`h-n?D{!{vh_1`U3?h51M(m?w;mC=atc`Y7fdKP{<_{fYHGKE+&x
zRmqS<CNX4iR8!!_MMp+Q;N{xrckKNwDmua-|BR+kv1En`SC_&Xl`2$bRcf=M8d8)b
zq$o2Q5-o=~YL?6};imTJ(StXCVV_}EoFy|%I2aFimeR35rAUF|HXUkR0=q(Hgwuer
z5Lf^AZTeQw11ivF)eg#V@MVMAMT0JA>XkEBGEl-m=>jD)RJvGF8CVjTAF4J<V`gGz
z7R)L@3WG!e64Mcwqc2lOUW~dJO)zD|MYe@XrllwgRS_1VC88@t5{&+iP9kVxr3nO0
z9vG@Jq%@QiiwQYUsiyQ)p$3GgFqy)nRx2%N2BVtVgHNZtPn{IT{bRv^YR^hmgtRYi
z&#m9i%@ThtsTlq;+Ogkxap(WBx0`40v9~zXGz{#r+Hln`MceMi*5@sde^}q+tUk-D
zItrKO-_`}qb91fl-!jLwalfV(sPp*2`8(hK{pOz~L(8k+0@uXKb-b}?eU`&jHK&$=
zlB2@^e*5g-YSk|av=PPJzs;&$j!rD9?@#^Nta`-=&D~T=K*Tzuxtm)3>icD_|KTPZ
z=fao=hOej-l!ux^GcqC~1xZ1Y4kH^_5SPOaCLI%iz`??Sp`tN37K}tO5SR6sWoSf5
zL_rIZRE7iI500$DeGtt5`hq=Avp%7-=jrx0Bzp!km_+(9%*PshP)cQ9AO9UUj4SFE
z)Y+ZT<T^?WGb5DSR3TiBV%e}xtc`_)tQ&X)l+1pa(nsCmW80BH`cABk1S<dDs-^3I
zVz!(+MyNim_(V@Bi^Ijd&|hH<DTan3oQc4Z#}OkRR%f8SO9=LeFSa=MV2NL(Y*!5u
znQp0;>^8^GEl3fVoLl9F%G36L4>SNA5|2KN_<s%u4l4|vGWsQ+9*$WR_5-Xu)2)ku
zsF$ap@;O!RGG!*7RIIOfWDDAsh0SIi1TzTx126I0vXAe+eI~65#P=Dxkl;A8E!t7J
z9CkOyWmgZgHq&KS54)zt<3)Q_l{>`S{_UT7@lFM)+oB-UO6U2vdD*&AlO9A}d5*YB
zwYP4;kVm4ORd5|sxg26O!)IUNFy5*eF29fXkT(>h&mUya6L7ODhjdwO{sD?64Goo<
zE4ugErvbwi+<%6&xO}~rsnJ7ZP?7nmM!OU@<H!)m&(M|5!~(6S&uD5G;a~qg7BlP4
zsx|p_>zhNQPtQ_myjQFpD;Vc0mX&tp-jSKCsq(`H2smpA^RcwFA}Hy%+-rmT5jZak
zM;AJiQj3@Y6q>6VFdv1$>mnpoH1;lGkd`B-E|Lr8ygBlyy1$W+xtM2;GG98K<9U~n
z7gRS^>SOZ{14p&A60hJ1pRv2G-29;Mj>4M>pa%<!pWXE&49FP5$fpO%SMMKY#(>PS
zG1Og4f*?3{L9q3#G%sy>5Pyg^C3ioES;7h`8qr@XCeaq(v`M!*dQ)D5AaeE@etyyX
zH!Y?6V@Eu~=?HB0K$O*`jYd&`dTLZ*+5*8v<lotL98CeG4M^L{)!cacXTUueree@F
zf`27z5q1vSvFW;w=E$-ro5DP_4S(d?w{BQkO@VqCIuG79o5zg`r{mR8H*CnEOET@+
z(+{xOnIq|KrfRf7py*r_WY|9LHS4hJdfQW_h(KoqPav4?R@#wE5S40~d>W8rgNe`i
zFo<UynjPdb&4FbxhBlPZx@!lMRx3r^Z4f5|7;K!qwwOe7lCOv$wr=O#GjoF(5jj(E
zh97edC!b~cNQlr@$ZXJpUwG=Un}A}!H73Sy6^Q=6SdgQBs;9&aT?&lb{dq%msi@`Y
zGqc$$R!NaB^QJ5n&7ng8sYN&bo+aFwlal}zpA-+2ryM<H<vYY_<<!FI{QX1zlG^?E
z;30N!q5K3nrF;rt^$1vWFpt<kIZyl>JBmz`<KkZ%fLGgL7absZGzL~)=xq#H#`nqj
z{>>o4prnnP^UL@&ns8y?*=|5xNdkU9_dLT4SZIbzKYp)q`K(`xdZ=!rZ09y5r^=Qy
zWSb6F3woTYf$f}va^w^ZjrLM65wDM78iZsoc_{Q7rEhN%l*{b|G9A&u2M0I0gF<21
zPqi&gA&)>eHQPec14I(Mh|mS_6NhsMJj0g>!zRayqON<2AYrHmF%->0ki<qG5Stup
zCPSCVMAP^mfcV9jh?N3e92esKDr=Z$6=m(%7V~687#A@NaRI`H<J%iK1W5Q5VX(|w
zC0O;Wj3hZFqNi)kkM(8-k_)#58sRi2sm+pbpi_pR$Dj&kbeTl4$c9D;l9`j((zoP9
zoo5I=FO?yNCPWBLK1|~y<`4cf1l9KZ<DEIg$A5m;&73zPFBcO}a3nM*MM=!5NG;<d
z#e}rI6_H?>0gR_6AoE6X4Lqaqocux}T3*Coh%QOU79%4C<)%;jia6q|HW(GnMih%b
zk>xL@NmMgNjVymA%Hp9HDn}QI`0Bb_ccnl3B-_Sedcbn@vc^e7tbN|q0?<Jzrtx1O
z^dQYsy)1^zG^&Y)iYxM{v-)6Elo=@<y*D89A+6brMk|aLoaP(yv189{C<PmlHok8{
z;wM_R8i5qFJuLkT;x=!!!Kg_xqAdR0h=e2BSPY426em0N7v!$a%9GJaV$v%9OwgH7
z>VK<<X+=cR1t5o>YCC7s#L{-e=_nC0Ekv&Q1fl1pGQ`k?2%*WFhQw*;0lE%itCa?Z
zGc@7TGK0%fa9qO~KAkhXgoG@Ti~>#>QSht(ib;a44wYLv09;>l2+L<q#s;3jX$zm!
zpb)7+hNR<A0cLQSM6k#vQ}<*Px*-m2*FYpXlwpP5{ZA!QTt+dNkmV<gZhZvsdJjLq
zPC05cjNuYgCH+1^HFRRxX5@`o(uX8-Q6CRfxwKYBESE!QC`|ZQ?5^lzsMFZK>3I2G
z=c+J_fpF~f*2C_v8&C0E7zp`Ns9=vOt_GOk#Dmb)DYC@dyd+vqsr7<YG{h%@N{J-S
z=GrP43r7Adh=f3ovB|m)deIn{f|(GM+?!0-!557AkRUPwk7uj18p4v%J_#cykYjDq
zPJ^(@r<n2y8CPUBzGsdvq<o?EwT7!q1hwXpYKca*%5ehZyGAqFj%JXCIy7cUj(xH+
zTE6j~;}0O-XPdKVPScExbr1+)K4z139YCQ)&kP?J=#*Yj&VTsKBp37#%Y>Wg9OJ$3
zk10CAG?wA2Jb6bRNEETqR~En+GsO$!Ok_a`t4t%tQv8bm*B&_cco)8Xp3(ExIL%{Y
zctun;t#Hc+I)-{UXbC}!vx&*0BlyNC&P9^fTlO0|x7`LonTG{Z=l1{(i*H*k^oG&P
zzx2o^peAv!);<|4RkP+<IqDqRtla^h0!k+%xZb+~M0Djz5JeKfd#a1<O)I0XPE;~a
z0naWWC-xdzfYrhob;y^4hlB@-MB%dTLD08wv=^Y^!5{?TO__TRV%eeS7a6q%+7X7I
z4db7I1Ruz((-1hojv)qr=9&!B0aWAH&I2PMJ_!ZysavyX!(_s8P5ww*-VTehg+lz0
zN(O0cnX^PpVv14%cdV<`0q8n`m?lWz?2-oAl?kN5UpdA*0zJ~-HU*QXBbSp4xPBEP
zGFGdbRn=7nEKDRM*Yp}*Gahwr8i?e1DCF;ovrKJNpjf7>%p|3vl6tAGGc72aOUmWC
zny931Dyg$1^K2cx)O|Hb%7B<KtVFTgHNjQ6K1)jGW*gZ>_P+=?fX6T)^@1*Nz;l7r
N%A%IFAG*~Lt?fbwP8<LL

literal 6016
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

diff --git a/src/box/box.cc b/src/box/box.cc
index 8dc3b130b..66e658fc3 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -3041,6 +3041,7 @@ box_free(void)
 		gc_free();
 		engine_shutdown();
 		wal_free();
+		sql_built_in_functions_cache_free();
 	}
 }
 
diff --git a/src/box/lua/upgrade.lua b/src/box/lua/upgrade.lua
index 97afc0b4d..6abce50f4 100644
--- a/src/box/lua/upgrade.lua
+++ b/src/box/lua/upgrade.lua
@@ -1003,19 +1003,19 @@ end
 --------------------------------------------------------------------------------
 -- Tarantool 2.9.1
 --------------------------------------------------------------------------------
-local function sql_builtin_function_uuid()
+local function remove_sql_builtin_functions_from_func()
     local _func = box.space._func
     local _priv = box.space._priv
-    local datetime = os.date("%Y-%m-%d %H:%M:%S")
-    local t = _func:auto_increment({ADMIN, 'UUID', 1, 'SQL_BUILTIN', '',
-                                    'function', {}, 'any', 'none', 'none',
-                                    false, false, true, {}, setmap({}), '',
-                                    datetime, datetime})
-    _priv:replace{ADMIN, PUBLIC, 'function', t.id, box.priv.X}
+    for _, v in _func:pairs() do
+        if v.language == "SQL_BUILTIN" then
+            _priv:delete({2, 'function', v.id})
+            _func:delete({v.id})
+        end
+    end
 end
 
 local function upgrade_to_2_9_1()
-    sql_builtin_function_uuid()
+    remove_sql_builtin_functions_from_func()
 end
 
 --------------------------------------------------------------------------------
diff --git a/src/box/sql.c b/src/box/sql.c
index 433264abe..f18dfa063 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -75,6 +75,7 @@ sql_init(void)
 		panic("failed to initialize SQL subsystem");
 
 	sql_stmt_cache_init();
+	sql_built_in_functions_cache_init();
 
 	assert(db != NULL);
 }
diff --git a/src/box/sql.h b/src/box/sql.h
index 4c364306c..2ac97c762 100644
--- a/src/box/sql.h
+++ b/src/box/sql.h
@@ -56,6 +56,15 @@ sql_init(void);
 struct sql *
 sql_get(void);
 
+/** Initialize global cache for built-in functions. */
+void
+sql_built_in_functions_cache_init(void);
+
+/** Free global cache for built-in functions. */
+void
+sql_built_in_functions_cache_free(void);
+
+
 struct Expr;
 struct Parse;
 struct Select;
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 7cdcce6bc..2a3a5d457 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -47,6 +47,10 @@
 #include <unicode/ucol.h>
 #include "box/coll_id_cache.h"
 #include "box/schema.h"
+#include "box/user.h"
+#include "assoc.h"
+
+static struct mh_strnptr_t *built_in_functions = NULL;
 
 static const unsigned char *
 mem_as_ustr(struct Mem *mem)
@@ -2643,11 +2647,49 @@ static struct {
 	},
 };
 
+static struct func *
+built_in_func_get(const char *name)
+{
+	uint32_t len = strlen(name);
+	mh_int_t k = mh_strnptr_find_inp(built_in_functions, name, len);
+	if (k == mh_end(built_in_functions))
+		return NULL;
+	return mh_strnptr_node(built_in_functions, k)->val;
+}
+
+static void
+built_in_func_put(struct func *func)
+{
+	const char *name = func->def->name;
+	uint32_t len = strlen(name);
+	assert(built_in_func_get(name) == NULL);
+
+	uint32_t hash = mh_strn_hash(name, len);
+	const struct mh_strnptr_node_t strnode = {name, len, hash, func};
+	mh_int_t k = mh_strnptr_put(built_in_functions, &strnode, NULL, NULL);
+	if (k == mh_end(built_in_functions)) {
+		panic("Out of memory on insertion into SQL built-in functions "
+		      "hash");
+	}
+}
+
 struct func *
 sql_func_find(struct Expr *expr)
 {
 	const char *name = expr->u.zToken;
-	struct func *func = func_by_name(name, strlen(name));
+	int n = expr->x.pList ? expr->x.pList->nExpr : 0;
+	struct func *func = built_in_func_get(name);
+	if (func != NULL) {
+		assert(func->def->exports.sql);
+		int param_count = func->def->param_count;
+		if (param_count != -1 && param_count != n) {
+			diag_set(ClientError, ER_FUNC_WRONG_ARG_COUNT, name,
+				 tt_sprintf("%d", func->def->param_count), n);
+			return NULL;
+		}
+		return func;
+	}
+	func = func_by_name(name, strlen(name));
 	if (func == NULL) {
 		diag_set(ClientError, ER_NO_SUCH_FUNCTION, name);
 		return NULL;
@@ -2658,8 +2700,7 @@ sql_func_find(struct Expr *expr)
 				     name));
 		return NULL;
 	}
-	int n = expr->x.pList != NULL ? expr->x.pList->nExpr : 0;
-	if (func->def->param_count != -1 && func->def->param_count != n) {
+	if (func->def->param_count != n) {
 		diag_set(ClientError, ER_FUNC_WRONG_ARG_COUNT, name,
 			 tt_sprintf("%d", func->def->param_count), n);
 		return NULL;
@@ -2670,9 +2711,10 @@ sql_func_find(struct Expr *expr)
 uint32_t
 sql_func_flags(const char *name)
 {
-	struct func *func = func_by_name(name, strlen(name));
-	if (func == NULL || func->def->language != FUNC_LANGUAGE_SQL_BUILTIN)
+	struct func *func = built_in_func_get(name);
+	if (func == NULL)
 		return 0;
+	assert(func->def->language == FUNC_LANGUAGE_SQL_BUILTIN);
 	uint32_t flags = ((struct func_sql_builtin *)func)->flags;
 	if (func->def->aggregate == FUNC_AGGREGATE_GROUP)
 		flags |= SQL_FUNC_AGG;
@@ -2681,6 +2723,72 @@ sql_func_flags(const char *name)
 
 static struct func_vtab func_sql_builtin_vtab;
 
+void
+sql_built_in_functions_cache_init(void)
+{
+	built_in_functions = mh_strnptr_new();
+	if (built_in_functions == NULL)
+		panic("Out of memory on creating SQL built-in functions hash");
+	for (uint32_t i = 0; i < nelem(sql_builtins); ++i) {
+		const char *name = sql_builtins[i].name;
+		if (!sql_builtins[i].export_to_sql)
+			continue;
+		uint32_t len = strlen(name);
+		uint32_t size = sizeof(struct func_def) + len + 1;
+		struct func_def *def = malloc(size);
+		if (def == NULL)
+			panic("Out of memory on creating SQL built-in");
+		def->fid = i;
+		def->uid = 1;
+		def->body = NULL;
+		def->comment = NULL;
+		def->setuid = true;
+		def->is_deterministic = sql_builtins[i].is_deterministic;
+		def->is_sandboxed = false;
+		def->param_count = sql_builtins[i].param_count;
+		def->returns = sql_builtins[i].returns;
+		def->aggregate = sql_builtins[i].aggregate;
+		def->language = FUNC_LANGUAGE_SQL_BUILTIN;
+		def->name_len = len;
+		def->exports.sql = sql_builtins[i].export_to_sql;
+		func_opts_create(&def->opts);
+		memcpy(def->name, name, len + 1);
+
+		struct func_sql_builtin *func = malloc(sizeof(*func));
+		if (func == NULL)
+			panic("Out of memory on creating SQL built-in");
+
+		func->base.def = def;
+		func->base.vtab = &func_sql_builtin_vtab;
+		credentials_create_empty(&func->base.owner_credentials);
+		memset(func->base.access, 0, sizeof(func->base.access));
+
+		func->flags = sql_builtins[i].flags;
+		func->call = sql_builtins[i].call;
+		func->finalize = sql_builtins[i].finalize;
+		built_in_func_put(&func->base);
+	}
+}
+
+void
+sql_built_in_functions_cache_free(void)
+{
+	if (built_in_functions == NULL)
+		return;
+	for (uint32_t i = 0; i < nelem(sql_builtins); ++i) {
+		const char *name = sql_builtins[i].name;
+		uint32_t len = strlen(name);
+		mh_int_t k = mh_strnptr_find_inp(built_in_functions, name, len);
+		if (k == mh_end(built_in_functions))
+			continue;
+		struct func *func = mh_strnptr_node(built_in_functions, k)->val;
+		mh_strnptr_del(built_in_functions, k, NULL);
+		func_delete(func);
+	}
+	assert(mh_size(built_in_functions) == 0);
+	mh_strnptr_delete(built_in_functions);
+}
+
 struct func *
 func_sql_builtin_new(struct func_def *def)
 {
diff --git a/test/box-py/bootstrap.result b/test/box-py/bootstrap.result
index b2328487c..cea440c64 100644
--- a/test/box-py/bootstrap.result
+++ b/test/box-py/bootstrap.result
@@ -176,73 +176,7 @@ box.space._priv:select{}
   - [1, 0, 'universe', 0, 24]
   - [1, 1, 'universe', 0, 4294967295]
   - [1, 2, 'function', 1, 4]
-  - [1, 2, 'function', 2, 4]
-  - [1, 2, 'function', 3, 4]
-  - [1, 2, 'function', 4, 4]
-  - [1, 2, 'function', 5, 4]
-  - [1, 2, 'function', 6, 4]
-  - [1, 2, 'function', 7, 4]
-  - [1, 2, 'function', 8, 4]
-  - [1, 2, 'function', 9, 4]
-  - [1, 2, 'function', 10, 4]
-  - [1, 2, 'function', 11, 4]
-  - [1, 2, 'function', 12, 4]
-  - [1, 2, 'function', 13, 4]
-  - [1, 2, 'function', 14, 4]
-  - [1, 2, 'function', 15, 4]
-  - [1, 2, 'function', 16, 4]
-  - [1, 2, 'function', 17, 4]
-  - [1, 2, 'function', 18, 4]
-  - [1, 2, 'function', 19, 4]
-  - [1, 2, 'function', 20, 4]
-  - [1, 2, 'function', 21, 4]
-  - [1, 2, 'function', 22, 4]
-  - [1, 2, 'function', 23, 4]
-  - [1, 2, 'function', 24, 4]
-  - [1, 2, 'function', 25, 4]
-  - [1, 2, 'function', 26, 4]
-  - [1, 2, 'function', 27, 4]
-  - [1, 2, 'function', 28, 4]
-  - [1, 2, 'function', 29, 4]
-  - [1, 2, 'function', 30, 4]
-  - [1, 2, 'function', 31, 4]
-  - [1, 2, 'function', 32, 4]
-  - [1, 2, 'function', 33, 4]
-  - [1, 2, 'function', 34, 4]
-  - [1, 2, 'function', 35, 4]
-  - [1, 2, 'function', 36, 4]
-  - [1, 2, 'function', 37, 4]
-  - [1, 2, 'function', 38, 4]
-  - [1, 2, 'function', 39, 4]
-  - [1, 2, 'function', 40, 4]
-  - [1, 2, 'function', 41, 4]
-  - [1, 2, 'function', 42, 4]
-  - [1, 2, 'function', 43, 4]
-  - [1, 2, 'function', 44, 4]
-  - [1, 2, 'function', 45, 4]
-  - [1, 2, 'function', 46, 4]
-  - [1, 2, 'function', 47, 4]
-  - [1, 2, 'function', 48, 4]
-  - [1, 2, 'function', 49, 4]
-  - [1, 2, 'function', 50, 4]
-  - [1, 2, 'function', 51, 4]
-  - [1, 2, 'function', 52, 4]
-  - [1, 2, 'function', 53, 4]
-  - [1, 2, 'function', 54, 4]
-  - [1, 2, 'function', 55, 4]
-  - [1, 2, 'function', 56, 4]
-  - [1, 2, 'function', 57, 4]
-  - [1, 2, 'function', 58, 4]
-  - [1, 2, 'function', 59, 4]
-  - [1, 2, 'function', 60, 4]
-  - [1, 2, 'function', 61, 4]
-  - [1, 2, 'function', 62, 4]
-  - [1, 2, 'function', 63, 4]
-  - [1, 2, 'function', 64, 4]
   - [1, 2, 'function', 65, 4]
-  - [1, 2, 'function', 66, 4]
-  - [1, 2, 'function', 67, 4]
-  - [1, 2, 'function', 68, 4]
   - [1, 2, 'space', 276, 2]
   - [1, 2, 'space', 277, 1]
   - [1, 2, 'space', 281, 1]
diff --git a/test/box/access_bin.result b/test/box/access_bin.result
index aeb8b3bd8..7c720192f 100644
--- a/test/box/access_bin.result
+++ b/test/box/access_bin.result
@@ -295,10 +295,10 @@ test:drop()
 box.schema.user.grant('guest', 'execute', 'universe')
 ---
 ...
-function f1() return box.space._func:get(1)[4] end
+function f1() return box.space._func.index[2]:get({'f1'})[4] end
 ---
 ...
-function f2() return box.space._func:get(69)[4] end
+function f2() return box.space._func.index[2]:get({'f1'})[4] end
 ---
 ...
 box.schema.func.create('f1')
diff --git a/test/box/access_bin.test.lua b/test/box/access_bin.test.lua
index 954266858..e82ec759c 100644
--- a/test/box/access_bin.test.lua
+++ b/test/box/access_bin.test.lua
@@ -111,8 +111,8 @@ test:drop()
 --
 -- notice that guest can execute stuff, but can't read space _func
 box.schema.user.grant('guest', 'execute', 'universe')
-function f1() return box.space._func:get(1)[4] end
-function f2() return box.space._func:get(69)[4] end
+function f1() return box.space._func.index[2]:get({'f1'})[4] end
+function f2() return box.space._func.index[2]:get({'f1'})[4] end
 box.schema.func.create('f1')
 box.schema.func.create('f2',{setuid=true})
 c = net.connect(box.cfg.listen)
diff --git a/test/box/access_sysview.result b/test/box/access_sysview.result
index d7a7b7534..071fc8de2 100644
--- a/test/box/access_sysview.result
+++ b/test/box/access_sysview.result
@@ -258,11 +258,11 @@ box.session.su('guest')
 ...
 #box.space._vpriv:select{}
 ---
-- 83
+- 17
 ...
 #box.space._vfunc:select{}
 ---
-- 68
+- 2
 ...
 #box.space._vcollation:select{}
 ---
@@ -290,11 +290,11 @@ box.session.su('guest')
 ...
 #box.space._vpriv:select{}
 ---
-- 83
+- 17
 ...
 #box.space._vfunc:select{}
 ---
-- 68
+- 2
 ...
 #box.space._vsequence:select{}
 ---
diff --git a/test/box/function1.result b/test/box/function1.result
index 0166c828f..a49a133f7 100644
--- a/test/box/function1.result
+++ b/test/box/function1.result
@@ -97,7 +97,7 @@ box.func["function1.args"]
   exports:
     lua: true
     sql: false
-  id: 69
+  id: 66
   setuid: false
   is_multikey: false
   is_deterministic: false
@@ -593,7 +593,7 @@ func
   exports:
     lua: true
     sql: false
-  id: 69
+  id: 66
   setuid: false
   is_multikey: false
   is_deterministic: false
@@ -665,7 +665,7 @@ func
   exports:
     lua: true
     sql: false
-  id: 69
+  id: 66
   setuid: false
   is_multikey: false
   is_deterministic: false
@@ -1032,7 +1032,7 @@ box.func.test ~= nil
 box.func.test:drop()
 ---
 ...
--- Check SQL builtins
+-- Make sure there is no SQL built-in functions in _func.
 test_run:cmd("setopt delimiter ';'")
 ---
 - true
@@ -1048,7 +1048,7 @@ sql_builtin_list = {
 	"RANDOMBLOB", "NULLIF", "ZEROBLOB", "MIN", "MAX", "COALESCE", "EVERY",
 	"EXISTS", "EXTRACT", "SOME", "GREATER", "LESSER", "SOUNDEX",
 	"LIKELIHOOD", "LIKELY", "UNLIKELY", "_sql_stat_get", "_sql_stat_push",
-	"_sql_stat_init", "GREATEST", "LEAST"
+	"_sql_stat_init", "GREATEST", "LEAST", "UUID"
 }
 test_run:cmd("setopt delimiter ''");
 ---
@@ -1056,7 +1056,7 @@ test_run:cmd("setopt delimiter ''");
 ok = true
 ---
 ...
-for _, v in pairs(sql_builtin_list) do ok = ok and (box.space._func.index.name:get(v) ~= nil) end
+for _, v in pairs(sql_builtin_list) do ok = ok and (box.space._func.index.name:get(v) == nil) end
 ---
 ...
 ok == true
@@ -1067,26 +1067,6 @@ box.func.LUA:call({"return 1 + 1"})
 ---
 - 2
 ...
-box.schema.user.grant('guest', 'execute', 'function', 'SUM')
----
-...
-c = net.connect(box.cfg.listen)
----
-...
-c:call("SUM")
----
-- error: sql builtin function does not support Lua frontend
-...
-c:close()
----
-...
-box.schema.user.revoke('guest', 'execute', 'function', 'SUM')
----
-...
-box.schema.func.drop("SUM")
----
-- error: 'Can''t drop function 1: function is SQL built-in'
-...
 -- Introduce function options
 box.schema.func.create('test', {body = "function(tuple) return tuple end", is_deterministic = true, opts = {is_multikey = true}})
 ---
diff --git a/test/box/function1.test.lua b/test/box/function1.test.lua
index ab7b586a0..4fdd48520 100644
--- a/test/box/function1.test.lua
+++ b/test/box/function1.test.lua
@@ -363,7 +363,7 @@ f == nil
 box.func.test ~= nil
 box.func.test:drop()
 
--- Check SQL builtins
+-- Make sure there is no SQL built-in functions in _func.
 test_run:cmd("setopt delimiter ';'")
 sql_builtin_list = {
 	"TRIM", "TYPEOF", "PRINTF", "UNICODE", "CHAR", "HEX", "VERSION",
@@ -376,22 +376,15 @@ sql_builtin_list = {
 	"RANDOMBLOB", "NULLIF", "ZEROBLOB", "MIN", "MAX", "COALESCE", "EVERY",
 	"EXISTS", "EXTRACT", "SOME", "GREATER", "LESSER", "SOUNDEX",
 	"LIKELIHOOD", "LIKELY", "UNLIKELY", "_sql_stat_get", "_sql_stat_push",
-	"_sql_stat_init", "GREATEST", "LEAST"
+	"_sql_stat_init", "GREATEST", "LEAST", "UUID"
 }
 test_run:cmd("setopt delimiter ''");
 ok = true
-for _, v in pairs(sql_builtin_list) do ok = ok and (box.space._func.index.name:get(v) ~= nil) end
+for _, v in pairs(sql_builtin_list) do ok = ok and (box.space._func.index.name:get(v) == nil) end
 ok == true
 
 box.func.LUA:call({"return 1 + 1"})
 
-box.schema.user.grant('guest', 'execute', 'function', 'SUM')
-c = net.connect(box.cfg.listen)
-c:call("SUM")
-c:close()
-box.schema.user.revoke('guest', 'execute', 'function', 'SUM')
-box.schema.func.drop("SUM")
-
 -- Introduce function options
 box.schema.func.create('test', {body = "function(tuple) return tuple end", is_deterministic = true, opts = {is_multikey = true}})
 box.func['test'].is_multikey == true
diff --git a/test/sql-tap/func5.test.lua b/test/sql-tap/func5.test.lua
index 13698582b..bd4561afc 100755
--- a/test/sql-tap/func5.test.lua
+++ b/test/sql-tap/func5.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 local test = require("sqltester")
-test:plan(27)
+test:plan(29)
 
 --!./tcltestrunner.lua
 -- 2010 August 27
@@ -346,4 +346,27 @@ box.func.F2:drop()
 box.space.T01:drop()
 box.space.T02:drop()
 
+--
+-- gh-6105:  Make sure that functions that were described in _func but were not
+-- implemented are now removed.
+--
+test:do_catchsql_test(
+    "func-7.3",
+    [[
+        SELECT SQRT();
+    ]], {
+        1, "Function 'SQRT' does not exist"
+    })
+
+-- Make sure that functions are looked up in built-in functions first.
+box.schema.func.create('ABS', {language = 'Lua', param_list = {"INTEGER"},
+                       body = body, returns = 'number', exports = {'LUA'}});
+test:do_execsql_test(
+    "func-7.4",
+    [[
+        SELECT ABS(-111);
+    ]], {
+        111
+    })
+
 test:finish_test()
diff --git a/test/wal_off/func_max.result b/test/wal_off/func_max.result
index cc5bcc141..a3ab5b431 100644
--- a/test/wal_off/func_max.result
+++ b/test/wal_off/func_max.result
@@ -42,11 +42,11 @@ test_run:cmd("setopt delimiter ''");
 ...
 func_limit()
 ---
-- error: 'Failed to create function ''func31933'': function id is too big'
+- error: 'Failed to create function ''func31936'': function id is too big'
 ...
 drop_limit_func()
 ---
-- error: Function 'func31933' does not exist
+- error: Function 'func31936' does not exist
 ...
 box.schema.user.create('testuser')
 ---
@@ -62,11 +62,11 @@ session.su('testuser')
 ...
 func_limit()
 ---
-- error: 'Failed to create function ''func31933'': function id is too big'
+- error: 'Failed to create function ''func31936'': function id is too big'
 ...
 drop_limit_func()
 ---
-- error: Function 'func31933' does not exist
+- error: Function 'func31936' does not exist
 ...
 session.su('admin')
 ---
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v2 4/6] alter: parse data dictionary version
  2021-08-09  7:18 [Tarantool-patches] [PATCH v2 0/6] Remove SQL built-in functions from _func Mergen Imeev via Tarantool-patches
                   ` (2 preceding siblings ...)
  2021-08-09  7:18 ` [Tarantool-patches] [PATCH v2 3/6] sql: remove SQL built-in functions from _func Mergen Imeev via Tarantool-patches
@ 2021-08-09  7:19 ` Mergen Imeev via Tarantool-patches
  2021-08-09  7:19 ` [Tarantool-patches] [PATCH v2 5/6] alter: disallow creation of SQL built-in function Mergen Imeev via Tarantool-patches
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-08-09  7:19 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

Version is needed to disallow creation of SQL built-in functions using
_func starting with 2.9.0.

Needed for #6106
---
 src/box/alter.cc  | 18 ++++++++++++++++++
 src/box/schema.cc |  3 +++
 src/box/schema.h  |  1 +
 3 files changed, 22 insertions(+)

diff --git a/src/box/alter.cc b/src/box/alter.cc
index 935790df4..217b882ba 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -4167,6 +4167,24 @@ on_replace_dd_schema(struct trigger * /* trigger */, void *event)
 			return -1;
 		REPLICASET_UUID = uu;
 		say_info("cluster uuid %s", tt_uuid_str(&uu));
+	} else if (strcmp(key, "version") == 0) {
+		if (new_tuple != NULL) {
+			uint32_t major, minor, patch;
+			if (tuple_field_u32(new_tuple, 1, &major) != 0 ||
+			    tuple_field_u32(new_tuple, 2, &minor) != 0)
+				tnt_raise(ClientError, ER_WRONG_DD_VERSION);
+			/* Version can be major.minor with no patch. */
+			if (tuple_field_u32(new_tuple, 3, &patch) != 0)
+				patch = 0;
+			dd_version_id = version_id(major, minor, patch);
+		} else {
+			assert(old_tuple != NULL);
+			/*
+			 * _schema:delete({'version'}) for
+			 * example, for box.internal.bootstrap().
+			 */
+			dd_version_id = tarantool_version_id();
+		}
 	}
 	return 0;
 }
diff --git a/src/box/schema.cc b/src/box/schema.cc
index 963278b19..5659e15b7 100644
--- a/src/box/schema.cc
+++ b/src/box/schema.cc
@@ -70,6 +70,9 @@ uint32_t schema_version = 0;
  */
 uint32_t space_cache_version = 0;
 
+/** Persistent version of the schema, stored in _schema["version"]. */
+uint32_t dd_version_id = 0;
+
 struct rlist on_schema_init = RLIST_HEAD_INITIALIZER(on_schema_init);
 struct rlist on_alter_space = RLIST_HEAD_INITIALIZER(on_alter_space);
 struct rlist on_alter_sequence = RLIST_HEAD_INITIALIZER(on_alter_sequence);
diff --git a/src/box/schema.h b/src/box/schema.h
index 25ac6f110..d3bbdd590 100644
--- a/src/box/schema.h
+++ b/src/box/schema.h
@@ -44,6 +44,7 @@ struct func;
 
 extern uint32_t schema_version;
 extern uint32_t space_cache_version;
+extern uint32_t dd_version_id;
 
 /** Triggers invoked after schema initialization. */
 extern struct rlist on_schema_init;
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v2 5/6] alter: disallow creation of SQL built-in function
  2021-08-09  7:18 [Tarantool-patches] [PATCH v2 0/6] Remove SQL built-in functions from _func Mergen Imeev via Tarantool-patches
                   ` (3 preceding siblings ...)
  2021-08-09  7:19 ` [Tarantool-patches] [PATCH v2 4/6] alter: parse data dictionary version Mergen Imeev via Tarantool-patches
@ 2021-08-09  7:19 ` Mergen Imeev via Tarantool-patches
  2021-08-09  7:19 ` [Tarantool-patches] [PATCH v2 6/6] sql: remove unnecessary function initialization Mergen Imeev via Tarantool-patches
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-08-09  7:19 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

This patch prohibits creation of user-defined functions with SQL_BUILTIN
engine.

Closes #6106
---
 src/box/alter.cc            | 38 +++++++++++++++++++++++++++++++++++++
 test/box/function1.result   |  7 ++++++-
 test/box/function1.test.lua |  3 +++
 3 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/src/box/alter.cc b/src/box/alter.cc
index 217b882ba..8a4f0b5a6 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -3213,6 +3213,36 @@ on_replace_dd_user(struct trigger * /* trigger */, void *event)
 	return 0;
 }
 
+/**
+ * Check if the version of the data dictionary is lower than 2.9.0 and return
+ * new func def if it is the case. If it is the case, then it is possible to
+ * insert values with the "SQL_BUILTIN" language into _func, otherwise it is
+ * prohibited. This is for upgradeability from 2.1.3 to 2.3.0. Since all we need
+ * is to allow such inserts, we set func def to its default values.
+ */
+static int
+func_def_create_sql_built_in(struct func_def *def)
+{
+	if (dd_version_id >= version_id(2, 9, 0)) {
+		diag_set(ClientError, ER_FUNCTION_LANGUAGE, "SQL_BUILTIN",
+			 def->name);
+		return -1;
+	}
+	def->body = NULL;
+	def->comment = NULL;
+	def->setuid = 1;
+	def->is_deterministic = false;
+	def->is_sandboxed = false;
+	def->param_count = 0;
+	def->returns = FIELD_TYPE_ANY;
+	def->aggregate = FUNC_AGGREGATE_NONE;
+	def->language = FUNC_LANGUAGE_LUA;
+	def->exports.lua = true;
+	def->exports.sql = true;
+	func_opts_create(&def->opts);
+	return 0;
+}
+
 /**
  * Get function identifiers from a tuple.
  *
@@ -3344,6 +3374,14 @@ func_def_new_from_tuple(struct tuple *tuple)
 				  language, def->name);
 			return NULL;
 		}
+		if (def->language == FUNC_LANGUAGE_SQL_BUILTIN) {
+			if (func_def_create_sql_built_in(def) != 0)
+				return NULL;
+			if (func_def_check(def) != 0)
+				return NULL;
+			def_guard.is_active = false;
+			return def;
+		}
 	} else {
 		/* Lua is the default. */
 		def->language = FUNC_LANGUAGE_LUA;
diff --git a/test/box/function1.result b/test/box/function1.result
index a49a133f7..a1c89850d 100644
--- a/test/box/function1.result
+++ b/test/box/function1.result
@@ -372,7 +372,7 @@ c:close()
 box.schema.func.create('WAITFOR', {language = 'SQL_BUILTIN', \
 	param_list = {'integer'}, returns = 'integer',exports = {'SQL'}})
 ---
-- error: 'Failed to create function ''WAITFOR'': given built-in is not predefined'
+- error: Unsupported language 'SQL_BUILTIN' specified for function 'WAITFOR'
 ...
 test_run:cmd("setopt delimiter ';'")
 ---
@@ -1078,3 +1078,8 @@ box.func['test'].is_multikey == true
 box.func['test']:drop()
 ---
 ...
+-- gh-6106: Check that user-defined functions cannot have SQL_BUILTIN engine.
+box.schema.func.create("ABS", {language = 'SQL_BUILTIN', returns = 'integer'})
+---
+- error: Unsupported language 'SQL_BUILTIN' specified for function 'ABS'
+...
diff --git a/test/box/function1.test.lua b/test/box/function1.test.lua
index 4fdd48520..e635b6e18 100644
--- a/test/box/function1.test.lua
+++ b/test/box/function1.test.lua
@@ -389,3 +389,6 @@ box.func.LUA:call({"return 1 + 1"})
 box.schema.func.create('test', {body = "function(tuple) return tuple end", is_deterministic = true, opts = {is_multikey = true}})
 box.func['test'].is_multikey == true
 box.func['test']:drop()
+
+-- gh-6106: Check that user-defined functions cannot have SQL_BUILTIN engine.
+box.schema.func.create("ABS", {language = 'SQL_BUILTIN', returns = 'integer'})
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v2 6/6] sql: remove unnecessary function initialization
  2021-08-09  7:18 [Tarantool-patches] [PATCH v2 0/6] Remove SQL built-in functions from _func Mergen Imeev via Tarantool-patches
                   ` (4 preceding siblings ...)
  2021-08-09  7:19 ` [Tarantool-patches] [PATCH v2 5/6] alter: disallow creation of SQL built-in function Mergen Imeev via Tarantool-patches
@ 2021-08-09  7:19 ` Mergen Imeev via Tarantool-patches
  2021-08-10  7:14 ` [Tarantool-patches] [PATCH v2 0/6] Remove SQL built-in functions from _func Kirill Yukhin via Tarantool-patches
  2021-08-10 13:12 ` Kirill Yukhin via Tarantool-patches
  7 siblings, 0 replies; 12+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-08-09  7:19 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

After removing the SQL built-in functions from _func, the code used to
initialize these SQL built-in functions is no longer used and should be
removed.

Follow-up #6106
---
 src/box/func.c     |  7 -------
 src/box/func_def.c |  8 --------
 src/box/sql/func.c | 49 ----------------------------------------------
 3 files changed, 64 deletions(-)

diff --git a/src/box/func.c b/src/box/func.c
index 731f18a3b..04ae1b958 100644
--- a/src/box/func.c
+++ b/src/box/func.c
@@ -394,10 +394,6 @@ restore_fail:
 static struct func *
 func_c_new(struct func_def *def);
 
-/** Construct a SQL builtin function object. */
-extern struct func *
-func_sql_builtin_new(struct func_def *def);
-
 struct func *
 func_new(struct func_def *def)
 {
@@ -409,9 +405,6 @@ func_new(struct func_def *def)
 	case FUNC_LANGUAGE_LUA:
 		func = func_lua_new(def);
 		break;
-	case FUNC_LANGUAGE_SQL_BUILTIN:
-		func = func_sql_builtin_new(def);
-		break;
 	default:
 		unreachable();
 	}
diff --git a/src/box/func_def.c b/src/box/func_def.c
index 11d2bdb84..630b4a43c 100644
--- a/src/box/func_def.c
+++ b/src/box/func_def.c
@@ -116,14 +116,6 @@ func_def_check(struct func_def *def)
 			return -1;
 		}
 		break;
-	case FUNC_LANGUAGE_SQL_BUILTIN:
-		if (def->body != NULL || def->is_sandboxed) {
-			diag_set(ClientError, ER_CREATE_FUNCTION, def->name,
-				 "body and is_sandboxed options are not compatible "
-				 "with SQL language");
-			return -1;
-		}
-		break;
 	default:
 		break;
 	}
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 2a3a5d457..50014b756 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -2789,55 +2789,6 @@ sql_built_in_functions_cache_free(void)
 	mh_strnptr_delete(built_in_functions);
 }
 
-struct func *
-func_sql_builtin_new(struct func_def *def)
-{
-	assert(def->language == FUNC_LANGUAGE_SQL_BUILTIN);
-	/** Binary search for corresponding builtin entry. */
-	int idx = -1, left = 0, right = nelem(sql_builtins) - 1;
-	while (left <= right) {
-		uint32_t mid = (left + right) / 2;
-		int rc = strcmp(def->name, sql_builtins[mid].name);
-		if (rc == 0) {
-			idx = mid;
-			break;
-		}
-		if (rc < 0)
-			right = mid - 1;
-		else
-			left = mid + 1;
-	}
-	/*
-	 * All SQL built-in(s) (stubs) are defined in a snapshot.
-	 * Implementation-specific metadata is defined in
-	 * sql_builtins list. When a definition were not found
-	 * above, the function name is invalid, i.e. it is
-	 * not built-in function.
-	 */
-	if (idx == -1) {
-		diag_set(ClientError, ER_CREATE_FUNCTION, def->name,
-			 "given built-in is not predefined");
-		return NULL;
-	}
-	struct func_sql_builtin *func =
-		(struct func_sql_builtin *) calloc(1, sizeof(*func));
-	if (func == NULL) {
-		diag_set(OutOfMemory, sizeof(*func), "malloc", "func");
-		return NULL;
-	}
-	func->base.def = def;
-	func->base.vtab = &func_sql_builtin_vtab;
-	func->flags = sql_builtins[idx].flags;
-	func->call = sql_builtins[idx].call;
-	func->finalize = sql_builtins[idx].finalize;
-	def->param_count = sql_builtins[idx].param_count;
-	def->is_deterministic = sql_builtins[idx].is_deterministic;
-	def->returns = sql_builtins[idx].returns;
-	def->aggregate = sql_builtins[idx].aggregate;
-	def->exports.sql = sql_builtins[idx].export_to_sql;
-	return &func->base;
-}
-
 static void
 func_sql_builtin_destroy(struct func *func)
 {
-- 
2.25.1


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

* Re: [Tarantool-patches] [PATCH v2 0/6] Remove SQL built-in functions from _func
  2021-08-09  7:18 [Tarantool-patches] [PATCH v2 0/6] Remove SQL built-in functions from _func Mergen Imeev via Tarantool-patches
                   ` (5 preceding siblings ...)
  2021-08-09  7:19 ` [Tarantool-patches] [PATCH v2 6/6] sql: remove unnecessary function initialization Mergen Imeev via Tarantool-patches
@ 2021-08-10  7:14 ` Kirill Yukhin via Tarantool-patches
  2021-08-10 12:52   ` Vitaliia Ioffe via Tarantool-patches
  2021-08-10 13:12 ` Kirill Yukhin via Tarantool-patches
  7 siblings, 1 reply; 12+ messages in thread
From: Kirill Yukhin via Tarantool-patches @ 2021-08-10  7:14 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches

Hello,

On 09 авг 10:18, imeevma@tarantool.org wrote:
> This patch-set removes SQL built-in functions from _func and prohibits functions
> with SQL_BUILTIN language to be decribed in _func system space.
> 
> https://github.com/tarantool/tarantool/issues/6106
> https://github.com/tarantool/tarantool/tree/imeevma/gh-6106-remove-sql-builtins-from-_func

The patchset LGTM.

--
Regards, Kirill Yukhin

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

* Re: [Tarantool-patches]  [PATCH v2 0/6] Remove SQL built-in functions from _func
  2021-08-10  7:14 ` [Tarantool-patches] [PATCH v2 0/6] Remove SQL built-in functions from _func Kirill Yukhin via Tarantool-patches
@ 2021-08-10 12:52   ` Vitaliia Ioffe via Tarantool-patches
  0 siblings, 0 replies; 12+ messages in thread
From: Vitaliia Ioffe via Tarantool-patches @ 2021-08-10 12:52 UTC (permalink / raw)
  To: Kirill Yukhin; +Cc: tarantool-patches

[-- Attachment #1: Type: text/plain, Size: 610 bytes --]


Hi team, 
 
QA LGTM.
 
 
--
Vitaliia Ioffe
 
  
>Вторник, 10 августа 2021, 10:14 +03:00 от Kirill Yukhin via Tarantool-patches <tarantool-patches@dev.tarantool.org>:
> 
>Hello,
>
>On 09 авг 10:18,  imeevma@tarantool.org wrote:
>> This patch-set removes SQL built-in functions from _func and prohibits functions
>> with SQL_BUILTIN language to be decribed in _func system space.
>>
>>  https://github.com/tarantool/tarantool/issues/6106
>>  https://github.com/tarantool/tarantool/tree/imeevma/gh-6106-remove-sql-builtins-from-_func
>The patchset LGTM.
>
>--
>Regards, Kirill Yukhin
 

[-- Attachment #2: Type: text/html, Size: 1390 bytes --]

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

* Re: [Tarantool-patches] [PATCH v2 0/6] Remove SQL built-in functions from _func
  2021-08-09  7:18 [Tarantool-patches] [PATCH v2 0/6] Remove SQL built-in functions from _func Mergen Imeev via Tarantool-patches
                   ` (6 preceding siblings ...)
  2021-08-10  7:14 ` [Tarantool-patches] [PATCH v2 0/6] Remove SQL built-in functions from _func Kirill Yukhin via Tarantool-patches
@ 2021-08-10 13:12 ` Kirill Yukhin via Tarantool-patches
  7 siblings, 0 replies; 12+ messages in thread
From: Kirill Yukhin via Tarantool-patches @ 2021-08-10 13:12 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches

Hello,

On 09 авг 10:18, imeevma@tarantool.org wrote:
> This patch-set removes SQL built-in functions from _func and prohibits functions
> with SQL_BUILTIN language to be decribed in _func system space.
> 
> https://github.com/tarantool/tarantool/issues/6106
> https://github.com/tarantool/tarantool/tree/imeevma/gh-6106-remove-sql-builtins-from-_func

I've checked your patch set into master.

--
Regards, Kirill Yukhin

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

* Re: [Tarantool-patches] [PATCH v2 6/6] sql: remove unnecessary function initialization
  2021-08-04 12:58 ` [Tarantool-patches] [PATCH v2 6/6] sql: remove unnecessary function initialization Mergen Imeev via Tarantool-patches
@ 2021-08-06 19:59   ` Mergen Imeev via Tarantool-patches
  0 siblings, 0 replies; 12+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-08-06 19:59 UTC (permalink / raw)
  To: v.shpilevoy, tarantool-patches

I removed SQL built-ins support from func_def_check(). Diff and new patch below.

On Wed, Aug 04, 2021 at 03:58:47PM +0300, Mergen Imeev via Tarantool-patches wrote:
> After removing the SQL built-in functions from _func, the code used to
> initialize these SQL built-in functions is no longer used and should be
> removed.
> 
> Follow-up #6106
> ---
>  src/box/func.c     |  7 -------
>  src/box/sql/func.c | 49 ----------------------------------------------
>  2 files changed, 56 deletions(-)
> 
> diff --git a/src/box/func.c b/src/box/func.c
> index 731f18a3b..04ae1b958 100644
> --- a/src/box/func.c
> +++ b/src/box/func.c
> @@ -394,10 +394,6 @@ restore_fail:
>  static struct func *
>  func_c_new(struct func_def *def);
>  
> -/** Construct a SQL builtin function object. */
> -extern struct func *
> -func_sql_builtin_new(struct func_def *def);
> -
>  struct func *
>  func_new(struct func_def *def)
>  {
> @@ -409,9 +405,6 @@ func_new(struct func_def *def)
>  	case FUNC_LANGUAGE_LUA:
>  		func = func_lua_new(def);
>  		break;
> -	case FUNC_LANGUAGE_SQL_BUILTIN:
> -		func = func_sql_builtin_new(def);
> -		break;
>  	default:
>  		unreachable();
>  	}
> diff --git a/src/box/sql/func.c b/src/box/sql/func.c
> index 2a3a5d457..50014b756 100644
> --- a/src/box/sql/func.c
> +++ b/src/box/sql/func.c
> @@ -2789,55 +2789,6 @@ sql_built_in_functions_cache_free(void)
>  	mh_strnptr_delete(built_in_functions);
>  }
>  
> -struct func *
> -func_sql_builtin_new(struct func_def *def)
> -{
> -	assert(def->language == FUNC_LANGUAGE_SQL_BUILTIN);
> -	/** Binary search for corresponding builtin entry. */
> -	int idx = -1, left = 0, right = nelem(sql_builtins) - 1;
> -	while (left <= right) {
> -		uint32_t mid = (left + right) / 2;
> -		int rc = strcmp(def->name, sql_builtins[mid].name);
> -		if (rc == 0) {
> -			idx = mid;
> -			break;
> -		}
> -		if (rc < 0)
> -			right = mid - 1;
> -		else
> -			left = mid + 1;
> -	}
> -	/*
> -	 * All SQL built-in(s) (stubs) are defined in a snapshot.
> -	 * Implementation-specific metadata is defined in
> -	 * sql_builtins list. When a definition were not found
> -	 * above, the function name is invalid, i.e. it is
> -	 * not built-in function.
> -	 */
> -	if (idx == -1) {
> -		diag_set(ClientError, ER_CREATE_FUNCTION, def->name,
> -			 "given built-in is not predefined");
> -		return NULL;
> -	}
> -	struct func_sql_builtin *func =
> -		(struct func_sql_builtin *) calloc(1, sizeof(*func));
> -	if (func == NULL) {
> -		diag_set(OutOfMemory, sizeof(*func), "malloc", "func");
> -		return NULL;
> -	}
> -	func->base.def = def;
> -	func->base.vtab = &func_sql_builtin_vtab;
> -	func->flags = sql_builtins[idx].flags;
> -	func->call = sql_builtins[idx].call;
> -	func->finalize = sql_builtins[idx].finalize;
> -	def->param_count = sql_builtins[idx].param_count;
> -	def->is_deterministic = sql_builtins[idx].is_deterministic;
> -	def->returns = sql_builtins[idx].returns;
> -	def->aggregate = sql_builtins[idx].aggregate;
> -	def->exports.sql = sql_builtins[idx].export_to_sql;
> -	return &func->base;
> -}
> -
>  static void
>  func_sql_builtin_destroy(struct func *func)
>  {
> -- 
> 2.25.1
> 


Diff:

diff --git a/src/box/func_def.c b/src/box/func_def.c
index 11d2bdb84..630b4a43c 100644
--- a/src/box/func_def.c
+++ b/src/box/func_def.c
@@ -116,14 +116,6 @@ func_def_check(struct func_def *def)
 			return -1;
 		}
 		break;
-	case FUNC_LANGUAGE_SQL_BUILTIN:
-		if (def->body != NULL || def->is_sandboxed) {
-			diag_set(ClientError, ER_CREATE_FUNCTION, def->name,
-				 "body and is_sandboxed options are not compatible "
-				 "with SQL language");
-			return -1;
-		}
-		break;
 	default:
 		break;
 	}



New patch:

commit 79871a45476aca400ecb921a44550a3807c309ca
Author: Mergen Imeev <imeevma@gmail.com>
Date:   Sat Jul 31 13:09:07 2021 +0300

    sql: remove unnecessary function initialization
    
    After removing the SQL built-in functions from _func, the code used to
    initialize these SQL built-in functions is no longer used and should be
    removed.
    
    Follow-up #6106

diff --git a/src/box/func.c b/src/box/func.c
index 731f18a3b..04ae1b958 100644
--- a/src/box/func.c
+++ b/src/box/func.c
@@ -394,10 +394,6 @@ restore_fail:
 static struct func *
 func_c_new(struct func_def *def);
 
-/** Construct a SQL builtin function object. */
-extern struct func *
-func_sql_builtin_new(struct func_def *def);
-
 struct func *
 func_new(struct func_def *def)
 {
@@ -409,9 +405,6 @@ func_new(struct func_def *def)
 	case FUNC_LANGUAGE_LUA:
 		func = func_lua_new(def);
 		break;
-	case FUNC_LANGUAGE_SQL_BUILTIN:
-		func = func_sql_builtin_new(def);
-		break;
 	default:
 		unreachable();
 	}
diff --git a/src/box/func_def.c b/src/box/func_def.c
index 11d2bdb84..630b4a43c 100644
--- a/src/box/func_def.c
+++ b/src/box/func_def.c
@@ -116,14 +116,6 @@ func_def_check(struct func_def *def)
 			return -1;
 		}
 		break;
-	case FUNC_LANGUAGE_SQL_BUILTIN:
-		if (def->body != NULL || def->is_sandboxed) {
-			diag_set(ClientError, ER_CREATE_FUNCTION, def->name,
-				 "body and is_sandboxed options are not compatible "
-				 "with SQL language");
-			return -1;
-		}
-		break;
 	default:
 		break;
 	}
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 2a3a5d457..50014b756 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -2789,55 +2789,6 @@ sql_built_in_functions_cache_free(void)
 	mh_strnptr_delete(built_in_functions);
 }
 
-struct func *
-func_sql_builtin_new(struct func_def *def)
-{
-	assert(def->language == FUNC_LANGUAGE_SQL_BUILTIN);
-	/** Binary search for corresponding builtin entry. */
-	int idx = -1, left = 0, right = nelem(sql_builtins) - 1;
-	while (left <= right) {
-		uint32_t mid = (left + right) / 2;
-		int rc = strcmp(def->name, sql_builtins[mid].name);
-		if (rc == 0) {
-			idx = mid;
-			break;
-		}
-		if (rc < 0)
-			right = mid - 1;
-		else
-			left = mid + 1;
-	}
-	/*
-	 * All SQL built-in(s) (stubs) are defined in a snapshot.
-	 * Implementation-specific metadata is defined in
-	 * sql_builtins list. When a definition were not found
-	 * above, the function name is invalid, i.e. it is
-	 * not built-in function.
-	 */
-	if (idx == -1) {
-		diag_set(ClientError, ER_CREATE_FUNCTION, def->name,
-			 "given built-in is not predefined");
-		return NULL;
-	}
-	struct func_sql_builtin *func =
-		(struct func_sql_builtin *) calloc(1, sizeof(*func));
-	if (func == NULL) {
-		diag_set(OutOfMemory, sizeof(*func), "malloc", "func");
-		return NULL;
-	}
-	func->base.def = def;
-	func->base.vtab = &func_sql_builtin_vtab;
-	func->flags = sql_builtins[idx].flags;
-	func->call = sql_builtins[idx].call;
-	func->finalize = sql_builtins[idx].finalize;
-	def->param_count = sql_builtins[idx].param_count;
-	def->is_deterministic = sql_builtins[idx].is_deterministic;
-	def->returns = sql_builtins[idx].returns;
-	def->aggregate = sql_builtins[idx].aggregate;
-	def->exports.sql = sql_builtins[idx].export_to_sql;
-	return &func->base;
-}
-
 static void
 func_sql_builtin_destroy(struct func *func)
 {

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

* [Tarantool-patches] [PATCH v2 6/6] sql: remove unnecessary function initialization
  2021-08-04 12:58 Mergen Imeev via Tarantool-patches
@ 2021-08-04 12:58 ` Mergen Imeev via Tarantool-patches
  2021-08-06 19:59   ` Mergen Imeev via Tarantool-patches
  0 siblings, 1 reply; 12+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-08-04 12:58 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: tarantool-patches

After removing the SQL built-in functions from _func, the code used to
initialize these SQL built-in functions is no longer used and should be
removed.

Follow-up #6106
---
 src/box/func.c     |  7 -------
 src/box/sql/func.c | 49 ----------------------------------------------
 2 files changed, 56 deletions(-)

diff --git a/src/box/func.c b/src/box/func.c
index 731f18a3b..04ae1b958 100644
--- a/src/box/func.c
+++ b/src/box/func.c
@@ -394,10 +394,6 @@ restore_fail:
 static struct func *
 func_c_new(struct func_def *def);
 
-/** Construct a SQL builtin function object. */
-extern struct func *
-func_sql_builtin_new(struct func_def *def);
-
 struct func *
 func_new(struct func_def *def)
 {
@@ -409,9 +405,6 @@ func_new(struct func_def *def)
 	case FUNC_LANGUAGE_LUA:
 		func = func_lua_new(def);
 		break;
-	case FUNC_LANGUAGE_SQL_BUILTIN:
-		func = func_sql_builtin_new(def);
-		break;
 	default:
 		unreachable();
 	}
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 2a3a5d457..50014b756 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -2789,55 +2789,6 @@ sql_built_in_functions_cache_free(void)
 	mh_strnptr_delete(built_in_functions);
 }
 
-struct func *
-func_sql_builtin_new(struct func_def *def)
-{
-	assert(def->language == FUNC_LANGUAGE_SQL_BUILTIN);
-	/** Binary search for corresponding builtin entry. */
-	int idx = -1, left = 0, right = nelem(sql_builtins) - 1;
-	while (left <= right) {
-		uint32_t mid = (left + right) / 2;
-		int rc = strcmp(def->name, sql_builtins[mid].name);
-		if (rc == 0) {
-			idx = mid;
-			break;
-		}
-		if (rc < 0)
-			right = mid - 1;
-		else
-			left = mid + 1;
-	}
-	/*
-	 * All SQL built-in(s) (stubs) are defined in a snapshot.
-	 * Implementation-specific metadata is defined in
-	 * sql_builtins list. When a definition were not found
-	 * above, the function name is invalid, i.e. it is
-	 * not built-in function.
-	 */
-	if (idx == -1) {
-		diag_set(ClientError, ER_CREATE_FUNCTION, def->name,
-			 "given built-in is not predefined");
-		return NULL;
-	}
-	struct func_sql_builtin *func =
-		(struct func_sql_builtin *) calloc(1, sizeof(*func));
-	if (func == NULL) {
-		diag_set(OutOfMemory, sizeof(*func), "malloc", "func");
-		return NULL;
-	}
-	func->base.def = def;
-	func->base.vtab = &func_sql_builtin_vtab;
-	func->flags = sql_builtins[idx].flags;
-	func->call = sql_builtins[idx].call;
-	func->finalize = sql_builtins[idx].finalize;
-	def->param_count = sql_builtins[idx].param_count;
-	def->is_deterministic = sql_builtins[idx].is_deterministic;
-	def->returns = sql_builtins[idx].returns;
-	def->aggregate = sql_builtins[idx].aggregate;
-	def->exports.sql = sql_builtins[idx].export_to_sql;
-	return &func->base;
-}
-
 static void
 func_sql_builtin_destroy(struct func *func)
 {
-- 
2.25.1


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

end of thread, other threads:[~2021-08-10 13:12 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-09  7:18 [Tarantool-patches] [PATCH v2 0/6] Remove SQL built-in functions from _func Mergen Imeev via Tarantool-patches
2021-08-09  7:18 ` [Tarantool-patches] [PATCH v2 1/6] sql: introduce sql_func_flags() Mergen Imeev via Tarantool-patches
2021-08-09  7:18 ` [Tarantool-patches] [PATCH v2 2/6] sql: introduce sql_func_find() Mergen Imeev via Tarantool-patches
2021-08-09  7:18 ` [Tarantool-patches] [PATCH v2 3/6] sql: remove SQL built-in functions from _func Mergen Imeev via Tarantool-patches
2021-08-09  7:19 ` [Tarantool-patches] [PATCH v2 4/6] alter: parse data dictionary version Mergen Imeev via Tarantool-patches
2021-08-09  7:19 ` [Tarantool-patches] [PATCH v2 5/6] alter: disallow creation of SQL built-in function Mergen Imeev via Tarantool-patches
2021-08-09  7:19 ` [Tarantool-patches] [PATCH v2 6/6] sql: remove unnecessary function initialization Mergen Imeev via Tarantool-patches
2021-08-10  7:14 ` [Tarantool-patches] [PATCH v2 0/6] Remove SQL built-in functions from _func Kirill Yukhin via Tarantool-patches
2021-08-10 12:52   ` Vitaliia Ioffe via Tarantool-patches
2021-08-10 13:12 ` Kirill Yukhin via Tarantool-patches
  -- strict thread matches above, loose matches on Subject: below --
2021-08-04 12:58 Mergen Imeev via Tarantool-patches
2021-08-04 12:58 ` [Tarantool-patches] [PATCH v2 6/6] sql: remove unnecessary function initialization Mergen Imeev via Tarantool-patches
2021-08-06 19:59   ` Mergen Imeev via Tarantool-patches

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