Changeset: d66505ca653e for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=d66505ca653e
Modified Files:
        sql/server/rel_optimizer.c
        sql/server/rel_select.c
        sql/server/rel_select.h
        
sql/test/BugTracker-2016/Tests/LEFT-JOIN_with_OR_conditions_triggers_assertion.Bug-3908.stable.out
        
sql/test/BugTracker-2016/Tests/incorrect_column_name_in_OR_condition_of_LEFT-JOIN_crashes_mserver.Bug-3909.stable.err
Branch: Jul2015
Log Message:

rewrite outer-joins with or expressions, fixes bug 3908.


diffs (221 lines):

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
@@ -6386,6 +6386,112 @@ rel_semijoin_use_fk(int *changes, mvc *s
        return rel;
 }
 
+/* leftouterjoin(a,b)[ a.C op b.D or a.E op2 b.F ]) -> 
+ * union(
+ *     join(a,b)[ a.C op b.D or a.E op2 b. F ], 
+ *     project( 
+ *             antijoin(a,b) [a.C op b.D or a.E op2 b.F ])
+ *             [ a.*, NULL * foreach column of b]
+ * )
+ */
+static int
+exps_nr_of_or(list *exps)
+{
+       int ors = 0;
+       node *n;
+
+       if (!exps)
+               return ors;
+       for(n=exps->h; n; n = n->next) {
+               sql_exp *e = n->data;
+
+               if (e->type == e_cmp && e->flag == cmp_or)
+                       ors++;
+       }
+       return ors;
+}
+
+static void 
+add_nulls(mvc *sql, sql_rel *rel, sql_rel *r)
+{
+       list *exps;
+       node *n;
+
+       exps = rel_projections(sql, r, NULL, 1, 1);
+       for(n = exps->h; n; n = n->next) {
+               sql_exp *e = n->data, *ne;
+
+               ne = exp_atom(sql->sa, atom_general(sql->sa, exp_subtype(e), 
NULL));
+               exp_setname(sql->sa, ne, exp_relname(e), exp_name(e));
+               append(rel->exps, ne);
+       }
+}
+
+static sql_rel *
+rel_split_outerjoin(int *changes, mvc *sql, sql_rel *rel)
+{
+       if ((rel->op == op_left || rel->op == op_right || rel->op == op_full) 
&& 
+                       list_length(rel->exps) && exps_nr_of_or(rel->exps) == 
list_length(rel->exps)) { 
+               sql_rel *l = rel_dup(rel->l), *nl, *nll, *nlr;
+               sql_rel *r = rel_dup(rel->r), *nr;
+               sql_exp *e;
+
+               nll = rel_crossproduct(sql->sa, l, r, op_join); 
+               nlr = rel_crossproduct(sql->sa, l, r, op_join); 
+
+               /* TODO find or exp, ie handle rest with extra joins */
+               /* expect only a single or expr for now */
+               assert(list_length(rel->exps) == 1);
+               e = rel->exps->h->data;
+               nll->exps = exps_copy(sql->sa, e->l);
+               nlr->exps = exps_copy(sql->sa, e->r);
+               nl = rel_or( sql, nll, nlr, NULL, e->l, e->r);
+
+               if (rel->op == op_full) {
+                       l = rel_dup(l);
+                       r = rel_dup(r);
+               }
+
+               if (rel->op == op_left || rel->op == op_full) {
+                       /* split in 2 anti joins */
+                       nr = rel_crossproduct(sql->sa, l, r, op_anti);
+                       nr->exps = exps_copy(sql->sa, e->l);
+                       nr = rel_crossproduct(sql->sa, nr, r, op_anti);
+                       nr->exps = exps_copy(sql->sa, e->r);
+
+                       /* project left */
+                       nr = rel_project(sql->sa, nr, 
+                               rel_projections(sql, l, NULL, 1, 1));
+                       /* add null's for right */
+                       add_nulls( sql, nr, r);
+                       nl = rel_setop(sql->sa, nl, nr, op_union);
+               }
+               if (rel->op == op_right || rel->op == op_full) {
+                       /* split in 2 anti joins */
+                       nr = rel_crossproduct(sql->sa, r, l, op_anti);
+                       nr->exps = exps_copy(sql->sa, e->l);
+                       nr = rel_crossproduct(sql->sa, nr, l, op_anti);
+                       nr->exps = exps_copy(sql->sa, e->r);
+
+                       nr = rel_project(sql->sa, nr, sa_list(sql->sa));
+                       /* add null's for left */
+                       add_nulls( sql, nr, l);
+                       /* project right */
+                       nr->exps = list_merge(nr->exps, 
+                               rel_projections(sql, r, NULL, 1, 1),
+                               (fdup)NULL);
+                       nl = rel_setop(sql->sa, nl, nr, op_union);
+               }
+
+               rel->l = NULL;
+               rel->r = NULL;
+               rel_destroy(rel);
+               *changes = 1;
+               rel = nl;
+       }
+       return rel;
+}
+
 /* rewrite sqltype into backend types */
 static sql_rel *
 rel_rewrite_types(int *changes, mvc *sql, sql_rel *rel)
@@ -7089,7 +7195,9 @@ static sql_rel *
                return rel;
        }
        rel = rel_project(sql->sa, rel, rel_projections(sql, rel, NULL, 1, 1));
-       e = rel_unop_(sql, rel->exps->h->data, NULL, "identity", card_value);
+       //e = rel_unop_(sql, rel->exps->h->data, NULL, "identity", card_value);
+       e = rel->exps->h->data;
+       e = exp_unop(sql->sa, e, sql_bind_func(sql->sa, NULL, "identity", 
exp_subtype(e), NULL, F_FUNC));
        e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
        *exp = exp_label(sql->sa, e, ++sql->label);
        rel_project_add_exp(sql, rel, e);
@@ -7587,6 +7695,8 @@ static sql_rel *
                if (level <= 0)
                        rel = rewrite_topdown(sql, rel, &rel_semijoin_use_fk, 
&changes);
        }
+       if (gp.cnt[op_left] || gp.cnt[op_right] || gp.cnt[op_full]) 
+               rel = rewrite_topdown(sql, rel, &rel_split_outerjoin, &changes);
 
        if (gp.cnt[op_select]) {
                /* only once */
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
@@ -2660,8 +2660,8 @@ rel_compare(mvc *sql, sql_rel *rel, symb
        return rel_compare_exp(sql, rel, ls, rs, compare_op, rs2, k.reduce);
 }
 
-static sql_rel *
-rel_or(mvc *sql, sql_rel *l, sql_rel *r, list *oexps, list *lexps, list 
*rexps, int f)
+sql_rel *
+rel_or(mvc *sql, sql_rel *l, sql_rel *r, list *oexps, list *lexps, list *rexps)
 {
        sql_rel *rel, *ll = l->l, *rl = r->l;
 
@@ -2676,7 +2676,7 @@ rel_or(mvc *sql, sql_rel *l, sql_rel *r,
        }
 
        if (l->op == r->op && 
-               ((ll == rl && l->r == r->r) ||
+               ((ll == rl && l->r == r->r && l->r == NULL /* or check if 
columns are equal*/) ||
                (exps_card(l->exps) == exps_card(r->exps) && exps_card(l->exps) 
<= CARD_ATOM))) {
                sql_exp *e = exp_or(sql->sa, l->exps, r->exps);
                list *nl = new_exp_list(sql->sa); 
@@ -2686,7 +2686,6 @@ rel_or(mvc *sql, sql_rel *l, sql_rel *r,
                l->exps = nl;
                return l;
        }
-       (void)f;
        l = rel_project(sql->sa, l, rel_projections(sql, l, NULL, 1, 1));
        r = rel_project(sql->sa, r, rel_projections(sql, r, NULL, 1, 1));
        set_processed(l);
@@ -3118,7 +3117,7 @@ rel_logical_exp(mvc *sql, sql_rel *rel, 
 
                if (!lr || !rr)
                        return NULL;
-               return rel_or(sql, lr, rr, exps, lexps, rexps, f);
+               return rel_or(sql, lr, rr, exps, lexps, rexps);
        }
        case SQL_AND:
        {
diff --git a/sql/server/rel_select.h b/sql/server/rel_select.h
--- a/sql/server/rel_select.h
+++ b/sql/server/rel_select.h
@@ -49,6 +49,7 @@ extern void rel_join_add_exp(sql_allocat
 
 extern sql_rel *rel_push_select(mvc *sql, sql_rel *rel, sql_exp *ls, sql_exp 
*e);
 extern sql_rel *rel_push_join(mvc *sql, sql_rel *rel, sql_exp *ls, sql_exp 
*rs, sql_exp *rs2, sql_exp *e);
+extern sql_rel *rel_or(mvc *sql, sql_rel *l, sql_rel *r, list *oexps, list 
*lexps, list *rexps);
 /* TODO rename to exp_check_type + move to rel_exp.mx */
 extern sql_exp *rel_check_type(mvc *sql, sql_subtype *t, sql_exp *exp, int 
tpe);
 extern int rel_convert_types(mvc *sql, sql_exp **L, sql_exp **R, int 
scale_fixing, int tpe);
diff --git 
a/sql/test/BugTracker-2016/Tests/LEFT-JOIN_with_OR_conditions_triggers_assertion.Bug-3908.stable.out
 
b/sql/test/BugTracker-2016/Tests/LEFT-JOIN_with_OR_conditions_triggers_assertion.Bug-3908.stable.out
--- 
a/sql/test/BugTracker-2016/Tests/LEFT-JOIN_with_OR_conditions_triggers_assertion.Bug-3908.stable.out
+++ 
b/sql/test/BugTracker-2016/Tests/LEFT-JOIN_with_OR_conditions_triggers_assertion.Bug-3908.stable.out
@@ -80,10 +80,10 @@ Ready.
 % .b,  .f # table_name
 % value,       id # name
 % char,        int # type
-% 10,  1 # length
+% 10,  3 # length
 [ "aaa",       100     ]
+[ "bbb",       101     ]
 [ "bbb",       100     ]
-[ "bbb",       101     ]
 [ "ccc",       101     ]
 #DROP TABLE bar;
 #DROP TABLE foo;
diff --git 
a/sql/test/BugTracker-2016/Tests/incorrect_column_name_in_OR_condition_of_LEFT-JOIN_crashes_mserver.Bug-3909.stable.err
 
b/sql/test/BugTracker-2016/Tests/incorrect_column_name_in_OR_condition_of_LEFT-JOIN_crashes_mserver.Bug-3909.stable.err
--- 
a/sql/test/BugTracker-2016/Tests/incorrect_column_name_in_OR_condition_of_LEFT-JOIN_crashes_mserver.Bug-3909.stable.err
+++ 
b/sql/test/BugTracker-2016/Tests/incorrect_column_name_in_OR_condition_of_LEFT-JOIN_crashes_mserver.Bug-3909.stable.err
@@ -30,13 +30,7 @@ stderr of test 'incorrect_column_name_in
 # 12:49:55 >  "mclient" "-lsql" "-ftest" "-Eutf-8" "-i" "-e" 
"--host=/var/tmp/mtest-29239" "--port=35896"
 # 12:49:55 >  
 
-MAPI  = (monetdb) /var/tmp/mtest-15285/.s.monetdb.30430
-QUERY = CREATE TABLE foo (id INTEGER, bar1 INTEGER, bar2 INTEGER);
-ERROR = !CREATE TABLE: name 'foo' already in use
-MAPI  = (monetdb) /var/tmp/mtest-15285/.s.monetdb.30430
-QUERY = CREATE TABLE bar (barid INTEGER, value CHAR(10));
-ERROR = !CREATE TABLE: name 'bar' already in use
-MAPI  = (monetdb) /var/tmp/mtest-15285/.s.monetdb.30430
+MAPI  = (monetdb) /var/tmp/mtest-17623/.s.monetdb.37506
 QUERY = SELECT B.value, F.id FROM bar B LEFT JOIN foo F ON (F.bar1 = B.barid 
OR F.bar2 = B.id);
 ERROR = !SELECT: no such column 'b.id' 
 
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to