SymbolMap references = (SymbolMap)frame.getProperty(NodeConstants.Info.CORRELATED_REFERENCES);
if (references != null) {
return root; //correlated nested table commands should not be merged
}
PlanNode parentProject = NodeEditor.findParent(frame, NodeConstants.Types.PROJECT);
// Check whether the upper frame is a SELECT INTO
if (parentProject.getProperty(NodeConstants.Info.INTO_GROUP) != null) {
return root;
}
if (!FrameUtil.canConvertAccessPatterns(frame)) {
return root;
}
PlanNode projectNode = frame.getFirstChild();
// Check if lower frame has only a stored procedure execution - this cannot be merged to parent frame
if (FrameUtil.isProcedure(projectNode)) {
return root;
}
SymbolMap symbolMap = (SymbolMap)frame.getProperty(NodeConstants.Info.SYMBOL_MAP);
PlanNode sortNode = NodeEditor.findParent(parentProject, NodeConstants.Types.SORT, NodeConstants.Types.SOURCE);
if (sortNode != null && sortNode.hasBooleanProperty(NodeConstants.Info.UNRELATED_SORT)) {
OrderBy sortOrder = (OrderBy)sortNode.getProperty(NodeConstants.Info.SORT_ORDER);
boolean unrelated = false;
for (OrderByItem item : sortOrder.getOrderByItems()) {
if (!item.isUnrelated()) {
continue;
}
Collection<ElementSymbol> elements = ElementCollectorVisitor.getElements(item.getSymbol(), true);
for (ElementSymbol elementSymbol : elements) {
if (virtualGroup.equals(elementSymbol.getGroupSymbol())) {
unrelated = true;
if (!(symbolMap.getMappedExpression(elementSymbol) instanceof ElementSymbol)) {
return root;
}
}
}
}
// the lower frame cannot contain DUP_REMOVE, GROUP, UNION if unrelated
if (unrelated && NodeEditor.findNodePreOrder(frame, NodeConstants.Types.DUP_REMOVE, NodeConstants.Types.PROJECT) != null
|| NodeEditor.findNodePreOrder(frame, NodeConstants.Types.SET_OP, NodeConstants.Types.SOURCE) != null
|| NodeEditor.findNodePreOrder(frame, NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE) != null) {
return root;
}
}
//try to remove the virtual layer if we are only doing a simple projection in the following cases:
// 1. if the frame root is something other than a project (SET_OP, SORT, LIMIT, etc.)
// 2. if the frame has a grouping node
// 3. if the frame has no sources
if (projectNode.getType() != NodeConstants.Types.PROJECT
|| NodeEditor.findNodePreOrder(frame.getFirstChild(), NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE
| NodeConstants.Types.JOIN) != null
|| NodeEditor.findAllNodes(frame.getFirstChild(), NodeConstants.Types.SOURCE, NodeConstants.Types.SOURCE).isEmpty()) {
PlanNode parentSource = NodeEditor.findParent(parentProject, NodeConstants.Types.SOURCE);
if (beforeDecomposeJoin && parentSource != null && parentSource.hasProperty(Info.PARTITION_INFO)
&& !NodeEditor.findAllNodes(frame.getFirstChild(), NodeConstants.Types.SET_OP, NodeConstants.Types.SOURCE).isEmpty()) {
return root; //don't bother to merge until after
}
return checkForSimpleProjection(frame, root, parentProject, metadata);
}
PlanNode parentJoin = NodeEditor.findParent(frame, NodeConstants.Types.JOIN, NodeConstants.Types.SOURCE);
if (!checkJoinCriteria(frame, virtualGroup, parentJoin)) {
return root;
}
PlanNode parentGroup = NodeEditor.findParent(frame, NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE);
List<SingleElementSymbol> groupCols = null;
if (parentGroup != null) {
groupCols = (List<SingleElementSymbol>)parentGroup.getProperty(NodeConstants.Info.GROUP_COLS);
}
if (!checkProjectedSymbols(projectNode, virtualGroup, parentJoin, groupCols, symbolMap, metadata)) {
return root;
}
// Otherwise merge should work
// Convert parent frame before merge
FrameUtil.convertFrame(frame, virtualGroup, FrameUtil.findJoinSourceNode(projectNode).getGroups(), symbolMap.asMap(), metadata);
PlanNode parentBottom = frame.getParent();
prepareFrame(frame);
// Remove top 2 nodes (SOURCE, PROJECT) of virtual group - they're no longer needed
NodeEditor.removeChildNode(parentBottom, frame);
NodeEditor.removeChildNode(parentBottom, projectNode);