Changeset: 5eacccb25119 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/5eacccb25119
Modified Files:
        sql/server/rel_optimizer.c
        sql/test/emptydb/Tests/check.stable.out
        sql/test/emptydb/Tests/check.stable.out.32bit
        sql/test/emptydb/Tests/check.stable.out.int128
Branch: default
Log Message:

Merged rel_remove_union_partitions and rel_remove_empty_join optimizers


diffs (275 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
@@ -5269,68 +5269,6 @@ rel_push_join_down_outer(visitor *v, sql
        return rel;
 }
 
-static int
-rel_is_empty(mvc *sql, sql_rel *rel)
-{
-       if (mvc_highwater(sql))
-               return 0;
-       if ((is_innerjoin(rel->op) || is_left(rel->op) || is_right(rel->op) || 
is_semi(rel->op)) && !list_empty(rel->exps)) {
-               sql_rel *l = rel->l, *r = rel->r;
-               sql_exp *je;
-
-               if (((is_innerjoin(rel->op) || is_left(rel->op) || 
is_semi(rel->op)) && rel_is_empty(sql, l)) ||
-                       ((is_innerjoin(rel->op) || is_right(rel->op)) && 
rel_is_empty(sql, r)))
-                       return 1;
-               /* check */
-               if ((je = rel_is_join_on_pkey(rel, true))) {
-                       int lpnr = rel_part_nr(l, je);
-
-                       if (lpnr >= 0 && !rel_uses_part_nr(r, je, lpnr))
-                               return 1;
-               }
-               return 0;
-       }
-       /* global aggregates always return 1 row */
-       if (is_simple_project(rel->op) || (is_groupby(rel->op) && 
!list_empty(rel->r)) || is_select(rel->op) ||
-               is_topn(rel->op) || is_sample(rel->op) || is_inter(rel->op) || 
is_except(rel->op)) {
-               if (rel->l)
-                       return rel_is_empty(sql, rel->l);
-       } else if (is_innerjoin(rel->op) && list_empty(rel->exps)) { /* 
cartesian product */
-               return rel_is_empty(sql, rel->l) || rel_is_empty(sql, rel->r);
-       }
-       return 0;
-}
-
-/* non overlapping partitions should be removed */
-static inline sql_rel *
-rel_remove_empty_join(visitor *v, sql_rel *rel)
-{
-       if (!is_union(rel->op) || rel_is_ref(rel))
-               return rel;
-       /* For half empty unions replace by projects */
-       if (!rel_is_ref(rel->l) && rel_is_empty(v->sql, rel->l)) {
-               sql_rel *r = rel->r;
-               if (!is_project(r->op))
-                       r = rel_project(v->sql->sa, r, rel_projections(v->sql, 
r, NULL, 1, 1));
-               rel_rename_exps(v->sql, rel->exps, r->exps);
-               rel->r = NULL;
-               rel_destroy(rel);
-               v->changes++;
-               return r;
-       }
-       if (!rel_is_ref(rel->r) && rel_is_empty(v->sql, rel->r)) {
-               sql_rel *l = rel->l;
-               if (!is_project(l->op))
-                       l = rel_project(v->sql->sa, l, rel_projections(v->sql, 
l, NULL, 1, 1));
-               rel_rename_exps(v->sql, rel->exps, l->exps);
-               rel->l = NULL;
-               rel_destroy(rel);
-               v->changes++;
-               return l;
-       }
-       return rel;
-}
-
 static bool
 find_projection_for_join2semi(sql_rel *rel)
 {
@@ -9437,63 +9375,76 @@ exp_skip_output_parts(sql_rel *rel)
 
 /* return true if the given expression is guaranteed to have no rows */
 static int
-exp_is_zero_rows(mvc *sql, sql_rel *rel, sql_rel *sel)
-{
-       sql_table *t;
-       node *n;
-
-       if (!rel || mvc_highwater(sql))
+exp_is_zero_rows(visitor *v, sql_rel *rel, sql_rel *sel)
+{
+       if (!rel || mvc_highwater(v->sql))
                return 0;
        rel = exp_skip_output_parts(rel);
        if (is_select(rel->op) && rel->l) {
                sel = rel;
                rel = exp_skip_output_parts(rel->l);
        }
-       if (!sel)
-               return 0;
-       if (rel->op == op_join)
-               return exp_is_zero_rows(sql, rel->l, sel) || 
exp_is_zero_rows(sql, rel->r, sel);
-       if (rel->op == op_left || is_semi(rel->op))
-               return exp_is_zero_rows(sql, rel->l, sel);
-       if (rel->op == op_right)
-               return exp_is_zero_rows(sql, rel->r, sel);
-       if (!is_basetable(rel->op) || !rel->l)
-               return 0;
-       t = rel->l;
-       if (!isTable(t) || t->access != TABLE_READONLY)
-               return 0;
-
-       if (sel->exps) for (n = sel->exps->h; n; n = n->next) {
-               sql_exp *e = n->data;
-               atom *lval = NULL, *hval = NULL;
-
-               if (e->type == e_cmp && (e->flag == cmp_equal || e->f)) {   /* 
half-ranges are theoretically optimizable here, but not implemented */
-                       sql_exp *c = e->l;
-                       if (c->type == e_column) {
-                               sql_exp *l = e->r;
-                               sql_exp *h = e->f;
-
-                               lval = exp_flatten(sql, l);
-                               hval = h ? exp_flatten(sql, h) : lval;
-                               if (lval && hval) {
-                                       sql_rel *bt;
-                                       sql_column *col = name_find_column(sel, 
exp_relname(c), exp_name(c), -2, &bt);
-                                       char *min = NULL, *max = NULL;
-                                       atom *amin, *amax;
-                                       sql_subtype *ct = exp_subtype(c);
-
-                                       if (col
-                                               && col->t == t
-                                               && 
sql_trans_ranges(sql->session->tr, col, &min, &max)
-                                               && min && max
-                                               && (amin = 
atom_general(sql->sa, ct, min)) && (amax = atom_general(sql->sa, ct, max))
-                                               && !exp_range_overlap(amin, 
amax, lval, hval, false, false)) {
-                                               return 1;
+
+       sql_table *t = is_basetable(rel->op) && rel->l ? rel->l : NULL;
+       bool table_readonly = t && isTable(t) && t->access == TABLE_READONLY;
+
+       if (sel && !list_empty(sel->exps) && (v->value_based_opt || 
table_readonly)) {
+               for (node *n = sel->exps->h; n; n = n->next) {
+                       sql_exp *e = n->data;
+
+                       /* if the expression is false, then the select is empty 
*/
+                       if (v->value_based_opt && (exp_is_false(e) || 
exp_is_null(e)))
+                               return 1;
+                       if (table_readonly && e->type == e_cmp && (e->flag == 
cmp_equal || e->f)) {
+                               /* half-ranges are theoretically optimizable 
here, but not implemented */
+                               sql_exp *c = e->l;
+                               if (c->type == e_column) {
+                                       sql_exp *l = e->r;
+                                       sql_exp *h = e->f;
+
+                                       atom *lval = exp_flatten(v->sql, l);
+                                       atom *hval = h ? exp_flatten(v->sql, h) 
: lval;
+                                       if (lval && hval) {
+                                               sql_rel *bt;
+                                               sql_column *col = 
name_find_column(sel, exp_relname(c), exp_name(c), -2, &bt);
+                                               char *min = NULL, *max = NULL;
+                                               atom *amin, *amax;
+                                               sql_subtype *ct = 
exp_subtype(c);
+
+                                               if (col
+                                                       && col->t == t
+                                                       && 
sql_trans_ranges(v->sql->session->tr, col, &min, &max)
+                                                       && min && max
+                                                       && (amin = 
atom_general(v->sql->sa, ct, min)) && (amax = atom_general(v->sql->sa, ct, max))
+                                                       && 
!exp_range_overlap(amin, amax, lval, hval, false, false)) {
+                                                       return 1;
+                                               }
                                        }
                                }
                        }
                }
        }
+       if ((is_innerjoin(rel->op) || is_left(rel->op) || is_right(rel->op) || 
is_semi(rel->op)) && !list_empty(rel->exps)) {
+               sql_exp *je;
+
+               /* check non overlaping pk-fk join */
+               if ((je = rel_is_join_on_pkey(rel, true))) {
+                       int lpnr = rel_part_nr(rel->l, je);
+
+                       if (lpnr >= 0 && !rel_uses_part_nr(rel->r, je, lpnr))
+                               return 1;
+               }
+               return (((is_innerjoin(rel->op) || is_left(rel->op) || 
is_semi(rel->op)) && exp_is_zero_rows(v, rel->l, sel)) ||
+                       ((is_innerjoin(rel->op) || is_right(rel->op)) && 
exp_is_zero_rows(v, rel->r, sel)));
+       }
+       /* global aggregates always return 1 row */
+       if (is_simple_project(rel->op) || (is_groupby(rel->op) && 
!list_empty(rel->r)) || is_select(rel->op) ||
+               is_topn(rel->op) || is_sample(rel->op) || is_inter(rel->op) || 
is_except(rel->op)) {
+               if (rel->l)
+                       return exp_is_zero_rows(v, rel->l, sel);
+       } else if (is_innerjoin(rel->op) && list_empty(rel->exps)) { /* 
cartesian product */
+               return exp_is_zero_rows(v, rel->l, sel) || exp_is_zero_rows(v, 
rel->r, sel);
+       }
        return 0;
 }
 
@@ -9507,7 +9458,24 @@ rel_remove_union_partitions(visitor *v, 
 {
        if (!is_union(rel->op) || rel_is_ref(rel))
                return rel;
-       if (!rel_is_ref(rel->l) && exp_is_zero_rows(v->sql, rel->l, NULL)) {
+       int left_zero_rows = !rel_is_ref(rel->l) && exp_is_zero_rows(v, rel->l, 
NULL);
+       int right_zero_rows = !rel_is_ref(rel->r) && exp_is_zero_rows(v, 
rel->r, NULL);
+
+       if (left_zero_rows && right_zero_rows) {
+               /* generate dummy relation */
+               list *converted = sa_list(v->sql->sa);
+               sql_rel *nrel = rel_project(v->sql->sa, NULL, 
list_append(sa_list(v->sql->sa), exp_atom_bool(v->sql->sa, 1)));
+               nrel = rel_select(v->sql->sa, nrel, exp_atom_bool(v->sql->sa, 
0));
+
+               for (node *n = rel->exps->h ; n ; n = n->next) {
+                       sql_exp *e = n->data, *a = exp_atom(v->sql->sa, 
atom_general(v->sql->sa, exp_subtype(e), NULL));
+                       exp_prop_alias(v->sql->sa, a, e);
+                       list_append(converted, a);
+               }
+               rel_destroy(rel);
+               v->changes++;
+               return rel_project(v->sql->sa, nrel, converted);
+       } else if (left_zero_rows) {
                sql_rel *r = rel->r;
                if (!is_project(r->op))
                        r = rel_project(v->sql->sa, r, rel_projections(v->sql, 
r, NULL, 1, 1));
@@ -9516,8 +9484,7 @@ rel_remove_union_partitions(visitor *v, 
                rel_destroy(rel);
                v->changes++;
                return r;
-       }
-       if (!rel_is_ref(rel->r) && exp_is_zero_rows(v->sql, rel->r, NULL)) {
+       } else if (right_zero_rows) {
                sql_rel *l = rel->l;
                if (!is_project(l->op))
                        l = rel_project(v->sql->sa, l, rel_projections(v->sql, 
l, NULL, 1, 1));
@@ -9564,7 +9531,6 @@ rel_optimize_unions_bottomup(visitor *v,
 {
        rel = rel_remove_union_partitions(v, rel);
        rel = rel_merge_union(v, rel);
-       rel = rel_remove_empty_join(v, rel);
        return rel;
 }
 
diff --git a/sql/test/emptydb/Tests/check.stable.out 
b/sql/test/emptydb/Tests/check.stable.out
--- a/sql/test/emptydb/Tests/check.stable.out
+++ b/sql/test/emptydb/Tests/check.stable.out
@@ -7786,7 +7786,7 @@ select 'null in value_partitions.value',
 % %12, access, id,     name,   schema_id,      query,  type,   system, 
commit_action,  access, temporary # name
 % char,        smallint,       int,    varchar,        int,    varchar,        
smallint,       boolean,        smallint,       smallint,       tinyint # type
 % 21,  1,      1,      0,      1,      0,      1,      5,      1,      1,      
1 # length
-% .%12,        .tables,        .tables,        .tables,        .tables,        
.tables,        .tables,        .tables,        .tables,        .tables,        
.tables # table_name
+% .%12,        .tables,        sys.tables,     sys.tables,     sys.tables,     
sys.tables,     .tables,        sys.tables,     sys.tables,     sys.tables,     
.tables # table_name
 % %12, temporary,      id,     name,   schema_id,      query,  type,   system, 
commit_action,  access, temporary # name
 % char,        tinyint,        int,    varchar,        int,    varchar,        
smallint,       boolean,        smallint,       smallint,       tinyint # type
 % 24,  1,      1,      0,      1,      0,      1,      5,      1,      1,      
1 # length
diff --git a/sql/test/emptydb/Tests/check.stable.out.32bit 
b/sql/test/emptydb/Tests/check.stable.out.32bit
--- a/sql/test/emptydb/Tests/check.stable.out.32bit
+++ b/sql/test/emptydb/Tests/check.stable.out.32bit
@@ -7786,7 +7786,7 @@ select 'null in value_partitions.value',
 % %12, access, id,     name,   schema_id,      query,  type,   system, 
commit_action,  access, temporary # name
 % char,        smallint,       int,    varchar,        int,    varchar,        
smallint,       boolean,        smallint,       smallint,       tinyint # type
 % 21,  1,      1,      0,      1,      0,      1,      5,      1,      1,      
1 # length
-% .%12,        .tables,        .tables,        .tables,        .tables,        
.tables,        .tables,        .tables,        .tables,        .tables,        
.tables # table_name
+% .%12,        .tables,        sys.tables,     sys.tables,     sys.tables,     
sys.tables,     .tables,        sys.tables,     sys.tables,     sys.tables,     
.tables # table_name
 % %12, temporary,      id,     name,   schema_id,      query,  type,   system, 
commit_action,  access, temporary # name
 % char,        tinyint,        int,    varchar,        int,    varchar,        
smallint,       boolean,        smallint,       smallint,       tinyint # type
 % 24,  1,      1,      0,      1,      0,      1,      5,      1,      1,      
1 # length
diff --git a/sql/test/emptydb/Tests/check.stable.out.int128 
b/sql/test/emptydb/Tests/check.stable.out.int128
--- a/sql/test/emptydb/Tests/check.stable.out.int128
+++ b/sql/test/emptydb/Tests/check.stable.out.int128
@@ -8001,7 +8001,7 @@ select 'null in value_partitions.value',
 % %12, access, id,     name,   schema_id,      query,  type,   system, 
commit_action,  access, temporary # name
 % char,        smallint,       int,    varchar,        int,    varchar,        
smallint,       boolean,        smallint,       smallint,       tinyint # type
 % 21,  1,      1,      0,      1,      0,      1,      5,      1,      1,      
1 # length
-% .%12,        .tables,        .tables,        .tables,        .tables,        
.tables,        .tables,        .tables,        .tables,        .tables,        
.tables # table_name
+% .%12,        .tables,        sys.tables,     sys.tables,     sys.tables,     
sys.tables,     .tables,        sys.tables,     sys.tables,     sys.tables,     
.tables # table_name
 % %12, temporary,      id,     name,   schema_id,      query,  type,   system, 
commit_action,  access, temporary # name
 % char,        tinyint,        int,    varchar,        int,    varchar,        
smallint,       boolean,        smallint,       smallint,       tinyint # type
 % 24,  1,      1,      0,      1,      0,      1,      5,      1,      1,      
1 # length
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to