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

Reply via email to