Changeset: 69a130fd3718 for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=69a130fd3718
Modified Files:
sql/server/rel_exp.c
sql/server/rel_graph.c
sql/server/rel_graph.h
sql/server/rel_optimizer.c
sql/server/rel_rel.c
Branch: graph0
Log Message:
QRW: DCE pass for both SYS.NEST and paths
Unify the same logic to mark & remove the unused attributes in the DCE
pass for both the SYS.NEST aggregate and the graph shortest path
operator. There might still be a latent and occasional bug where the
list of attributes for a scalar function is not NULL even when the
type is not a nested table. Currently I am not able to reproduce it
anymore though :/
diffs (truncated from 338 to 300 lines):
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
@@ -214,6 +214,7 @@ exp_op( sql_allocator *sa, list *l, sql_
e->card = CARD_MULTI;
e->l = l;
e->f = f;
+ assert(exp_subtype(e) == NULL || exp_subtype(e)->attributes == NULL);
return e;
}
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
@@ -180,6 +180,49 @@ static list* bind_shortest_path_return(m
}
}
+// create the column needed to compute the spfw expr~
+static sql_exp* create_compute_path_expr(mvc *sql, sql_rel* rel_edges){
+ sql_schema* schema_sys = NULL;
+ sql_subtype* type_nested_table = NULL;
+ sql_subaggr* aggregate = NULL;
+ list* arguments = NULL; // the parameters of SYS.NEST (i.e. all columns
produced by rel_edges)
+ sql_exp* result = NULL; // the generated expression
+ list* nt_attributes = NULL; // the attributes associated to the nested
table type
+
+ assert(rel_edges != NULL);
+
+ schema_sys = mvc_bind_schema(sql, "sys");
+ assert(schema_sys != NULL && "Unable to find the schema 'sys'");
+ type_nested_table = sql_bind_subtype(sql->sa, "nested_table", 0, 0);
+ assert(type_nested_table != NULL && "Unable to find type
'nested_table'");
+
+ aggregate = sql_bind_aggr(sql->sa, schema_sys, "nest",
type_nested_table);
+ assert(aggregate != NULL && "Unable to bind the sys.nest aggregate");
+
+ arguments = rel_projections(sql, rel_edges, /*tname=*/ NULL, true, /*
intern = */ false);
+
+ // we use an aggregate expression to express the path to compute just
to have
+ // a similar DCE pass for nested tables. However codegen only looks for
the flag
+ // GRAPH_EXPR_SHORTEST_PATH.
+ // Not sure how the flags nil & no_nil can affect the generated
expression
+ result = exp_aggr(sql->sa, arguments, aggregate, /* distinct = */
FALSE, TRUE, CARD_MULTI, have_nil(arguments));
+ result->flag |= GRAPH_EXPR_SHORTEST_PATH;
+
+ // record the attributes for the nested table
+ type_nested_table = aggregate->res->h->data;
+ nt_attributes = sa_list(sql->sa);
+ for(node* n = arguments->h; n; n = n->next){
+ sql_exp* e = n->data;
+ list_append(nt_attributes, exp_column(sql->sa, exp_relname(e),
exp_name(e), exp_subtype(e), exp_card(e), has_nil(e), is_intern(e)));
+ }
+ type_nested_table->attributes = nt_attributes;
+
+ // finally provide a unique label
+ result = exp_label(sql->sa, result, ++sql->label);
+
+ return result;
+}
+
static list* bind_shortest_path_graph(mvc *sql, sql_graph *graph, dlist
*parse_tree, bool compute_path){
const char* table_ref = NULL; // the table referred (optional)
symbol* expr_weight = NULL; // the expression inside CHEAPEST SUM ( ...
);
@@ -274,21 +317,8 @@ static list* bind_shortest_path_graph(mv
// otherwise we need to create an hoc column & register
in the list graph->spfw
// to represent the path to compute
- if(!column_path) {
- const char* label = make_label(sql->sa,
++sql->label);
- sql_subtype* type = sql_bind_subtype(sql->sa,
"nested_table", 0, 0);
-
- 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;
+ if(!column_path){
+ column_path = create_compute_path_expr(sql,
edges);
// record the column in the 'spfw' list
if(duplicate){
@@ -374,48 +404,3 @@ 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,6 +19,4 @@ 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
@@ -6006,15 +6006,11 @@ exp_nested_table_mark_used(sql_exp* exp_
}
if(exp_down->type == e_aggr /*&& exp_nest->f ~ "sys.nest"*/){
- sql_subaggr* subaggr = NULL;
- sql_subtype* type = NULL;
+ sql_subtype* type = exp_subtype(exp_down);
exp_nest = exp_down;
- subaggr = exp_nest->f;
- assert(list_length(subaggr->res) == 1);
- type = subaggr->res->h->data;
- assert(type->attributes != NULL);
-
+
+ assert(type != NULL && type->attributes != NULL);
target_attributes = type->attributes;
} else {
assert(exp_down->type == e_column);
@@ -6398,21 +6394,22 @@ rel_mark_used(mvc *sql, sql_rel *rel, in
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){
+ list* arguments = e->l;
+ bool shortest_path_used = false;
+
+ assert(e->type == e_aggr && "Expecting
SYS.NEST(...) as the function to create the path");
+ assert(list_length(arguments) >= 1 && "SYS.NEST
with no parameters. Is the edge table empty?");
+ for(node* m = arguments->h; m; m = m->next){
sql_exp* me = m->data;
- // since unnest is not a barrier in the
DCE analysis, we need to explicitly
+ // since the graph operators are not
barriers 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);
+ int mark =
exp_mark_used(graph_ptr->edges, me);
+ assert(mark > 0 && "All
arguments should be marked in the subrel");
+ shortest_path_used = true;
}
}
- if(nr == list_length(e->tpe.attributes)){
- e->used = 1;
- }
+ e->used = shortest_path_used;
} else {
assert(0 && "Invalid graph expression");
}
@@ -6438,6 +6435,42 @@ exps_remove_unused(mvc* sql, list* exps)
return new_exps;
}
+// DCE for the nested tables
+// It alters the flags e->used, the actual subtype && the params in case of
SYS.NEST
+static void
+exp_nested_table_remove_unused(mvc* sql, sql_exp* e){
+ sql_subtype* type;
+ list** nt_attributes_ptr = NULL;
+ list* new_nt_attributes = NULL;
+
+ // if the expression is not used, it is going to be removed all
together by the rest of the DCE
+ if(!e->used) return;
+
+ type = exp_subtype(e);
+ if(!type) return; // uh? thsi expression doesn't have a type..
+
+ nt_attributes_ptr = &(type->attributes);
+ if(!(nt_attributes_ptr && *nt_attributes_ptr)) return; // this is not a
nested table
+
+ // alter the attributes in the subtype
+ new_nt_attributes = exps_remove_unused(sql, *nt_attributes_ptr);
+ *nt_attributes_ptr = new_nt_attributes;
+ if(!list_length(new_nt_attributes)){
+ e->used = 0; // it removed all the sub-attributes in the column
+ return; // this expression needs to be completely removed by
the DCE
+ }
+
+ // alter the parameters for SYS.NEST
+ if(e->type == e_aggr /* => rel->op == op_groupby*/){ // SYS.NEST(...)
+ list* new_nt_arguments = NULL;
+
+ assert(list_length(e->l) >= 1);
+
+ new_nt_arguments = exps_remove_unused(sql, e->l);
+ e->l = new_nt_arguments;
+ }
+}
+
static sql_rel *
rel_remove_unused(mvc *sql, sql_rel *rel)
@@ -6534,35 +6567,7 @@ rel_remove_unused(mvc *sql, sql_rel *rel
for(n=rel->exps->h; n; n = n->next) {
sql_exp *e = n->data;
- // DCE for nested tables
- if (e->used) {
- list** nt_attributes_ptr = NULL;
- list** nt_arguments_ptr = NULL; // in
case of sys.nest
-
- if(rel->op == op_project){ // do not
use is_project(rel->op) as it also includes the group by (subtle bug)
- nt_attributes_ptr =
&(e->tpe.attributes);
- } else if (rel->op == op_groupby &&
e->f){ // sys.nest ( ... )
- sql_subaggr* aggr = e->f;
- if(list_length(aggr->res) == 1){
- sql_subtype* type =
aggr->res->h->data;
- nt_attributes_ptr =
&(type->attributes);
- nt_arguments_ptr =
(list**) &(e->l);
-
- }
- }
- if(nt_attributes_ptr &&
*nt_attributes_ptr) {
- list* new_nt_attributes =
exps_remove_unused(sql, *nt_attributes_ptr);
- *nt_attributes_ptr =
new_nt_attributes;
-
if(!list_length(new_nt_attributes)){
- e->used = 0; // it
removed all the sub-attributes in the column
- }
- }
-
- if(e->used && nt_arguments_ptr){
- list* new_nt_arguments =
exps_remove_unused(sql, *nt_arguments_ptr);
- *nt_arguments_ptr =
new_nt_arguments;
- }
- }
+ exp_nested_table_remove_unused(sql, e);
if(e->used){ // nt analysis might have changed
this flag
append(exps, e);
@@ -6628,8 +6633,13 @@ rel_remove_unused(mvc *sql, sql_rel *rel
for(node* n = graph_ptr->spfw->h; n && !needed; n = n->next){
sql_exp* e = n->data;
needed = !(e->used);
+
+ // nested tables
if (!needed && (e->flag & GRAPH_EXPR_SHORTEST_PATH)){
- for (node *m = e->tpe.attributes->h; m &&
!needed; m = m->next){
+ sql_subtype* t = exp_subtype(e);
+ assert(t != NULL && t->attributes != NULL);
+
+ for (node *m = t->attributes->h; m && !needed;
m = m->next){
sql_exp* me = m->data;
if(!me->used){
needed = 1;
@@ -6642,23 +6652,10 @@ rel_remove_unused(mvc *sql, sql_rel *rel
list* exps = sa_list(sql->sa);
for(node* n = graph_ptr->spfw->h; n; n = n->next){
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list