From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id 61E536EC40; Wed, 18 Aug 2021 17:36:56 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 61E536EC40 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1629297416; bh=85KIUCGz7IKxLAYvkMxAggLXymhSPqzsOVGrJthRP5s=; h=To:Cc:Date:In-Reply-To:References:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=cbn+uwcrBFAvRUn1WfODcW8lTzHRBVEMtoPU37hP+BUcVXhOhYK90lK2EJX5YV2cc M/CoRpyZWMFrLvkGXgLvs2Vh4xNM+Im+L76jmmfKvh0ahBpGI37gBdIaYYqHALmTBx lY/dBbewdtGKzh34TVM0IU9P54HM1O2LYwscSGos= Received: from smtpng1.i.mail.ru (smtpng1.i.mail.ru [94.100.181.251]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 10B9A6EC43 for ; Wed, 18 Aug 2021 17:35:05 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 10B9A6EC43 Received: by smtpng1.m.smailru.net with esmtpa (envelope-from ) id 1mGMem-0002zW-6C; Wed, 18 Aug 2021 17:35:04 +0300 To: vdavydov@tarantool.org Cc: tarantool-patches@dev.tarantool.org Date: Wed, 18 Aug 2021 17:35:03 +0300 Message-Id: <4d7ba8434f561a54bddbff576e1b0acab4089ff2.1629297142.git.imeevma@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-4EC0790: 10 X-7564579A: 646B95376F6C166E X-77F55803: 4F1203BC0FB41BD92087353F0EC44DD9736CF3E71F18CE0C3E1D5927724F4AAA182A05F5380850401728CC907BF6130DA774854672D5ED7532B0C9B6A36F86E6B2CF574C75D92F52 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE72CCF2B407A2A5B3DEA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637A438E411C989120A8638F802B75D45FF36EB9D2243A4F8B5A6FCA7DBDB1FC311F39EFFDF887939037866D6147AF826D86CDE59A35F5CA218EC15A6CD68464603117882F4460429724CE54428C33FAD305F5C1EE8F4F765FCAA867293B0326636D2E47CDBA5A96583BD4B6F7A4D31EC0BC014FD901B82EE079FA2833FD35BB23D27C277FBC8AE2E8BAA867293B0326636D2E47CDBA5A96583BA9C0B312567BB231DD303D21008E29813377AFFFEAFD269A417C69337E82CC2E827F84554CEF50127C277FBC8AE2E8BA83251EDC214901ED5E8D9A59859A8B6B1CFA6D474D4A6A4089D37D7C0E48F6C5571747095F342E88FB05168BE4CE3AF X-B7AD71C0: AC4F5C86D027EB782CDD5689AFBDA7A213B5FB47DCBC3458834459D11680B5050C8E7512C1707E8F933C3E1CD4ED6E19 X-C1DE0DAB: C20DE7B7AB408E4181F030C43753B8186998911F362727C414F749A5E30D975CF160826E4E1956AED916E8C0AA9BC74B7F55F042248AD94E9C2B6934AE262D3EE7EAB7254005DCED7532B743992DF240BDC6A1CF3F042BAD6DF99611D93F60EFCE66FDB1904541E0699F904B3F4130E343918A1A30D5E7FCCB5012B2E24CD356 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D342B8615F5CFAD9D02703EAC6ABDA45CBFFC81C280ED51F4388F5398CC607B7CDCA8DAF895BF7644B91D7E09C32AA3244CEC6E40D38A3A71C0EE99CD4D76EF856F95A9E0DC41E9A4CF729B2BEF169E0186 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojuRQ/H5n28tq9LssiyxIbOA== X-Mailru-Sender: 689FA8AB762F7393C37E3C1AEC41BA5DDCBDD5CCDB9226069B993283D6FA4A0F83D72C36FC87018B9F80AB2734326CD2FB559BB5D741EB96352A0ABBE4FDA4210A04DAD6CC59E33667EA787935ED9F1B X-Mras: Ok Subject: [Tarantool-patches] [PATCH v2 4/5] sql: separate function flags from functions X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Mergen Imeev via Tarantool-patches Reply-To: imeevma@tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" 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