[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