Changeset: 5df7adacf00d for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=5df7adacf00d Modified Files: sql/server/rel_select.c sql/server/rel_unnest.c sql/server/rel_unnest.h sql/test/Tests/hot-snapshot.py sql/test/subquery/Tests/subquery3.stable.err sql/test/subquery/Tests/subquery5.stable.err Branch: mbedded Log Message:
merged with default diffs (truncated from 329 to 300 lines): 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 @@ -1191,7 +1191,7 @@ rel_column_ref(sql_query *query, sql_rel if (exp) break; } - if (exp && outer && outer->card <= CARD_AGGR && exp->card > CARD_AGGR && (!is_sql_aggr(f) || is_sql_farg(f))) + if (exp && outer && outer->card <= CARD_AGGR && exp->card > CARD_AGGR && !is_sql_aggr(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_aggr(f)) { if (query_outer_used_exp( query, i, exp, f)) { @@ -1257,7 +1257,7 @@ rel_column_ref(sql_query *query, sql_rel if (exp) break; } - if (exp && outer && outer->card <= CARD_AGGR && exp->card > CARD_AGGR && (!is_sql_aggr(f) || is_sql_farg(f))) + if (exp && outer && outer->card <= CARD_AGGR && exp->card > CARD_AGGR && !is_sql_aggr(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_aggr(f)) { if (query_outer_used_exp( query, i, exp, f)) { @@ -3349,14 +3349,16 @@ static sql_exp * exps = sa_list(sql->sa); if (args && args->data.sym) { - int ungrouped_col = -1, i, all_aggr = query_has_outer(query); + int i, all_aggr = query_has_outer(query); + bool found_nested_aggr = false; + list *ungrouped_cols = NULL; + all_freevar = 1; - bool found_nested_aggr = false; for (i = 0; args && args->data.sym; args = args->next, i++) { int base = (!groupby || !is_project(groupby->op) || is_base(groupby->op) || is_processed(groupby)); - bool found_one = false; - sql_rel *outer = NULL, *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), *a = NULL; + 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); + bool found_one_freevar = false; has_args = true; if (gl && gl != ogl) { @@ -3384,38 +3386,15 @@ static sql_exp * return e; } - if (is_freevar(e) && e->type == e_column) { - if ((outer = query_fetch_outer(query, is_freevar(e)-1))) { - if ((a = rel_find_exp(outer, e)) && is_aggr(a->type)) - return sql_error(sql, 05, SQLSTATE(42000) "SELECT: aggregate function calls cannot be nested"); - } - } - - if (all_aggr) { - /* get expression from outer */ - int aggr = 0; - if (a) - aggr = is_aggr(a->type); - else if (outer && outer->grouped) - ungrouped_col = i; - all_aggr &= aggr; - } 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))); - } - all_freevar &= (exp_only_freevar(query, e, &found_one, &found_nested_aggr) && found_one); + 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))); + exp_only_freevar(query, e, &all_freevar, &found_one_freevar, &found_nested_aggr, &ungrouped_cols); + all_freevar &= found_one_freevar; /* no uncorrelated variables must be found, plus at least one correlated variable to push this aggregate to an outer query */ list_append(exps, e); } - if (all_freevar && (all_aggr || found_nested_aggr)) + if (all_aggr || (all_freevar && found_nested_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); - sql_exp *e = sql_error(sql, 02, SQLSTATE(42000) "%s: aggregate functions cannot be nested", - uaname ? toUpperCopy(uaname, aname) : aname); - if (uaname) - GDKfree(uaname); - return e; - } else if (is_sql_groupby(f)) { + if (is_sql_groupby(f)) { char *uaname = GDKmalloc(strlen(aname) + 1); sql_exp *e = sql_error(sql, 02, SQLSTATE(42000) "%s: aggregate function '%s' not allowed in GROUP BY clause", uaname ? toUpperCopy(uaname, aname) : aname, aname); @@ -3450,9 +3429,26 @@ static sql_exp * if (uaname) GDKfree(uaname); return e; - } else if (!all_aggr && ungrouped_col >= 0) { - sql_exp *u = list_fetch(exps, ungrouped_col); - return sql_error(sql, ERR_GROUPBY, SQLSTATE(42000) "SELECT: subquery uses ungrouped column \"%s.%s\" from outer query", exp_relname(u), exp_name(u)); + } else if (!all_aggr && ungrouped_cols && !list_empty(ungrouped_cols)) { + for (node *n = ungrouped_cols->h ; n ; n = n->next) { + sql_rel *outer; + sql_exp *e = (sql_exp*) n->data; + + if ((outer = query_fetch_outer(query, is_freevar(e)-1)) && outer->grouped) { + bool err = false, was_processed = false; + + if (is_processed(outer)) { + was_processed = true; + reset_processed(outer); + } + if (!is_groupby_col(outer, e)) + err = true; + if (was_processed) + set_processed(outer); + if (err) + return sql_error(sql, ERR_GROUPBY, SQLSTATE(42000) "SELECT: subquery uses ungrouped column \"%s.%s\" from outer query", exp_relname(e), exp_name(e)); + } + } } } } diff --git a/sql/server/rel_unnest.c b/sql/server/rel_unnest.c --- a/sql/server/rel_unnest.c +++ b/sql/server/rel_unnest.c @@ -171,97 +171,109 @@ rel_has_freevar(mvc *sql, sql_rel *rel) return 0; } -static int exps_only_freevar(sql_query *query, list *exps, bool *found_one, bool *found_aggr); -static int rel_only_freevar(sql_query *query, sql_rel *rel, bool *found_one, bool *found_aggr); +static void exps_only_freevar(sql_query *query, list *exps, unsigned int *all_freevar, bool *found_one_freevar, bool *found_aggr, list **ungrouped_cols); +static void rel_only_freevar(sql_query *query, sql_rel *rel, unsigned int *all_freevar, bool *found_one_freevar, bool *found_aggr, list **ungrouped_cols); -int /* look for expressions with either only freevars or atoms */ -exp_only_freevar(sql_query *query, sql_exp *e, bool *found_one, bool *found_aggr) +void /* look for expressions with either only freevars or atoms */ +exp_only_freevar(sql_query *query, sql_exp *e, unsigned int *all_freevar, bool *found_one_freevar, bool *found_aggr, list **ungrouped_cols) { if (THRhighwater()) { (void) sql_error(query->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space"); - return 0; + return ; } if (is_freevar(e)) { sql_rel *outer; - sql_exp *a; - *found_one = true; + *found_one_freevar = true; if (e->type == e_column) { if ((outer = query_fetch_outer(query, is_freevar(e)-1))) { - if ((a = rel_find_exp(outer, e)) && is_aggr(a->type)) + sql_exp *a = rel_find_exp(outer, e); + if (a && is_aggr(a->type)) *found_aggr = true; + else { + if (!*ungrouped_cols) + *ungrouped_cols = new_exp_list(query->sql->sa); + list_append(*ungrouped_cols, e); + } } } - return 1; + return ; } switch(e->type) { case e_cmp: if (e->flag == cmp_or || e->flag == cmp_filter) { - return (exps_only_freevar(query, e->l, found_one, found_aggr) && exps_only_freevar(query, e->r, found_one, found_aggr)); + exps_only_freevar(query, e->l, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); + exps_only_freevar(query, e->r, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); } else if (e->flag == cmp_in || e->flag == cmp_notin) { - return (exp_only_freevar(query, e->l, found_one, found_aggr) && exps_only_freevar(query, e->r, found_one, found_aggr)); + exp_only_freevar(query, e->l, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); + exps_only_freevar(query, e->r, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); } else { - return (exp_only_freevar(query, e->l, found_one, found_aggr) && exp_only_freevar(query, e->r, found_one, found_aggr) && - (!e->f || (e->f && exp_only_freevar(query, e->f, found_one, found_aggr)))); + exp_only_freevar(query, e->l, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); + exp_only_freevar(query, e->r, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); + if (e->f) + exp_only_freevar(query, e->f, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); } + break; case e_convert: - return exp_only_freevar(query, e->l, found_one, found_aggr); + exp_only_freevar(query, e->l, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); + break; case e_func: case e_aggr: if (e->l) - return exps_only_freevar(query, e->l, found_one, found_aggr); - return 1; + exps_only_freevar(query, e->l, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); + break; case e_psm: if (exp_is_rel(e)) - return rel_only_freevar(query, e->l, found_one, found_aggr); - return 1; + rel_only_freevar(query, e->l, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); + break; case e_atom: - return 1; + break; case e_column: - return 0; + *all_freevar = 0; + break; } - return 0; } -int -exps_only_freevar(sql_query *query, list *exps, bool *found_one, bool *found_aggr) -{ - int all_freevar = 1; - - if (THRhighwater()) { - (void) sql_error(query->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space"); - return 0; - } - if (!exps) - return 0; - for (node *n = exps->h; n && all_freevar; n = n->next) { - sql_exp *e = n->data; - all_freevar &= exp_only_freevar(query, e, found_one, found_aggr); - } - return all_freevar; -} - -int -rel_only_freevar(sql_query *query, sql_rel *rel, bool *found_one, bool *found_aggr) +void +exps_only_freevar(sql_query *query, list *exps, unsigned int *all_freevar, bool *found_one_freevar, bool *found_aggr, list **ungrouped_cols) { if (THRhighwater()) { (void) sql_error(query->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space"); - return 0; + return ; + } + if (!exps) + return ; + for (node *n = exps->h; n ; n = n->next) + exp_only_freevar(query, n->data, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); +} + +void +rel_only_freevar(sql_query *query, sql_rel *rel, unsigned int *all_freevar, bool *found_one_freevar, bool *found_aggr, list **ungrouped_cols) +{ + if (THRhighwater()) { + (void) sql_error(query->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space"); + return ; } if (is_basetable(rel->op)) { - return 0; + return ; } else if (is_base(rel->op)) { - return exps_only_freevar(query, rel->exps, found_one, found_aggr) && (!rel->r || (rel->r && rel_only_freevar(query, rel->r, found_one, found_aggr))); + exps_only_freevar(query, rel->exps, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); + if (rel->r) + rel_only_freevar(query, rel->r, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); } else if (is_simple_project(rel->op) || is_groupby(rel->op) || is_select(rel->op) || is_topn(rel->op) || is_sample(rel->op)) { - if ((is_simple_project(rel->op) || is_groupby(rel->op)) && (rel->r && !exps_only_freevar(query, rel->r, found_one, found_aggr))) - return 0; - return exps_only_freevar(query, rel->exps, found_one, found_aggr) && (!rel->l || (rel->l && rel_only_freevar(query, rel->l, found_one, found_aggr))); + if ((is_simple_project(rel->op) || is_groupby(rel->op)) && rel->r) + exps_only_freevar(query, rel->r, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); + exps_only_freevar(query, rel->exps, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); + if (rel->l) + rel_only_freevar(query, rel->l, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); } else if (is_join(rel->op) || is_set(rel->op) || is_semi(rel->op) || is_modify(rel->op)) { - return exps_only_freevar(query, rel->exps, found_one, found_aggr) && rel_only_freevar(query, rel->l, found_one, found_aggr) && rel_only_freevar(query, rel->r, found_one, found_aggr); + exps_only_freevar(query, rel->exps, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); + rel_only_freevar(query, rel->l, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); + rel_only_freevar(query, rel->r, all_freevar, found_one_freevar, found_aggr, ungrouped_cols); } - return 0; + return ; } static int diff --git a/sql/server/rel_unnest.h b/sql/server/rel_unnest.h --- a/sql/server/rel_unnest.h +++ b/sql/server/rel_unnest.h @@ -17,7 +17,7 @@ extern int exp_has_freevar(mvc *sql, sql extern int exps_have_freevar(mvc *sql, list *exps); extern int rel_has_freevar(mvc *sql, sql_rel *r); -extern int exp_only_freevar(sql_query *query, sql_exp *e, bool *found_one, bool *found_aggr); +extern void exp_only_freevar(sql_query *query, sql_exp *e, unsigned int *all_freevar, bool *found_one_freevar, bool *found_aggr, list **ungrouped_cols); extern sql_rel *rel_unnest(mvc *sql, sql_rel *rel); extern void exps_set_freevar(mvc *sql, list *exps, sql_rel *r); diff --git a/sql/test/Tests/hot-snapshot.py b/sql/test/Tests/hot-snapshot.py --- a/sql/test/Tests/hot-snapshot.py +++ b/sql/test/Tests/hot-snapshot.py @@ -108,6 +108,10 @@ def main(): # uncommitted1 and uncommitted2 should not be present assert foo == [('committed1',)] + cur3.close() + conn3.close() _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list