private static PlanNode checkForSimpleProjection(PlanNode frame,
PlanNode root,
PlanNode parentProject,
QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
// check that the parent only performs projection
PlanNode nodeToCheck = parentProject.getFirstChild();
while (nodeToCheck != frame) {
if (nodeToCheck.getType() != NodeConstants.Types.SELECT
|| !nodeToCheck.hasBooleanProperty(NodeConstants.Info.IS_PHANTOM)) {
return root;
}
nodeToCheck = nodeToCheck.getFirstChild();
}
if (frame.getFirstChild().getType() == NodeConstants.Types.TUPLE_LIMIT
&& NodeEditor.findParent(parentProject,
NodeConstants.Types.SORT | NodeConstants.Types.DUP_REMOVE,
NodeConstants.Types.SOURCE | NodeConstants.Types.SET_OP) != null) {
return root;
}
List<? extends SingleElementSymbol> requiredElements = RuleAssignOutputElements.determineSourceOutput(frame, new ArrayList<SingleElementSymbol>(), metadata, null);
List<SingleElementSymbol> selectSymbols = (List<SingleElementSymbol>)parentProject.getProperty(NodeConstants.Info.PROJECT_COLS);
// check that it only performs simple projection and that all required symbols are projected
LinkedHashSet<ElementSymbol> symbols = new LinkedHashSet<ElementSymbol>(); //ensuring there are no duplicates prevents problems with subqueries
for (SingleElementSymbol symbol : selectSymbols) {
Expression expr = SymbolMap.getExpression(symbol);
if (!(expr instanceof ElementSymbol)) {
return root;
}
requiredElements.remove(expr);
if (!symbols.add((ElementSymbol)expr)) {
return root;
}
}
if (!requiredElements.isEmpty()) {
return root;
}
// re-order the lower projects
RuleAssignOutputElements.filterVirtualElements(frame, new ArrayList<SingleElementSymbol>(symbols), metadata);
// remove phantom select nodes
nodeToCheck = parentProject.getFirstChild();
while (nodeToCheck != frame) {
PlanNode current = nodeToCheck;
nodeToCheck = nodeToCheck.getFirstChild();
NodeEditor.removeChildNode(current.getParent(), current);
}
if (NodeEditor.findParent(parentProject, NodeConstants.Types.DUP_REMOVE, NodeConstants.Types.SOURCE) != null) {
PlanNode lowerDup = NodeEditor.findNodePreOrder(frame.getFirstChild(), NodeConstants.Types.DUP_REMOVE, NodeConstants.Types.PROJECT);
if (lowerDup != null) {
NodeEditor.removeChildNode(lowerDup.getParent(), lowerDup);
}
PlanNode setOp = NodeEditor.findNodePreOrder(frame.getFirstChild(), NodeConstants.Types.SET_OP, NodeConstants.Types.SOURCE);
if (setOp != null) {
setOp.setProperty(NodeConstants.Info.USE_ALL, Boolean.FALSE);
if (parentProject.getParent().getParent() != null) {
NodeEditor.removeChildNode(parentProject.getParent().getParent(), parentProject.getParent());
} else {
parentProject.removeFromParent();
root = parentProject;
}
}
}
correctOrderBy(frame, selectSymbols, parentProject);
PlanNode parentSource = NodeEditor.findParent(frame, NodeConstants.Types.SOURCE);
PlanNode parentSetOp = NodeEditor.findParent(parentProject, NodeConstants.Types.SET_OP, NodeConstants.Types.SOURCE);
if (parentSetOp == null || NodeEditor.findNodePreOrder(parentSetOp, NodeConstants.Types.PROJECT) == parentProject) {
if (parentSource != null) {
FrameUtil.correctSymbolMap(((SymbolMap)frame.getProperty(NodeConstants.Info.SYMBOL_MAP)).asMap(), parentSource);
}