Search in sources :

Example 16 with JoinType

use of org.teiid.query.sql.lang.JoinType in project teiid by teiid.

the class RuleChooseDependent method isValidJoin.

/**
 * Check whether a join is valid.  Invalid joins are CROSS JOIN, FULL OUTER JOIN,
 * any join without criteria, any join with no equality criteria, and any outer
 * join that has the outer side not the same as the dependent.
 * @param joinNode The join node to check
 * @param sourceNode The access node being considered
 * @param analysisRecord
 * @return True if valid for making dependent
 * @throws TeiidComponentException
 * @throws QueryMetadataException
 */
boolean isValidJoin(PlanNode joinNode, PlanNode sourceNode, AnalysisRecord analysisRecord) throws QueryMetadataException, TeiidComponentException {
    JoinType jtype = (JoinType) joinNode.getProperty(NodeConstants.Info.JOIN_TYPE);
    // Check that join is not a CROSS join or FULL OUTER join
    if (jtype.equals(JoinType.JOIN_CROSS)) {
        // $NON-NLS-1$ //$NON-NLS-2$
        sourceNode.recordDebugAnnotation("parent join is CROSS", null, "Rejecting dependent join", analysisRecord, null);
        return false;
    }
    if (!joinNode.getExportedCorrelatedReferences().isEmpty()) {
        // $NON-NLS-1$ //$NON-NLS-2$
        sourceNode.recordDebugAnnotation("parent join has a correlated nested table", null, "Rejecting dependent join", analysisRecord, null);
        return false;
    }
    // Check that join criteria exist
    List jcrit = (List) joinNode.getProperty(NodeConstants.Info.JOIN_CRITERIA);
    if (jcrit == null || jcrit.size() == 0) {
        // $NON-NLS-1$ //$NON-NLS-2$
        sourceNode.recordDebugAnnotation("parent join has has no join criteria", null, "Rejecting dependent join", analysisRecord, null);
        return false;
    }
    if (joinNode.getProperty(NodeConstants.Info.LEFT_EXPRESSIONS) == null) {
        // $NON-NLS-1$ //$NON-NLS-2$
        sourceNode.recordDebugAnnotation("parent join has no equa-join predicates", null, "Rejecting dependent join", analysisRecord, null);
        return false;
    }
    return true;
}
Also used : JoinType(org.teiid.query.sql.lang.JoinType) ArrayList(java.util.ArrayList) List(java.util.List)

Example 17 with JoinType

use of org.teiid.query.sql.lang.JoinType in project teiid by teiid.

the class RuleChooseDependent method findCandidate.

/**
 * Walk the tree pre-order, finding all access nodes that are candidates and
 * adding them to the matches list.
 * @param metadata Metadata implementation
 * @param node Root node to search
 * @param matches Collection to accumulate matches in
 * @throws TeiidComponentException
 * @throws QueryMetadataException
 */
List<CandidateJoin> findCandidate(PlanNode root, QueryMetadataInterface metadata, AnalysisRecord analysisRecord) throws QueryMetadataException, TeiidComponentException {
    List<CandidateJoin> candidates = new ArrayList<CandidateJoin>();
    for (PlanNode joinNode : NodeEditor.findAllNodes(root, NodeConstants.Types.JOIN, NodeConstants.Types.ACCESS)) {
        CandidateJoin candidate = null;
        for (Iterator<PlanNode> j = joinNode.getChildren().iterator(); j.hasNext(); ) {
            PlanNode child = j.next();
            child = FrameUtil.findJoinSourceNode(child);
            if (child.hasBooleanProperty(NodeConstants.Info.MAKE_NOT_DEP) || !isValidJoin(joinNode, child, analysisRecord)) {
                continue;
            }
            if (candidate == null) {
                candidate = new CandidateJoin();
                candidate.joinNode = joinNode;
            }
            if (j.hasNext()) {
                JoinType jtype = (JoinType) joinNode.getProperty(NodeConstants.Info.JOIN_TYPE);
                if (!jtype.isOuter()) {
                    candidate.leftCandidate = true;
                    candidates.add(candidate);
                }
            } else {
                candidate.rightCandidate = true;
                if (!candidate.leftCandidate) {
                    candidates.add(candidate);
                }
            }
        }
    }
    return candidates;
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) ArrayList(java.util.ArrayList) JoinType(org.teiid.query.sql.lang.JoinType)

Example 18 with JoinType

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

Example 19 with JoinType

use of org.teiid.query.sql.lang.JoinType in project teiid by teiid.

the class RulePushLimit method canPushLimit.

private boolean canPushLimit(PlanNode[] rootNode, PlanNode limitNode, List<PlanNode> limitNodes, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord record, CommandContext context) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
    PlanNode child = limitNode.getFirstChild();
    if (child == null || child.getChildCount() == 0) {
        return false;
    }
    Expression parentLimit = (Expression) limitNode.getProperty(NodeConstants.Info.MAX_TUPLE_LIMIT);
    Expression parentOffset = (Expression) limitNode.getProperty(NodeConstants.Info.OFFSET_TUPLE_COUNT);
    switch(child.getType()) {
        case NodeConstants.Types.TUPLE_LIMIT:
            {
                // combine the limits
                Expression childLimit = (Expression) child.getProperty(NodeConstants.Info.MAX_TUPLE_LIMIT);
                Expression childOffset = (Expression) child.getProperty(NodeConstants.Info.OFFSET_TUPLE_COUNT);
                combineLimits(limitNode, metadata, parentLimit, parentOffset, childLimit, childOffset);
                if (child.hasBooleanProperty(Info.IS_NON_STRICT)) {
                    limitNode.setProperty(Info.IS_NON_STRICT, true);
                }
                NodeEditor.removeChildNode(limitNode, child);
                limitNodes.remove(child);
                return canPushLimit(rootNode, limitNode, limitNodes, metadata, capFinder, record, context);
            }
        case NodeConstants.Types.SET_OP:
            {
                if (!canPushToBranches(limitNode, child)) {
                    return false;
                }
                // distribute the limit
                List<PlanNode> grandChildren = new LinkedList<PlanNode>(child.getChildren());
                for (PlanNode grandChild : grandChildren) {
                    addBranchLimit(limitNode, limitNodes, metadata, parentLimit, parentOffset, grandChild);
                }
                return false;
            }
        case NodeConstants.Types.JOIN:
            if (parentLimit == null) {
                return false;
            }
            JoinType joinType = (JoinType) child.getProperty(Info.JOIN_TYPE);
            boolean pushLeft = false;
            boolean pushRight = false;
            if (joinType == JoinType.JOIN_CROSS) {
                pushLeft = true;
                pushRight = true;
            } else if (joinType == JoinType.JOIN_LEFT_OUTER || joinType == JoinType.JOIN_FULL_OUTER) {
                // we're allowed to do this based upon two conditions
                // 1 - we're not going to further change the join type/structure
                // 2 - outer results will be produced using the left product first
                pushLeft = true;
            }
            if (pushLeft && !FrameUtil.findJoinSourceNode(child.getLastChild()).hasProperty(NodeConstants.Info.CORRELATED_REFERENCES)) {
                PlanNode newLimit = newLimit(limitNode);
                newLimit.setProperty(NodeConstants.Info.MAX_TUPLE_LIMIT, op(SourceSystemFunctions.ADD_OP, parentLimit, parentOffset, metadata.getFunctionLibrary()));
                child.getFirstChild().addAsParent(newLimit);
                newLimit.setProperty(NodeConstants.Info.OUTPUT_COLS, newLimit.getFirstChild().getProperty(NodeConstants.Info.OUTPUT_COLS));
                limitNodes.add(newLimit);
            }
            if (pushRight) {
                PlanNode newLimit = newLimit(limitNode);
                newLimit.setProperty(NodeConstants.Info.MAX_TUPLE_LIMIT, op(SourceSystemFunctions.ADD_OP, parentLimit, parentOffset, metadata.getFunctionLibrary()));
                child.getLastChild().addAsParent(newLimit);
                newLimit.setProperty(NodeConstants.Info.OUTPUT_COLS, newLimit.getFirstChild().getProperty(NodeConstants.Info.OUTPUT_COLS));
                limitNodes.add(newLimit);
            }
            return false;
        case NodeConstants.Types.ACCESS:
            {
                raiseAccessOverLimit(rootNode[0], child, metadata, capFinder, limitNode, record);
                return false;
            }
        case NodeConstants.Types.PROJECT:
            {
                return child.getProperty(NodeConstants.Info.INTO_GROUP) == null && !child.hasProperty(Info.HAS_WINDOW_FUNCTIONS);
            }
        case NodeConstants.Types.SOURCE:
            {
                return canPushThroughView(child);
            }
        case NodeConstants.Types.SELECT:
        case NodeConstants.Types.DUP_REMOVE:
            return limitNode.hasBooleanProperty(Info.IS_NON_STRICT);
        case NodeConstants.Types.SORT:
            switch(child.getFirstChild().getType()) {
                case NodeConstants.Types.SOURCE:
                    {
                        if (canPushThroughView(child.getFirstChild())) {
                            PlanNode sourceNode = child.getFirstChild();
                            NodeEditor.removeChildNode(limitNode, child);
                            NodeEditor.removeChildNode(limitNode.getParent(), limitNode);
                            limitNode.setProperty(NodeConstants.Info.OUTPUT_COLS, sourceNode.getFirstChild().getProperty(NodeConstants.Info.OUTPUT_COLS));
                            child.setProperty(NodeConstants.Info.OUTPUT_COLS, sourceNode.getFirstChild().getProperty(NodeConstants.Info.OUTPUT_COLS));
                            // project the order through the source - which needs to preserve the aliasing
                            HashMap<ElementSymbol, Expression> symbolMap = new HashMap<ElementSymbol, Expression>();
                            List<ElementSymbol> virtual = ((SymbolMap) sourceNode.getProperty(NodeConstants.Info.SYMBOL_MAP)).getKeys();
                            List<Expression> projected = (List<Expression>) NodeEditor.findNodePreOrder(sourceNode, NodeConstants.Types.PROJECT).getProperty(Info.PROJECT_COLS);
                            for (int i = 0; i < virtual.size(); i++) {
                                symbolMap.put(virtual.get(i), projected.get(i));
                            }
                            // map the expression directly to avoid issues with naming logic in the general node conversion
                            OrderBy orderBy = (OrderBy) child.getProperty(Info.SORT_ORDER);
                            for (OrderByItem item : orderBy.getOrderByItems()) {
                                Expression ex = symbolMap.get(item.getSymbol());
                                if (ex != null) {
                                    item.setSymbol(ex);
                                    item.setExpressionPosition(projected.indexOf(ex));
                                }
                            }
                            FrameUtil.convertNode(child, sourceNode.getGroups().iterator().next(), null, symbolMap, metadata, false);
                            sourceNode.getFirstChild().addAsParent(child);
                            child.addAsParent(limitNode);
                            // push again
                            limitNodes.add(limitNode);
                            return false;
                        }
                    }
                case NodeConstants.Types.SET_OP:
                    {
                        PlanNode setOp = child.getFirstChild();
                        if (!canPushToBranches(limitNode, setOp)) {
                            return false;
                        }
                        OrderBy parentOrderBy = (OrderBy) child.getProperty(NodeConstants.Info.SORT_ORDER);
                        distributeLimit(limitNode, setOp, parentOrderBy, metadata, limitNodes, parentLimit, parentOffset, capFinder, context);
                        break;
                    }
                case NodeConstants.Types.JOIN:
                    {
                        if (parentLimit == null) {
                            return false;
                        }
                        PlanNode join = child.getFirstChild();
                        JoinType jt = (JoinType) join.getProperty(NodeConstants.Info.JOIN_TYPE);
                        if (!jt.isOuter()) {
                            return false;
                        }
                        if ((jt == JoinType.JOIN_FULL_OUTER || jt == JoinType.JOIN_LEFT_OUTER) && join.getFirstChild().getGroups().containsAll(child.getGroups()) && !FrameUtil.findJoinSourceNode(join.getLastChild()).hasProperty(NodeConstants.Info.CORRELATED_REFERENCES)) {
                            pushOrderByAndLimit(limitNode, limitNodes, metadata, capFinder, context, child, parentLimit, parentOffset, join.getFirstChild());
                        } else if (jt == JoinType.JOIN_FULL_OUTER && join.getLastChild().getGroups().containsAll(child.getGroups())) {
                            pushOrderByAndLimit(limitNode, limitNodes, metadata, capFinder, context, child, parentLimit, parentOffset, join.getLastChild());
                        }
                        break;
                    }
                case NodeConstants.Types.PROJECT:
                    {
                        rootNode[0] = RulePlanSorts.checkForProjectOptimization(child, rootNode[0], metadata, capFinder, record, context);
                        if (child.getFirstChild().getType() != NodeConstants.Types.PROJECT && NodeEditor.findParent(child, NodeConstants.Types.ACCESS) == null) {
                            return canPushLimit(rootNode, limitNode, limitNodes, metadata, capFinder, record, context);
                        }
                        break;
                    }
                case NodeConstants.Types.ACCESS:
                    {
                        if (RuleRaiseAccess.canRaiseOverSort(child.getFirstChild(), metadata, capFinder, child, null, false, context)) {
                            NodeEditor.removeChildNode(limitNode, child);
                            limitNode.getFirstChild().getFirstChild().addAsParent(child);
                            // try to keep pushing
                            limitNodes.add(limitNode);
                            return false;
                        }
                    }
            }
            return false;
        default:
            {
                return false;
            }
    }
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) OrderBy(org.teiid.query.sql.lang.OrderBy) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) OrderByItem(org.teiid.query.sql.lang.OrderByItem) SearchedCaseExpression(org.teiid.query.sql.symbol.SearchedCaseExpression) Expression(org.teiid.query.sql.symbol.Expression) HashMap(java.util.HashMap) JoinType(org.teiid.query.sql.lang.JoinType) LinkedList(java.util.LinkedList) List(java.util.List)

Example 20 with JoinType

use of org.teiid.query.sql.lang.JoinType in project teiid by teiid.

the class RulePushSelectCriteria method examinePath.

/**
 * Examine the path from crit node to source node to determine how far down a node
 * can be pushed.
 * @return destinationChild
 */
PlanNode examinePath(PlanNode critNode, PlanNode sourceNode, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryPlannerException, TeiidComponentException {
    // Walk from source node up to critNode to build list of intervening nodes
    Stack<PlanNode> path = new Stack<PlanNode>();
    PlanNode currentNode = sourceNode.getParent();
    while (currentNode != critNode) {
        path.push(currentNode);
        currentNode = currentNode.getParent();
    }
    // Examine path in reverse order (by popping stack)
    while (!path.empty()) {
        currentNode = path.pop();
        // Look for situations where we don't allow SELECT to be pushed
        switch(currentNode.getType()) {
            case NodeConstants.Types.ACCESS:
                try {
                    if (!RuleRaiseAccess.canRaiseOverSelect(currentNode, metadata, capFinder, critNode, null)) {
                        return currentNode;
                    }
                    if (!RuleRaiseAccess.checkConformedSubqueries(currentNode, critNode, this.createdNodes == null)) {
                        return currentNode;
                    }
                    if (this.createdNodes == null) {
                        satisfyConditions(critNode, currentNode, metadata);
                    }
                    if (isDependentFinalDestination(critNode, currentNode)) {
                        // 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
                        markDependent(critNode, currentNode, metadata, capFinder);
                        return currentNode.getFirstChild();
                    }
                } catch (QueryMetadataException e) {
                    throw new QueryPlannerException(QueryPlugin.Event.TEIID30267, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30267, currentNode.getGroups()));
                }
                break;
            case NodeConstants.Types.JOIN:
                // pushing below a join is not necessary under an access node
                if (this.createdNodes == null && NodeEditor.findParent(currentNode, NodeConstants.Types.ACCESS) != null) {
                    return currentNode;
                }
                // Check whether this criteria is on the inner side of an outer join.
                // If so, can't push past the join
                JoinType jt = JoinUtil.getJoinTypePreventingCriteriaOptimization(currentNode, critNode);
                if (jt != null) {
                    // if we successfully optimized then this should no longer inhibit the criteria from being pushed
                    // since the criteria must then be on the outer side of an outer join or on either side of an inner join
                    JoinType optimized = JoinUtil.optimizeJoinType(critNode, currentNode, metadata, this.createdNodes == null);
                    if (optimized == null || optimized.isOuter()) {
                        return currentNode;
                    }
                }
                if (this.createdNodes == null) {
                    satisfyConditions(critNode, currentNode, metadata);
                }
                break;
            default:
                if (FrameUtil.isOrderedOrStrictLimit(currentNode)) {
                    return currentNode;
                }
        }
    }
    return sourceNode;
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) JoinType(org.teiid.query.sql.lang.JoinType) QueryMetadataException(org.teiid.api.exception.query.QueryMetadataException) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException) RuleStack(org.teiid.query.optimizer.relational.RuleStack)

Aggregations

JoinType (org.teiid.query.sql.lang.JoinType)21 PlanNode (org.teiid.query.optimizer.relational.plantree.PlanNode)17 List (java.util.List)11 Criteria (org.teiid.query.sql.lang.Criteria)10 GroupSymbol (org.teiid.query.sql.symbol.GroupSymbol)10 ArrayList (java.util.ArrayList)9 Expression (org.teiid.query.sql.symbol.Expression)8 CompareCriteria (org.teiid.query.sql.lang.CompareCriteria)6 LinkedList (java.util.LinkedList)5 SymbolMap (org.teiid.query.sql.util.SymbolMap)5 ElementSymbol (org.teiid.query.sql.symbol.ElementSymbol)4 LinkedHashSet (java.util.LinkedHashSet)3 IsNullCriteria (org.teiid.query.sql.lang.IsNullCriteria)3 Collection (java.util.Collection)2 HashMap (java.util.HashMap)2 HashSet (java.util.HashSet)2 Iterator (java.util.Iterator)2 LinkedHashMap (java.util.LinkedHashMap)2 Set (java.util.Set)2 OrderBy (org.teiid.query.sql.lang.OrderBy)2