Author: mdrillin
Date: 2011-06-27 17:46:26 -0400 (Mon, 27 Jun 2011)
New Revision: 3277
Modified:
branches/7.1.1.CP3/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java
branches/7.1.1.CP3/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java
branches/7.1.1.CP3/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java
branches/7.1.1.CP3/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java
Log:
TEIID-1656 adding support for pushdown of aggs over unions with grouping expressions
Modified:
branches/7.1.1.CP3/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java
===================================================================
---
branches/7.1.1.CP3/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java 2011-06-27
21:44:19 UTC (rev 3276)
+++
branches/7.1.1.CP3/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java 2011-06-27
21:46:26 UTC (rev 3277)
@@ -29,6 +29,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
@@ -45,6 +46,7 @@
import org.teiid.query.function.FunctionLibrary;
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.metadata.TempMetadataAdapter;
+import org.teiid.query.metadata.TempMetadataID;
import org.teiid.query.metadata.TempMetadataStore;
import org.teiid.query.optimizer.capabilities.CapabilitiesFinder;
import org.teiid.query.optimizer.capabilities.SourceCapabilities.Capability;
@@ -58,6 +60,7 @@
import org.teiid.query.resolver.util.ResolverUtil;
import org.teiid.query.resolver.util.ResolverVisitor;
import org.teiid.query.rewriter.QueryRewriter;
+import org.teiid.query.sql.LanguageObject;
import org.teiid.query.sql.LanguageObject.Util;
import org.teiid.query.sql.lang.CompareCriteria;
import org.teiid.query.sql.lang.Criteria;
@@ -116,7 +119,7 @@
PlanNode setOp = child.getFirstChild();
try {
- pushGroupNodeOverUnion(plan, metadata, capFinder, groupNode, child,
groupingExpressions, setOp);
+ pushGroupNodeOverUnion(plan, metadata, capFinder, groupNode, child,
groupingExpressions, setOp, context, analysisRecord);
} catch (QueryResolverException e) {
throw new TeiidComponentException(e);
}
@@ -154,21 +157,66 @@
* source
* child 1
* ...
- *
+ *
* Or if the child does not support pushdown we add dummy aggregate projection
* count(*) = 1, count(x) = case x is null then 0 else 1 end, avg(x) = x, etc.
*/
private void pushGroupNodeOverUnion(PlanNode plan,
QueryMetadataInterface metadata, CapabilitiesFinder capFinder,
- PlanNode groupNode, PlanNode child,
- List<SingleElementSymbol> groupingExpressions, PlanNode setOp)
+ PlanNode groupNode, PlanNode unionSourceParent,
+ List<SingleElementSymbol> groupingExpressions, PlanNode setOp, CommandContext
context, AnalysisRecord record)
throws TeiidComponentException, QueryMetadataException,
QueryPlannerException, QueryResolverException {
- if (setOp == null || setOp.getType() != NodeConstants.Types.SET_OP ||
setOp.getProperty(NodeConstants.Info.SET_OPERATION) != Operation.UNION) {
- return; //must not be a union
+ if (setOp == null) {
+ return;
}
+ PlanNode intermediateView = null;
+ if (setOp.getType() != NodeConstants.Types.SET_OP) {
+ if (setOp.getType() != NodeConstants.Types.PROJECT) {
+ return;
+ }
+ intermediateView = unionSourceParent;
+ unionSourceParent = setOp.getFirstChild();
+ if (unionSourceParent == null || unionSourceParent.getType() !=
NodeConstants.Types.SOURCE || unionSourceParent.getFirstChild() == null
+ || unionSourceParent.getFirstChild().getType() != NodeConstants.Types.SET_OP ||
unionSourceParent.getFirstChild().getProperty(NodeConstants.Info.SET_OPERATION) !=
Operation.UNION) {
+ return; //not an eligible union
+ }
+ setOp = unionSourceParent.getFirstChild();
+ if (groupingExpressions == null) {
+ return; //shouldn't happen - the view should have been removed
+ }
+ }
+ if (setOp.getProperty(NodeConstants.Info.SET_OPERATION) != Operation.UNION) {
+ return;
+ }
LinkedHashSet<AggregateSymbol> aggregates = collectAggregates(groupNode);
+ //check to see if any aggregate is dependent upon cardinality
+ boolean cardinalityDependent =
RuleRemoveOptionalJoins.areAggregatesCardinalityDependent(aggregates);
+
+ LinkedList<PlanNode> unionChildren = new LinkedList<PlanNode>();
+ findUnionChildren(unionChildren, cardinalityDependent, setOp);
+
+ SymbolMap parentMap =
(SymbolMap)unionSourceParent.getProperty(NodeConstants.Info.SYMBOL_MAP);
+ List<ElementSymbol> virtualElements = parentMap.getKeys();
+ GroupSymbol virtualGroup = unionSourceParent.getGroups().iterator().next();
+
+ List<SingleElementSymbol> actualGroupingExpressions = groupingExpressions;
+ if (intermediateView != null) {
+ actualGroupingExpressions = new
ArrayList<SingleElementSymbol>(groupingExpressions.size());
+ SymbolMap viewMap =
(SymbolMap)intermediateView.getProperty(NodeConstants.Info.SYMBOL_MAP);
+ for (SingleElementSymbol ses : groupingExpressions) {
+ Expression ex = viewMap.getMappedExpression((ElementSymbol)ses);
+ SingleElementSymbol newCol = null;
+ if (ex instanceof SingleElementSymbol) {
+ newCol = (SingleElementSymbol)ex;
+ } else {
+ newCol = new ExpressionSymbol("grouping", ex); //$NON-NLS-1$
+ }
+ actualGroupingExpressions.add(newCol);
+ }
+ }
+
/*
* if there are no aggregates, this is just duplicate removal
* mark the union as not all, which should be removed later but
@@ -181,26 +229,19 @@
return;
}
- //check to see if any aggregate is dependent upon cardinality
- boolean cardinalityDependent =
RuleRemoveOptionalJoins.areAggregatesCardinalityDependent(aggregates);
-
- LinkedList<PlanNode> unionChildren = new LinkedList<PlanNode>();
- findUnionChildren(unionChildren, cardinalityDependent, setOp);
-
if (unionChildren.size() < 2) {
return;
}
- SymbolMap parentMap = (SymbolMap)child.getProperty(NodeConstants.Info.SYMBOL_MAP);
- List<ElementSymbol> virtualElements = parentMap.getKeys();
List<SingleElementSymbol> copy = new
ArrayList<SingleElementSymbol>(aggregates);
aggregates.clear();
Map<AggregateSymbol, Expression> aggMap = buildAggregateMap(copy, metadata,
aggregates);
boolean shouldPushdown = false;
List<Boolean> pushdownList = new ArrayList<Boolean>(unionChildren.size());
+
for (PlanNode planNode : unionChildren) {
- boolean pushdown = canPushGroupByToUnionChild(metadata, capFinder,
groupingExpressions, aggregates, planNode);
+ boolean pushdown = canPushGroupByToUnionChild(metadata, capFinder,
actualGroupingExpressions, aggregates, planNode, record);
pushdownList.add(pushdown);
shouldPushdown |= pushdown;
}
@@ -209,17 +250,70 @@
return;
}
+ if (intermediateView != null) {
+ parentMap = pushGroupByView(plan, metadata, capFinder, unionSourceParent,
+ setOp, intermediateView, cardinalityDependent,
+ unionChildren, virtualElements, virtualGroup);
+ virtualElements = parentMap.getKeys();
+ virtualGroup = unionSourceParent.getGroups().iterator().next();
+ }
+
Iterator<Boolean> pushdownIterator = pushdownList.iterator();
for (PlanNode planNode : unionChildren) {
- addView(plan, planNode, pushdownIterator.next(), groupingExpressions, aggregates,
virtualElements, metadata, capFinder);
+ addView(plan, planNode, pushdownIterator.next(), new GroupSymbol("X"),
groupingExpressions, aggregates, virtualElements, metadata, capFinder, null);
//$NON-NLS-1$
}
//update the parent plan with the staged aggregates and the new projected symbols
- List<SingleElementSymbol> projectedViewSymbols =
(List<SingleElementSymbol>)NodeEditor.findNodePreOrder(child,
NodeConstants.Types.PROJECT).getProperty(NodeConstants.Info.PROJECT_COLS);
- List<ElementSymbol> updatedVirturalElement = new
ArrayList<ElementSymbol>(virtualElements);
+ List<SingleElementSymbol> projectedViewSymbols =
(List<SingleElementSymbol>)NodeEditor.findNodePreOrder(unionSourceParent,
NodeConstants.Types.PROJECT).getProperty(NodeConstants.Info.PROJECT_COLS);
//hack to introduce aggregate symbols to the parent view TODO: this should change the
metadata properly.
- GroupSymbol virtualGroup = child.getGroups().iterator().next();
+ SymbolMap newParentMap = modifyUnionSourceParent(unionSourceParent, virtualGroup,
projectedViewSymbols, virtualElements);
+ Map<AggregateSymbol, ElementSymbol> projectedMap = new
HashMap<AggregateSymbol, ElementSymbol>();
+ Iterator<AggregateSymbol> aggIter = aggregates.iterator();
+ for (ElementSymbol projectedViewSymbol :
newParentMap.getKeys().subList(projectedViewSymbols.size() - aggregates.size(),
projectedViewSymbols.size())) {
+ projectedMap.put(aggIter.next(), projectedViewSymbol);
+ }
+ for (Expression expr : aggMap.values()) {
+ ExpressionMappingVisitor.mapExpressions(expr, projectedMap);
+ }
+ mapExpressions(groupNode.getParent(), aggMap, metadata);
+ }
+
+ private SymbolMap pushGroupByView(PlanNode plan,
+ QueryMetadataInterface metadata, CapabilitiesFinder capFinder,
+ PlanNode unionSourceParent, PlanNode setOp,
+ PlanNode intermediateView, boolean cardinalityDependent,
+ LinkedList<PlanNode> unionChildren,
+ List<ElementSymbol> virtualElements, GroupSymbol virtualGroup)
+ throws TeiidComponentException, QueryPlannerException,
+ QueryResolverException {
+ //perform view pushing
+ /*
+ * TODO: this introduces yet another potentially unneeded view, but cannot be removed
by the normal merge virtual logic
+ * due to an intervening access node
+ */
+ PlanNode intermediateProject = intermediateView.getFirstChild();
+ List<SingleElementSymbol> projectedViewSymbols =
(List<SingleElementSymbol>)intermediateProject.getProperty(NodeConstants.Info.PROJECT_COLS);
+ for (PlanNode planNode : unionChildren) {
+ addView(plan, planNode, false, (GroupSymbol) virtualGroup.clone(), null,
Collections.EMPTY_SET, virtualElements, metadata, capFinder,
LanguageObject.Util.deepClone(projectedViewSymbols, SingleElementSymbol.class));
+ }
+ unionChildren.clear();
+ findUnionChildren(unionChildren, cardinalityDependent, setOp);
+ virtualGroup = intermediateView.getGroups().iterator().next();
+ unionSourceParent.getGroups().clear();
+ unionSourceParent.addGroup(virtualGroup);
+ projectedViewSymbols =
(List<SingleElementSymbol>)NodeEditor.findNodePreOrder(unionSourceParent,
NodeConstants.Types.PROJECT).getProperty(NodeConstants.Info.PROJECT_COLS);
+ SymbolMap parentMap = modifyUnionSourceParent(unionSourceParent, virtualGroup,
projectedViewSymbols, Collections.EMPTY_LIST);
+ //remove the old view
+ NodeEditor.removeChildNode(intermediateView, intermediateProject);
+ NodeEditor.removeChildNode(intermediateView.getParent(), intermediateView);
+ return parentMap;
+ }
+
+ private SymbolMap modifyUnionSourceParent(PlanNode unionSourceParent,
+ GroupSymbol virtualGroup,
+ List<SingleElementSymbol> projectedViewSymbols, List<ElementSymbol>
baseVirtualElements) {
+ List<ElementSymbol> updatedVirturalElement = new
ArrayList<ElementSymbol>(baseVirtualElements);
for (int i = updatedVirturalElement.size(); i < projectedViewSymbols.size(); i++) {
SingleElementSymbol symbol = projectedViewSymbols.get(i);
String name = symbol.getShortName();
@@ -227,25 +321,18 @@
ElementSymbol virtualElement = new ElementSymbol(virtualElementName);
virtualElement.setGroupSymbol(virtualGroup);
virtualElement.setType(symbol.getType());
+ virtualElement.setMetadataID(new TempMetadataID(virtualElementName,
symbol.getType()));
updatedVirturalElement.add(virtualElement);
}
SymbolMap newParentMap = SymbolMap.createSymbolMap(updatedVirturalElement,
projectedViewSymbols);
- child.setProperty(NodeConstants.Info.SYMBOL_MAP, newParentMap);
- Map<AggregateSymbol, ElementSymbol> projectedMap = new
HashMap<AggregateSymbol, ElementSymbol>();
- Iterator<AggregateSymbol> aggIter = aggregates.iterator();
- for (ElementSymbol projectedViewSymbol :
newParentMap.getKeys().subList(projectedViewSymbols.size() - aggregates.size(),
projectedViewSymbols.size())) {
- projectedMap.put(aggIter.next(), projectedViewSymbol);
- }
- for (Expression expr : aggMap.values()) {
- ExpressionMappingVisitor.mapExpressions(expr, projectedMap);
- }
- mapExpressions(groupNode.getParent(), aggMap, metadata);
+ unionSourceParent.setProperty(NodeConstants.Info.SYMBOL_MAP, newParentMap);
+ return newParentMap;
}
private boolean canPushGroupByToUnionChild(QueryMetadataInterface metadata,
CapabilitiesFinder capFinder,
List<SingleElementSymbol> groupingExpressions,
- LinkedHashSet<AggregateSymbol> aggregates, PlanNode planNode)
+ LinkedHashSet<AggregateSymbol> aggregates, PlanNode planNode, AnalysisRecord
record)
throws QueryMetadataException, TeiidComponentException {
if (planNode.getType() != NodeConstants.Types.ACCESS) {
return false;
@@ -260,8 +347,16 @@
return false;
}
}
- if ((groupingExpressions == null || groupingExpressions.isEmpty()) &&
!CapabilitiesUtil.supports(Capability.QUERY_AGGREGATES_COUNT_STAR, modelId, metadata,
capFinder)) {
- return false;
+ if ((groupingExpressions == null || groupingExpressions.isEmpty())) {
+ if (!CapabilitiesUtil.supports(Capability.QUERY_AGGREGATES_COUNT_STAR, modelId,
metadata, capFinder)) {
+ return false;
+ }
+ } else {
+ for (SingleElementSymbol ses : groupingExpressions) {
+ if(! CriteriaCapabilityValidatorVisitor.canPushLanguageObject(ses, modelId, metadata,
capFinder, record)) {
+ return false;
+ }
+ }
}
//TODO: check to see if we are distinct
return true;
@@ -270,7 +365,7 @@
/**
* Recursively searches the union tree for all applicable source nodes
*/
- private PlanNode findUnionChildren(List<PlanNode> unionChildren, boolean
carinalityDependent, PlanNode setOp) {
+ static PlanNode findUnionChildren(List<PlanNode> unionChildren, boolean
carinalityDependent, PlanNode setOp) {
if (setOp.getType() != NodeConstants.Types.SET_OP ||
setOp.getProperty(NodeConstants.Info.SET_OPERATION) != Operation.UNION) {
return setOp;
}
@@ -292,11 +387,14 @@
return null;
}
- public void addView(PlanNode root, PlanNode unionSource, boolean pushdown,
List<SingleElementSymbol> groupingExpressions,
+ public void addView(PlanNode root, PlanNode unionSource, boolean pushdown, GroupSymbol
group, List<SingleElementSymbol> groupingExpressions,
Set<AggregateSymbol> aggregates, List<ElementSymbol> virtualElements,
- QueryMetadataInterface metadata, CapabilitiesFinder capFinder)
+ QueryMetadataInterface metadata, CapabilitiesFinder capFinder,
List<SingleElementSymbol> actualProject)
throws TeiidComponentException, QueryPlannerException, QueryResolverException {
- PlanNode originalNode = unionSource;
+ PlanNode accessNode = null;
+ if (pushdown) {
+ accessNode = NodeEditor.findNodePreOrder(unionSource, NodeConstants.Types.ACCESS);
+ }
//branches other than the first need to have their projected column names updated
PlanNode sortNode = NodeEditor.findNodePreOrder(unionSource, NodeConstants.Types.SORT,
NodeConstants.Types.SOURCE);
List<SingleElementSymbol> sortOrder = null;
@@ -320,34 +418,23 @@
updateSymbolName(projectCols, i, virtualElem, projectedSymbol);
}
}
- PlanNode intermediateView = NodeFactory.getNewNode(NodeConstants.Types.SOURCE);
- unionSource.addAsParent(intermediateView);
+ PlanNode intermediateView = createView(group, virtualElements, unionSource, metadata);
+ SymbolMap symbolMap = (SymbolMap)intermediateView.getProperty(Info.SYMBOL_MAP);
unionSource = intermediateView;
- TempMetadataStore store = new TempMetadataStore();
- TempMetadataAdapter tma = new TempMetadataAdapter(metadata, store);
- GroupSymbol group = new GroupSymbol("X"); //$NON-NLS-1$
- try {
- group.setMetadataID(ResolverUtil.addTempGroup(tma, group, virtualElements, false));
- } catch (QueryResolverException e) {
- throw new TeiidComponentException(e);
- }
- intermediateView.addGroup(group);
- List<ElementSymbol> projectedSymbols =
ResolverUtil.resolveElementsInGroup(group, metadata);
- SymbolMap symbolMap = SymbolMap.createSymbolMap(projectedSymbols,
- (List<Expression>)NodeEditor.findNodePreOrder(unionSource,
NodeConstants.Types.PROJECT).getProperty(NodeConstants.Info.PROJECT_COLS));
- intermediateView.setProperty(NodeConstants.Info.SYMBOL_MAP, symbolMap);
Set<SingleElementSymbol> newGroupingExpressions = Collections.emptySet();
if (groupingExpressions != null) {
newGroupingExpressions = new HashSet<SingleElementSymbol>();
for (SingleElementSymbol singleElementSymbol : groupingExpressions) {
- newGroupingExpressions.add((SingleElementSymbol)symbolMap.getKeys().get(virtualElements.indexOf(singleElementSymbol)).clone());
+ newGroupingExpressions.add((SingleElementSymbol)
symbolMap.getKeys().get(virtualElements.indexOf(singleElementSymbol)).clone());
}
}
- List<SingleElementSymbol> projectedViewSymbols =
Util.deepClone(projectedSymbols, SingleElementSymbol.class);
+ List<SingleElementSymbol> projectedViewSymbols =
Util.deepClone(symbolMap.getKeys(), SingleElementSymbol.class);
- SymbolMap viewMapping =
SymbolMap.createSymbolMap(NodeEditor.findParent(unionSource,
NodeConstants.Types.SOURCE).getGroups().iterator().next(), projectedSymbols, metadata);
+ PlanNode parent = NodeEditor.findParent(unionSource,
NodeConstants.Types.SOURCE);
+ SymbolMap parentMap = (SymbolMap)
parent.getProperty(NodeConstants.Info.SYMBOL_MAP);
+ SymbolMap viewMapping = SymbolMap.createSymbolMap(parentMap.getKeys(),
projectedViewSymbols);
for (AggregateSymbol agg : aggregates) {
agg = (AggregateSymbol)agg.clone();
ExpressionMappingVisitor.mapExpressions(agg, viewMapping.asMap());
@@ -380,18 +467,50 @@
unionSource = projectPlanNode;
//create proper names for the aggregate symbols
- Select select = new Select(projectedViewSymbols);
+ Select select = null;
+ if (actualProject == null) {
+ select = new Select(projectedViewSymbols);
+ } else {
+ select = new Select(actualProject);
+ }
QueryRewriter.makeSelectUnique(select, false);
projectedViewSymbols = select.getProjectedSymbols();
projectPlanNode.setProperty(NodeConstants.Info.PROJECT_COLS,
projectedViewSymbols);
projectPlanNode.addGroup(group);
if (pushdown) {
- while (RuleRaiseAccess.raiseAccessNode(root, originalNode, metadata, capFinder,
true, null) != null) {
+ while (RuleRaiseAccess.raiseAccessNode(root, accessNode, metadata, capFinder,
true, null) != null) {
//continue to raise
}
}
}
+
+ static PlanNode createView(GroupSymbol group, List<? extends SingleElementSymbol>
virtualElements, PlanNode child, QueryMetadataInterface metadata) throws
TeiidComponentException {
+ SymbolMap symbolMap = createSymbolMap(group, virtualElements, child, metadata);
+ PlanNode branchSource = NodeFactory.getNewNode(NodeConstants.Types.SOURCE);
+ branchSource.addGroup(group);
+ PlanNode projectNode = NodeEditor.findNodePreOrder(child,
NodeConstants.Types.PROJECT);
+ branchSource.setProperty(Info.SYMBOL_MAP,
SymbolMap.createSymbolMap(symbolMap.getKeys(), (List<? extends
SingleElementSymbol>)projectNode.getProperty(Info.PROJECT_COLS)));
+ child.addAsParent(branchSource);
+ return branchSource;
+ }
+ private static SymbolMap createSymbolMap(GroupSymbol group,
+ List<? extends SingleElementSymbol> virtualElements,
+ PlanNode child, QueryMetadataInterface metadata)
+ throws TeiidComponentException, QueryMetadataException {
+ TempMetadataStore store = new TempMetadataStore();
+ TempMetadataAdapter tma = new TempMetadataAdapter(metadata, store);
+ try {
+ group.setMetadataID(ResolverUtil.addTempGroup(tma, group, virtualElements, false));
+ } catch (QueryResolverException e) {
+ throw new TeiidComponentException(e);
+ }
+ List<ElementSymbol> projectedSymbols =
ResolverUtil.resolveElementsInGroup(group, metadata);
+ SymbolMap symbolMap = SymbolMap.createSymbolMap(projectedSymbols,
+ (List<Expression>)NodeEditor.findNodePreOrder(child,
NodeConstants.Types.PROJECT).getProperty(NodeConstants.Info.PROJECT_COLS));
+ return symbolMap;
+ }
+
private void updateSymbolName(List<SingleElementSymbol> projectCols, int i,
ElementSymbol virtualElem, SingleElementSymbol projectedSymbol) {
if (projectedSymbol instanceof AliasSymbol) {
@@ -450,20 +569,19 @@
}
Map<PlanNode, List<SingleElementSymbol>> groupingMap =
createNodeMapping(groupNode, groupingExpressions, false);
- Set<PlanNode> possibleTargetNodes = new
HashSet<PlanNode>(aggregateMap.keySet());
+ Set<PlanNode> possibleTargetNodes = new
LinkedHashSet<PlanNode>(aggregateMap.keySet());
possibleTargetNodes.addAll(groupingMap.keySet());
for (PlanNode planNode : possibleTargetNodes) {
Set<SingleElementSymbol> stagedGroupingSymbols = new
LinkedHashSet<SingleElementSymbol>();
List<AggregateSymbol> aggregates = aggregateMap.get(planNode);
- List<SingleElementSymbol> groupBy = groupingMap.get(planNode);
if (!canPush(groupNode, stagedGroupingSymbols, planNode)) {
continue;
}
- if (groupBy != null) {
- stagedGroupingSymbols.addAll(groupBy);
+ if (groupingExpressions != null) {
+ filterJoinColumns(stagedGroupingSymbols, planNode.getGroups(),
groupingExpressions);
}
collectSymbolsFromOtherAggregates(allAggregates, aggregates, planNode,
stagedGroupingSymbols);
@@ -625,7 +743,7 @@
private <T extends SingleElementSymbol> Map<PlanNode, List<T>>
createNodeMapping(PlanNode groupNode,
Collection<T> expressions, boolean aggs) {
- Map<PlanNode, List<T>> result = new HashMap<PlanNode,
List<T>>();
+ Map<PlanNode, List<T>> result = new LinkedHashMap<PlanNode,
List<T>>();
if (expressions == null) {
return result;
}
@@ -657,7 +775,7 @@
if (originatingNode.getParent() == groupNode) {
//anything logically applied after the join and is
//dependent upon the cardinality prevents us from optimizing.
- if (aggs &&
RuleRemoveOptionalJoins.isCardinalityDependent((AggregateSymbol)aggregateSymbol)) {
+ if (aggs &&
((AggregateSymbol)aggregateSymbol).isCardinalityDependent()) {
return null;
}
continue;
@@ -753,7 +871,8 @@
nestedAggregates.add(countAgg);
nestedAggregates.add(sumAgg);
nestedAggregates.add(sumSqAgg);
- } else {
+ }
+ else {
//AGG(X) -> AGG(AGG(X))
newExpression = new AggregateSymbol("stagedAgg",
aggFunction.name(), false, partitionAgg); //$NON-NLS-1$
nestedAggregates.add(partitionAgg);
@@ -787,4 +906,5 @@
public String toString() {
return "PushAggregates"; //$NON-NLS-1$
}
+
}
Modified:
branches/7.1.1.CP3/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java
===================================================================
---
branches/7.1.1.CP3/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java 2011-06-27
21:44:19 UTC (rev 3276)
+++
branches/7.1.1.CP3/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java 2011-06-27
21:46:26 UTC (rev 3277)
@@ -299,30 +299,13 @@
static boolean areAggregatesCardinalityDependent(Set<AggregateSymbol> aggs) {
for (AggregateSymbol aggregateSymbol : aggs) {
- if (isCardinalityDependent(aggregateSymbol)) {
+ if (aggregateSymbol.isCardinalityDependent()) {
return true;
}
}
return false;
}
- static boolean isCardinalityDependent(AggregateSymbol aggregateSymbol) {
- if (aggregateSymbol.isDistinct()) {
- return false;
- }
- switch (aggregateSymbol.getAggregateFunction()) {
- case COUNT:
- case AVG:
- case STDDEV_POP:
- case STDDEV_SAMP:
- case VAR_POP:
- case VAR_SAMP:
- case SUM:
- return true;
- }
- return false;
- }
-
public String toString() {
return "RuleRemoveOptionalJoins"; //$NON-NLS-1$
}
Modified:
branches/7.1.1.CP3/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java
===================================================================
---
branches/7.1.1.CP3/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java 2011-06-27
21:44:19 UTC (rev 3276)
+++
branches/7.1.1.CP3/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java 2011-06-27
21:46:26 UTC (rev 3277)
@@ -243,5 +243,22 @@
&& EquivalenceUtil.areEqual(this.getExpression(),
other.getExpression())
&& EquivalenceUtil.areEqual(this.getOrderBy(), other.getOrderBy());
}
+
+ public boolean isCardinalityDependent() {
+ if (isDistinct()) {
+ return false;
+ }
+ switch (getAggregateFunction()) {
+ case COUNT:
+ case AVG:
+ case STDDEV_POP:
+ case STDDEV_SAMP:
+ case VAR_POP:
+ case VAR_SAMP:
+ case SUM:
+ return true;
+ }
+ return false;
+ }
}
Modified:
branches/7.1.1.CP3/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java
===================================================================
---
branches/7.1.1.CP3/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java 2011-06-27
21:44:19 UTC (rev 3276)
+++
branches/7.1.1.CP3/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java 2011-06-27
21:46:26 UTC (rev 3277)
@@ -22,7 +22,10 @@
package org.teiid.query.optimizer;
-import static org.teiid.query.optimizer.TestOptimizer.*;
+import static org.teiid.query.optimizer.TestOptimizer.SHOULD_SUCCEED;
+import static org.teiid.query.optimizer.TestOptimizer.checkNodeTypes;
+import static org.teiid.query.optimizer.TestOptimizer.getTypicalCapabilities;
+import static org.teiid.query.optimizer.TestOptimizer.helpPlan;
import org.junit.Test;
import org.teiid.query.metadata.QueryMetadataInterface;
@@ -35,6 +38,7 @@
import org.teiid.query.processor.ProcessorPlan;
import org.teiid.query.unittest.FakeMetadataFacade;
import org.teiid.query.unittest.FakeMetadataFactory;
+import org.teiid.query.unittest.RealMetadataFactory;
import org.teiid.translator.SourceSystemFunctions;
@SuppressWarnings("nls")
@@ -899,6 +903,37 @@
}
/**
+ * pushdown won't happen since searched case is not supported
+ */
+ @Test public void testPushDownOverUnionGroupingExpression() throws Exception {
+ FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
+ BasicSourceCapabilities caps = getAggregateCapabilities();
+ caps.setCapabilitySupport(Capability.QUERY_SEARCHED_CASE, true);
+ capFinder.addCapabilities("pm1", caps); //$NON-NLS-1$
+ capFinder.addCapabilities("pm2", getAggregateCapabilities());
//$NON-NLS-1$
+
+ ProcessorPlan plan = TestOptimizer.helpPlan("select max(e2), case when e1 is
null then 0 else 1 end from (select e1, e2 from pm1.g1 union all select e1, e2 from
pm2.g2) z group by case when e1 is null then 0 else 1 end",
FakeMetadataFactory.example1Cached(), null, capFinder, //$NON-NLS-1$
+ new String[]{"SELECT v_1.c_0, MAX(v_1.c_1) FROM (SELECT CASE WHEN
v_0.c_0 IS NULL THEN 0 ELSE 1 END AS c_0, v_0.c_1 FROM (SELECT g_0.e1 AS c_0, g_0.e2 AS
c_1 FROM pm1.g1 AS g_0) AS v_0) AS v_1 GROUP BY v_1.c_0", //$NON-NLS-1$
+ "SELECT g_0.e1, g_0.e2 FROM pm2.g2 AS g_0"},
ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
+ TestOptimizer.checkNodeTypes(plan, new int[] {
+ 2, // Access
+ 0, // DependentAccess
+ 0, // DependentSelect
+ 0, // DependentProject
+ 0, // DupRemove
+ 1, // Grouping
+ 0, // NestedLoopJoinStrategy
+ 0, // MergeJoinStrategy
+ 0, // Null
+ 0, // PlanExecution
+ 3, // Project
+ 0, // Select
+ 0, // Sort
+ 1 // UnionAll
+ });
+ }
+
+ /**
* Ensures that we do not raise criteria over a group by
* TODO: check if the criteria only depends on grouping columns
*/