use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.
the class RulePushNonJoinCriteria method pushCriteria.
/**
* True if the criteria is pushed.
*
* It's possible to push to the inner side of the join if the new criteria node
* originates there
*
* @param joinNode
* @param tgtCrit
* @param metadata
* @return
*/
private boolean pushCriteria(PlanNode joinNode, Criteria tgtCrit, Iterator iter, QueryMetadataInterface metadata) {
PlanNode newCritNode = RelationalPlanner.createSelectNode(tgtCrit, false);
Set<GroupSymbol> groups = newCritNode.getGroups();
PlanNode[] innerJoinNodes = JoinUtil.getInnerSideJoinNodes(joinNode);
boolean pushed = false;
for (int i = 0; i < innerJoinNodes.length; i++) {
if (FrameUtil.findOriginatingNode(innerJoinNodes[i], groups) != null) {
if (pushed) {
// create a new copy since the old one has been used
newCritNode = RelationalPlanner.createSelectNode(tgtCrit, false);
}
innerJoinNodes[i].addAsParent(newCritNode);
pushed = true;
}
}
if (pushed) {
iter.remove();
} else if (firstRun && tgtCrit instanceof CompareCriteria) {
CompareCriteria crit = (CompareCriteria) tgtCrit;
Expression leftExpr = crit.getLeftExpression();
Expression rightExpr = crit.getRightExpression();
for (int i = 0; i < innerJoinNodes.length; i++) {
PlanNode node = FrameUtil.findJoinSourceNode(innerJoinNodes[i]);
boolean outer = false;
for (PlanNode child : NodeEditor.findAllNodes(node, NodeConstants.Types.JOIN)) {
if (((JoinType) child.getProperty(Info.JOIN_TYPE)).isOuter()) {
outer = true;
break;
}
}
if (!outer) {
continue;
}
Set<GroupSymbol> leftExprGroups = GroupsUsedByElementsVisitor.getGroups(leftExpr);
Set<GroupSymbol> rightExprGroups = GroupsUsedByElementsVisitor.getGroups(rightExpr);
ArrayList<ElementSymbol> notNull = new ArrayList<ElementSymbol>(2);
if (node.getGroups().containsAll(leftExprGroups)) {
collectNotNull(leftExpr, notNull);
} else if (node.getGroups().containsAll(rightExprGroups)) {
collectNotNull(rightExpr, notNull);
}
if (!notNull.isEmpty()) {
pushed = true;
for (ElementSymbol es : notNull) {
IsNullCriteria inc = new IsNullCriteria(es);
inc.setNegated(true);
PlanNode notNullCrit = RelationalPlanner.createSelectNode(inc, false);
notNullCrit.setProperty(NodeConstants.Info.IS_TEMPORARY, true);
innerJoinNodes[i].addAsParent(notNullCrit);
}
}
}
}
return pushed;
}
use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.
the class RulePushSelectCriteria method pushAcrossGroupBy.
boolean pushAcrossGroupBy(PlanNode sourceNode, PlanNode critNode, QueryMetadataInterface metadata, boolean inPlan, CapabilitiesFinder capFinder) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
if (critNode.hasBooleanProperty(NodeConstants.Info.IS_HAVING)) {
return false;
}
if (critNode.hasBooleanProperty(NodeConstants.Info.IS_DEPENDENT_SET)) {
PlanNode accessNode = NodeEditor.findParent(critNode, NodeConstants.Types.ACCESS);
if (accessNode != null) {
List<Expression> cols = (List<Expression>) sourceNode.getProperty(Info.GROUP_COLS);
if (cols != null) {
boolean hasExpression = false;
boolean hasLiteral = false;
for (final Iterator<Expression> iterator = cols.iterator(); iterator.hasNext(); ) {
Expression ex = iterator.next();
hasExpression |= !(ex instanceof ElementSymbol);
hasLiteral |= EvaluatableVisitor.willBecomeConstant(ex, true);
}
if (hasLiteral || (hasExpression && !CapabilitiesUtil.supports(Capability.QUERY_FUNCTIONS_IN_GROUP_BY, RuleRaiseAccess.getModelIDFromAccess(accessNode, metadata), metadata, capFinder))) {
markDependent(critNode, accessNode, metadata, capFinder);
critNode.setProperty(Info.IS_HAVING, true);
return false;
}
}
}
}
if (sourceNode.hasBooleanProperty(Info.ROLLUP)) {
// but instead we'll just clone the node
if (inPlan) {
PlanNode copy = copyNode(critNode);
critNode.setProperty(Info.IS_PUSHED, true);
critNode.setProperty(Info.IS_HAVING, true);
critNode.getFirstChild().addAsParent(copy);
critNode = copy;
}
}
boolean moved = false;
SymbolMap symbolMap = (SymbolMap) sourceNode.getProperty(NodeConstants.Info.SYMBOL_MAP);
FrameUtil.convertNode(critNode, null, null, symbolMap.asMap(), metadata, true);
if (inPlan) {
NodeEditor.removeChildNode(critNode.getParent(), critNode);
sourceNode.getFirstChild().addAsParent(critNode);
}
moved = true;
if (critNode.hasBooleanProperty(NodeConstants.Info.IS_DEPENDENT_SET)) {
PlanNode accessNode = NodeEditor.findParent(critNode, NodeConstants.Types.ACCESS);
if (accessNode != null) {
markDependent(critNode, accessNode, metadata, capFinder);
// terminal position
moved = false;
}
}
return moved;
}
use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.
the class RulePushSelectCriteria method findOriginatingNode.
private PlanNode findOriginatingNode(QueryMetadataInterface metadata, CapabilitiesFinder capFinder, PlanNode critNode, AnalysisRecord record) throws TeiidComponentException, QueryMetadataException {
if (critNode.getGroups().isEmpty()) {
// check to see if pushing may impact cardinality
PlanNode groupNode = NodeEditor.findNodePreOrder(critNode, NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE);
if (groupNode != null && !groupNode.hasCollectionProperty(NodeConstants.Info.GROUP_COLS)) {
return groupNode;
}
Object modelId = getSubqueryModelId(metadata, capFinder, critNode, record);
if (modelId != null) {
for (PlanNode node : NodeEditor.findAllNodes(critNode, NodeConstants.Types.SOURCE)) {
GroupSymbol group = node.getGroups().iterator().next();
Object srcModelID = metadata.getModelID(group.getMetadataID());
if (CapabilitiesUtil.isSameConnector(srcModelID, modelId, metadata, capFinder)) {
return node;
}
}
}
}
return FrameUtil.findOriginatingNode(critNode, critNode.getGroups());
}
use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.
the class RulePushSelectCriteria method moveNodeAcrossFrame.
Boolean moveNodeAcrossFrame(PlanNode critNode, PlanNode sourceNode, final QueryMetadataInterface metadata) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
// Check that sourceNode has a child to push across
if (sourceNode.getChildCount() == 0) {
return false;
}
final PlanNode projectNode = NodeEditor.findNodePreOrder(sourceNode.getFirstChild(), NodeConstants.Types.PROJECT, NodeConstants.Types.SOURCE);
if (FrameUtil.isProcedure(projectNode)) {
return false;
}
final SymbolMap symbolMap = (SymbolMap) sourceNode.getProperty(NodeConstants.Info.SYMBOL_MAP);
final GroupSymbol sourceGroup = sourceNode.getGroups().iterator().next();
if (!placeConvertedSelectNode(critNode, sourceGroup, projectNode, symbolMap, metadata)) {
if (createdNodes == null) {
Criteria crit = (Criteria) critNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
if (isMultiAttributeDependentSet(crit) && splitSet(critNode, new DependentNodeTest() {
@Override
public boolean isValid(PlanNode copyNode) throws QueryMetadataException, QueryPlannerException, TeiidComponentException {
return createConvertedSelectNode(copyNode, sourceGroup, projectNode, symbolMap, metadata) != null;
}
}, (DependentSetCriteria) crit, sourceNode)) {
return null;
}
}
return false;
}
if (createdNodes == null) {
satisfyConditions(critNode, sourceNode, metadata);
}
// Mark critNode as a "phantom"
critNode.setProperty(NodeConstants.Info.IS_PHANTOM, Boolean.TRUE);
return true;
}
use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.
the class RulePushSelectCriteria method markDependent.
private void markDependent(PlanNode critNode, PlanNode accessNode, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryMetadataException, TeiidComponentException {
// once a dependent crit node is pushed, don't bother pushing it further into the command
// dependent access node will use this as an assumption for where dependent sets can appear in the command
critNode.setProperty(NodeConstants.Info.IS_PUSHED, Boolean.TRUE);
if (createdNodes != null) {
// this is during a planning run and should not cause additional side-effects
return;
}
accessNode.setProperty(NodeConstants.Info.IS_DEPENDENT_SET, Boolean.TRUE);
Criteria crit = (Criteria) critNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
if (isMultiAttributeDependentSet(crit)) {
// split the criteria as needed
List<DependentSetCriteria> crits = splitDependentSetCriteria((DependentSetCriteria) crit, CapabilitiesUtil.supports(Capability.ARRAY_TYPE, RuleRaiseAccess.getModelIDFromAccess(accessNode, metadata), metadata, capFinder), metadata);
critNode.setProperty(NodeConstants.Info.SELECT_CRITERIA, new CompoundCriteria(crits));
}
Collection<ElementSymbol> elements = null;
for (PlanNode joinNode : NodeEditor.findAllNodes(accessNode, NodeConstants.Types.JOIN, NodeConstants.Types.SOURCE)) {
List<Criteria> joinCriteria = (List<Criteria>) joinNode.getProperty(Info.JOIN_CRITERIA);
if (joinCriteria == null) {
continue;
}
for (Criteria joinPredicate : joinCriteria) {
if (!(joinPredicate instanceof CompareCriteria)) {
continue;
}
CompareCriteria cc = (CompareCriteria) joinPredicate;
if (!cc.isOptional()) {
continue;
}
if (elements == null) {
elements = ElementCollectorVisitor.getElements((LanguageObject) critNode.getProperty(Info.SELECT_CRITERIA), true);
}
if (!Collections.disjoint(elements, ElementCollectorVisitor.getElements(cc, false))) {
cc.setOptional(false);
}
}
}
}
Aggregations