Changeset: ae6674917107 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=ae6674917107
Modified Files:
        sql/server/rel_optimizer.c
        sql/server/rel_rel.c
        
sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-plan-1join-query.stable.out
        
sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-plan-1join-view.stable.out
        
sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-plan-2join-query.stable.out
        
sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-plan-2join-view.stable.out
        
sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-prologue.sql
        
sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-prologue.stable.out
        sql/test/xquery/Tests/q01.stable.out
Branch: Jun2020
Log Message:

If a column of an index has NULL values, set the index as nullable. At the 
foreign key join simplification, if the foreign key has NULL values and the 
other side doesn't, then filter those out


diffs (truncated from 598 to 300 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
@@ -1801,12 +1801,12 @@ rel_simplify_project_fk_join(mvc *sql, s
 {
        sql_rel *rl = r->l;
        sql_rel *rr = r->r;
-       sql_exp *je;
+       sql_exp *je, *le, *nje, *re;
        node *n;
        int fk_left = 1;
 
        /* check for foreign key join */
-       if (!r->exps || list_length(r->exps) != 1)
+       if (list_length(r->exps) != 1)
                return r;
        je = r->exps->h->data;
        if (je && !find_prop(je->p, PROP_JOINIDX))
@@ -1851,10 +1851,23 @@ rel_simplify_project_fk_join(mvc *sql, s
        }
 
        (*changes)++;
-       /* rewrite, ie remove pkey side */
-       if (fk_left)
-               return r->l;
-       return r->r;
+       /* rewrite, ie remove pkey side if possible */
+       le = (sql_exp*)je->l, re = (sql_exp*)je->l;
+
+       /* both have NULL and there are semantics, the join cannot be removed */
+       if (is_semantics(je) && has_nil(le) && has_nil(re))
+               return r;
+
+       /* if the foreign key column doesn't have NULL values, then return it */
+       if (!has_nil(le) || is_full(r->op) || (fk_left && is_left(r->op)) || 
(!fk_left && is_right(r->op)))
+               return fk_left ? r->l : r->r;
+
+       /* remove NULL values, ie generate a select not null */
+       nje = exp_compare(sql->sa, exp_ref(sql, le), exp_atom(sql->sa, 
atom_general(sql->sa, exp_subtype(le), NULL)), cmp_equal);
+       set_anti(nje);
+       set_has_no_nil(nje);
+       set_semantics(nje);
+       return rel_select(sql->sa, fk_left ? r->l : r->r, nje);
 }
 
 static sql_rel *
@@ -1862,11 +1875,11 @@ rel_simplify_count_fk_join(mvc *sql, sql
 {
        sql_rel *rl = r->l;
        sql_rel *rr = r->r;
-       sql_exp *oce, *je;
+       sql_exp *je, *le, *nje, *re, *oce;
        int fk_left = 1;
 
        /* check for foreign key join */
-       if (!r->exps || list_length(r->exps) != 1)
+       if (list_length(r->exps) != 1)
                return r;
        je = r->exps->h->data;
        if (je && !find_prop(je->p, PROP_JOINIDX))
@@ -1899,10 +1912,23 @@ rel_simplify_count_fk_join(mvc *sql, sql
        }
 
        (*changes)++;
-       /* rewrite, ie remove pkey side */
-       if (fk_left)
-               return r->l;
-       return r->r;
+       /* rewrite, ie remove pkey side if possible */
+       le = (sql_exp*)je->l, re = (sql_exp*)je->l;
+
+       /* both have NULL and there are semantics, the join cannot be removed */
+       if (is_semantics(je) && has_nil(le) && has_nil(re))
+               return r;
+
+       /* if the foreign key column doesn't have NULL values, then return it */
+       if (!has_nil(le) || is_full(r->op) || (fk_left && is_left(r->op)) || 
(!fk_left && is_right(r->op)))
+               return fk_left ? r->l : r->r;
+
+       /* remove NULL values, ie generate a select not null */
+       nje = exp_compare(sql->sa, exp_ref(sql, le), exp_atom(sql->sa, 
atom_general(sql->sa, exp_subtype(le), NULL)), cmp_equal);
+       set_anti(nje);
+       set_has_no_nil(nje);
+       set_semantics(nje);
+       return rel_select(sql->sa, fk_left ? r->l : r->r, nje);
 }
 
 /*
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
@@ -835,6 +835,7 @@ rel_basetable(mvc *sql, sql_table *t, co
                        sql_idx *i = cn->data;
                        sql_subtype *t = sql_bind_localtype("lng"); /* hash 
"lng" */
                        char *iname = NULL;
+                       int has_nils = 0;
 
                        /* do not include empty indices in the plan */
                        if (hash_index(i->type) && list_length(i->columns) <= 1)
@@ -844,7 +845,13 @@ rel_basetable(mvc *sql, sql_table *t, co
                                t = sql_bind_localtype("oid");
 
                        iname = sa_strconcat( sa, "%", i->base.name);
-                       e = exp_alias(sa, atname, iname, tname, iname, t, 
CARD_MULTI, 0, 1);
+                       for (node *n = i->columns->h ; n && !has_nils; n = 
n->next) { /* check for NULL values */
+                               sql_kc *kc = n->data;
+
+                               if (kc->c->null)
+                                       has_nils = 1;
+                       }
+                       e = exp_alias(sa, atname, iname, tname, iname, t, 
CARD_MULTI, has_nils, 1);
                        /* index names are prefixed, to make them independent */
                        if (hash_index(i->type)) {
                                p = e->p = prop_create(sa, PROP_HASHIDX, e->p);
diff --git 
a/sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-plan-1join-query.stable.out
 
b/sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-plan-1join-query.stable.out
--- 
a/sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-plan-1join-query.stable.out
+++ 
b/sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-plan-1join-query.stable.out
@@ -50,24 +50,24 @@ project (
 % .plan # table_name
 % rel # name
 % clob # type
-% 114 # length
+% 105 # length
 project (
 | left outer join (
-| | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk1_fkey" NOT NULL 
JOINIDX sys.fk.fk_fk1_fkey ] COUNT ,
+| | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk1_fkey" JOINIDX 
sys.fk.fk_fk1_fkey ] COUNT ,
 | | table(sys.pk1) [ "pk1"."v1", "pk1"."%TID%" NOT NULL ] COUNT 
-| ) [ "fk"."%fk_fk1_fkey" NOT NULL = "pk1"."%TID%" NOT NULL JOINIDX 
sys.fk.fk_fk1_fkey ]
+| ) [ "fk"."%fk_fk1_fkey" = "pk1"."%TID%" NOT NULL JOINIDX sys.fk.fk_fk1_fkey ]
 ) [ "fk"."id" NOT NULL HASHCOL , "pk1"."v1" ] [ "fk"."id" ASC NOT NULL HASHCOL 
 ]
 
 #plan select id , v2  from fk left outer join pk2 on fk.fk2 = pk2.pk2 order by 
id;
 % .plan # table_name
 % rel # name
 % clob # type
-% 114 # length
+% 105 # length
 project (
 | left outer join (
-| | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk2_fkey" NOT NULL 
JOINIDX sys.fk.fk_fk2_fkey ] COUNT ,
+| | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk2_fkey" JOINIDX 
sys.fk.fk_fk2_fkey ] COUNT ,
 | | table(sys.pk2) [ "pk2"."v2", "pk2"."%TID%" NOT NULL ] COUNT 
-| ) [ "fk"."%fk_fk2_fkey" NOT NULL = "pk2"."%TID%" NOT NULL JOINIDX 
sys.fk.fk_fk2_fkey ]
+| ) [ "fk"."%fk_fk2_fkey" = "pk2"."%TID%" NOT NULL JOINIDX sys.fk.fk_fk2_fkey ]
 ) [ "fk"."id" NOT NULL HASHCOL , "pk2"."v2" ] [ "fk"."id" ASC NOT NULL HASHCOL 
 ]
 #plan select count(*) from pk1 right outer join fk on fk.fk1 = pk1.pk1;
 % .plan # table_name
@@ -91,23 +91,23 @@ project (
 % .plan # table_name
 % rel # name
 % clob # type
-% 113 # length
+% 104 # length
 project (
 | right outer join (
 | | table(sys.pk1) [ "pk1"."v1", "pk1"."%TID%" NOT NULL ] COUNT ,
-| | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk1_fkey" NOT NULL 
JOINIDX sys.fk.fk_fk1_fkey ] COUNT 
-| ) [ "fk"."%fk_fk1_fkey" NOT NULL = "pk1"."%TID%" NOT NULL JOINIDX 
sys.fk.fk_fk1_fkey ]
+| | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk1_fkey" JOINIDX 
sys.fk.fk_fk1_fkey ] COUNT 
+| ) [ "fk"."%fk_fk1_fkey" = "pk1"."%TID%" NOT NULL JOINIDX sys.fk.fk_fk1_fkey ]
 ) [ "fk"."id" NOT NULL HASHCOL , "pk1"."v1" ] [ "fk"."id" ASC NOT NULL HASHCOL 
 ]
 #plan select id , v2  from pk2 right outer join fk on fk.fk2 = pk2.pk2 order 
by id;
 % .plan # table_name
 % rel # name
 % clob # type
-% 113 # length
+% 104 # length
 project (
 | right outer join (
 | | table(sys.pk2) [ "pk2"."v2", "pk2"."%TID%" NOT NULL ] COUNT ,
-| | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk2_fkey" NOT NULL 
JOINIDX sys.fk.fk_fk2_fkey ] COUNT 
-| ) [ "fk"."%fk_fk2_fkey" NOT NULL = "pk2"."%TID%" NOT NULL JOINIDX 
sys.fk.fk_fk2_fkey ]
+| | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk2_fkey" JOINIDX 
sys.fk.fk_fk2_fkey ] COUNT 
+| ) [ "fk"."%fk_fk2_fkey" = "pk2"."%TID%" NOT NULL JOINIDX sys.fk.fk_fk2_fkey ]
 ) [ "fk"."id" NOT NULL HASHCOL , "pk2"."v2" ] [ "fk"."id" ASC NOT NULL HASHCOL 
 ]
 #plan select count(*) from pk1 full outer join fk on fk.fk1 = pk1.pk1;
 % .plan # table_name
@@ -131,63 +131,67 @@ project (
 % .plan # table_name
 % rel # name
 % clob # type
-% 113 # length
+% 104 # length
 project (
 | full outer join (
 | | table(sys.pk1) [ "pk1"."v1", "pk1"."%TID%" NOT NULL ] COUNT ,
-| | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk1_fkey" NOT NULL 
JOINIDX sys.fk.fk_fk1_fkey ] COUNT 
-| ) [ "fk"."%fk_fk1_fkey" NOT NULL = "pk1"."%TID%" NOT NULL JOINIDX 
sys.fk.fk_fk1_fkey ]
+| | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk1_fkey" JOINIDX 
sys.fk.fk_fk1_fkey ] COUNT 
+| ) [ "fk"."%fk_fk1_fkey" = "pk1"."%TID%" NOT NULL JOINIDX sys.fk.fk_fk1_fkey ]
 ) [ "fk"."id" HASHCOL , "pk1"."v1" ] [ "fk"."id" ASC HASHCOL  ]
 #plan select id , v2  from pk2 full outer join fk on fk.fk2 = pk2.pk2 order by 
id;
 % .plan # table_name
 % rel # name
 % clob # type
-% 113 # length
+% 104 # length
 project (
 | full outer join (
 | | table(sys.pk2) [ "pk2"."v2", "pk2"."%TID%" NOT NULL ] COUNT ,
-| | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk2_fkey" NOT NULL 
JOINIDX sys.fk.fk_fk2_fkey ] COUNT 
-| ) [ "fk"."%fk_fk2_fkey" NOT NULL = "pk2"."%TID%" NOT NULL JOINIDX 
sys.fk.fk_fk2_fkey ]
+| | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk2_fkey" JOINIDX 
sys.fk.fk_fk2_fkey ] COUNT 
+| ) [ "fk"."%fk_fk2_fkey" = "pk2"."%TID%" NOT NULL JOINIDX sys.fk.fk_fk2_fkey ]
 ) [ "fk"."id" HASHCOL , "pk2"."v2" ] [ "fk"."id" ASC HASHCOL  ]
 #plan select count(*) from pk1 join fk on fk.fk1 = pk1.pk1;
 % .plan # table_name
 % rel # name
 % clob # type
-% 56 # length
+% 77 # length
 project (
 | group by (
-| | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL  ] COUNT 
+| | select (
+| | | table(sys.fk) [ "fk"."%fk_fk1_fkey" JOINIDX sys.fk.fk_fk1_fkey ] COUNT 
+| | ) [ "fk"."%fk_fk1_fkey" ! * = oid "NULL" ]
 | ) [  ] [ sys.count() NOT NULL as "%3"."%3" ]
 ) [ "%3"."%3" NOT NULL ]
 #plan select id       from pk1 join fk on fk.fk1 = pk1.pk1 order by id;
 % .plan # table_name
 % rel # name
 % clob # type
-% 69 # length
+% 104 # length
 project (
-| table(sys.fk) [ "fk"."id" NOT NULL HASHCOL  ] COUNT 
+| select (
+| | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk1_fkey" JOINIDX 
sys.fk.fk_fk1_fkey ] COUNT 
+| ) [ "fk"."%fk_fk1_fkey" ! * = oid "NULL" ]
 ) [ "fk"."id" NOT NULL HASHCOL  ] [ "fk"."id" ASC NOT NULL HASHCOL  ]
 #plan select id , v1  from pk1 join fk on fk.fk1 = pk1.pk1 order by id;
 % .plan # table_name
 % rel # name
 % clob # type
-% 114 # length
+% 105 # length
 project (
 | join (
-| | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk1_fkey" NOT NULL 
JOINIDX sys.fk.fk_fk1_fkey ] COUNT ,
+| | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk1_fkey" JOINIDX 
sys.fk.fk_fk1_fkey ] COUNT ,
 | | table(sys.pk1) [ "pk1"."v1", "pk1"."%TID%" NOT NULL ] COUNT 
-| ) [ "fk"."%fk_fk1_fkey" NOT NULL = "pk1"."%TID%" NOT NULL JOINIDX 
sys.fk.fk_fk1_fkey ]
+| ) [ "fk"."%fk_fk1_fkey" = "pk1"."%TID%" NOT NULL JOINIDX sys.fk.fk_fk1_fkey ]
 ) [ "fk"."id" NOT NULL HASHCOL , "pk1"."v1" ] [ "fk"."id" ASC NOT NULL HASHCOL 
 ]
 #plan select id , v2  from pk2 join fk on fk.fk2 = pk2.pk2 order by id;
 % .plan # table_name
 % rel # name
 % clob # type
-% 114 # length
+% 105 # length
 project (
 | join (
-| | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk2_fkey" NOT NULL 
JOINIDX sys.fk.fk_fk2_fkey ] COUNT ,
+| | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk2_fkey" JOINIDX 
sys.fk.fk_fk2_fkey ] COUNT ,
 | | table(sys.pk2) [ "pk2"."v2", "pk2"."%TID%" NOT NULL ] COUNT 
-| ) [ "fk"."%fk_fk2_fkey" NOT NULL = "pk2"."%TID%" NOT NULL JOINIDX 
sys.fk.fk_fk2_fkey ]
+| ) [ "fk"."%fk_fk2_fkey" = "pk2"."%TID%" NOT NULL JOINIDX sys.fk.fk_fk2_fkey ]
 ) [ "fk"."id" NOT NULL HASHCOL , "pk2"."v2" ] [ "fk"."id" ASC NOT NULL HASHCOL 
 ]
 
 # 01:44:33 >  
diff --git 
a/sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-plan-1join-view.stable.out
 
b/sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-plan-1join-view.stable.out
--- 
a/sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-plan-1join-view.stable.out
+++ 
b/sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-plan-1join-view.stable.out
@@ -52,13 +52,13 @@ project (
 % .plan # table_name
 % rel # name
 % clob # type
-% 116 # length
+% 107 # length
 project (
 | project (
 | | left outer join (
-| | | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk1_fkey" NOT 
NULL JOINIDX sys.fk.fk_fk1_fkey ] COUNT ,
+| | | table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk1_fkey" JOINIDX 
sys.fk.fk_fk1_fkey ] COUNT ,
 | | | table(sys.pk1) [ "pk1"."v1", "pk1"."%TID%" NOT NULL ] COUNT 
-| | ) [ "fk"."%fk_fk1_fkey" NOT NULL = "pk1"."%TID%" NOT NULL JOINIDX 
sys.fk.fk_fk1_fkey ]
+| | ) [ "fk"."%fk_fk1_fkey" = "pk1"."%TID%" NOT NULL JOINIDX 
sys.fk.fk_fk1_fkey ]
 | ) [ "fk"."id" NOT NULL HASHCOL  as "v1"."id", "pk1"."v1" as "v1"."v1" ]
 ) [ "v1"."id" NOT NULL HASHCOL , "v1"."v1" ] [ "v1"."id" ASC NOT NULL HASHCOL  
]
 
diff --git 
a/sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-plan-2join-query.stable.out
 
b/sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-plan-2join-query.stable.out
--- 
a/sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-plan-2join-query.stable.out
+++ 
b/sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-plan-2join-query.stable.out
@@ -41,36 +41,36 @@ project (
 % .plan # table_name
 % rel # name
 % clob # type
-% 168 # length
+% 150 # length
 project (
-| table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk1_fkey" NOT NULL 
JOINIDX sys.fk.fk_fk1_fkey, "fk"."%fk_fk2_fkey" NOT NULL JOINIDX 
sys.fk.fk_fk2_fkey ] COUNT 
+| table(sys.fk) [ "fk"."id" NOT NULL HASHCOL , "fk"."%fk_fk1_fkey" JOINIDX 
sys.fk.fk_fk1_fkey, "fk"."%fk_fk2_fkey" JOINIDX sys.fk.fk_fk2_fkey ] COUNT 
 ) [ "fk"."id" NOT NULL HASHCOL  ] [ "fk"."id" ASC NOT NULL HASHCOL  ]
 
 #plan select id , v1  from fk left outer join pk1 on fk.fk1 = pk1.pk1 left 
outer join pk2 on fk.fk2 = pk2.pk2 order by id;
 % .plan # table_name
 % rel # name
 % clob # type
_______________________________________________
checkin-list mailing list
checkin-list@monetdb.org
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to