[tarantool-patches] Re: [PATCH v1 1/1] sql: support HAVING without GROUP BY clause
n.pettik
korablev at tarantool.org
Mon Oct 1 19:37:56 MSK 2018
>> Still, other DBs (as usual I checked - Postgres, Oracle and DB2) process this
>> query as well:
>>
>> select 1 from t1 having min(a) > 0;
>>
>> In other words, not only aggregate can appear in SELECT args,
>> but also constant literals. Semantically, it seems to be correct.
>> Moreover, quieres like
>>
>> select date() from t1 having min(a) > 0;
>>
>> are valid too. What I mean is SELECT arguments must return
>> single value for all rows in table (i.e. be single-group).
>>
>> From the first sight, this problem is likely to be minor, but I guess
>> we should implement correct behaviour as far as we are dealing
>> with this issue right now.
> This cases are totally useless, not so trivial to implement (need to calculate
> expression in VDBE, e.g.
> SELECT (SELECT s1 FROM te40 LIMIT 1) FROM te40 HAVING min(s1) > 0
> is a valid construction for Postgress.
> Moreover, current checks are the part of resolveSelectStep that
>
> Asked Peter, does it really important.
I would like to notice that we’ve decided to allow literals and constant functions also
appear in select arg list.
From new diff:
diff --git a/src/box/sql/resolve.c b/src/box/sql/resolve.c
index 9a2d6ff4e..7c0d9b44e 100644
--- a/src/box/sql/resolve.c
+++ b/src/box/sql/resolve.c
@@ -602,6 +602,8 @@ resolveExprStep(Walker * pWalker, Expr * pExpr)
/* A lone identifier is the name of a column.
*/
case TK_ID:{
+ if ((pNC->ncFlags & NC_AllowAgg) != 0)
+ pNC->ncFlags |= NC_HasUnaggregatedId;
return lookupName(pParse, 0, pExpr->u.zToken, pNC,
pExpr);
}
@@ -1180,6 +1182,44 @@ resolveOrderGroupBy(NameContext * pNC, /* The name context of the SELECT stateme
return sqlite3ResolveOrderGroupBy(pParse, pSelect, pOrderBy, zType);
}
+/**
+ * Test if specified expression is a regular literal.
+ * @param expr Expression to analyse.
+ * @retval true If expression is literal.
+ * @retval false Otherwise.
+ */
+static bool
+sql_expr_is_literal(struct Expr *expr)
+{
+ return expr->op == TK_INTEGER || expr->op == TK_FLOAT ||
+ expr->op == TK_BLOB || expr->op == TK_STRING;
+}
What about TK_NULL? What about unary minus?
This examples now fail:
tarantool> SELECT -1 FROM te40 HAVING SUM(s1) > 0;
---
- error: 'SQL error: HAVING argument must appear in the GROUP BY clause or be used
in an aggregate function’
…
tarantool> SELECT NULL FROM te40 HAVING SUM(s1) > 0;
---
- error: 'SQL error: HAVING argument must appear in the GROUP BY clause or be used
in an aggregate function'
...
+
+/**
+ * Test if specified expression is a constant function.
+ * @param parser Parsing context.
+ * @param expr Expression to analyse.
+ * @retval true If expression is a existent constant function.
+ * @retval false Otherwise.
+ */
+static bool
+sql_expr_is_constat_func(struct Parse *parser, struct Expr *expr)
+{
+ if (expr->op != TK_FUNCTION)
+ return false;
+ char *func_name = expr->u.zToken;
+ struct ExprList *args_list = expr->x.pList;
+ int args_count = args_list != NULL ? args_list->nExpr : 0;
+ struct FuncDef *func =
+ sqlite3FindFunction(parser->db, func_name, args_count, 0);
+ if (func == NULL)
+ func = sqlite3FindFunction(parser->db, func_name, -2, 0);
+ if (func == NULL)
+ return false;
+ return func != NULL ?
+ (func->funcFlags & SQLITE_FUNC_CONSTANT) != 0 : false;
+}
+
Consider refactoring: at last return ‘func’ can’t be NULL - this check is performed one
line above.
@@ -1203,7 +1204,7 @@ sql_expr_is_literal(struct Expr *expr)
* @retval false Otherwise.
*/
static bool
-sql_expr_is_constat_func(struct Parse *parser, struct Expr *expr)
+sql_expr_is_constant_func(struct Parse *parser, struct Expr *expr)
{
if (expr->op != TK_FUNCTION)
return false;
@@ -1212,12 +1213,17 @@ sql_expr_is_constat_func(struct Parse *parser, struct Expr *expr)
int args_count = args_list != NULL ? args_list->nExpr : 0;
struct FuncDef *func =
sqlite3FindFunction(parser->db, func_name, args_count, 0);
- if (func == NULL)
- func = sqlite3FindFunction(parser->db, func_name, -2, 0);
- if (func == NULL)
- return false;
- return func != NULL ?
- (func->funcFlags & SQLITE_FUNC_CONSTANT) != 0 : false;
+ if (func == NULL) {
+ /*
+ * If we fail to find function with exact number
+ * of arguments, lets try to search similar
+ * function but with different number of args.
+ */
+ func = sqlite3FindFunction(parser->db, func_name, -2, 0);
+ if (func == NULL)
+ return false;
+ }
+ return (func->funcFlags & SQLITE_FUNC_CONSTANT) != 0;
}
/*
@@ -1338,8 +1344,8 @@ resolveSelectStep(Walker * pWalker, Select * p)
return WRC_Abort;
is_all_select_agg &= (sNC.ncFlags & NC_HasAgg) != 0 ||
sql_expr_is_literal(expr) ||
- sql_expr_is_constat_func(pParse,
- expr);
+ sql_expr_is_constant_func(pParse,
+ expr);
More information about the Tarantool-patches
mailing list