Search in sources :

Example 36 with PlanNode

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;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) ArrayList(java.util.ArrayList) List(java.util.List) Criteria(org.teiid.query.sql.lang.Criteria)

Example 37 with PlanNode

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;
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) Reference(org.teiid.query.sql.symbol.Reference) SPParameter(org.teiid.query.sql.lang.SPParameter) DependentSetCriteria(org.teiid.query.sql.lang.DependentSetCriteria) IsNullCriteria(org.teiid.query.sql.lang.IsNullCriteria) Criteria(org.teiid.query.sql.lang.Criteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria) SetCriteria(org.teiid.query.sql.lang.SetCriteria) LinkedList(java.util.LinkedList) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) StoredProcedure(org.teiid.query.sql.lang.StoredProcedure) Expression(org.teiid.query.sql.symbol.Expression) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException) HashSet(java.util.HashSet)

Example 38 with PlanNode

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;
}
Also used : OrderBy(org.teiid.query.sql.lang.OrderBy) ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) AggregateSymbol(org.teiid.query.sql.symbol.AggregateSymbol) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) Expression(org.teiid.query.sql.symbol.Expression) ArrayList(java.util.ArrayList) SymbolMap(org.teiid.query.sql.util.SymbolMap) ArrayList(java.util.ArrayList) List(java.util.List)

Example 39 with PlanNode

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;
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode)

Example 40 with PlanNode

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
        }
    }
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode)

Aggregations

PlanNode (org.teiid.query.optimizer.relational.plantree.PlanNode)204 Expression (org.teiid.query.sql.symbol.Expression)50 GroupSymbol (org.teiid.query.sql.symbol.GroupSymbol)50 ArrayList (java.util.ArrayList)47 List (java.util.List)43 SymbolMap (org.teiid.query.sql.util.SymbolMap)42 ElementSymbol (org.teiid.query.sql.symbol.ElementSymbol)36 Criteria (org.teiid.query.sql.lang.Criteria)35 LinkedList (java.util.LinkedList)24 CompareCriteria (org.teiid.query.sql.lang.CompareCriteria)24 Test (org.junit.Test)22 HashSet (java.util.HashSet)17 JoinType (org.teiid.query.sql.lang.JoinType)17 LinkedHashSet (java.util.LinkedHashSet)16 CompoundCriteria (org.teiid.query.sql.lang.CompoundCriteria)12 DependentSetCriteria (org.teiid.query.sql.lang.DependentSetCriteria)12 QueryPlannerException (org.teiid.api.exception.query.QueryPlannerException)11 LanguageObject (org.teiid.query.sql.LanguageObject)11 OrderBy (org.teiid.query.sql.lang.OrderBy)10 IsNullCriteria (org.teiid.query.sql.lang.IsNullCriteria)9