Changeset: 04bd882874bd for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=04bd882874bd Modified Files: sql/server/rel_rewriter.c sql/server/rel_select.c sql/server/rel_unnest.c sql/server/rel_updates.c sql/test/BugDay_2005-10-06_2.9.3/Tests/bool_boolean.SF-935601.stable.out sql/test/subquery/Tests/subquery5.sql Branch: Jun2020 Log Message:
Added isnull(not null) -> false optimization, plus fixed a bug in merge statements, where a not nullable expression after being projected as a right column on the left join was stil treated as not nullable diffs (202 lines): diff --git a/sql/server/rel_rewriter.c b/sql/server/rel_rewriter.c --- a/sql/server/rel_rewriter.c +++ b/sql/server/rel_rewriter.c @@ -16,6 +16,7 @@ /* simplify expressions, such as not(not(x)) */ /* exp visitor */ +#define is_null(sf) (strcmp(sf->func->base.name, "isnull") == 0) #define is_not_func(sf) (strcmp(sf->func->base.name, "not") == 0) #define is_not_anyequal(sf) (strcmp(sf->func->base.name, "sql_not_anyequal") == 0) @@ -115,6 +116,7 @@ rewrite_simplify_exp(mvc *sql, sql_rel * ie = args->h->data; if (exp_name(e)) exp_prop_alias(sql->sa, ie, e); + (*changes)++; return ie; } if (is_func(ie->type) && list_length(ie->l) == 2 && is_not_anyequal(sf)) { @@ -126,6 +128,7 @@ rewrite_simplify_exp(mvc *sql, sql_rel * ie = exp_in_func(sql, l, vals, 1, 0); if (exp_name(e)) exp_prop_alias(sql->sa, ie, e); + (*changes)++; return ie; } /* TRUE or X -> TRUE @@ -138,24 +141,50 @@ rewrite_simplify_exp(mvc *sql, sql_rel * if (list_length(l) == 1) { sql_exp *ie = l->h->data; - if (exp_is_true(sql, ie)) + if (exp_is_true(sql, ie)) { + (*changes)++; return ie; - else if (exp_is_false(sql, ie) && list_length(r) == 1) + } else if (exp_is_false(sql, ie) && list_length(r) == 1) { + (*changes)++; return r->h->data; + } } else if (list_length(l) == 0) { /* left is true */ + (*changes)++; return exp_atom_bool(sql->sa, 1); } if (list_length(r) == 1) { sql_exp *ie = r->h->data; - if (exp_is_true(sql, ie)) + if (exp_is_true(sql, ie)) { + (*changes)++; return ie; - else if (exp_is_false(sql, ie) && list_length(l) == 1) + } else if (exp_is_false(sql, ie) && list_length(l) == 1) { + (*changes)++; return l->h->data; + } } else if (list_length(r) == 0) { /* right is true */ + (*changes)++; return exp_atom_bool(sql->sa, 1); } } + } else if (is_func(e->type) && list_length(e->l) == 1 && is_null(sf)) { + list *args = e->l; + sql_exp *ie = args->h->data; + + if (!has_nil(ie) || exp_is_false(sql, ie) || exp_is_true(sql, ie) || exp_is_not_null(sql, ie)) { /* is null on something that is never null, is always false */ + ie = exp_atom_bool(sql->sa, 0); + if (exp_name(e)) + exp_prop_alias(sql->sa, ie, e); + (*changes)++; + return ie; + } + if (exp_is_null(sql, ie)) { /* is null on something that is always null, is always true */ + ie = exp_atom_bool(sql->sa, 1); + if (exp_name(e)) + exp_prop_alias(sql->sa, ie, e); + (*changes)++; + return ie; + } } return e; } 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 @@ -2003,6 +2003,7 @@ exp_exist(sql_query *query, sql_rel *rel mvc *sql = query->sql; sql_subfunc *exists_func = NULL; sql_subtype *t; + sql_exp *res; if (!exp_name(le)) exp_label(sql->sa, le, ++sql->label); @@ -2017,7 +2018,9 @@ exp_exist(sql_query *query, sql_rel *rel if (!exists_func) return sql_error(sql, 02, SQLSTATE(42000) "exist operator on type %s missing", t->type->sqlname); - return exp_unop(sql->sa, le, exists_func); + res = exp_unop(sql->sa, le, exists_func); + set_has_no_nil(res); + return res; } static sql_exp * diff --git a/sql/server/rel_unnest.c b/sql/server/rel_unnest.c --- a/sql/server/rel_unnest.c +++ b/sql/server/rel_unnest.c @@ -2448,7 +2448,9 @@ exp_exist(mvc *sql, sql_exp *le, sql_exp le = rel_nop_(sql, NULL, ne, exp_atom_bool(sql->sa, !exists), exp_atom_bool(sql->sa, exists), NULL, NULL, "ifthenelse", card_value); return le; } else { - return exp_unop(sql->sa, le, exists_func); + sql_exp *res = exp_unop(sql->sa, le, exists_func); + set_has_no_nil(res); + return res; } } diff --git a/sql/server/rel_updates.c b/sql/server/rel_updates.c --- a/sql/server/rel_updates.c +++ b/sql/server/rel_updates.c @@ -1343,6 +1343,7 @@ merge_into_table(sql_query *query, dlist symbol *sym = m->data.sym, *opt_search, *action; tokens token = sym->token; dlist* dl = sym->data.lval, *sts; + list *nexps; opt_search = dl->h->data.sym; action = dl->h->next->data.sym; sts = action->data.lval; @@ -1370,7 +1371,10 @@ merge_into_table(sql_query *query, dlist } //project columns of both bt and joined + oid - extra_project = rel_project(sql->sa, join_rel, rel_projections(sql, bt, NULL, 1, 0)); + nexps = rel_projections(sql, bt, NULL, 1, 0); + for (node *n = nexps->h ; n ; n = n->next) /* after going through the left outer join, a NOT NULL column may have NULL values */ + set_has_nil((sql_exp*)n->data); + extra_project = rel_project(sql->sa, join_rel, nexps); extra_project->exps = list_merge(extra_project->exps, rel_projections(sql, joined, NULL, 1, 0), (fdup)NULL); list_append(extra_project->exps, exp_column(sql->sa, bt_name, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1)); @@ -1383,7 +1387,10 @@ merge_into_table(sql_query *query, dlist extra_select = rel_select(sql->sa, extra_project, exp_compare(sql->sa, nils, exp_atom_bool(sql->sa, 0), cmp_equal)); //the update statement requires a projection on the right side - extra_project = rel_project(sql->sa, extra_select, rel_projections(sql, bt, NULL, 1, 0)); + nexps = rel_projections(sql, bt, NULL, 1, 0); + for (node *n = nexps->h ; n ; n = n->next) /* after going through the left outer join, a NOT NULL column may have NULL values */ + set_has_nil((sql_exp*)n->data); + extra_project = rel_project(sql->sa, extra_select, nexps); extra_project->exps = list_merge(extra_project->exps, rel_projections(sql, joined, NULL, 1, 0), (fdup)NULL); list_append(extra_project->exps, exp_column(sql->sa, bt_name, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1)); @@ -1401,7 +1408,10 @@ merge_into_table(sql_query *query, dlist } //project columns of bt + oid - extra_project = rel_project(sql->sa, join_rel, rel_projections(sql, bt, NULL, 1, 0)); + nexps = rel_projections(sql, bt, NULL, 1, 0); + for (node *n = nexps->h ; n ; n = n->next) /* after going through the left outer join, a NOT NULL column may have NULL values */ + set_has_nil((sql_exp*)n->data); + extra_project = rel_project(sql->sa, join_rel, nexps); list_append(extra_project->exps, exp_column(sql->sa, bt_name, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1)); //select bt values which are not null (they had a match in the join) @@ -1439,7 +1449,10 @@ merge_into_table(sql_query *query, dlist } //project columns of both - extra_project = rel_project(sql->sa, join_rel, rel_projections(sql, bt, NULL, 1, 0)); + nexps = rel_projections(sql, bt, NULL, 1, 0); + for (node *n = nexps->h ; n ; n = n->next) /* after going through the left outer join, a NOT NULL column may have NULL values */ + set_has_nil((sql_exp*)n->data); + extra_project = rel_project(sql->sa, join_rel, nexps); extra_project->exps = list_merge(extra_project->exps, rel_projections(sql, joined, NULL, 1, 0), (fdup)NULL); //select bt values which are null (they didn't have match in the join) diff --git a/sql/test/BugDay_2005-10-06_2.9.3/Tests/bool_boolean.SF-935601.stable.out b/sql/test/BugDay_2005-10-06_2.9.3/Tests/bool_boolean.SF-935601.stable.out --- a/sql/test/BugDay_2005-10-06_2.9.3/Tests/bool_boolean.SF-935601.stable.out +++ b/sql/test/BugDay_2005-10-06_2.9.3/Tests/bool_boolean.SF-935601.stable.out @@ -25,7 +25,7 @@ stdout of test 'bool_boolean.SF-935601` #select isnull(1); % . # table_name -% %1 # name +% single_value # name % boolean # type % 5 # length [ false ] diff --git a/sql/test/subquery/Tests/subquery5.sql b/sql/test/subquery/Tests/subquery5.sql --- a/sql/test/subquery/Tests/subquery5.sql +++ b/sql/test/subquery/Tests/subquery5.sql @@ -284,6 +284,9 @@ SELECT ((SELECT i1.i NOT IN (SELECT i1.i SELECT (SELECT 6 EXCEPT (SELECT SUM(i1.i))) IN (SELECT 1) FROM integers i1; -- OPTmergetableImplementation: !ERROR: Mergetable bailout on group input reuse in group statement -- NULL +SELECT (SELECT CASE WHEN MIN(i1.i) IS NULL THEN (SELECT i2.i FROM integers i2) ELSE MAX(i1.i) END) FROM integers i1; + -- 3 + DROP FUNCTION evilfunction(INT); DROP TABLE tbl_ProductSales; DROP TABLE another_T; _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list