Changeset: c942d8b7c404 for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=c942d8b7c404 Modified Files: sql/common/sql_types.c sql/server/rel_dump.c sql/server/rel_exp.c sql/server/rel_graph.c sql/server/rel_graph.h sql/server/rel_optimizer.c Branch: graph0 Log Message:
QRW: fix DCE for nested tables Propagate the attributes removed by the DCE pass up to the generator expression. Still need to be fixed for SYS.NEST(...) diffs (truncated from 401 to 300 lines): diff --git a/sql/common/sql_types.c b/sql/common/sql_types.c --- a/sql/common/sql_types.c +++ b/sql/common/sql_types.c @@ -906,11 +906,8 @@ sql_bind_func_(sql_allocator *sa, sql_sc if (f->type != type && f->type != filt) continue; if (strcmp(f->base.name, sqlfname) == 0) { - printf("match %s\n", f->base.name); - if (list_cmp(f->ops, ops, (fcmp) &arg_subtype_cmp) == 0) { - printf("found\n"); + if (list_cmp(f->ops, ops, (fcmp) &arg_subtype_cmp) == 0) return sql_dup_subfunc(sa, f, ops, NULL); - } } } if (s) { diff --git a/sql/server/rel_dump.c b/sql/server/rel_dump.c --- a/sql/server/rel_dump.c +++ b/sql/server/rel_dump.c @@ -538,7 +538,7 @@ rel_print_(mvc *sql, stream *fout, sql_ case op_graph_select: { sql_graph *graph_ptr = (sql_graph*) rel; print_indent(sql, fout, depth, decorate); - mnstr_printf(fout, "%s", op2string(rel->op)); + mnstr_printf(fout, "%s (", op2string(rel->op)); if (rel_is_ref(rel->l)) { int nr = find_ref(refs, rel->l); print_indent(sql, fout, depth+1, decorate); @@ -562,14 +562,15 @@ rel_print_(mvc *sql, stream *fout, sql_ rel_print_(sql, fout, graph_ptr->edges, depth+1, refs, decorate); } print_indent(sql, fout, depth, decorate); + mnstr_printf(fout, ")"); exps_print(sql, fout, rel->exps, depth, 1, 0); mnstr_printf(fout, ", src:"); exps_print(sql, fout, graph_ptr->efrom, depth, 1, 0); mnstr_printf(fout, ", dst:"); exps_print(sql, fout, graph_ptr->eto, depth, 1, 0); print_indent(sql, fout, depth, decorate); - mnstr_printf(fout, "shortest paths: "); - exps_print(sql, fout, graph_ptr->spfw, depth, 1, 1); + mnstr_printf(fout, "Ï :"); + exps_print(sql, fout, graph_ptr->spfw, depth, 1, 0); } break; default: assert(0); diff --git a/sql/server/rel_exp.c b/sql/server/rel_exp.c --- a/sql/server/rel_exp.c +++ b/sql/server/rel_exp.c @@ -9,6 +9,7 @@ #include <monetdb_config.h> #include "sql_relation.h" #include "rel_exp.h" +#include "rel_graph.h" #include "rel_prop.h" /* for prop_copy() */ #include "rel_optimizer.h" #include "rel_distribute.h" @@ -1274,6 +1275,7 @@ rel_find_exp_( sql_rel *rel, sql_exp *e) // check whether this is some kind of shortest path else if (is_graph(rel->op) && e->l){ sql_graph* graph_ptr = (sql_graph*) rel; +// ne = graph_bind_spfw(rel, e->l, e->r); ne = exps_bind_column2(graph_ptr->spfw, e->l, e->r); } return ne; diff --git a/sql/server/rel_graph.c b/sql/server/rel_graph.c --- a/sql/server/rel_graph.c +++ b/sql/server/rel_graph.c @@ -281,6 +281,11 @@ static list* bind_shortest_path_graph(mv assert(type != NULL && "Cannot find the 'nested_table' type"); // record the columns composing the nested_table type, from the edge table type->attributes = exps_copy(sql->sa, rel_projections(sql, edges, NULL, /* settname = */ true, /* intern = */ false)); + // set the relation name to label + for(node* n = type->attributes->h; n; n = n->next){ + sql_exp* ne = n->data; + ne->rname = label; + } column_path = exp_column(sql->sa, label, label, type, CARD_MULTI, /* has_nil = */ FALSE, /* is_intern = */ FALSE); column_path->flag |= GRAPH_EXPR_SHORTEST_PATH; @@ -369,3 +374,48 @@ list* rel_graph_shortest_path(mvc *sql, return result; // this can be an exp~ or NULL + an error set } } + + +/***************************************************************************** + * * + * Bind an expression produced by a graph operator * + * * + *****************************************************************************/ +// Attempt to bind the column with table name `tbl_name' and column name `col_name' +// to one of the expression generated by the graph operator (i.e. a shortest path). +// It returns the expression bound if found, NULL otherwise. +sql_exp* graph_bind_spfw(sql_rel* rel, const char* tbl_name, const char* col_name){ + sql_graph* graph_ptr = NULL; + + assert(rel && is_graph(rel->op) && "The given operator is not a graph"); + graph_ptr = (sql_graph*) rel; + + // all expressions associated to a graph operator need to have a table name + if(!tbl_name) return NULL; + + for(node* n = graph_ptr->spfw->h; n; n = n->next){ + sql_exp* candidate = n->data; + + if(candidate->flag & GRAPH_EXPR_COST){ + if(strcmp(tbl_name, candidate->rname) == 0 && strcmp(col_name, candidate->name) == 0){ + return candidate; + } + } else if (candidate->flag & GRAPH_EXPR_SHORTEST_PATH){ + assert(candidate->type == e_column && "Paths should be columns"); + if(strcmp(tbl_name, candidate->rname) == 0){ + assert(candidate->tpe.type->eclass == EC_NESTED_TABLE && "Expected a nested table (class)"); + assert(candidate->tpe.attributes != NULL && "Expected a nested table (attrs)"); + if(strcmp(col_name, candidate->name) == 0){ // fetch the nested table + return candidate; + } + + candidate = exps_bind_column(candidate->tpe.attributes, col_name, NULL); + assert(candidate != NULL && "How was it able to match the table name and not the column name?"); + return candidate; + } + } + } + + // not found + return NULL; +} diff --git a/sql/server/rel_graph.h b/sql/server/rel_graph.h --- a/sql/server/rel_graph.h +++ b/sql/server/rel_graph.h @@ -19,4 +19,6 @@ sql_graph* rel_graph_create(sql_allocato sql_graph* rel_graph_move(mvc* sql, sql_rel* graph_old, sql_rel* l, sql_rel* r, sql_exp* e); sql_rel* rel_graph_move2rel(mvc* sql, sql_rel* graph_old, sql_rel* l, sql_rel* r, sql_exp* e); +sql_exp* graph_bind_spfw(sql_rel* rel, const char* relname, const char* colname); + #endif /* _REL_GRAPH_H_ */ 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 @@ -5987,6 +5987,74 @@ rel_push_project_up(int *changes, mvc *s return rel; } + +static void +exp_nested_table_mark_used(sql_exp* exp_up, sql_exp* exp_down){ + sql_exp* exp_nest = NULL; // the summary sys.nest( ... ) + sql_exp* exp_unnest = NULL; + list* used_attributes = NULL; + list* target_attributes = NULL; +// list* new_attributes = NULL; + + assert(exp_up != NULL && exp_down != NULL); + + if(exp_up->type == e_cmp && get_cmp(exp_up) == cmp_unnest){ + exp_unnest = exp_up; + exp_up = exp_unnest->l; + } else { + assert(exp_up->type == e_column); + } + + if(exp_down->type == e_aggr /*&& exp_nest->f ~ "sys.nest"*/){ + sql_subaggr* subaggr = exp_down->f; + sql_subtype* type = subaggr->res->h->data; + assert(type->attributes != NULL); + + exp_nest = exp_down; + target_attributes = type->attributes; + } else { + assert(exp_down->type == e_column); + target_attributes = exp_down->tpe.attributes; + } + + assert(exp_up->tpe.attributes != NULL); + assert(exp_down->tpe.attributes != NULL); + + if(exp_unnest){ + used_attributes = exp_unnest->r; + } else { + used_attributes = exp_up->tpe.attributes; + } + + // mark the sub type +// new_attributes = sa_list(used_attributes->sa); + for(node* m = used_attributes->h; m; m = m->next){ + sql_exp* attribute = m->data; + sql_exp* target = NULL; + + assert(attribute->type == e_column); + if(!attribute->used) continue; + if(exp_nest){ + target = exps_bind_column2(target_attributes, attribute->l, attribute->r); + } else { + target = exps_bind_column2(target_attributes, attribute->rname, attribute->name); + } + + + assert(target != NULL && target->type == e_column); + target->used = 1; +// list_append(new_attributes, target); + } + +// exp_down->tpe.attributes = new_attributes; +// if(exp_unnest){ +// exp_up->tpe.attributes = new_attributes; +// } + if(exp_unnest){ + exp_up->tpe.attributes = exp_unnest->tpe.attributes; + } +} + static int exp_mark_used(sql_rel *subrel, sql_exp *e) { @@ -5996,6 +6064,9 @@ exp_mark_used(sql_rel *subrel, sql_exp * switch(e->type) { case e_column: ne = rel_find_exp(subrel, e); + if(e && ne && e->tpe.type->eclass == EC_NESTED_TABLE){ + exp_nested_table_mark_used(e, ne); + } break; case e_convert: return exp_mark_used(subrel, e->l); @@ -6021,8 +6092,10 @@ exp_mark_used(sql_rel *subrel, sql_exp * for (n = l->h; n != NULL; n = n->next) nr += exp_mark_used(subrel, n->data); } else if (e->flag == cmp_unnest) { - nr += exp_mark_used(subrel, e->l); - // do not mark the attributes here + sql_exp* column = e->l; + assert(column->type == e_column && "Expected a column in the LHS of an unnest expression"); + ne = rel_find_exp(subrel, column); + exp_nested_table_mark_used(e, ne); } else if (e->flag == cmp_in || e->flag == cmp_notin) { list *r = e->r; node *n; @@ -6302,8 +6375,34 @@ rel_mark_used(mvc *sql, sql_rel *rel, in // edges exps_mark_used_(sql->sa, rel, graph_ptr->edges, graph_ptr->efrom); exps_mark_used_(sql->sa, rel, graph_ptr->edges, graph_ptr->eto); - exps_mark_used_(sql->sa, rel, graph_ptr->edges, graph_ptr->spfw); - +// exps_mark_used_(sql->sa, rel, graph_ptr->edges, graph_ptr->spfw); + // shortest paths + for(node* n = graph_ptr->spfw->h; n; n = n->next){ + sql_exp* e = n->data; + if(e->flag & GRAPH_EXPR_COST){ + exp_mark_used(graph_ptr->edges, e); + } else if(e->flag & GRAPH_EXPR_SHORTEST_PATH){ + int nr = 0; + + assert(e->tpe.attributes != NULL && "Expected a nested table as type"); + for(node* m = e->tpe.attributes->h; m; m = m->next){ + sql_exp* me = m->data; + // since unnest is not a barrier in the DCE analysis, we need to explicitly + // check whether the attribute has been marked earlier + if(me->used){ + nr++; + exp_mark_used(graph_ptr->edges, e); + } + } + if(nr == list_length(e->tpe.attributes)){ + e->used = 1; + } + } else { + assert(0 && "Invalid graph expression"); + } + } + + // this should be a nop because graph_ptr->edges should be a projection rel_mark_used(sql, graph_ptr->edges, 0); } break; } @@ -6373,9 +6472,31 @@ rel_remove_unused(mvc *sql, sql_rel *rel for(n=rel->exps->h; n && !needed; n = n->next) { sql_exp *e = n->data; + list* nt_attributes = NULL; // nested table attributes if (!e->used) needed = 1; + + // nested tables + else if(e->type == e_column){ + nt_attributes = e->tpe.attributes; + } else if (e->type == e_aggr) { // sys.nest() + sql_subaggr* aggr = e->f; + sql_subtype* type = NULL; + if(list_length(aggr->res) == 1){ + type = aggr->res->h->data; + nt_attributes = type->attributes; + } + } + if (nt_attributes){ // a bit of spaghetti :D + for (node *m = nt_attributes->h; m && !needed; m = m->next){ + sql_exp* me = m->data; _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list