* @param metadata Metadata implementation
* @return The filtered list of columns for this node (used in recursing tree)
*/
static List<SingleElementSymbol> filterVirtualElements(PlanNode sourceNode, List<SingleElementSymbol> outputColumns, QueryMetadataInterface metadata) {
PlanNode virtualRoot = sourceNode.getLastChild();
// Update project cols - typically there is exactly one and that node can
// just get the filteredCols determined above. In the case of one or more
// nested set operations (UNION, INTERSECT, EXCEPT) there will be 2 or more
// projects.
List<PlanNode> allProjects = NodeEditor.findAllNodes(virtualRoot, NodeConstants.Types.PROJECT, NodeConstants.Types.PROJECT);
int[] filteredIndex = new int[outputColumns.size()];
Arrays.fill(filteredIndex, -1);
SymbolMap symbolMap = (SymbolMap)sourceNode.getProperty(NodeConstants.Info.SYMBOL_MAP);
List<ElementSymbol> originalOrder = symbolMap.getKeys();
boolean updateGroups = outputColumns.size() != originalOrder.size();
boolean[] seenIndex = new boolean[outputColumns.size()];
for (int i = 0; i < outputColumns.size(); i++) {
Expression expr = outputColumns.get(i);
filteredIndex[i] = originalOrder.indexOf(expr);
if (!updateGroups) {
seenIndex[filteredIndex[i]] = true;
}
}
if (!updateGroups) {
for (boolean b : seenIndex) {
if (!b) {
updateGroups = true;
break;
}
}
}
List<SingleElementSymbol> newCols = null;
for(int i=allProjects.size()-1; i>=0; i--) {
PlanNode projectNode = allProjects.get(i);
List<SingleElementSymbol> projectCols = (List<SingleElementSymbol>) projectNode.getProperty(NodeConstants.Info.PROJECT_COLS);
newCols = RelationalNode.projectTuple(filteredIndex, projectCols);
projectNode.setProperty(NodeConstants.Info.PROJECT_COLS, newCols);
if (updateGroups) {
projectNode.getGroups().clear();
projectNode.addGroups(GroupsUsedByElementsVisitor.getGroups(newCols));
projectNode.addGroups(GroupsUsedByElementsVisitor.getGroups(projectNode.getCorrelatedReferenceElements()));
}
}
if (!updateGroups) {
for (int i : filteredIndex) {
if (i != filteredIndex[i]) {
updateGroups = true;
break;
}
}
}
if (updateGroups) {
SymbolMap newMap = new SymbolMap();
List<Expression> originalExpressionOrder = symbolMap.getValues();
for (int i = 0; i < filteredIndex.length; i++) {
newMap.addMapping(originalOrder.get(filteredIndex[i]), originalExpressionOrder.get(filteredIndex[i]));
}
PlanNode sortNode = NodeEditor.findNodePreOrder(sourceNode, NodeConstants.Types.SORT, NodeConstants.Types.PROJECT);
if (sortNode != null) {
OrderBy elements = (OrderBy) sortNode.getProperty(NodeConstants.Info.SORT_ORDER);
for (OrderByItem item : elements.getOrderByItems()) {
if (item.getExpressionPosition() == -1) {
continue;
}
item.setExpressionPosition(-1);
for (int i = 0; i < filteredIndex.length; i++) {
if (item.getExpressionPosition() == filteredIndex[i]) {
item.setExpressionPosition(i);
break;
}
}
if (item.getExpressionPosition() == -1) {
sortNode.setProperty(NodeConstants.Info.UNRELATED_SORT, true);
}
}
}
sourceNode.setProperty(NodeConstants.Info.SYMBOL_MAP, newMap);
}