Changeset: 2374e4677140 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=2374e4677140 Modified Files: sql/server/rel_exp.c sql/server/rel_rel.c sql/server/rel_rel.h sql/server/rel_unnest.c sql/test/subquery/Tests/subquery4.sql sql/test/subquery/Tests/subquery4.stable.out Branch: default Log Message:
Reverting this morning changes and added rel_exp_visitor_bottomup and rel_exp_visitor_topdown. Changing the cardinality of an expression at rel_unnesting without propagating the changes, is dangerous. I did my best to fix the DISTINCT bugs, but I gave up. Changing the cardinality at unnesting it's HARD diffs (truncated from 360 to 300 lines): 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 @@ -2176,7 +2176,7 @@ exps_card( list *l ) if (l) for(n = l->h; n; n = n->next) { sql_exp *e = n->data; - if (card < e->card) + if (e && card < e->card) card = e->card; } return card; @@ -2190,7 +2190,7 @@ exps_fix_card( list *exps, unsigned int for (n = exps->h; n; n = n->next) { sql_exp *e = n->data; - if (e->card > card) + if (e && e->card > card) e->card = card; } } @@ -2203,7 +2203,7 @@ exps_setcard( list *exps, unsigned int c for (n = exps->h; n; n = n->next) { sql_exp *e = n->data; - if (e->card != CARD_ATOM) + if (e && e->card != CARD_ATOM) e->card = card; } } diff --git a/sql/server/rel_rel.c b/sql/server/rel_rel.c --- a/sql/server/rel_rel.c +++ b/sql/server/rel_rel.c @@ -1808,109 +1808,114 @@ rel_dependencies(mvc *sql, sql_rel *r) return l; } -static list *exps_exp_visitor(mvc *sql, sql_rel *rel, list *exps, int depth, exp_rewrite_fptr exp_rewriter); +static list *exps_exp_visitor(mvc *sql, sql_rel *rel, list *exps, int depth, exp_rewrite_fptr exp_rewriter, bool topdown); -static list * -exps_exps_exp_visitor(mvc *sql, sql_rel *rel, list *lists, int depth, exp_rewrite_fptr exp_rewriter) +static inline list * +exps_exps_exp_visitor(mvc *sql, sql_rel *rel, list *lists, int depth, exp_rewrite_fptr exp_rewriter, bool topdown) { node *n; if (list_empty(lists)) return lists; for (n = lists->h; n; n = n->next) { - if (n->data && (n->data = exps_exp_visitor(sql, rel, n->data, depth, exp_rewriter)) == NULL) + if (n->data && (n->data = exps_exp_visitor(sql, rel, n->data, depth, exp_rewriter, topdown)) == NULL) return NULL; } return lists; } +static sql_rel *rel_exp_visitor(mvc *sql, sql_rel *rel, exp_rewrite_fptr exp_rewriter, bool topdown); + static sql_exp * -exp_visitor(mvc *sql, sql_rel *rel, sql_exp *e, int depth, exp_rewrite_fptr exp_rewriter) +exp_visitor(mvc *sql, sql_rel *rel, sql_exp *e, int depth, exp_rewrite_fptr exp_rewriter, bool topdown) { if (THRhighwater()) return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space"); assert(e); + if (topdown && !(e = exp_rewriter(sql, rel, e, depth))) + return NULL; + switch(e->type) { case e_column: break; case e_convert: - if ((e->l = exp_visitor(sql, rel, e->l, depth+1, exp_rewriter)) == NULL) + if ((e->l = exp_visitor(sql, rel, e->l, depth+1, exp_rewriter, topdown)) == NULL) return NULL; break; case e_aggr: case e_func: if (e->r) /* rewrite rank -r is list of lists */ - if ((e->r = exps_exps_exp_visitor(sql, rel, e->r, depth+1, exp_rewriter)) == NULL) + if ((e->r = exps_exps_exp_visitor(sql, rel, e->r, depth+1, exp_rewriter, topdown)) == NULL) return NULL; if (e->l) - if ((e->l = exps_exp_visitor(sql, rel, e->l, depth+1, exp_rewriter)) == NULL) + if ((e->l = exps_exp_visitor(sql, rel, e->l, depth+1, exp_rewriter, topdown)) == NULL) return NULL; break; case e_cmp: if (e->flag == cmp_or || e->flag == cmp_filter) { - if ((e->l = exps_exp_visitor(sql, rel, e->l, depth+1, exp_rewriter)) == NULL) + if ((e->l = exps_exp_visitor(sql, rel, e->l, depth+1, exp_rewriter, topdown)) == NULL) return NULL; - if ((e->r = exps_exp_visitor(sql, rel, e->r, depth+1, exp_rewriter)) == NULL) + if ((e->r = exps_exp_visitor(sql, rel, e->r, depth+1, exp_rewriter, topdown)) == NULL) return NULL; } else if (e->flag == cmp_in || e->flag == cmp_notin) { - if ((e->l = exp_visitor(sql, rel, e->l, depth+1, exp_rewriter)) == NULL) + if ((e->l = exp_visitor(sql, rel, e->l, depth+1, exp_rewriter, topdown)) == NULL) return NULL; - if ((e->r = exps_exp_visitor(sql, rel, e->r, depth+1, exp_rewriter)) == NULL) + if ((e->r = exps_exp_visitor(sql, rel, e->r, depth+1, exp_rewriter, topdown)) == NULL) return NULL; } else { - if ((e->l = exp_visitor(sql, rel, e->l, depth+1, exp_rewriter)) == NULL) + if ((e->l = exp_visitor(sql, rel, e->l, depth+1, exp_rewriter, topdown)) == NULL) return NULL; - if ((e->r = exp_visitor(sql, rel, e->r, depth+1, exp_rewriter)) == NULL) + if ((e->r = exp_visitor(sql, rel, e->r, depth+1, exp_rewriter, topdown)) == NULL) return NULL; - if (e->f && (e->f = exp_visitor(sql, rel, e->f, depth+1, exp_rewriter)) == NULL) + if (e->f && (e->f = exp_visitor(sql, rel, e->f, depth+1, exp_rewriter, topdown)) == NULL) return NULL; } break; case e_psm: if (e->flag & PSM_SET || e->flag & PSM_RETURN || e->flag & PSM_EXCEPTION) { - if ((e->l = exp_visitor(sql, rel, e->l, depth+1, exp_rewriter)) == NULL) + if ((e->l = exp_visitor(sql, rel, e->l, depth+1, exp_rewriter, topdown)) == NULL) return NULL; } else if (e->flag & PSM_VAR) { return e; } else if (e->flag & PSM_WHILE || e->flag & PSM_IF) { - if ((e->l = exp_visitor(sql, rel, e->l, depth+1, exp_rewriter)) == NULL) + if ((e->l = exp_visitor(sql, rel, e->l, depth+1, exp_rewriter, topdown)) == NULL) return NULL; - if ((e->r = exps_exp_visitor(sql, rel, e->r, depth+1, exp_rewriter)) == NULL) + if ((e->r = exps_exp_visitor(sql, rel, e->r, depth+1, exp_rewriter, topdown)) == NULL) return NULL; - if (e->flag == PSM_IF && e->f && (e->f = exps_exp_visitor(sql, rel, e->f, depth+1, exp_rewriter)) == NULL) + if (e->flag == PSM_IF && e->f && (e->f = exps_exp_visitor(sql, rel, e->f, depth+1, exp_rewriter, topdown)) == NULL) return NULL; } else if (e->flag & PSM_REL) { - if ((e->l = rel_exp_visitor(sql, e->l, exp_rewriter)) == NULL) + if ((e->l = rel_exp_visitor(sql, e->l, exp_rewriter, topdown)) == NULL) return NULL; } break; case e_atom: if (e->f) - if ((e->f = exps_exp_visitor(sql, rel, e->f, depth+1, exp_rewriter)) == NULL) + if ((e->f = exps_exp_visitor(sql, rel, e->f, depth+1, exp_rewriter, topdown)) == NULL) return NULL; break; } - return exp_rewriter(sql, rel, e, depth); + if (!topdown && !(e = exp_rewriter(sql, rel, e, depth))) + return NULL; + return e; } -static list * -exps_exp_visitor(mvc *sql, sql_rel *rel, list *exps, int depth, exp_rewrite_fptr exp_rewriter) +static inline list * +exps_exp_visitor(mvc *sql, sql_rel *rel, list *exps, int depth, exp_rewrite_fptr exp_rewriter, bool topdown) { - node *n; - if (list_empty(exps)) return exps; - for (n = exps->h; n; n = n->next) { - if (n->data && (n->data = exp_visitor(sql, rel, n->data, depth, exp_rewriter)) == NULL) + for (node *n = exps->h; n; n = n->next) { + if (n->data && (n->data = exp_visitor(sql, rel, n->data, depth, exp_rewriter, topdown)) == NULL) return NULL; } list_hash_clear(exps); return exps; } -sql_rel * -rel_exp_visitor(mvc *sql, sql_rel *rel, exp_rewrite_fptr exp_rewriter) +static inline sql_rel * +rel_exp_visitor(mvc *sql, sql_rel *rel, exp_rewrite_fptr exp_rewriter, bool topdown) { if (THRhighwater()) return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space"); @@ -1918,9 +1923,9 @@ rel_exp_visitor(mvc *sql, sql_rel *rel, if (!rel) return rel; - if (rel->exps && (rel->exps = exps_exp_visitor(sql, rel, rel->exps, 0, exp_rewriter)) == NULL) + if (rel->exps && (rel->exps = exps_exp_visitor(sql, rel, rel->exps, 0, exp_rewriter, topdown)) == NULL) return NULL; - if ((is_groupby(rel->op) || is_simple_project(rel->op)) && rel->r && (rel->r = exps_exp_visitor(sql, rel, rel->r, 0, exp_rewriter)) == NULL) + if ((is_groupby(rel->op) || is_simple_project(rel->op)) && rel->r && (rel->r = exps_exp_visitor(sql, rel, rel->r, 0, exp_rewriter, topdown)) == NULL) return NULL; switch(rel->op){ @@ -1929,21 +1934,21 @@ rel_exp_visitor(mvc *sql, sql_rel *rel, case op_table: if (IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION) { if (rel->l) - if ((rel->l = rel_exp_visitor(sql, rel->l, exp_rewriter)) == NULL) + if ((rel->l = rel_exp_visitor(sql, rel->l, exp_rewriter, topdown)) == NULL) return NULL; } break; case op_ddl: if (rel->flag == ddl_output || rel->flag == ddl_create_seq || rel->flag == ddl_alter_seq) { if (rel->l) - if ((rel->l = rel_exp_visitor(sql, rel->l, exp_rewriter)) == NULL) + if ((rel->l = rel_exp_visitor(sql, rel->l, exp_rewriter, topdown)) == NULL) return NULL; } else if (rel->flag == ddl_list || rel->flag == ddl_exception) { if (rel->l) - if ((rel->l = rel_exp_visitor(sql, rel->l, exp_rewriter)) == NULL) + if ((rel->l = rel_exp_visitor(sql, rel->l, exp_rewriter, topdown)) == NULL) return NULL; if (rel->r) - if ((rel->r = rel_exp_visitor(sql, rel->r, exp_rewriter)) == NULL) + if ((rel->r = rel_exp_visitor(sql, rel->r, exp_rewriter, topdown)) == NULL) return NULL; } else if (rel->flag == ddl_psm) { break; @@ -1964,10 +1969,10 @@ rel_exp_visitor(mvc *sql, sql_rel *rel, case op_inter: case op_except: if (rel->l) - if ((rel->l = rel_exp_visitor(sql, rel->l, exp_rewriter)) == NULL) + if ((rel->l = rel_exp_visitor(sql, rel->l, exp_rewriter, topdown)) == NULL) return NULL; if (rel->r) - if ((rel->r = rel_exp_visitor(sql, rel->r, exp_rewriter)) == NULL) + if ((rel->r = rel_exp_visitor(sql, rel->r, exp_rewriter, topdown)) == NULL) return NULL; break; case op_select: @@ -1977,13 +1982,25 @@ rel_exp_visitor(mvc *sql, sql_rel *rel, case op_groupby: case op_truncate: if (rel->l) - if ((rel->l = rel_exp_visitor(sql, rel->l, exp_rewriter)) == NULL) + if ((rel->l = rel_exp_visitor(sql, rel->l, exp_rewriter, topdown)) == NULL) return NULL; break; } return rel; } +sql_rel * +rel_exp_visitor_topdown(mvc *sql, sql_rel *rel, exp_rewrite_fptr exp_rewriter) +{ + return rel_exp_visitor(sql, rel, exp_rewriter, true); +} + +sql_rel * +rel_exp_visitor_bottomup(mvc *sql, sql_rel *rel, exp_rewrite_fptr exp_rewriter) +{ + return rel_exp_visitor(sql, rel, exp_rewriter, false); +} + static list *exps_rel_visitor(mvc *sql, list *exps, rel_rewrite_fptr rel_rewriter, int *changes, bool topdown); static sql_exp * diff --git a/sql/server/rel_rel.h b/sql/server/rel_rel.h --- a/sql/server/rel_rel.h +++ b/sql/server/rel_rel.h @@ -114,7 +114,8 @@ extern list *rel_dependencies(mvc *sql, extern sql_exp * exps_find_match_exp(list *l, sql_exp *e); typedef sql_exp *(*exp_rewrite_fptr)(mvc *sql, sql_rel *rel, sql_exp *e, int depth /* depth of the nested expression */ ); -extern sql_rel *rel_exp_visitor(mvc *sql, sql_rel *rel, exp_rewrite_fptr exp_rewriter); +extern sql_rel *rel_exp_visitor_topdown(mvc *sql, sql_rel *rel, exp_rewrite_fptr exp_rewriter); +extern sql_rel *rel_exp_visitor_bottomup(mvc *sql, sql_rel *rel, exp_rewrite_fptr exp_rewriter); typedef sql_rel *(*rel_rewrite_fptr)(mvc *sql, sql_rel *rel, int *changes); extern sql_rel *rel_visitor_topdown(mvc *sql, sql_rel *rel, rel_rewrite_fptr rel_rewriter, int *changes); 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 @@ -1556,7 +1556,8 @@ rewrite_exp_rel(mvc *sql, sql_rel *rel, } } if (exp_is_rel(e) && is_ddl(rel->op)) - e->l = rel_exp_visitor(sql, e->l, &rewrite_exp_rel); + if (!(e->l = rel_exp_visitor_bottomup(sql, e->l, &rewrite_exp_rel))) + return NULL; return e; } @@ -1741,7 +1742,6 @@ rewrite_rank(mvc *sql, sql_rel *rel, sql /* ranks/window functions only exist in the projection */ assert(is_simple_project(rel->op)); list *l = e->l, *r = e->r, *gbe = r->h->data, *obe = r->h->next->data; - e->card = (rel->card == CARD_AGGR) ? CARD_AGGR : CARD_MULTI; /* After the unnesting, the cardinality of the window function becomes larger */ needed = (gbe || obe); for (node *n = l->h; n && !needed; n = n->next) { @@ -2403,7 +2403,8 @@ rewrite_exists(mvc *sql, sql_rel *rel, s ne = le; if (exp_has_rel(ie)) - (void)rewrite_exp_rel(sql, rel, ie, depth); + if (!rewrite_exp_rel(sql, rel, ie, depth)) + return NULL; if (is_project(rel->op) && rel_has_freevar(sql, sq)) le = exp_exist(sql, le, ne, is_exists(sf)); _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list