// same order that are straight TupleValueExpression, then we
// know that we're just dumping out the table, so therefore we don't
// need the projection at all!
if (element instanceof AbstractScanPlanNode) {
AbstractScanPlanNode scan_node = (AbstractScanPlanNode) element;
ProjectionPlanNode proj_node = element.getInlinePlanNode(PlanNodeType.PROJECTION);
if (proj_node == null) {
if (debug.val)
LOG.debug("SKIP - " + element + " does not an inline ProjectionPlanNode");
return;
}
String table_name = scan_node.getTargetTableName();
Table catalog_tbl = state.catalog_db.getTables().get(table_name);
assert (catalog_tbl != null) : "Unexpected table '" + table_name + "'";
if (catalog_tbl.getColumns().size() != proj_node.getOutputColumnGUIDCount()) {
if (debug.val)
LOG.debug("SKIP - Inline " + proj_node + " does not have the same number of output columns as " + catalog_tbl);
return;
}
for (int i = 0, cnt = catalog_tbl.getColumns().size(); i < cnt; i++) {
int col_guid = proj_node.getOutputColumnGUID(i);
PlanColumn plan_col = state.plannerContext.get(col_guid);
assert (plan_col != null);
AbstractExpression col_exp = plan_col.getExpression();
assert (col_exp != null);
if ((col_exp instanceof TupleValueExpression) == false) {
if (debug.val)
LOG.debug("SKIP - Inline " + proj_node + " does not have a TupleValueExpression for output column #" + i);
return;
}
Collection<Column> columns = ExpressionUtil.getReferencedColumns(state.catalog_db, col_exp);
assert (columns.size() == 1);
Column catalog_col = CollectionUtil.first(columns);
if (catalog_col.getIndex() != i) {
return;
}
} // FOR
// If we're here, the new know that we can remove the
// projection
scan_node.removeInlinePlanNode(PlanNodeType.PROJECTION);
modified.set(true);
if (debug.val)
LOG.debug(String.format("PLANOPT - Removed redundant %s from %s\n%s", proj_node, scan_node, PlanNodeUtil.debug(rootNode)));
}
// CASE #2
// We are ProjectionPlanNode that references the same columns as one
// further below. That means we are unnecessary and can be removed!
if (element instanceof ProjectionPlanNode) {
// Find the first ProjectionPlanNode below us
ProjectionPlanNode next_proj = getFirstProjection(element);
assert (next_proj == null || next_proj != element);
if (next_proj == null) {
if (debug.val)
LOG.debug("SKIP - No other Projection found below " + element);
return;
}
// They must at least have the same number of output columns
else if (element.getOutputColumnGUIDCount() != next_proj.getOutputColumnGUIDCount()) {
if (debug.val)
LOG.debug(String.format("SKIP - %s and %s do not have the same number of output columns", element, next_proj));
return;
}
// There can't be a JOIN PlanNode in between us, since that may mean we need
// to prune out the colums at the bottom scan node
Collection<AbstractJoinPlanNode> join_nodes = PlanNodeUtil.getPlanNodes(element, AbstractJoinPlanNode.class);
if (debug.val) LOG.debug(String.format("%s has %d join nodes below it: %s",
element, join_nodes.size(), join_nodes));
if (join_nodes.isEmpty() == false) {
// Check to see whether the joins appear *after* the projection node
int elementDepth = PlanNodeUtil.getDepth(rootNode, element);
int nextDepth = PlanNodeUtil.getDepth(rootNode, next_proj);
assert(elementDepth < nextDepth) :
String.format("%s %d < %s %d", element, elementDepth, next_proj, nextDepth);
for (AbstractJoinPlanNode join_node : join_nodes) {
int joinDepth = PlanNodeUtil.getDepth(rootNode, join_node);
assert(elementDepth < joinDepth);
assert(nextDepth != joinDepth);
if (joinDepth < nextDepth) {
if (debug.val)
LOG.debug(String.format("SKIP - %s has %s that comes after %s", element, join_node, next_proj));
return;
}
} // FOR
}
// Check whether we have the same output columns
List<PlanColumn> elementColumns = new ArrayList<PlanColumn>();
for (Integer guid : element.getOutputColumnGUIDs()) {
PlanColumn pc = state.plannerContext.get(guid);
assert(pc != null);
elementColumns.add(pc);
} // FOR
boolean match = true;
int idx = 0;
for (Integer guid : next_proj.getOutputColumnGUIDs()) {
PlanColumn pc = state.plannerContext.get(guid);
assert(pc != null);
if (elementColumns.get(idx).equals(pc, true, true) == false) {
match = false;
break;