Changeset: 188ae9768946 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=188ae9768946 Modified Files: sql/backends/monet5/rel_bin.c sql/server/rel_optimizer.c sql/server/rel_rel.c sql/server/rel_unnest.c sql/test/BugTracker-2016/Tests/memory-consumption-query-PLAN-25joins.Bug-3972.stable.out sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-explain-2join-query.stable.out sql/test/FeatureRequests/Tests/foreign_key_outer_join_dead_code_elimination-explain-2join-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 Branch: mbedded Log Message:
merged with default diffs (truncated from 651 to 300 lines): diff --git a/sql/backends/monet5/rel_bin.c b/sql/backends/monet5/rel_bin.c --- a/sql/backends/monet5/rel_bin.c +++ b/sql/backends/monet5/rel_bin.c @@ -2635,6 +2635,7 @@ rel2bin_semijoin(backend *be, sql_rel *r join = stmt_join(be, l, r, 0, cmp_all, 0, false); } } else { + right = subrel_project(be, right, refs, rel->r); stmt *l = bin_first_column(be, left); stmt *r = bin_first_column(be, right); join = stmt_join(be, l, r, 0, cmp_all, 0, false); 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 @@ -1946,6 +1946,31 @@ rel_push_topn_and_sample_down(mvc *sql, operator_type relation_type = is_topn(rel->op) ? op_topn : op_sample; sql_rel *(*func) (sql_allocator *, sql_rel *, list *) = is_topn(rel->op) ? rel_topn : rel_sample; + /* nested topN relations without offset */ + if (r && is_topn(rel->op) && is_topn(r->op) && list_length(rel->exps) == 1 && list_length(r->exps) == 1) { + sql_exp *topN1 = rel->exps->h->data, *topN2 = r->exps->h->data; + + if (topN1->l && topN2->l) { + atom *a1 = (atom *)topN1->l, *a2 = (atom *)topN2->l; + + if (a1->tpe.type->localtype == a2->tpe.type->localtype && !a1->isnull && !a2->isnull) { + if (atom_cmp(a1, a2) < 0) { + rel->l = r->l; + r->l = NULL; + rel_destroy(r); + (*changes)++; + return rel; + } else { + rel->l = NULL; + rel_destroy(rel); + rel = r; + (*changes)++; + return rel; + } + } + } + } + if (r && is_simple_project(r->op) && need_distinct(r)) return rel; @@ -6218,6 +6243,12 @@ rel_remove_join(mvc *sql, sql_rel *rel, static sql_rel * rel_push_project_up(mvc *sql, sql_rel *rel, int *changes) { + if (is_simple_project(rel->op) && rel->l && !rel_is_ref(rel)) { + sql_rel *l = rel->l; + if (is_simple_project(l->op)) + return rel_merge_projects(sql, rel, changes); + } + /* project/project cleanup is done later */ if (is_join(rel->op) || is_select(rel->op)) { node *n; @@ -7392,7 +7423,7 @@ rel_simplify_like_select(mvc *sql, sql_r static sql_exp * rel_simplify_predicates(mvc *sql, sql_rel *rel, sql_exp *e, int depth, int *changes) { - (void) depth; + (void)depth; if (is_select(rel->op) || is_join(rel->op) || is_semi(rel->op)) { if (is_atom(e->type) && ((!e->l && !e->r && !e->f) || e->r)) /* prepared statement parameter or argument */ return e; @@ -7426,8 +7457,7 @@ rel_simplify_predicates(mvc *sql, sql_re list *args = l->l; sql_exp *ie = args->h->data; - /* TODO, we have to fix the NOT NULL flag propagation on columns after an outer join, so we can remove the is_outerjoin check */ - if (!is_outerjoin(rel->op) && (!has_nil(ie) || exp_is_not_null(sql, ie))) { /* is null on something that is never null, is always false */ + if (!has_nil(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); (*changes)++; e->l = ie; 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 @@ -238,7 +238,7 @@ rel_issubquery(sql_rel*r) } static sql_rel * -rel_bind_column_(mvc *sql, sql_rel **p, sql_rel *rel, const char *cname, int no_tname) +rel_bind_column_(mvc *sql, int *exp_has_nil, sql_rel *rel, const char *cname, int no_tname) { int ambiguous = 0; sql_rel *l = NULL, *r = NULL; @@ -253,15 +253,12 @@ rel_bind_column_(mvc *sql, sql_rel **p, case op_full: { sql_rel *right = rel->r; - *p = rel; - r = rel_bind_column_(sql, p, rel->r, cname, no_tname); - + r = rel_bind_column_(sql, exp_has_nil, rel->r, cname, no_tname); if (!r || !rel_issubquery(right)) { sql_exp *e = r?exps_bind_column(r->exps, cname, &ambiguous, 0):NULL; if (!r || !e || !is_freevar(e)) { - *p = rel; - l = rel_bind_column_(sql, p, rel->l, cname, no_tname); + l = rel_bind_column_(sql, exp_has_nil, rel->l, cname, no_tname); if (l && r && !rel_issubquery(r) && !is_dependent(rel)) { (void) sql_error(sql, ERR_AMBIGUOUS, SQLSTATE(42000) "SELECT: identifier '%s' ambiguous", cname); return NULL; @@ -270,8 +267,13 @@ rel_bind_column_(mvc *sql, sql_rel **p, } if (sql->session->status == -ERR_AMBIGUOUS) return NULL; - if (l && !r) + if (l && !r) { + if (is_full(rel->op) || is_right(rel->op)) + *exp_has_nil = 1; return l; + } + if (r && (is_full(rel->op) || is_left(rel->op))) + *exp_has_nil = 1; return r; } case op_union: @@ -289,11 +291,10 @@ rel_bind_column_(mvc *sql, sql_rel **p, (void) sql_error(sql, ERR_AMBIGUOUS, SQLSTATE(42000) "SELECT: identifier '%s' ambiguous", cname); return NULL; } - *p = rel; if (is_processed(rel)) return NULL; if (rel->l && !(is_base(rel->op))) - return rel_bind_column_(sql, p, rel->l, cname, no_tname); + return rel_bind_column_(sql, exp_has_nil, rel->l, cname, no_tname); break; case op_semi: case op_anti: @@ -301,9 +302,8 @@ rel_bind_column_(mvc *sql, sql_rel **p, case op_select: case op_topn: case op_sample: - *p = rel; if (rel->l) - return rel_bind_column_(sql, p, rel->l, cname, no_tname); + return rel_bind_column_(sql, exp_has_nil, rel->l, cname, no_tname); /* fall through */ default: return NULL; @@ -314,12 +314,12 @@ rel_bind_column_(mvc *sql, sql_rel **p, sql_exp * rel_bind_column( mvc *sql, sql_rel *rel, const char *cname, int f, int no_tname) { - sql_rel *p = NULL; + int exp_has_nil = 0; /* mark if we passed any outer joins */ if (is_sql_sel(f) && rel && is_simple_project(rel->op) && !is_processed(rel)) rel = rel->l; - if (!rel || (rel = rel_bind_column_(sql, &p, rel, cname, no_tname)) == NULL) + if (!rel || (rel = rel_bind_column_(sql, &exp_has_nil, rel, cname, no_tname)) == NULL) return NULL; if ((is_project(rel->op) || is_base(rel->op)) && rel->exps) { @@ -330,8 +330,9 @@ rel_bind_column( mvc *sql, sql_rel *rel, sql_exp *e = exps_bind_column(rel->r, cname, NULL, no_tname); if (e) e = exp_alias_or_copy(sql, exp_relname(e), cname, rel, e); - return e; } + if (e && exp_has_nil) + set_has_nil(e); return e; } return NULL; @@ -377,8 +378,14 @@ rel_bind_column2( mvc *sql, sql_rel *rel return rel_bind_column2(sql, rel->l, tname, cname, f); } else if (is_join(rel->op)) { sql_exp *e = rel_bind_column2(sql, rel->l, tname, cname, f); - if (!e) + + if (e && (is_right(rel->op) || is_full(rel->op))) + set_has_nil(e); + if (!e) { e = rel_bind_column2(sql, rel->r, tname, cname, f); + if (e && (is_left(rel->op) || is_full(rel->op))) + set_has_nil(e); + } return e; } else if (is_set(rel->op) || is_sort(rel) || 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 @@ -1819,6 +1819,51 @@ rewrite_or_exp(mvc *sql, sql_rel *rel, i return rel; } +static sql_rel * +rewrite_split_select_exps(mvc *sql, sql_rel *rel, int *changes) +{ + if (is_select(rel->op) && !list_empty(rel->exps)) { + int i = 0; + bool has_complex_exps = false, has_simple_exps = false, *complex_exps = (bool*) GDKmalloc(list_length(rel->exps) * sizeof(bool)); + + if (!complex_exps) + return sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL); + + for (node *n = rel->exps->h ; n ; n = n->next) { + sql_exp *e = n->data; + + if (exp_has_rel(e) || exp_has_freevar(sql, e)) { + complex_exps[i] = true; + has_complex_exps = true; + } else { + complex_exps[i] = false; + has_simple_exps = true; + } + i++; + } + + if (has_complex_exps && has_simple_exps) { + sql_rel *nsel = rel_select_copy(sql->sa, rel->l, NULL); + rel->l = nsel; + + i = 0; + for (node *n = rel->exps->h ; n ; ) { + node *nxt = n->next; + + if (!complex_exps[i]) { + rel_select_add_exp(sql->sa, nsel, n->data); + list_remove_node(rel->exps, n); + } + n = nxt; + i++; + } + (*changes)++; + } + GDKfree(complex_exps); + } + return rel; +} + /* exp visitor */ static sql_exp * rewrite_rank(mvc *sql, sql_rel *rel, sql_exp *e, int depth, int *changes) @@ -3028,6 +3073,8 @@ rel_unnest(mvc *sql, sql_rel *rel) rel = rel_visitor_bottomup(sql, rel, &rewrite_or_exp, &changes); if (changes > 0) rel = rel_visitor_bottomup(sql, rel, &rel_remove_empty_select, &changes); + rel = rel_visitor_bottomup(sql, rel, &rewrite_split_select_exps, &changes); /* has to run before rewrite_complex */ + rel = rel_visitor_bottomup(sql, rel, &rewrite_aggregates, &changes); rel = rel_exp_visitor_bottomup(sql, rel, &rewrite_rank, &changes); rel = rel_visitor_bottomup(sql, rel, &rewrite_outer2inner_union, &changes); diff --git a/sql/test/BugTracker-2016/Tests/memory-consumption-query-PLAN-25joins.Bug-3972.stable.out b/sql/test/BugTracker-2016/Tests/memory-consumption-query-PLAN-25joins.Bug-3972.stable.out --- a/sql/test/BugTracker-2016/Tests/memory-consumption-query-PLAN-25joins.Bug-3972.stable.out +++ b/sql/test/BugTracker-2016/Tests/memory-consumption-query-PLAN-25joins.Bug-3972.stable.out @@ -94,13 +94,13 @@ top N ( | | project ( | | | select ( | | | | left outer join ( -| | | | | project ( +| | | | | left outer join ( | | | | | | left outer join ( -| | | | | | | project ( +| | | | | | | left outer join ( | | | | | | | | left outer join ( -| | | | | | | | | project ( +| | | | | | | | | left outer join ( | | | | | | | | | | left outer join ( -| | | | | | | | | | | project ( +| | | | | | | | | | | left outer join ( | | | | | | | | | | | | left outer join ( | | | | | | | | | | | | | left outer join ( | | | | | | | | | | | | | | left outer join ( @@ -118,63 +118,55 @@ top N ( | | | | | | | | | | | | | | | | | | | | | | | | | | left outer join ( | | | | | | | | | | | | | | | | | | | | | | | | | | | left outer join ( | | | | | | | | | | | | | | | | | | | | | | | | | | | | left outer join ( -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | left outer join ( -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | left outer join ( -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | left outer join ( -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | left outer join ( -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | table(sys.table1) [ "table1"."t1pkcol" NOT NULL HASHCOL , "table1"."t1cola1", "table1"."t1cola11", "table1"."t1cola12", "table1"."t1cola82", "table1"."t1cola91", "table1"."t1cola101", "table1"."t1cola111", "table1"."t1cola112", "table1"."t1cola114", "table1"."t1colb1", "table1"."t1colb111", "table1"."t1colb112", "table1"."t1colb113", "table1"."t1colb114", "table1"."t1colc91", "table1"."t1cold1", "table1"."t1cold111", "table1"."t1cold112", "table1"."t1cold113" ] COUNT , -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | table(sys.table4) [ "table4"."t4cola1", "table4"."t4cola2", "table4"."t4cola111", "table4"."t4colb111", "table4"."t4colb112", "table4"."t4colb114", "table4"."t4colb115" ] COUNT -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ) [ "table1"."t1cola111" = "table4"."t4cola111" ], -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | table(sys.table2) [ "table2"."t2cola1", "table2"."t2cola10", "table2"."t2cola81", "table2"."t2cola82", "table2"."t2cola112", "table2"."t2cola113", "table2"."t2colc111", "table2"."t2colc112", "table2"."t2colc113", "table2"."t2colc114", "table2"."t2colc115" ] COUNT -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ) [ "table1"."t1cola112" = "table2"."t2cola112" ], -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | table(sys.table5) [ "table5"."t5cola1", "table5"."t5cola2", "table5"."t5cola3", "table5"."t5cola5", "table5"."t5cola81", "table5"."t5cola113", "table5"."t5colb113" ] COUNT -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ) [ "table5"."t5cola113" = "table2"."t2cola113" ], -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | table(sys.table6) [ "table6"."t6pkcol" NOT NULL HASHCOL as "lookup1"."t6pkcol" ] COUNT -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | ) [ "table1"."t1cola114" = "lookup1"."t6pkcol" NOT NULL HASHCOL ], -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | table(sys.table2) [ "table2"."t2colb111" as "lookup2"."t2colb111" ] COUNT -| | | | | | | | | | | | | | | | | | | | | | | | | | | | ) [ "table1"."t1colb111" = "lookup2"."t2colb111" ], -| | | | | | | | | | | | | | | | | | | | | | | | | | | | table(sys.table5) [ "table5"."t5colb112" as "lookup3"."t5colb112" ] COUNT -| | | | | | | | | | | | | | | | | | | | | | | | | | | ) [ "table1"."t1colb112" = "lookup3"."t5colb112" ], -| | | | | | | | | | | | | | | | | | | | | | | | | | | table(sys.table7) [ "table7"."t7colb113" as "lookup4"."t7colb113" ] COUNT -| | | | | | | | | | | | | | | | | | | | | | | | | | ) [ "table1"."t1colb113" = "lookup4"."t7colb113" ], -| | | | | | | | | | | | | | | | | | | | | | | | | | table(sys.table8) [ "table8"."t8colb114" as "lookup5"."t8colb114" ] COUNT -| | | | | | | | | | | | | | | | | | | | | | | | | ) [ "table1"."t1colb114" = "lookup5"."t8colb114" ], -| | | | | | | | | | | | | | | | | | | | | | | | | table(sys.table6) [ "table6"."t6pkcol" NOT NULL HASHCOL as "lookup11"."t6pkcol" ] COUNT _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list