use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.
the class RulePlanOuterJoins method planLeftOuterJoinAssociativity.
private boolean planLeftOuterJoinAssociativity(PlanNode plan, QueryMetadataInterface metadata, CapabilitiesFinder capabilitiesFinder, AnalysisRecord analysisRecord, CommandContext context) throws QueryMetadataException, TeiidComponentException {
boolean changedAny = false;
LinkedHashSet<PlanNode> joins = new LinkedHashSet<PlanNode>(NodeEditor.findAllNodes(plan, NodeConstants.Types.JOIN, NodeConstants.Types.ACCESS));
while (!joins.isEmpty()) {
Iterator<PlanNode> i = joins.iterator();
PlanNode join = i.next();
i.remove();
if (!join.getProperty(Info.JOIN_TYPE).equals(JoinType.JOIN_LEFT_OUTER) || join.hasBooleanProperty(Info.PRESERVE)) {
continue;
}
PlanNode childJoin = null;
PlanNode other = null;
PlanNode left = join.getFirstChild();
PlanNode right = join.getLastChild();
if (left.getType() == NodeConstants.Types.JOIN && left.getProperty(Info.JOIN_TYPE) == JoinType.JOIN_LEFT_OUTER) {
childJoin = left;
other = right;
} else if (right.getType() == NodeConstants.Types.JOIN && (right.getProperty(Info.JOIN_TYPE) == JoinType.JOIN_LEFT_OUTER || right.getProperty(Info.JOIN_TYPE) == JoinType.JOIN_INNER)) {
childJoin = right;
other = left;
} else {
continue;
}
PlanNode cSource = other;
if (cSource.getType() != NodeConstants.Types.ACCESS) {
continue;
}
List<Criteria> joinCriteria = (List<Criteria>) join.getProperty(Info.JOIN_CRITERIA);
if (!isCriteriaValid(joinCriteria, metadata, join)) {
continue;
}
List<Criteria> childJoinCriteria = (List<Criteria>) childJoin.getProperty(Info.JOIN_CRITERIA);
if (!isCriteriaValid(childJoinCriteria, metadata, childJoin) || childJoin.hasBooleanProperty(Info.PRESERVE)) {
continue;
}
// there are 4 forms we can take
// (a b) c -> a (b c) or (a c) b
// c (b a) -> (c b) a or (c a) b
Set<GroupSymbol> groups = GroupsUsedByElementsVisitor.getGroups(joinCriteria);
if (Collections.disjoint(groups, FrameUtil.findJoinSourceNode(childJoin == left ? childJoin.getFirstChild() : childJoin.getLastChild()).getGroups())) {
// case where absolute order remains the same
PlanNode bSource = childJoin == left ? childJoin.getLastChild() : childJoin.getFirstChild();
if (bSource.getType() != NodeConstants.Types.ACCESS) {
continue;
}
Object modelId = RuleRaiseAccess.canRaiseOverJoin(childJoin == left ? Arrays.asList(bSource, cSource) : Arrays.asList(cSource, bSource), metadata, capabilitiesFinder, joinCriteria, JoinType.JOIN_LEFT_OUTER, analysisRecord, context, false, false);
if (modelId == null) {
continue;
}
// rearrange
PlanNode newParent = RulePlanJoins.createJoinNode();
newParent.setProperty(Info.JOIN_TYPE, JoinType.JOIN_LEFT_OUTER);
PlanNode newChild = RulePlanJoins.createJoinNode();
newChild.setProperty(Info.JOIN_TYPE, JoinType.JOIN_LEFT_OUTER);
joins.remove(childJoin);
if (childJoin == left) {
// a (b c)
newChild.addFirstChild(childJoin.getLastChild());
newChild.addLastChild(other);
newChild.setProperty(Info.JOIN_CRITERIA, joinCriteria);
newParent.addFirstChild(childJoin.getFirstChild());
newParent.addLastChild(newChild);
newParent.setProperty(Info.JOIN_CRITERIA, childJoinCriteria);
} else {
// (c b) a
newChild.addFirstChild(other);
newChild.addLastChild(childJoin.getFirstChild());
newChild.setProperty(Info.JOIN_CRITERIA, joinCriteria);
newParent.addFirstChild(newChild);
newParent.addLastChild(childJoin.getLastChild());
newParent.setProperty(Info.JOIN_CRITERIA, childJoinCriteria);
}
updateGroups(newChild);
updateGroups(newParent);
join.getParent().replaceChild(join, newParent);
if (RuleRaiseAccess.checkConformedSubqueries(newChild.getFirstChild(), newChild, true)) {
RuleRaiseAccess.raiseAccessOverJoin(newChild, newChild.getFirstChild(), modelId, capabilitiesFinder, metadata, true);
changedAny = true;
}
} else if (Collections.disjoint(groups, FrameUtil.findJoinSourceNode(childJoin == right ? childJoin.getFirstChild() : childJoin.getLastChild()).getGroups())) {
PlanNode aSource = childJoin == left ? childJoin.getFirstChild() : childJoin.getLastChild();
if (aSource.getType() != NodeConstants.Types.ACCESS) {
continue;
}
if (!join.getExportedCorrelatedReferences().isEmpty()) {
// TODO: we are not really checking that specifically
continue;
}
Object modelId = RuleRaiseAccess.canRaiseOverJoin(childJoin == left ? Arrays.asList(aSource, cSource) : Arrays.asList(cSource, aSource), metadata, capabilitiesFinder, joinCriteria, JoinType.JOIN_LEFT_OUTER, analysisRecord, context, false, false);
if (modelId == null) {
continue;
}
// rearrange
PlanNode newParent = RulePlanJoins.createJoinNode();
newParent.setProperty(Info.JOIN_TYPE, JoinType.JOIN_LEFT_OUTER);
PlanNode newChild = RulePlanJoins.createJoinNode();
newChild.setProperty(Info.JOIN_TYPE, JoinType.JOIN_LEFT_OUTER);
joins.remove(childJoin);
if (childJoin == left) {
newChild.addFirstChild(childJoin.getFirstChild());
newChild.addLastChild(other);
newParent.addLastChild(childJoin.getLastChild());
} else {
newChild.addFirstChild(other);
newChild.addLastChild(childJoin.getLastChild());
newParent.addLastChild(childJoin.getFirstChild());
}
newChild.addGroups(newChild.getFirstChild().getGroups());
newChild.setProperty(Info.JOIN_CRITERIA, joinCriteria);
newParent.addFirstChild(newChild);
newParent.setProperty(Info.JOIN_CRITERIA, childJoinCriteria);
updateGroups(newChild);
updateGroups(newParent);
join.getParent().replaceChild(join, newParent);
if (RuleRaiseAccess.checkConformedSubqueries(newChild.getFirstChild(), newChild, true)) {
RuleRaiseAccess.raiseAccessOverJoin(newChild, newChild.getFirstChild(), modelId, capabilitiesFinder, metadata, true);
changedAny = true;
}
}
}
return changedAny;
}
use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.
the class RulePlanProcedures method execute.
/**
* @see org.teiid.query.optimizer.relational.OptimizerRule#execute(org.teiid.query.optimizer.relational.plantree.PlanNode, org.teiid.query.metadata.QueryMetadataInterface, org.teiid.query.optimizer.capabilities.CapabilitiesFinder, org.teiid.query.optimizer.relational.RuleStack, org.teiid.query.analysis.AnalysisRecord, org.teiid.query.util.CommandContext)
*/
public PlanNode execute(PlanNode plan, final QueryMetadataInterface metadata, CapabilitiesFinder capabilitiesFinder, RuleStack rules, AnalysisRecord analysisRecord, CommandContext context) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
for (PlanNode node : NodeEditor.findAllNodes(plan, NodeConstants.Types.SOURCE, NodeConstants.Types.ACCESS)) {
if (!FrameUtil.isProcedure(node.getFirstChild())) {
continue;
}
StoredProcedure proc = (StoredProcedure) node.getProperty(NodeConstants.Info.NESTED_COMMAND);
if (!proc.isProcedureRelational()) {
continue;
}
HashSet<ElementSymbol> inputSymbols = new HashSet<ElementSymbol>();
List<Reference> inputReferences = new LinkedList<Reference>();
PlanNode critNode = node.getParent();
List<Criteria> conjuncts = new LinkedList<Criteria>();
HashSet<ElementSymbol> coveredParams = new HashSet<ElementSymbol>();
for (Iterator<SPParameter> params = proc.getInputParameters().iterator(); params.hasNext(); ) {
SPParameter param = params.next();
ElementSymbol symbol = param.getParameterSymbol();
Expression input = param.getExpression();
inputReferences.add((Reference) input);
inputSymbols.add(symbol);
}
findInputNodes(inputSymbols, critNode, conjuncts, coveredParams);
List<Expression> defaults = new LinkedList<Expression>();
for (Reference ref : inputReferences) {
ElementSymbol symbol = ref.getExpression();
Expression defaultValue = null;
/*try {
defaultValue = ResolverUtil.getDefault(symbol, metadata);
} catch (QueryResolverException qre) {
//Just ignore
}*/
defaults.add(defaultValue);
if (defaultValue == null && !coveredParams.contains(symbol)) {
throw new QueryPlannerException(QueryPlugin.Event.TEIID30270, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30270, symbol));
}
}
/*if (conjuncts.isEmpty()) {
for (int j = 0; j < inputReferences.size(); j++) {
Reference ref = (Reference)inputReferences.get(j);
ref.setValue(defaults.get(j));
}
continue;
}*/
PlanNode accessNode = NodeEditor.findNodePreOrder(node, NodeConstants.Types.ACCESS);
Criteria crit = Criteria.combineCriteria(conjuncts);
if (crit != null) {
accessNode.setProperty(NodeConstants.Info.PROCEDURE_CRITERIA, crit);
accessNode.setProperty(NodeConstants.Info.PROCEDURE_INPUTS, inputReferences);
accessNode.setProperty(NodeConstants.Info.PROCEDURE_DEFAULTS, defaults);
accessNode.setProperty(NodeConstants.Info.IS_DEPENDENT_SET, Boolean.TRUE);
}
}
return plan;
}
use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.
the class RulePlanSorts method optimizeSorts.
private PlanNode optimizeSorts(boolean parentBlocking, PlanNode node, PlanNode root, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord record, CommandContext context) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
node = NodeEditor.findNodePreOrder(node, NodeConstants.Types.SORT | NodeConstants.Types.DUP_REMOVE | NodeConstants.Types.GROUP | NodeConstants.Types.JOIN | NodeConstants.Types.SET_OP, NodeConstants.Types.ACCESS);
if (node == null) {
return root;
}
switch(node.getType()) {
case NodeConstants.Types.SORT:
parentBlocking = true;
if (node.hasBooleanProperty(NodeConstants.Info.IS_DUP_REMOVAL)) {
break;
}
if (mergeSortWithDupRemoval(node)) {
node.setProperty(NodeConstants.Info.IS_DUP_REMOVAL, true);
} else {
root = checkForProjectOptimization(node, root, metadata, capFinder, record, context);
if (NodeEditor.findParent(node, NodeConstants.Types.ACCESS) != null) {
return root;
}
}
OrderBy orderBy = (OrderBy) node.getProperty(NodeConstants.Info.SORT_ORDER);
List<Expression> orderColumns = orderBy.getSortKeys();
List<Expression> sortExpressions = new ArrayList<Expression>(orderColumns.size());
PlanNode possibleSort = NodeEditor.findNodePreOrder(node, NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE | NodeConstants.Types.ACCESS);
if (possibleSort != null && !possibleSort.hasBooleanProperty(Info.ROLLUP)) {
boolean otherExpression = false;
SymbolMap groupMap = (SymbolMap) possibleSort.getProperty(Info.SYMBOL_MAP);
for (Expression singleElementSymbol : orderColumns) {
Expression ex = SymbolMap.getExpression(singleElementSymbol);
if (ex instanceof ElementSymbol) {
sortExpressions.add(groupMap.getMappedExpression((ElementSymbol) ex));
} else {
otherExpression = true;
break;
}
}
List<Expression> exprs = (List<Expression>) possibleSort.getProperty(Info.GROUP_COLS);
if (!otherExpression && exprs != null && exprs.containsAll(sortExpressions)) {
exprs.removeAll(sortExpressions);
exprs.addAll(0, sortExpressions);
if (node.getParent() == null) {
root = node.getFirstChild();
root.removeFromParent();
Object cols = node.getProperty(NodeConstants.Info.OUTPUT_COLS);
root.setProperty(NodeConstants.Info.OUTPUT_COLS, cols);
if (root.getType() == NodeConstants.Types.PROJECT) {
root.setProperty(NodeConstants.Info.PROJECT_COLS, cols);
}
node = root;
} else {
PlanNode nextNode = node.getFirstChild();
NodeEditor.removeChildNode(node.getParent(), node);
node = nextNode;
}
possibleSort.setProperty(Info.SORT_ORDER, orderBy);
}
}
break;
case NodeConstants.Types.DUP_REMOVE:
if (parentBlocking) {
node.setType(NodeConstants.Types.SORT);
node.setProperty(NodeConstants.Info.IS_DUP_REMOVAL, true);
}
break;
case NodeConstants.Types.GROUP:
if (!node.hasCollectionProperty(NodeConstants.Info.GROUP_COLS)) {
break;
}
SymbolMap map = (SymbolMap) node.getProperty(Info.SYMBOL_MAP);
boolean cardinalityDependent = false;
boolean canOptimize = true;
for (Expression ex : map.asMap().values()) {
if (ex instanceof AggregateSymbol) {
AggregateSymbol agg = (AggregateSymbol) ex;
if (agg.isCardinalityDependent()) {
cardinalityDependent = true;
break;
}
} else if (!(ex instanceof ElementSymbol)) {
// there is an expression in the grouping columns
canOptimize = false;
break;
}
}
if (canOptimize && mergeSortWithDupRemovalAcrossSource(node)) {
node.setProperty(NodeConstants.Info.IS_DUP_REMOVAL, true);
if (cardinalityDependent) {
PlanNode source = NodeEditor.findNodePreOrder(node, NodeConstants.Types.SOURCE);
List<Expression> sourceOutput = (List<Expression>) source.getProperty(Info.OUTPUT_COLS);
PlanNode child = node.getFirstChild();
while (child != source) {
child.setProperty(Info.OUTPUT_COLS, sourceOutput);
child = child.getFirstChild();
}
}
}
// TODO: check the join interesting order
parentBlocking = true;
break;
case NodeConstants.Types.JOIN:
if (node.getProperty(NodeConstants.Info.JOIN_STRATEGY) == JoinStrategyType.NESTED_LOOP || node.getProperty(NodeConstants.Info.JOIN_STRATEGY) == JoinStrategyType.NESTED_TABLE) {
break;
}
/*
* Look under the left and the right sources for a dup removal operation
* join
* [project]
* source
* dup remove | union not all
*/
parentBlocking = true;
PlanNode toTest = node.getFirstChild();
if (mergeSortWithDupRemovalAcrossSource(toTest)) {
node.setProperty(NodeConstants.Info.SORT_LEFT, SortOption.SORT_DISTINCT);
if (node.getProperty(NodeConstants.Info.SORT_RIGHT) != SortOption.SORT) {
node.setProperty(NodeConstants.Info.JOIN_STRATEGY, JoinStrategyType.MERGE);
}
}
toTest = node.getLastChild();
if (mergeSortWithDupRemovalAcrossSource(toTest)) {
node.setProperty(NodeConstants.Info.SORT_RIGHT, SortOption.SORT_DISTINCT);
if (node.getProperty(NodeConstants.Info.SORT_LEFT) != SortOption.SORT) {
node.setProperty(NodeConstants.Info.JOIN_STRATEGY, JoinStrategyType.MERGE);
}
}
break;
case NodeConstants.Types.SET_OP:
// assumes the use of the merge algorithm
if (node.getProperty(NodeConstants.Info.SET_OPERATION) != SetQuery.Operation.UNION) {
parentBlocking = true;
} else if (!node.hasBooleanProperty(NodeConstants.Info.USE_ALL) && !parentBlocking) {
// do the incremental dup removal for lower latency
node.setProperty(NodeConstants.Info.IS_DUP_REMOVAL, true);
}
break;
}
for (PlanNode child : node.getChildren()) {
root = optimizeSorts(parentBlocking, child, root, metadata, capFinder, record, context);
}
return root;
}
use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.
the class RulePlanUnions method buildUnionTree.
static PlanNode buildUnionTree(PlanNode rootUnionNode, List<PlanNode> sources) {
PlanNode root = null;
for (PlanNode source : sources) {
if (root == null) {
root = source;
} else {
PlanNode union = NodeFactory.getNewNode(NodeConstants.Types.SET_OP);
union.setProperty(NodeConstants.Info.SET_OPERATION, rootUnionNode.getProperty(NodeConstants.Info.SET_OPERATION));
union.setProperty(NodeConstants.Info.USE_ALL, rootUnionNode.getProperty(NodeConstants.Info.USE_ALL));
union.addLastChild(root);
union.addLastChild(source);
root = union;
}
}
return root;
}
use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.
the class RulePushAggregates method removeUnnecessaryViews.
/**
* TODO: remove me - the logic in {@link #addUnionGroupBy} should be redone
* to not use a view, but the logic there is more straight-forward there
* and then we correct here.
* @param sourceNode
* @param metadata
* @param capFinder
* @param context
* @throws QueryPlannerException
* @throws QueryMetadataException
* @throws TeiidComponentException
*/
private void removeUnnecessaryViews(PlanNode sourceNode, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
for (PlanNode source : NodeEditor.findAllNodes(sourceNode.getFirstChild(), NodeConstants.Types.SOURCE, NodeConstants.Types.ACCESS)) {
PlanNode planNode = source.getFirstChild();
if (planNode == null || planNode.getType() != NodeConstants.Types.ACCESS) {
continue;
}
// temporarily remove the access node
NodeEditor.removeChildNode(source, planNode);
PlanNode parent = RuleMergeVirtual.doMerge(source, source.getParent(), false, metadata, capFinder);
// add it back
if (parent.getFirstChild() == source) {
source.getFirstChild().addAsParent(planNode);
} else {
parent.getFirstChild().addAsParent(planNode);
}
while (RuleRaiseAccess.raiseAccessNode(planNode, planNode, metadata, capFinder, true, null, context) != null) {
// continue to raise
}
}
}
Aggregations