Changeset: ff5d86a2b7b5 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/ff5d86a2b7b5
Modified Files:
sql/backends/monet5/sql_statement.c
sql/include/sql_relation.h
sql/server/rel_distribute.c
sql/server/rel_dump.c
sql/server/rel_optimizer.c
sql/server/rel_rel.c
sql/server/rel_rel.h
sql/server/rel_unnest.c
Branch: default
Log Message:
added protection against optimizing/unnesting subgraphes repeatedly.
diffs (truncated from 305 to 300 lines):
diff --git a/sql/backends/monet5/sql_statement.c
b/sql/backends/monet5/sql_statement.c
--- a/sql/backends/monet5/sql_statement.c
+++ b/sql/backends/monet5/sql_statement.c
@@ -4323,6 +4323,7 @@ stmt_func(backend *be, stmt *ops, const
if ((p = find_prop(rel->p, PROP_REMOTE)))
rel->p = prop_remove(rel->p, p);
/* sql_processrelation may split projections, so make sure the topmost
relation only contains references */
+ int opt = rel->opt;
rel = rel_project(be->mvc->sa, rel, rel_projections(be->mvc, rel, NULL,
1, 1));
if (!(rel = sql_processrelation(be->mvc, rel, 0, 0, 1, 1)))
goto bailout;
@@ -4330,6 +4331,7 @@ stmt_func(backend *be, stmt *ops, const
p->p = rel->p;
rel->p = p;
}
+ rel->opt = opt;
if (monet5_create_relational_function(be->mvc, sql_private_module_name,
name, rel, ops, NULL, 1) < 0)
goto bailout;
diff --git a/sql/include/sql_relation.h b/sql/include/sql_relation.h
--- a/sql/include/sql_relation.h
+++ b/sql/include/sql_relation.h
@@ -325,6 +325,7 @@ typedef struct relation {
* The list is kept at rel_optimizer_private.h Please update it
accordingly
*/
uint8_t used;
+ int opt;
void *p; /* properties for the optimizer, distribution */
} sql_rel;
diff --git a/sql/server/rel_distribute.c b/sql/server/rel_distribute.c
--- a/sql/server/rel_distribute.c
+++ b/sql/server/rel_distribute.c
@@ -505,8 +505,6 @@ rel_rewrite_remote(visitor *v, global_pr
(void) gp;
rel = rel_visitor_bottomup(v, rel, &rel_rewrite_remote_);
v->data = NULL;
- rel = rel_visitor_topdown(v, rel, &rel_rewrite_replica_);
- v->data = NULL;
return rel;
}
@@ -526,13 +524,13 @@ rel_remote_func_(visitor *v, sql_rel *re
/* Don't modify the same relation twice */
if (is_rel_remote_func_used(rel->used))
return rel;
- rel->used |= rel_remote_func_used;
if (find_prop(rel->p, PROP_REMOTE) != NULL) {
list *exps = rel_projections(v->sql, rel, NULL, 1, 1);
rel = rel_unique_exps(v->sql, rel); /* remove any duplicate
results (aliases) */
rel = rel_relational_func(v->sql->sa, rel, exps);
}
+ rel->used |= rel_remote_func_used;
return rel;
}
diff --git a/sql/server/rel_dump.c b/sql/server/rel_dump.c
--- a/sql/server/rel_dump.c
+++ b/sql/server/rel_dump.c
@@ -486,6 +486,9 @@ rel_print_rel(mvc *sql, stream *fout, s
print_indent(sql, fout, depth, decorate);
+ if (mvc_debug_on(sql, 4) && rel->opt)
+ mnstr_printf(fout, "opt %d ", rel->opt);
+
if (is_single(rel))
mnstr_printf(fout, "single ");
diff --git a/sql/server/rel_optimizer.c b/sql/server/rel_optimizer.c
--- a/sql/server/rel_optimizer.c
+++ b/sql/server/rel_optimizer.c
@@ -711,7 +711,7 @@ rel_optimizer(mvc *sql, sql_rel *rel, in
visitor v = { .sql = sql, .value_based_opt =
value_based_opt, .storage_based_opt = storage_based_opt, .changes = instantiate
};
for(node *n = rel->exps->h; n; n = n->next) {
sql_exp *e = n->data;
- exp_visitor(&v, rel, e, 1, exp_optimize_one,
true, true, true, &changed);
+ n->data = exp_visitor(&v, rel, e, 1,
exp_optimize_one, true, true, true, &changed);
}
}
return rel;
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
@@ -2394,6 +2394,9 @@ rel_exp_visitor(visitor *v, sql_rel *rel
if (!rel)
return rel;
+ if (v->opt >= 0 && rel->opt >= v->opt) /* only once */
+ return rel;
+
if (relations_topdown) {
if (rel->exps && (rel->exps = exps_exp_visitor(v, rel,
rel->exps, 0, exp_rewriter, topdown, relations_topdown, false)) == NULL)
return NULL;
@@ -2475,19 +2478,28 @@ rel_exp_visitor(visitor *v, sql_rel *rel
if ((is_groupby(rel->op) || is_simple_project(rel->op)) &&
rel->r && (rel->r = exps_exp_visitor(v, rel, rel->r, 0, exp_rewriter, topdown,
relations_topdown, false)) == NULL)
return NULL;
}
-
+ if (rel && v->opt >= 0)
+ rel->opt = v->opt;
return rel;
}
sql_rel *
rel_exp_visitor_topdown(visitor *v, sql_rel *rel, exp_rewrite_fptr
exp_rewriter, bool relations_topdown)
{
+ if (!rel)
+ return rel;
+ if (v->opt >= 0)
+ v->opt = rel->opt+1;
return rel_exp_visitor(v, rel, exp_rewriter, true, relations_topdown);
}
sql_rel *
rel_exp_visitor_bottomup(visitor *v, sql_rel *rel, exp_rewrite_fptr
exp_rewriter, bool relations_topdown)
{
+ if (!rel)
+ return rel;
+ if (v->opt >= 0)
+ v->opt = rel->opt+1;
return rel_exp_visitor(v, rel, exp_rewriter, false, relations_topdown);
}
@@ -2604,21 +2616,43 @@ do_rel_visitor(visitor *v, sql_rel *rel,
return rel;
}
-static inline sql_rel *
+static sql_rel *rel_visitor(visitor *v, sql_rel *rel, rel_rewrite_fptr
rel_rewriter, bool topdown);
+
+static sql_rel *
+rel_visitor_td(visitor *v, sql_rel *rel, rel_rewrite_fptr rel_rewriter)
+{
+ v->depth++;
+ rel = rel_visitor(v, rel, rel_rewriter, true);
+ v->depth--;
+ return rel;
+}
+
+static sql_rel *
+rel_visitor_bu(visitor *v, sql_rel *rel, rel_rewrite_fptr rel_rewriter)
+{
+ v->depth++;
+ rel = rel_visitor(v, rel, rel_rewriter, false);
+ v->depth--;
+ return rel;
+}
+
+static sql_rel *
rel_visitor(visitor *v, sql_rel *rel, rel_rewrite_fptr rel_rewriter, bool
topdown)
{
sql_rel *parent = v->parent;
-
if (mvc_highwater(v->sql))
return sql_error(v->sql, 10, SQLSTATE(42000) "Query too
complex: running out of stack space");
if (!rel)
return NULL;
+ if (v->opt >= 0 && rel->opt >= v->opt) /* only once */
+ return rel;
+
if (topdown && !(rel = do_rel_visitor(v, rel, rel_rewriter, true)))
return NULL;
- sql_rel *(*func)(visitor *, sql_rel *, rel_rewrite_fptr) = topdown ?
rel_visitor_topdown : rel_visitor_bottomup;
+ sql_rel *(*func)(visitor *, sql_rel *, rel_rewrite_fptr) = topdown ?
rel_visitor_td : rel_visitor_bu;
v->parent = rel;
switch(rel->op){
@@ -2691,12 +2725,18 @@ rel_visitor(visitor *v, sql_rel *rel, re
if (!topdown)
rel = do_rel_visitor(v, rel, rel_rewriter, false);
+ if (rel && v->opt >= 0)
+ rel->opt = v->opt;
return rel;
}
sql_rel *
rel_visitor_topdown(visitor *v, sql_rel *rel, rel_rewrite_fptr rel_rewriter)
{
+ if (!rel)
+ return rel;
+ if (v->opt >= 0)
+ v->opt = rel->opt+1;
v->depth++;
rel = rel_visitor(v, rel, rel_rewriter, true);
v->depth--;
@@ -2706,6 +2746,10 @@ rel_visitor_topdown(visitor *v, sql_rel
sql_rel *
rel_visitor_bottomup(visitor *v, sql_rel *rel, rel_rewrite_fptr rel_rewriter)
{
+ if (!rel)
+ return rel;
+ if (v->opt >= 0)
+ v->opt = rel->opt+1;
v->depth++;
rel = rel_visitor(v, rel, rel_rewriter, false);
v->depth--;
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
@@ -143,6 +143,7 @@ extern list *rel_dependencies(mvc *sql,
typedef struct visitor {
int changes;
int depth; /* depth of the current relation */
+ int opt;
sql_rel *parent;
mvc *sql;
void *data;
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
@@ -2291,15 +2291,15 @@ exp_physical_types(visitor *v, sql_rel *
(void)depth;
sql_exp *ne = e;
- if (!e || (e->type != e_func && e->type != e_convert) || !e->l)
+ if (!e || e->type != e_func || !e->l)
return e;
- if (e->type != e_convert) {
- list *args = e->l;
- sql_subfunc *f = e->f;
-
+ list *args = e->l;
+ sql_subfunc *f = e->f;
+
+ if (list_length(args) == 2) {
/* multiplication and division on decimals */
- if (is_multiplication(f) && list_length(args) == 2) {
+ if (is_multiplication(f)) {
sql_exp *le = args->h->data;
sql_subtype *lt = exp_subtype(le);
@@ -2325,7 +2325,7 @@ exp_physical_types(visitor *v, sql_rel *
ne = exp_binop(v->sql->sa, e,
exp_atom(v->sql->sa, a), c);
}
}
- } else if (is_division(f) && list_length(args) == 2) {
+ } else if (is_division(f)) {
sql_exp *le = args->h->data;
sql_subtype *lt = exp_subtype(le);
@@ -2488,6 +2488,8 @@ exp_set_type(mvc *sql, sql_exp *te, sql_
static sql_rel *
rel_set_type(visitor *v, sql_rel *rel)
{
+ if (!rel)
+ return rel;
if (is_project(rel->op) && rel->l) {
if (is_set(rel->op)) {
sql_rel *l = rel->l, *r = rel->r;
@@ -3733,7 +3735,7 @@ rewrite_ifthenelse(visitor *v, sql_rel *
sf = e->f;
/* TODO also handle ifthenelse with more than 3 arguments */
- if (is_case_func(sf) && !list_empty(e->l) && list_length(e->l) == 3 &&
rel_has_freevar(v->sql, rel)) {
+ if (is_case_func(sf) && !list_empty(e->l) && list_length(e->l) == 3) {
list *l = e->l;
/* remove unnecessary = true expressions under ifthenelse */
@@ -3750,6 +3752,8 @@ rewrite_ifthenelse(visitor *v, sql_rel *
sql_exp *not_cond;
if (!exp_has_rel(cond) && (exp_has_rel(then_exp) ||
exp_has_rel(else_exp))) {
+ if (!rel_has_freevar(v->sql, rel))
+ return e;
bool single = false;
/* return sql_error(v->sql, 10, SQLSTATE(42000) "time
to rewrite into union\n");
union(
@@ -4478,11 +4482,12 @@ rel_inline_table_func(visitor *v, sql_re
append(r->exps,
e);
}
sql_args a;
+ visitor vv = *v;
if (f->func->ops) {
a.args =
f->func->ops;
a.exps = opf->l;
- v->data = &a;
- r =
rel_exp_visitor_topdown(v, r, &exp_inline_arg, true);
+ vv.data = &a;
+ r =
rel_exp_visitor_topdown(&vv, r, &exp_inline_arg, true);
v->data = NULL;
}
r = rel_unnest(v->sql,
r);
@@ -4560,6 +4565,7 @@ static inline sql_rel *
run_exp_rewriter(visitor *v, sql_rel *rel, exp_rewrite_fptr rewriter, bool
direction, const char *name)
{
(void)name;
+ v->changes = 0;
/*
#ifndef NDEBUG
int changes = v->changes;
@@ -4577,6 +4583,7 @@ static inline sql_rel *
run_rel_rewriter(visitor *v, sql_rel *rel, rel_rewrite_fptr rewriter, const
char *name)
{
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]