use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RulePushAggregates method collectAggregates.
/**
* Walk up the plan from the GROUP node. Should encounter only (optionally) a SELECT and can stop at the PROJECT node. Need to
* collect any AggregateSymbols used in the select criteria or projected columns.
*
* @param groupNode
* @return the set of aggregate symbols found
* @since 4.2
*/
static LinkedHashSet<AggregateSymbol> collectAggregates(PlanNode groupNode) {
LinkedHashSet<AggregateSymbol> aggregates = new LinkedHashSet<AggregateSymbol>();
PlanNode currentNode = groupNode.getParent();
SymbolMap symbolMap = (SymbolMap) groupNode.getProperty(NodeConstants.Info.SYMBOL_MAP);
while (currentNode != null) {
if (currentNode.getType() == NodeConstants.Types.PROJECT) {
List<Expression> projectedSymbols = (List<Expression>) currentNode.getProperty(NodeConstants.Info.PROJECT_COLS);
for (Expression symbol : projectedSymbols) {
mapAggregates(ElementCollectorVisitor.getAggregates(symbol, true), symbolMap, aggregates);
}
break;
}
if (currentNode.getType() == NodeConstants.Types.SELECT) {
Criteria crit = (Criteria) currentNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
mapAggregates(ElementCollectorVisitor.getAggregates(crit, true), symbolMap, aggregates);
}
currentNode = currentNode.getParent();
}
return aggregates;
}
use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RulePushAggregates method canPush.
/**
* Ensures that we are only pushing through inner equi joins or cross joins. Also collects the necessary staged grouping symbols
* @param aggregates
* @param metadata
* @return null if we cannot push otherwise the target join node
*/
private PlanNode canPush(PlanNode groupNode, Set<Expression> stagedGroupingSymbols, PlanNode planNode, Collection<AggregateSymbol> aggregates, QueryMetadataInterface metadata) {
PlanNode parentJoin = planNode.getParent();
Set<GroupSymbol> groups = FrameUtil.findJoinSourceNode(planNode).getGroups();
PlanNode result = planNode;
while (parentJoin != groupNode) {
if (parentJoin.getType() != NodeConstants.Types.JOIN) {
return null;
}
JoinType joinType = (JoinType) parentJoin.getProperty(NodeConstants.Info.JOIN_TYPE);
if (joinType.isOuter() && aggregates != null) {
for (AggregateSymbol as : aggregates) {
if (as.getArgs().length != 1) {
continue;
}
Collection<GroupSymbol> expressionGroups = GroupsUsedByElementsVisitor.getGroups(as.getArg(0));
Collection<GroupSymbol> innerGroups = null;
if (joinType == JoinType.JOIN_LEFT_OUTER) {
innerGroups = FrameUtil.findJoinSourceNode(parentJoin.getLastChild()).getGroups();
} else {
// full outer
innerGroups = parentJoin.getGroups();
}
if (Collections.disjoint(expressionGroups, innerGroups)) {
continue;
}
if (as.getFunctionDescriptor() != null && as.getFunctionDescriptor().isNullDependent()) {
return null;
}
if (as.getArgs().length == 1 && JoinUtil.isNullDependent(metadata, innerGroups, as.getArg(0))) {
return null;
}
}
}
// check for sideways correlation
PlanNode other = null;
if (planNode == parentJoin.getFirstChild()) {
other = parentJoin.getLastChild();
} else {
other = parentJoin.getFirstChild();
}
SymbolMap map = (SymbolMap) other.getProperty(NodeConstants.Info.CORRELATED_REFERENCES);
if (map != null) {
return null;
// TODO: handle this case. the logic would look something like below,
// but we would need to handle the updating of the symbol maps in addGroupBy
/*filterExpressions(stagedGroupingSymbols, groups, map.getKeys(), true);
for (ElementSymbol ex : map.getKeys()) {
if (DataTypeManager.isNonComparable(DataTypeManager.getDataTypeName(ex.getType()))) {
return null;
}
}*/
}
if (!parentJoin.hasCollectionProperty(NodeConstants.Info.LEFT_EXPRESSIONS) || !parentJoin.hasCollectionProperty(NodeConstants.Info.RIGHT_EXPRESSIONS)) {
List<Criteria> criteria = (List<Criteria>) parentJoin.getProperty(Info.JOIN_CRITERIA);
if (!findStagedGroupingExpressions(groups, criteria, stagedGroupingSymbols)) {
return null;
}
} else {
List<Criteria> criteria = (List<Criteria>) parentJoin.getProperty(Info.NON_EQUI_JOIN_CRITERIA);
if (!findStagedGroupingExpressions(groups, criteria, stagedGroupingSymbols)) {
return null;
}
// we move the target up if the filtered expressions introduce outside groups
if (planNode == parentJoin.getFirstChild()) {
if (filterExpressions(stagedGroupingSymbols, groups, (List<Expression>) parentJoin.getProperty(NodeConstants.Info.LEFT_EXPRESSIONS), true)) {
result = parentJoin;
groups = result.getGroups();
}
} else {
if (filterExpressions(stagedGroupingSymbols, groups, (List<Expression>) parentJoin.getProperty(NodeConstants.Info.RIGHT_EXPRESSIONS), true)) {
result = parentJoin;
groups = result.getGroups();
}
}
}
planNode = parentJoin;
parentJoin = parentJoin.getParent();
}
if (result.getParent() == groupNode) {
// can't be pushed as we are already at the direct child
return null;
}
return result;
}
use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RuleChooseJoinStrategy method chooseJoinStrategy.
/**
* Determines whether this node should be converted to a merge join node
* @param joinNode The join node
* @param metadata The metadata
*/
static void chooseJoinStrategy(PlanNode joinNode, QueryMetadataInterface metadata) {
// Check that join is an inner join
JoinType jtype = (JoinType) joinNode.getProperty(NodeConstants.Info.JOIN_TYPE);
if (jtype.equals(JoinType.JOIN_CROSS)) {
return;
}
PlanNode leftChild = joinNode.getFirstChild();
leftChild = FrameUtil.findJoinSourceNode(leftChild);
if (leftChild == null) {
return;
}
PlanNode rightChild = joinNode.getLastChild();
rightChild = FrameUtil.findJoinSourceNode(rightChild);
if (rightChild == null) {
return;
}
Collection<GroupSymbol> leftGroups = leftChild.getGroups();
Collection<GroupSymbol> rightGroups = rightChild.getGroups();
List<Expression> leftExpressions = new ArrayList<Expression>();
List<Expression> rightExpressions = new ArrayList<Expression>();
// Check that join criteria are all equality criteria and that there are elements from
// no more than one group on each side
List<Criteria> crits = (List<Criteria>) joinNode.getProperty(NodeConstants.Info.JOIN_CRITERIA);
filterOptionalCriteria(crits, true);
if (crits.isEmpty() && jtype == JoinType.JOIN_INNER) {
joinNode.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_CROSS);
return;
}
List<Criteria> nonEquiJoinCriteria = new ArrayList<Criteria>();
separateCriteria(leftGroups, rightGroups, leftExpressions, rightExpressions, crits, nonEquiJoinCriteria);
if (!leftExpressions.isEmpty()) {
joinNode.setProperty(NodeConstants.Info.LEFT_EXPRESSIONS, createExpressionSymbols(leftExpressions));
joinNode.setProperty(NodeConstants.Info.RIGHT_EXPRESSIONS, createExpressionSymbols(rightExpressions));
// make use of the one side criteria
joinNode.setProperty(NodeConstants.Info.JOIN_STRATEGY, JoinStrategyType.MERGE);
joinNode.setProperty(NodeConstants.Info.NON_EQUI_JOIN_CRITERIA, nonEquiJoinCriteria);
} else if (nonEquiJoinCriteria.isEmpty()) {
joinNode.setProperty(NodeConstants.Info.JOIN_CRITERIA, nonEquiJoinCriteria);
if (joinNode.getProperty(NodeConstants.Info.JOIN_TYPE) == JoinType.JOIN_INNER) {
joinNode.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_CROSS);
}
}
}
use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RuleCopyCriteria method createCriteria.
private boolean createCriteria(boolean copyingJoinCriteria, Collection<Criteria> toCopy, Set<Criteria> combinedCriteria, Map<Expression, Expression> srcToTgt, List<Criteria> newJoinCrits, QueryMetadataInterface metadata, boolean underAccess) {
boolean changedTree = false;
if (srcToTgt.size() == 0) {
return changedTree;
}
Iterator<Criteria> i = toCopy.iterator();
while (i.hasNext()) {
Criteria crit = i.next();
Integer endGroups = copyCriteria(crit, srcToTgt, newJoinCrits, combinedCriteria, copyingJoinCriteria, metadata, underAccess);
if (endGroups != null) {
changedTree = true;
if (copyingJoinCriteria && endGroups < 2) {
if (crit instanceof CompareCriteria) {
CompareCriteria cc = (CompareCriteria) crit;
// don't remove theta criteria, just mark it as optional
cc.setOptional(null);
continue;
}
i.remove();
}
}
}
return changedTree;
}
use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RulePushSelectCriteria method createConvertedSelectNode.
private PlanNode createConvertedSelectNode(PlanNode critNode, GroupSymbol sourceGroup, PlanNode projectNode, SymbolMap symbolMap, QueryMetadataInterface metadata) throws QueryPlannerException {
// If projectNode has children, then it is from a SELECT without a FROM and the criteria should not be pushed
if (projectNode.getChildCount() == 0) {
return null;
}
Criteria crit = (Criteria) critNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
Collection<ElementSymbol> cols = ElementCollectorVisitor.getElements(crit, true);
if (projectNode.hasBooleanProperty(Info.HAS_WINDOW_FUNCTIONS)) {
// we can push iff the predicate is against partitioning columns in all projected window functions
Set<WindowFunction> windowFunctions = RuleAssignOutputElements.getWindowFunctions((List<Expression>) projectNode.getProperty(Info.PROJECT_COLS));
for (WindowFunction windowFunction : windowFunctions) {
WindowSpecification spec = windowFunction.getWindowSpecification();
if (spec.getPartition() == null) {
return null;
}
for (ElementSymbol col : cols) {
if (!spec.getPartition().contains(symbolMap.getMappedExpression(col))) {
return null;
}
}
}
}
Boolean conversionResult = checkConversion(symbolMap, cols);
if (conversionResult == Boolean.FALSE) {
// not convertable
return null;
}
if (!critNode.getSubqueryContainers().isEmpty() && checkConversion(symbolMap, critNode.getCorrelatedReferenceElements()) != null) {
// not convertable, or has an aggregate for a correlated reference
return null;
}
PlanNode copyNode = copyNode(critNode);
if (conversionResult == Boolean.TRUE) {
copyNode.setProperty(NodeConstants.Info.IS_HAVING, Boolean.TRUE);
}
FrameUtil.convertNode(copyNode, sourceGroup, null, symbolMap.asMap(), metadata, true);
// any proc relational criteria that is not input criteria should stay above the source
if (sourceGroup.isProcedure() && !copyNode.getGroups().isEmpty()) {
if (this.createdNodes != null) {
this.createdNodes.remove(this.createdNodes.size() - 1);
}
return null;
}
return copyNode;
}
Aggregations