Changeset: de367bfd5f32 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=de367bfd5f32 Modified Files: sql/backends/monet5/rel_bin.c sql/server/rel_exp.c sql/server/rel_select.c sql/server/sql_query.c sql/server/sql_query.h sql/test/miscellaneous/Tests/groupby_error.stable.out sql/test/subquery/Tests/subquery3.sql sql/test/subquery/Tests/subquery3.stable.err sql/test/subquery/Tests/subquery3.stable.out sql/test/subquery/Tests/subquery5.sql Branch: Jun2020 Log Message:
improved errors/checks for nested aggregates improved errors/checks for using non-grouped columns solved issue with non-aligned bats caused by batcalc pushdown changes diffs (truncated from 450 to 300 lines): diff --git a/sql/backends/monet5/rel_bin.c b/sql/backends/monet5/rel_bin.c --- a/sql/backends/monet5/rel_bin.c +++ b/sql/backends/monet5/rel_bin.c @@ -1058,6 +1058,15 @@ exp_bin(backend *be, sql_exp *e, stmt *l stmt_uselect(be, l, r2, range2rcompare(e->flag), sel, is_anti(e), 0), is_anti(e), 0); #endif } else { + if (sel && ((l->cand && l->nrcols) || (r->cand && r->nrcols) || (r2->cand && r->nrcols))) { + if (!l->cand && l->nrcols) + l = stmt_project(be, sel, l); + if (!r->cand && r->nrcols) + r = stmt_project(be, sel, r); + if (!r2->cand && r2->nrcols) + r2 = stmt_project(be, sel, r2); + sel = NULL; + } s = stmt_uselect2(be, l, r, r2, (comp_type)e->flag, sel, is_anti(e)); } } else { diff --git a/sql/server/rel_exp.c b/sql/server/rel_exp.c --- a/sql/server/rel_exp.c +++ b/sql/server/rel_exp.c @@ -660,7 +660,7 @@ exp_alias_or_copy( mvc *sql, const char sql_exp *ne = NULL; if (!tname) - tname = old->alias.rname; + tname = exp_relname(old); if (!cname && exp_name(old) && has_label(old)) { ne = exp_column(sql->sa, exp_relname(old), exp_name(old), exp_subtype(old), orel?orel->card:CARD_ATOM, has_nil(old), is_intern(old)); diff --git a/sql/server/rel_select.c b/sql/server/rel_select.c --- a/sql/server/rel_select.c +++ b/sql/server/rel_select.c @@ -1193,6 +1193,12 @@ rel_column_ref(sql_query *query, sql_rel } if (exp && outer && outer->card <= CARD_AGGR && exp->card > CARD_AGGR && (!is_sql_aggr(f) || is_sql_farg(f))) return sql_error(sql, ERR_GROUPBY, SQLSTATE(42000) "SELECT: cannot use non GROUP BY column '%s' in query results without an aggregate function", name); + if (exp && outer && (is_sql_groupby(f) || is_sql_aggr(f))) { + if (query_outer_used_exp( query, i, exp, is_sql_aggr(f) && !is_sql_farg(f))) { + sql_exp *lu = query_outer_last_used(query, i); + return sql_error(sql, 05, SQLSTATE(42000) "SELECT: subquery uses ungrouped column \"%s.%s\" from outer query", exp_relname(lu), exp_name(lu)); + } + } if (exp) { if (is_groupby(outer->op) && !is_sql_aggr(f)) { exp = rel_groupby_add_aggr(sql, outer, exp); @@ -1256,6 +1262,12 @@ rel_column_ref(sql_query *query, sql_rel } if (exp && outer && outer->card <= CARD_AGGR && exp->card > CARD_AGGR && (!is_sql_aggr(f) || is_sql_farg(f))) return sql_error(sql, ERR_GROUPBY, SQLSTATE(42000) "SELECT: cannot use non GROUP BY column '%s.%s' in query results without an aggregate function", tname, cname); + if (exp && outer && (is_sql_groupby(f) || is_sql_aggr(f))) { + if (query_outer_used_exp( query, i, exp, is_sql_aggr(f) && !is_sql_farg(f))) { + sql_exp *lu = query_outer_last_used(query, i); + return sql_error(sql, 05, SQLSTATE(42000) "SELECT: subquery uses ungrouped column \"%s.%s\" from outer query", exp_relname(lu), exp_name(lu)); + } + } if (exp) { if (is_groupby(outer->op) && !is_sql_aggr(f)) { exp = rel_groupby_add_aggr(sql, outer, exp); @@ -3345,7 +3357,7 @@ static sql_exp * for ( ; args && args->data.sym; args = args->next ) { int base = (!groupby || !is_project(groupby->op) || is_base(groupby->op) || is_processed(groupby)); sql_rel *gl = base?groupby:groupby->l, *ogl = gl; /* handle case of subqueries without correlation */ - sql_exp *e = rel_value_exp(query, &gl, args->data.sym, (f | sql_aggr)& ~sql_farg, ek); + sql_exp *e = rel_value_exp(query, &gl, args->data.sym, (f | sql_aggr)& ~sql_farg, ek), *lu; has_args = true; if (gl && gl != ogl) { @@ -3372,11 +3384,17 @@ static sql_exp * GDKfree(uaname); return e; } - all_aggr &= (exp_card(e) <= CARD_AGGR && !exp_is_atom(e) && is_aggr(e->type) && !is_func(e->type) && (!groupby || !is_groupby(groupby->op) || !groupby->r || !exps_find_exp(groupby->r, e))); + if (all_aggr && is_freevar(e) && (lu=query_outer_last_used(query, is_freevar(e)-1)) != NULL) { + all_aggr &= is_aggr(lu->type); + } else { + all_aggr &= (exp_card(e) <= CARD_AGGR && !exp_is_atom(e) && is_aggr(e->type) && !is_func(e->type) && (!groupby || !is_groupby(groupby->op) || !groupby->r || !exps_find_exp(groupby->r, e))); + } has_freevar |= exp_has_freevar(sql, e); all_freevar &= (is_freevar(e)>0); list_append(exps, e); } + if (all_freevar && all_aggr) + return sql_error(sql, 05, SQLSTATE(42000) "SELECT: aggregate function calls cannot be nested"); if (!all_freevar) { if (all_aggr) { char *uaname = GDKmalloc(strlen(aname) + 1); @@ -3425,6 +3443,7 @@ static sql_exp * } if (all_freevar) { /* case 2, ie use outer */ + //int card; sql_exp *exp = NULL; /* find proper relation, base on freevar (stack hight) */ for (node *n = exps->h; n; n = n->next) { @@ -3436,6 +3455,7 @@ static sql_exp * } int sql_state = query_fetch_outer_state(query,all_freevar-1); res = groupby = query_fetch_outer(query, all_freevar-1); + //card = query_outer_used_card(query, all_freevar-1); if (exp && !is_groupby_col(res, exp)) { if (is_sql_groupby(sql_state)) return sql_error(sql, 05, SQLSTATE(42000) "SELECT: aggregate function '%s' not allowed in GROUP BY clause", aname); @@ -3453,6 +3473,12 @@ static sql_exp * return sql_error(sql, 05, SQLSTATE(42000) "CALL: aggregate functions not allowed inside CALL"); if (is_sql_from(sql_state)) return sql_error(sql, 05, SQLSTATE(42000) "SELECT: aggregate functions not allowed in functions in FROM"); +#if 0 + if (card > CARD_AGGR) { /* used a expression before on the non grouped relation */ + sql_exp *lu = query_outer_last_used(query, all_freevar-1); + return sql_error(sql, 05, SQLSTATE(42000) "SELECT: subquery uses ungrouped column \"%s.%s\" from outer query", exp_relname(lu), exp_name(lu)); + } +#endif } } @@ -3535,6 +3561,8 @@ static sql_exp * if (!groupby) return e; + if (all_freevar) + query_outer_used_exp(query, all_freevar-1, e, 1); e = rel_groupby_add_aggr(sql, groupby, e); if (!group && !all_freevar) return e; @@ -3689,6 +3717,8 @@ static sql_exp * if (!groupby) return e; + if (all_freevar) + query_outer_used_exp(query, all_freevar-1, e, 1); e = rel_groupby_add_aggr(sql, groupby, e); if (!group && !all_freevar) return e; diff --git a/sql/server/sql_query.c b/sql/server/sql_query.c --- a/sql/server/sql_query.c +++ b/sql/server/sql_query.c @@ -17,6 +17,9 @@ sq_create( sql_allocator *sa, sql_rel *r assert(rel); q->rel = rel; q->sql_state = sql_state; + q->last_used = NULL; + q->used_card = 0; + q->groupby = 0; return q; } @@ -69,6 +72,8 @@ query_update_outer(sql_query *q, sql_rel { stacked_query *sq = sql_stack_fetch(q->outer, i); sq->rel = r; + sq->last_used = NULL; + sq->used_card = 0; } int @@ -76,3 +81,33 @@ query_has_outer(sql_query *q) { return sql_stack_top(q->outer); } + +int +query_outer_used_exp(sql_query *q, int i, sql_exp *e, bool aggr) +{ + stacked_query *sq = sql_stack_fetch(q->outer, i); + + if (aggr && sq->groupby) + return -1; + sq->last_used = e; + sq->used_card = sq->rel->card; + if (!aggr) + sq->groupby = 1; + return 0; +} + +int +query_outer_used_card(sql_query *q, int i) +{ + stacked_query *sq = sql_stack_fetch(q->outer, i); + + return sq->used_card; +} + +sql_exp * +query_outer_last_used(sql_query *q, int i) +{ + stacked_query *sq = sql_stack_fetch(q->outer, i); + + return sq->last_used; +} diff --git a/sql/server/sql_query.h b/sql/server/sql_query.h --- a/sql/server/sql_query.h +++ b/sql/server/sql_query.h @@ -16,6 +16,9 @@ typedef struct stacked_query { sql_rel *rel; int sql_state; + sql_exp *last_used; + int used_card; + int groupby; } stacked_query; typedef struct sql_query { @@ -31,4 +34,8 @@ extern int query_fetch_outer_state(sql_q extern void query_update_outer(sql_query *q, sql_rel *r, int i); extern int query_has_outer(sql_query *q); /* returns number of outer relations */ +extern int query_outer_used_exp(sql_query *q, int i, sql_exp *e, bool aggr); +extern int query_outer_used_card(sql_query *q, int i); +extern sql_exp *query_outer_last_used(sql_query *q, int i); + #endif diff --git a/sql/test/miscellaneous/Tests/groupby_error.stable.out b/sql/test/miscellaneous/Tests/groupby_error.stable.out --- a/sql/test/miscellaneous/Tests/groupby_error.stable.out +++ b/sql/test/miscellaneous/Tests/groupby_error.stable.out @@ -182,6 +182,16 @@ project ( [ 2 ] [ 2 ] [ 2 ] +#SELECT * FROM tab0 WHERE NOT - col0 - col1 * col2 <= ( + col0 ) AND NOT ( + col2 + col1 - col1 ) NOT BETWEEN - col0 AND - col1 + - col2 / col1; +% sys.tab0, sys.tab0, sys.tab0 # table_name +% col0, col1, col2 # name +% int, int, int # type +% 1, 1, 1 # length +#SELECT * FROM tab0 AS cor0 WHERE NOT col1 BETWEEN - col0 AND col0 + col1 * col1 AND - col1 BETWEEN col0 AND ( NULL ) OR NOT col0 * col0 + col0 <= NULL; +% sys.cor0, sys.cor0, sys.cor0 # table_name +% col0, col1, col2 # name +% int, int, int # type +% 1, 1, 1 # length #SELECT DISTINCT * FROM tab2 WHERE NOT ( - + 50 + ( 70 ) ) = + col2; % sys.tab2, sys.tab2, sys.tab2 # table_name % col0, col1, col2 # name diff --git a/sql/test/subquery/Tests/subquery3.sql b/sql/test/subquery/Tests/subquery3.sql --- a/sql/test/subquery/Tests/subquery3.sql +++ b/sql/test/subquery/Tests/subquery3.sql @@ -361,7 +361,7 @@ FROM integers i1; --SUM(i1.i) is a corre SELECT (SELECT SUM(SUM(i1.i)) FROM integers i2 GROUP BY i2.i) -FROM integers i1; --error, more than one row returned by a subquery used as an expression +FROM integers i1; --error, aggregation functions cannot be nested SELECT (SELECT SUM(SUM(i2.i)) FROM integers i2 GROUP BY i2.i) diff --git a/sql/test/subquery/Tests/subquery3.stable.err b/sql/test/subquery/Tests/subquery3.stable.err --- a/sql/test/subquery/Tests/subquery3.stable.err +++ b/sql/test/subquery/Tests/subquery3.stable.err @@ -178,10 +178,10 @@ CODE = M0M29 MAPI = (monetdb) /var/tmp/mtest-224250/.s.monetdb.30823 QUERY = SELECT (SELECT SUM(SUM(i1.i)) FROM integers i2 GROUP BY i2.i) - FROM integers i1; --error, more than one row returned by a subquery used as an expression -ERROR = !zero_or_one: cardinality violation, scalar expression expected -CODE = M0M29 -MAPI = (monetdb) /var/tmp/mtest-22911/.s.monetdb.35494 + FROM integers i1; --error, aggregation functions cannot be nested +ERROR = !SELECT: aggregate function calls cannot be nested +CODE = 42000 +MAPI = (monetdb) /var/tmp/mtest-766253/.s.monetdb.34755 QUERY = SELECT (SELECT SUM(SUM(i2.i)) FROM integers i2 GROUP BY i2.i) FROM integers i1; --error, aggregation functions cannot be nested diff --git a/sql/test/subquery/Tests/subquery3.stable.out b/sql/test/subquery/Tests/subquery3.stable.out --- a/sql/test/subquery/Tests/subquery3.stable.out +++ b/sql/test/subquery/Tests/subquery3.stable.out @@ -36,7 +36,7 @@ stdout of test 'subquery3` in directory #FROM another_T t1 #GROUP BY t1.col6, t1.col7; % . # table_name -% %32 # name +% %36 # name % boolean # type % 5 # length [ false ] @@ -63,7 +63,7 @@ stdout of test 'subquery3` in directory #FROM another_T #GROUP BY col1, col2, col5; % ., . # table_name -% %50, %51 # name +% %53, %54 # name % int, int # type % 1, 1 # length [ 1, 0 ] @@ -193,8 +193,8 @@ stdout of test 'subquery3` in directory # NOT SUM(t1.col2) * MIN(t1.col6 + t1.col6 - t1.col6 * t1.col6) NOT IN (SELECT MAX(t2.col6) FROM another_T t2 GROUP BY t1.col6 HAVING t1.col7 + MIN(t2.col8) < MAX(t2.col7 - t1.col6)) #FROM another_T t1 #GROUP BY t1.col7, t1.col6; -% .%22 # table_name -% %22 # name +% .%23 # table_name +% %23 # name % boolean # type % 5 # length [ false ] @@ -207,7 +207,7 @@ stdout of test 'subquery3` in directory #FROM another_T t1 #GROUP BY t1.col1, t1.col2; % ., . # table_name -% %205, %206 # name _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list