[Tarantool-patches] [PATCH v2 4/5] sql: separate function flags from functions

imeevma at tarantool.org imeevma at tarantool.org
Wed Aug 18 17:35:03 MSK 2021


This patch separates function flags from function definition. This
allows us not to look for a function where we need its flags, but not
the function itself. It also allows us to search for a function after
the function arguments have been properly initialized, which will help
us to check the types of those arguments.

Part of #6105
---
 src/box/sql/expr.c    |  49 +++++++--------
 src/box/sql/func.c    | 137 +++++++++++++++++++++++++++++++++++++-----
 src/box/sql/parse.y   |  82 ++++++++++++-------------
 src/box/sql/resolve.c |  33 ++++------
 src/box/sql/select.c  |  12 ++--
 src/box/sql/sqlInt.h  |  20 +++---
 6 files changed, 214 insertions(+), 119 deletions(-)

diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index 6c24dc09a..0544539d2 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -351,7 +351,7 @@ sql_expr_coll(Parse *parse, Expr *p, bool *is_explicit_coll, uint32_t *coll_id,
 		if (op == TK_BUILT_IN_FUNC) {
 			uint32_t arg_count = p->x.pList == NULL ? 0 :
 					     p->x.pList->nExpr;
-			uint32_t flags = sql_func_flags(p->u.zToken);
+			uint32_t flags = sql_func_flags(p->func_id);
 			if (((flags & SQL_FUNC_DERIVEDCOLL) != 0) &&
 			    arg_count > 0) {
 				/*
@@ -1219,7 +1219,7 @@ sqlExprFunction(Parse * pParse, ExprList * pList, Token * pToken)
 
 struct Expr *
 sql_expr_new_built_in(struct Parse *parser, struct ExprList *list,
-		      struct Token *token)
+		      struct Token *token, uint8_t id)
 {
 	struct sql *db = parser->db;
 	assert(token != NULL);
@@ -1231,6 +1231,7 @@ sql_expr_new_built_in(struct Parse *parser, struct ExprList *list,
 		return NULL;
 	}
 	new_expr->x.pList = list;
+	new_expr->func_id = id;
 	assert(!ExprHasProperty(new_expr, EP_xIsSelect));
 	sqlExprSetHeightAndFlags(parser, new_expr);
 	return new_expr;
@@ -1513,6 +1514,8 @@ sql_expr_dup(struct sql *db, struct Expr *p, int flags, char **buffer)
 			nToken = sqlStrlen30(p->u.zToken) + 1;
 		else
 			nToken = 0;
+		if (p->op == TK_BUILT_IN_FUNC)
+			pNew->func_id = p->func_id;
 		if (flags) {
 			assert(ExprHasProperty(p, EP_Reduced) == 0);
 			memcpy(zAlloc, p, nNewSize);
@@ -1549,7 +1552,6 @@ sql_expr_dup(struct sql *db, struct Expr *p, int flags, char **buffer)
 					sql_expr_list_dup(db, p->x.pList, flags);
 			}
 		}
-
 		/* Fill in pNew->pLeft and pNew->pRight. */
 		if (ExprHasProperty(pNew, EP_Reduced | EP_TokenOnly)) {
 			zAlloc += dupedExprNodeSize(p, flags);
@@ -4022,21 +4024,17 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 			}
 			nFarg = pFarg ? pFarg->nExpr : 0;
 			assert(!ExprHasProperty(pExpr, EP_IntValue));
-			struct func *func = sql_func_find(pExpr);
-			if (func == NULL) {
-				pParse->is_aborted = true;
-				break;
-			}
+			uint32_t flags = sql_func_flags(pExpr->func_id);
 			/* Attempt a direct implementation of the built-in COALESCE() and
 			 * IFNULL() functions.  This avoids unnecessary evaluation of
 			 * arguments past the first non-NULL argument.
 			 */
-			if (sql_func_flag_is_set(func, SQL_FUNC_COALESCE)) {
+			if ((flags & SQL_FUNC_COALESCE) != 0) {
 				int endCoalesce = sqlVdbeMakeLabel(v);
 				if (nFarg < 2) {
 					diag_set(ClientError,
 						 ER_FUNC_WRONG_ARG_COUNT,
-						 func->def->name,
+						 pExpr->u.zToken,
 						 "at least two", nFarg);
 					pParse->is_aborted = true;
 					break;
@@ -4062,11 +4060,11 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 			/* The UNLIKELY() function is a no-op.  The result is the value
 			 * of the first argument.
 			 */
-			if (sql_func_flag_is_set(func, SQL_FUNC_UNLIKELY)) {
+			if ((flags & SQL_FUNC_UNLIKELY) != 0) {
 				if (nFarg < 1) {
 					diag_set(ClientError,
 						 ER_FUNC_WRONG_ARG_COUNT,
-						 func->def->name,
+						 pExpr->u.zToken,
 						 "at least one", nFarg);
 					pParse->is_aborted = true;
 					break;
@@ -4092,8 +4090,7 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 			 * is done using ANSI rules from
 			 * collations_check_compatibility().
 			 */
-			if (sql_func_flag_is_set(func, SQL_FUNC_NEEDCOLL) &&
-			    nFarg > 0) {
+			if ((flags & SQL_FUNC_NEEDCOLL) != 0 && nFarg > 0) {
 				struct coll *unused = NULL;
 				uint32_t curr_id = COLL_NONE;
 				bool is_curr_forced = false;
@@ -4140,8 +4137,8 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 				 * or OPFLAG_TYPEOFARG respectively, to avoid unnecessary data
 				 * loading.
 				 */
-				if (sql_func_flag_is_set(func, SQL_FUNC_LENGTH |
-							       SQL_FUNC_TYPEOF)) {
+				if ((flags & (SQL_FUNC_LENGTH |
+					      SQL_FUNC_TYPEOF)) != 0) {
 					u8 exprOp;
 					assert(nFarg == 1);
 					assert(pFarg->a[0].pExpr != 0);
@@ -4164,10 +4161,15 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 			} else {
 				r1 = 0;
 			}
-			if (sql_func_flag_is_set(func, SQL_FUNC_NEEDCOLL)) {
+			if ((flags & SQL_FUNC_NEEDCOLL) != 0) {
 				sqlVdbeAddOp4(v, OP_CollSeq, 0, 0, 0,
 						  (char *)coll, P4_COLLSEQ);
 			}
+			struct func *func = sql_func_find(pExpr);
+			if (func == NULL) {
+				pParse->is_aborted = true;
+				break;
+			}
 			sqlVdbeAddOp4(v, OP_BuiltinFunction0, constMask, r1,
 				      target, (char *)func, P4_FUNC);
 			sqlVdbeChangeP5(v, (u8) nFarg);
@@ -5470,15 +5472,10 @@ analyzeAggregate(Walker * pWalker, Expr * pExpr)
 						pItem->iMem = ++pParse->nMem;
 						assert(!ExprHasProperty
 						       (pExpr, EP_IntValue));
-						pItem->func =
-							sql_func_find(pExpr);
-						assert(pItem->func != NULL);
-						assert(pItem->func->def->
-						       language ==
-						       FUNC_LANGUAGE_SQL_BUILTIN &&
-						       pItem->func->def->
-						       aggregate ==
-						       FUNC_AGGREGATE_GROUP);
+						pItem->flags =
+							sql_func_flags(pExpr->func_id);
+						assert((pItem->flags &
+							SQL_FUNC_AGG) != 0);
 						if (pExpr->flags & EP_Distinct) {
 							pItem->iDistinct =
 								pParse->nTab++;
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 492960443..29235ed62 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -1907,8 +1907,7 @@ sql_is_like_func(struct Expr *expr)
 	    expr->x.pList->nExpr != 2)
 		return 0;
 	assert(!ExprHasProperty(expr, EP_xIsSelect));
-	struct func *func = sql_func_find(expr);
-	if (func == NULL || !sql_func_flag_is_set(func, SQL_FUNC_LIKE))
+	if ((sql_func_flags(expr->func_id) & SQL_FUNC_LIKE) == 0)
 		return 0;
 	return 1;
 }
@@ -2677,19 +2676,6 @@ sql_func_find(struct Expr *expr)
 	return func;
 }
 
-uint32_t
-sql_func_flags(const char *name)
-{
-	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;
-	return flags;
-}
-
 static struct func_vtab func_sql_builtin_vtab;
 
 void
@@ -2770,3 +2756,124 @@ static struct func_vtab func_sql_builtin_vtab = {
 	.call = func_sql_builtin_call_stub,
 	.destroy = func_sql_builtin_destroy,
 };
+
+uint32_t
+sql_func_flags(uint8_t id)
+{
+	switch(id) {
+	case TK_ABS:
+	case TK_CHAR:
+	case TK_CHAR_LEN:
+	case TK_HEX:
+	case TK_PRINTF:
+	case TK_QUOTE:
+	case TK_ROUND:
+	case TK_ROW_COUNT:
+	case TK_SOUNDEX:
+	case TK_UNICODE:
+	case TK_VERSION:
+	case TK_ZEROBLOB:
+		return SQL_FUNC_DETERM;
+	case TK_AVG:
+	case TK_COUNT:
+	case TK_GROUP_CONCAT:
+	case TK_SUM:
+	case TK_TOTAL:
+		return SQL_FUNC_AGG;
+	case TK_COALESCE:
+	case TK_IFNULL:
+		return SQL_FUNC_COALESCE | SQL_FUNC_DETERM;
+	case TK_GREATEST:
+		return SQL_FUNC_MAX | SQL_FUNC_NEEDCOLL | SQL_FUNC_DETERM;
+	case TK_LEAST:
+		return SQL_FUNC_MIN | SQL_FUNC_NEEDCOLL | SQL_FUNC_DETERM;
+	case TK_LENGTH:
+		return SQL_FUNC_LENGTH | SQL_FUNC_DETERM;
+	case TK_LIKE_KW:
+		return SQL_FUNC_LIKE | SQL_FUNC_NEEDCOLL | SQL_FUNC_DETERM;
+	case TK_LIKELIHOOD:
+	case TK_LIKELY:
+	case TK_UNLIKELY:
+		return SQL_FUNC_UNLIKELY | SQL_FUNC_DETERM;
+	case TK_LOWER:
+	case TK_UPPER:
+		return SQL_FUNC_DERIVEDCOLL | SQL_FUNC_NEEDCOLL |
+		       SQL_FUNC_DETERM;
+	case TK_MAX:
+		return SQL_FUNC_MAX | SQL_FUNC_AGG | SQL_FUNC_NEEDCOLL;
+	case TK_MIN:
+		return SQL_FUNC_MIN | SQL_FUNC_AGG | SQL_FUNC_NEEDCOLL;
+	case TK_NULLIF:
+	case TK_POSITION:
+		return SQL_FUNC_NEEDCOLL | SQL_FUNC_DETERM;
+	case TK_RANDOM:
+	case TK_RANDOMBLOB:
+	case TK_UUID:
+		return 0;
+	case TK_REPLACE:
+	case TK_SUBSTR:
+	case TK_TRIM:
+		return SQL_FUNC_DERIVEDCOLL | SQL_FUNC_DETERM;
+	case TK_TYPEOF:
+		return SQL_FUNC_TYPEOF | SQL_FUNC_DETERM;
+	default:
+		unreachable();
+	}
+	return 0;
+}
+
+enum field_type
+sql_func_result(struct Expr *expr)
+{
+	switch(expr->func_id) {
+	case TK_ABS:
+	case TK_AVG:
+	case TK_SUM:
+	case TK_TOTAL:
+		return FIELD_TYPE_NUMBER;
+	case TK_CHAR:
+	case TK_GROUP_CONCAT:
+	case TK_HEX:
+	case TK_LOWER:
+	case TK_PRINTF:
+	case TK_QUOTE:
+	case TK_REPLACE:
+	case TK_SOUNDEX:
+	case TK_SUBSTR:
+	case TK_TRIM:
+	case TK_TYPEOF:
+	case TK_UNICODE:
+	case TK_UPPER:
+	case TK_VERSION:
+		return FIELD_TYPE_STRING;
+	case TK_CHAR_LEN:
+	case TK_COUNT:
+	case TK_LENGTH:
+	case TK_LIKE_KW:
+	case TK_POSITION:
+	case TK_RANDOM:
+	case TK_ROUND:
+	case TK_ROW_COUNT:
+		return FIELD_TYPE_INTEGER;
+	case TK_COALESCE:
+	case TK_GREATEST:
+	case TK_IFNULL:
+	case TK_LEAST:
+	case TK_MAX:
+	case TK_MIN:
+	case TK_NULLIF:
+		return FIELD_TYPE_SCALAR;
+	case TK_LIKELIHOOD:
+	case TK_LIKELY:
+	case TK_UNLIKELY:
+		return FIELD_TYPE_BOOLEAN;
+	case TK_RANDOMBLOB:
+	case TK_ZEROBLOB:
+		return FIELD_TYPE_VARBINARY;
+	case TK_UUID:
+		return FIELD_TYPE_UUID;
+	default:
+		unreachable();
+	}
+	return field_type_MAX;
+}
diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y
index 2327482ec..4a4ca96c3 100644
--- a/src/box/sql/parse.y
+++ b/src/box/sql/parse.y
@@ -1125,7 +1125,7 @@ expr(A) ::= CAST(X) LP expr(E) AS typedef(T) RP(Y). {
 }
 
 expr(A) ::= TRIM(X) LP trim_operands(Y) RP(E). {
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_TRIM);
   spanSet(&A, &X, &E);
 }
 
@@ -1179,7 +1179,7 @@ expr(A) ::= ABS(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_ABS);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1192,7 +1192,7 @@ expr(A) ::= AVG(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_AVG);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1206,7 +1206,7 @@ expr(A) ::= CHAR(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_CHAR);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1221,7 +1221,7 @@ expr(A) ::= CHAR_LEN(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_CHAR_LEN);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1237,7 +1237,7 @@ expr(A) ::= COALESCE(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_COALESCE);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1250,14 +1250,14 @@ expr(A) ::= COUNT(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_COUNT);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
 }
 
 expr(A) ::= COUNT(X) LP STAR RP(E). {
-  A.pExpr = sql_expr_new_built_in(pParse, NULL, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, NULL, &X, TK_COUNT);
   spanSet(&A, &X, &E);
 }
 
@@ -1271,7 +1271,7 @@ expr(A) ::= GREATEST(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_GREATEST);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1285,7 +1285,7 @@ expr(A) ::= GROUP_CONCAT(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_GROUP_CONCAT);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1298,7 +1298,7 @@ expr(A) ::= HEX(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_HEX);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1311,7 +1311,7 @@ expr(A) ::= IFNULL(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_IFNULL);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1327,7 +1327,7 @@ expr(A) ::= LEAST(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_LEAST);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1340,7 +1340,7 @@ expr(A) ::= LENGTH(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_LENGTH);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1353,7 +1353,7 @@ expr(A) ::= LIKELIHOOD(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_LIKELIHOOD);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1366,7 +1366,7 @@ expr(A) ::= LIKELY(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_LIKELY);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1379,7 +1379,7 @@ expr(A) ::= LOWER(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_LOWER);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1392,7 +1392,7 @@ expr(A) ::= MAX(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_MAX);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1405,7 +1405,7 @@ expr(A) ::= MIN(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_MIN);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1418,7 +1418,7 @@ expr(A) ::= NULLIF(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_NULLIF);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1431,7 +1431,7 @@ expr(A) ::= POSITION(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_POSITION);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1445,7 +1445,7 @@ expr(A) ::= PRINTF(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_PRINTF);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1458,7 +1458,7 @@ expr(A) ::= QUOTE(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_QUOTE);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1470,7 +1470,7 @@ expr(A) ::= RANDOM(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_RANDOM);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1483,7 +1483,7 @@ expr(A) ::= RANDOMBLOB(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_RANDOMBLOB);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1496,7 +1496,7 @@ expr(A) ::= REPLACE(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_REPLACE);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1510,7 +1510,7 @@ expr(A) ::= ROUND(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_ROUND);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1522,7 +1522,7 @@ expr(A) ::= ROW_COUNT(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_ROW_COUNT);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1535,7 +1535,7 @@ expr(A) ::= SOUNDEX(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_SOUNDEX);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1549,7 +1549,7 @@ expr(A) ::= SUBSTR(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_SUBSTR);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1562,7 +1562,7 @@ expr(A) ::= SUM(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_SUM);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1575,7 +1575,7 @@ expr(A) ::= TOTAL(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_TOTAL);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1588,7 +1588,7 @@ expr(A) ::= TYPEOF(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_TYPEOF);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1601,7 +1601,7 @@ expr(A) ::= UNICODE(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_UNICODE);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1614,7 +1614,7 @@ expr(A) ::= UNLIKELY(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_UNLIKELY);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1627,7 +1627,7 @@ expr(A) ::= UPPER(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_UPPER);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1640,7 +1640,7 @@ expr(A) ::= UUID(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_UUID);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1652,7 +1652,7 @@ expr(A) ::= VERSION(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_VERSION);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1665,7 +1665,7 @@ expr(A) ::= ZEROBLOB(X) LP distinct(D) exprlist(Y) RP(E). {
     pParse->is_aborted = true;
     return;
   }
-  A.pExpr = sql_expr_new_built_in(pParse, Y, &X);
+  A.pExpr = sql_expr_new_built_in(pParse, Y, &X, TK_ZEROBLOB);
   spanSet(&A, &X, &E);
   if(D == SF_Distinct && A.pExpr)
     A.pExpr->flags |= EP_Distinct;
@@ -1753,7 +1753,7 @@ expr(A) ::= expr(A) likeop(OP) expr(Y).  [LIKE_KW]  {
   OP.n &= 0x7fffffff;
   pList = sql_expr_list_append(pParse->db,NULL, Y.pExpr);
   pList = sql_expr_list_append(pParse->db,pList, A.pExpr);
-  A.pExpr = sql_expr_new_built_in(pParse, pList, &OP);
+  A.pExpr = sql_expr_new_built_in(pParse, pList, &OP, TK_LIKE_KW);
   exprNot(pParse, bNot, &A);
   A.zEnd = Y.zEnd;
   if( A.pExpr ) A.pExpr->flags |= EP_InfixFunc;
@@ -1765,7 +1765,7 @@ expr(A) ::= expr(A) likeop(OP) expr(Y) ESCAPE expr(E).  [LIKE_KW]  {
   pList = sql_expr_list_append(pParse->db,NULL, Y.pExpr);
   pList = sql_expr_list_append(pParse->db,pList, A.pExpr);
   pList = sql_expr_list_append(pParse->db,pList, E.pExpr);
-  A.pExpr = sql_expr_new_built_in(pParse, pList, &OP);
+  A.pExpr = sql_expr_new_built_in(pParse, pList, &OP, TK_LIKE_KW);
   exprNot(pParse, bNot, &A);
   A.zEnd = E.zEnd;
   if( A.pExpr ) A.pExpr->flags |= EP_InfixFunc;
diff --git a/src/box/sql/resolve.c b/src/box/sql/resolve.c
index 32ab1ac68..833ccbc83 100644
--- a/src/box/sql/resolve.c
+++ b/src/box/sql/resolve.c
@@ -618,19 +618,9 @@ resolveExprStep(Walker * pWalker, Expr * pExpr)
 			assert(!ExprHasProperty(pExpr, EP_xIsSelect));
 			zId = pExpr->u.zToken;
 			nId = sqlStrlen30(zId);
-			struct func *func = sql_func_find(pExpr);
-			if (func == NULL) {
-				pParse->is_aborted = true;
-				pNC->nErr++;
-				return WRC_Abort;
-			}
-			bool is_agg = func->def->aggregate ==
-				      FUNC_AGGREGATE_GROUP;
-			assert(!is_agg || func->def->language ==
-					  FUNC_LANGUAGE_SQL_BUILTIN);
-			pExpr->type = func->def->returns;
-			if (sql_func_flag_is_set(func, SQL_FUNC_UNLIKELY) &&
-			    n == 2) {
+			uint32_t flags = sql_func_flags(pExpr->func_id);
+			bool is_agg = (flags & SQL_FUNC_AGG) != 0;
+			if ((flags & SQL_FUNC_UNLIKELY) != 0 && n == 2) {
 				ExprSetProperty(pExpr, EP_Unlikely | EP_Skip);
 				pExpr->iTable =
 					exprProbability(pList->a[1].pExpr);
@@ -643,19 +633,18 @@ resolveExprStep(Walker * pWalker, Expr * pExpr)
 					pNC->nErr++;
 					return WRC_Abort;
 				}
-			} else if (sql_func_flag_is_set(func,
-							SQL_FUNC_UNLIKELY)) {
+			} else if ((flags & SQL_FUNC_UNLIKELY) != 0) {
 				ExprSetProperty(pExpr, EP_Unlikely | EP_Skip);
 				/*
 				 * unlikely() probability is
 				 * 0.0625, likely() is 0.9375
 				 */
-				pExpr->iTable = func->def->name[0] == 'u' ?
+				pExpr->iTable = zId[0] == 'u' ?
 						8388608 : 125829120;
 			}
-			assert(!func->def->is_deterministic ||
+			assert(((flags & SQL_FUNC_DETERM) == 0) ||
 			       (pNC->ncFlags & NC_IdxExpr) == 0);
-			if (func->def->is_deterministic)
+			if ((flags & SQL_FUNC_DETERM) != 0)
 				ExprSetProperty(pExpr, EP_ConstFunc);
 			if (is_agg && (pNC->ncFlags & NC_AllowAgg) == 0) {
 				const char *err =
@@ -681,16 +670,16 @@ resolveExprStep(Walker * pWalker, Expr * pExpr)
 					pExpr->op2++;
 					pNC2 = pNC2->pNext;
 				}
-				assert(func != NULL);
 				if (pNC2) {
 					pNC2->ncFlags |= NC_HasAgg;
-					if (sql_func_flag_is_set(func,
-							         SQL_FUNC_MIN |
-								 SQL_FUNC_MAX))
+					if ((flags & (SQL_FUNC_MIN |
+						      SQL_FUNC_MAX)) != 0)
 						pNC2->ncFlags |= NC_MinMaxAgg;
 				}
 				pNC->ncFlags |= NC_AllowAgg;
 			}
+			pExpr->type = sql_func_result(pExpr);
+			assert(pExpr->type != field_type_MAX);
 			return WRC_Prune;
 		}
 	case TK_SELECT:
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 8003703a1..2f8a7a031 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -4647,9 +4647,7 @@ is_simple_count(struct Select *select, struct AggInfo *agg_info)
 		return NULL;
 	if (NEVER(agg_info->nFunc == 0))
 		return NULL;
-	assert(agg_info->aFunc->func->def->language ==
-	       FUNC_LANGUAGE_SQL_BUILTIN);
-	if (sql_func_flag_is_set(agg_info->aFunc->func, SQL_FUNC_COUNT) ||
+	if ((agg_info->aFunc->flags & SQL_FUNC_COUNT) != 0 ||
 	    (agg_info->aFunc->pExpr->x.pList != NULL &&
 	     agg_info->aFunc->pExpr->x.pList->nExpr > 0))
 		return NULL;
@@ -5576,7 +5574,8 @@ finalizeAggFunctions(Parse * pParse, AggInfo * pAggInfo)
 		assert(!ExprHasProperty(pF->pExpr, EP_xIsSelect));
 		sqlVdbeAddOp2(v, OP_AggFinal, pF->iMem,
 				  pList ? pList->nExpr : 0);
-		sqlVdbeAppendP4(v, pF->func, P4_FUNC);
+		struct func *func = sql_func_find(pF->pExpr);
+		sqlVdbeAppendP4(v, func, P4_FUNC);
 	}
 }
 
@@ -5617,7 +5616,7 @@ updateAccumulator(Parse * pParse, AggInfo * pAggInfo)
 			vdbe_insert_distinct(pParse, pF->iDistinct, pF->reg_eph,
 					     addrNext, 1, regAgg);
 		}
-		if (sql_func_flag_is_set(pF->func, SQL_FUNC_NEEDCOLL)) {
+		if ((pF->flags & SQL_FUNC_NEEDCOLL) != 0) {
 			struct coll *coll = NULL;
 			struct ExprList_item *pItem;
 			int j;
@@ -5636,7 +5635,8 @@ updateAccumulator(Parse * pParse, AggInfo * pAggInfo)
 					  (char *)coll, P4_COLLSEQ);
 		}
 		sqlVdbeAddOp3(v, OP_AggStep0, 0, regAgg, pF->iMem);
-		sqlVdbeAppendP4(v, pF->func, P4_FUNC);
+		struct func *func = sql_func_find(pF->pExpr);
+		sqlVdbeAppendP4(v, func, P4_FUNC);
 		sqlVdbeChangeP5(v, (u8) nArg);
 		sql_expr_type_cache_change(pParse, regAgg, nArg);
 		sqlReleaseTempRange(pParse, regAgg, nArg);
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 1fd9d2bbf..01701e271 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -1188,6 +1188,8 @@ struct type_def {
  */
 /** Function is one of aggregate functions. */
 #define SQL_FUNC_AGG      0x0001
+/** Function is deterministic. */
+#define SQL_FUNC_DETERM   0x0002
 #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
@@ -1398,8 +1400,7 @@ struct AggInfo {
 				 */
 	struct AggInfo_func {	/* For each aggregate function */
 		Expr *pExpr;	/* Expression encoding the function */
-		/** The aggregate function implementation. */
-		struct func *func;
+		uint32_t flags;
 		int iMem;	/* Memory location that acts as accumulator */
 		int iDistinct;	/* Ephemeral table used to enforce DISTINCT */
 		/**
@@ -1494,6 +1495,9 @@ struct Expr {
 	 * access them will result in a segfault or malfunction.
 	 ********************************************************************/
 
+	/** SQL Built-in function id. */
+	uint8_t func_id;
+
 	Expr *pLeft;		/* Left subnode */
 	Expr *pRight;		/* Right subnode */
 	union {
@@ -2705,7 +2709,7 @@ ExprList *sqlExprListAppendVector(Parse *, ExprList *, IdList *, Expr *);
 /** Construct a new expression node for a built-in function. */
 struct Expr *
 sql_expr_new_built_in(struct Parse *parser, struct ExprList *list,
-		      struct Token *token);
+		      struct Token *token, uint8_t id);
 
 /**
  * Set the sort order for the last element on the given ExprList.
@@ -4400,13 +4404,11 @@ sql_func_find(struct Expr *expr);
 struct func *
 sql_func_by_signature(const char *name, uint32_t 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);
+sql_func_flags(uint8_t id);
+
+enum field_type
+sql_func_result(struct Expr *expr);
 
 /**
  * Generate VDBE code to halt execution with correct error if
-- 
2.25.1



More information about the Tarantool-patches mailing list