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
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list