Changeset: 41f41926cf97 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/41f41926cf97
Modified Files:
        sql/server/rel_optimize_sel.c
Branch: Aug2024
Log Message:

make sure we handle range joins correctly when reordering joins.


diffs (157 lines):

diff --git a/sql/server/rel_optimize_sel.c b/sql/server/rel_optimize_sel.c
--- a/sql/server/rel_optimize_sel.c
+++ b/sql/server/rel_optimize_sel.c
@@ -2090,7 +2090,7 @@ popcount64(uint64_t x)
 static sql_rel *
 order_joins(visitor *v, list *rels, list *exps)
 {
-       sql_rel *top = NULL, *l = NULL, *r = NULL;
+       sql_rel *top = NULL, *l = NULL, *r = NULL, *f = NULL;
        sql_exp *cje;
        node *djn;
        list *sdje, *n_rels = NULL;
@@ -2130,8 +2130,7 @@ order_joins(visitor *v, list *rels, list
        for (node *n = sdje->h; n; n = n->next, ci++) {
                sql_exp *cje = n->data;
 
-               h[ci] = r1[ci] = r2[ci] = 0;
-               r3[ci] = 0;
+               h[ci] = r1[ci] = r2[ci] = r3[ci] = 0;
                if (cje->type == e_cmp) {
                        cje->tmp = ci;
                        r1[ci] = cje->flag == cmp_filter ? 
exps_find_one_rel(rels_a, nr_rels, cje->l) : exp_find_one_rel(rels_a, nr_rels, 
cje->l);
@@ -2142,7 +2141,7 @@ order_joins(visitor *v, list *rels, list
                                h[ci] |= ((ulng)1)<<((r2[ci]-1)%64);
                        if (cje->f && cje->flag != cmp_filter) {
                                r3[ci] = exp_find_one_rel(rels_a, nr_rels, 
cje->f);
-                               if (r3[ci] == r2[ci])
+                               if (r3[ci] == r2[ci] || r3[ci] == r1[ci])
                                        r3[ci] = 0;
                                if (r3[ci])
                                        h[ci] |= ((ulng)1)<<((r3[ci]-1)%64);
@@ -2155,13 +2154,15 @@ order_joins(visitor *v, list *rels, list
                for (node *n = sdje->h; n && !l && !r; n = n->next, ci++) {
                        cje = n->data;
 
-                       /* find the involved relations */
+                       if (n->next && r3[cje->tmp])
+                               continue;
 
                        /* complex expressions may touch multiple base tables
                         * Should be pushed up to extra selection.
                         * */
                        if (0 && popcount64(h[cje->tmp]) > 2)
                                assert(0);
+                       /* find the involved relations */
                        if (cje->type == e_cmp) {
                                l = rels_a[r1[cje->tmp]];
                                r = rels_a[r2[cje->tmp]];
@@ -2184,10 +2185,10 @@ order_joins(visitor *v, list *rels, list
                }
 
                /* Create a relation between l and r. Since the calling
-                  functions rewrote the join tree, into a list of expressions
-                  and a list of (simple) relations, there are no outer joins
-                  involved, we can simply do a crossproduct here.
-                */
+                  functions rewrote the join tree, into a list of expressions
+                  and a list of (simple) relations, there are no outer joins
+                  involved, we can simply do a crossproduct here.
+                  */
                rsingle = is_single(r);
                reset_single(r);
                top = rel_crossproduct(v->sql->sa, l, r, op_join);
@@ -2213,7 +2214,8 @@ order_joins(visitor *v, list *rels, list
                /* find the first expression which could be added */
                for(djn = sdje->h; djn && !fnd && rels->h; djn = 
(!fnd)?djn->next:NULL) {
                        node *en;
-                       l = r = NULL;
+                       l = r = f = NULL;
+                       int needs3 = 0;
 
                        cje = djn->data;
                        if ((h[cje->tmp] & rel_mask) > 0) {
@@ -2221,48 +2223,65 @@ order_joins(visitor *v, list *rels, list
                                        l = rels_a[r1[cje->tmp]];
                                if (rel_mask & 
(((ulng)1)<<((r2[cje->tmp]-1)%64)))
                                        r = rels_a[r2[cje->tmp]];
+                               if (cje->f && r3[cje->tmp] && (rel_mask & 
(((ulng)1)<<((r3[cje->tmp]-1)%64)))) {
+                                       f = rels_a[r3[cje->tmp]];
+                                       needs3 = 1;
+                               }
                        }
                        if (!direct) { /* check if at least one side in n_rels 
*/
                                if (l && !list_find(n_rels, l, NULL))
                                        l = NULL;
                                if (r && !list_find(n_rels, r, NULL))
                                        r = NULL;
+                               if (f && !list_find(n_rels, f, NULL))
+                                       f = NULL;
                        }
 
-                       if (l && r) {
+                       if ((!needs3 && l && r) || (needs3 && l && r && f)) {
                                assert(0);
                                /* create a selection on the current */
                                rel_join_add_exp(v->sql->sa, top, cje);
                                fnd = 1;
-                       } else if (l || r) {
-                               /* TODO: handle case for joins which need > 2 
relations, ie where the current 'top' of the
-                                * join tree needs to add more then one 
relation */
+                       } else if ((!needs3 && (l || r)) || (needs3 && (l || r 
|| f))) {
+                               sql_rel *nr[2]= {NULL, NULL};
                                rel_mask |= h[cje->tmp];
-                               if (l) {
-                                       r = rels_a[r2[cje->tmp]];
-                               } else {
-                                       l = r;
-                                       r = rels_a[r1[cje->tmp]];
-                               }
-                               if (!r) {
+                               int i = 0;
+                               if (!l)
+                                       nr[i++] = rels_a[r1[cje->tmp]];
+                               if (!r)
+                                       nr[i++] = rels_a[r2[cje->tmp]];
+                               if (needs3 && !f)
+                                       nr[i++] = rels_a[r3[cje->tmp]];
+                               if (!nr[0]) {
                                        fnd = 1; /* not really, but this bails 
out */
                                        list_remove_data(sdje, NULL, cje); /* 
handle later as select */
                                        continue;
                                }
-
                                /* remove the expression from the lists */
                                list_remove_data(sdje, NULL, cje);
 
-                               list_remove_data(rels, NULL, r);
+                               list_remove_data(rels, NULL, nr[0]);
                                if (!direct)
-                                       append(n_rels, r);
+                                       append(n_rels, nr[0]);
+                               if (i > 1 && nr[1]) {
+                                       list_remove_data(rels, NULL, nr[1]);
+                                       if (!direct)
+                                               append(n_rels, nr[1]);
+                               }
 
                                /* create a join using the current expression */
-                               rsingle = is_single(r);
-                               reset_single(r);
-                               top = rel_crossproduct(v->sql->sa, top, r, 
op_join);
+                               rsingle = is_single(nr[0]);
+                               reset_single(nr[0]);
+                               top = rel_crossproduct(v->sql->sa, top, nr[0], 
op_join);
                                if (rsingle)
-                                       set_single(r);
+                                       set_single(nr[0]);
+                               if (i > 1 && nr[1]) {
+                                       rsingle = is_single(nr[1]);
+                                       reset_single(nr[1]);
+                                       top = rel_crossproduct(v->sql->sa, top, 
nr[1], op_join);
+                                       if (rsingle)
+                                               set_single(nr[1]);
+                               }
                                rel_join_add_exp(v->sql->sa, top, cje);
 
                                /* all join expressions on these tables */
_______________________________________________
checkin-list mailing list -- checkin-list@monetdb.org
To unsubscribe send an email to checkin-list-le...@monetdb.org

Reply via email to