LinkedList<OptimizerRule> ruleStack ) {
// Find all of the ACCESS nodes to make sure there is a PROJECT ...
for (PlanNode access : plan.findAllAtOrBelow(Type.ACCESS)) {
// Find the first node that is below any LIMIT, SORT, or DUP_REMOVE ...
PlanNode parentOfProject = access;
while (parentOfProject.isOneOf(Type.LIMIT, Type.SORT, Type.DUP_REMOVE)) {
parentOfProject = parentOfProject.getParent();
}
// Is there already a PROJECT here ?
assert parentOfProject.getChildCount() == 1; // should only have one child ...
PlanNode child = parentOfProject.getFirstChild(); // should only have one child ...
if (child.is(Type.PROJECT)) {
// Check to see if there is a PROJECT above the access node ...
PlanNode accessParent = access.getParent();
if (accessParent == null || accessParent.isNot(Type.PROJECT)) continue;
// Otherwise, the parent is a PROJECT, but there is another PROJECT above the ACCESS node.
// Remove the lower PROJECT so the next code block moves the top PROJECT down below the ACCESS node ...
assert accessParent.is(Type.PROJECT);
child.extractFromParent();
child = parentOfProject.getFirstChild();
}
// If the parent of the ACCESS node is a PROJECT, then we can simply move it to here ...
PlanNode accessParent = access.getParent();
if (accessParent != null && accessParent.is(Type.PROJECT)) {
PlanNode project = accessParent;
if (project == plan) {
// The PROJECT node is the root, so the ACCESS node will be the root ...
plan = access;
access.removeFromParent();
} else {
project.extractFromParent();
}
child.insertAsParent(project);
if (plan == access) return plan;
// We need to make sure we have all of the columns needed for any ancestor ...
List<Column> requiredColumns = PlanUtil.findRequiredColumns(context, project);
project.setProperty(Property.PROJECT_COLUMNS, requiredColumns);
project.addSelectors(getSelectorsFor(requiredColumns));
continue;
}
// There is no PROJECT, so find the columns that are required by the plan above this point ...
List<Column> requiredColumns = PlanUtil.findRequiredColumns(context, child);
// And insert the PROJECT ...
PlanNode projectNode = new PlanNode(Type.PROJECT);
projectNode.setProperty(Property.PROJECT_COLUMNS, requiredColumns);
projectNode.addSelectors(getSelectorsFor(requiredColumns));
child.insertAsParent(projectNode);
}
return plan;
}