Search in sources :

Example 6 with JoinType

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

the class JoinUtil method getInnerSideJoinNodes.

/**
 * Can be called after join planning on a join node to get the inner sides of the join
 * @param joinNode
 * @return
 */
static PlanNode[] getInnerSideJoinNodes(PlanNode joinNode) {
    Assertion.assertTrue(joinNode.getType() == NodeConstants.Types.JOIN);
    JoinType jt = (JoinType) joinNode.getProperty(NodeConstants.Info.JOIN_TYPE);
    if (jt == JoinType.JOIN_INNER || jt == JoinType.JOIN_CROSS) {
        return new PlanNode[] { joinNode.getFirstChild(), joinNode.getLastChild() };
    }
    if (jt == JoinType.JOIN_RIGHT_OUTER) {
        return new PlanNode[] { joinNode.getFirstChild() };
    }
    if (jt == JoinType.JOIN_LEFT_OUTER) {
        return new PlanNode[] { joinNode.getLastChild() };
    }
    // must be full outer, so there is no inner side
    return new PlanNode[] {};
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) JoinType(org.teiid.query.sql.lang.JoinType)

Example 7 with JoinType

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

the class RulePushNonJoinCriteria method execute.

/**
 * Execute the rule as described in the class comments.
 * @param plan Incoming query plan, may be modified during method and may be returned from method
 * @param metadata Metadata source
 * @param rules Rules from optimizer rule stack, may be manipulated during method
 * @return Updated query plan if rule fired, else original query plan
 */
public PlanNode execute(PlanNode plan, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, RuleStack rules, AnalysisRecord analysisRecord, CommandContext context) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
    boolean treeChanged = false;
    boolean removeCopiedFlag = false;
    boolean pushRuleRaiseNull = false;
    for (PlanNode node : NodeEditor.findAllNodes(plan, NodeConstants.Types.JOIN)) {
        List criteria = (List) node.getProperty(NodeConstants.Info.JOIN_CRITERIA);
        JoinType joinType = (JoinType) node.getProperty(NodeConstants.Info.JOIN_TYPE);
        // criteria cannot be pushed out of a full outer join clause
        if (joinType == JoinType.JOIN_FULL_OUTER || joinType == JoinType.JOIN_CROSS) {
            continue;
        }
        Iterator crits = criteria.iterator();
        while (crits.hasNext()) {
            Criteria crit = (Criteria) crits.next();
            // special case handling for true/false criteria
            if (crit.equals(QueryRewriter.FALSE_CRITERIA) || crit.equals(QueryRewriter.UNKNOWN_CRITERIA)) {
                if (joinType == JoinType.JOIN_INNER) {
                    FrameUtil.replaceWithNullNode(node);
                } else {
                    // must be a left or right outer join, replace the inner side with null
                    FrameUtil.replaceWithNullNode(JoinUtil.getInnerSideJoinNodes(node)[0]);
                    removeCopiedFlag = true;
                }
                // since a null node has been created, raise it to its highest point
                pushRuleRaiseNull = true;
                treeChanged = true;
                break;
            } else if (crit.equals(QueryRewriter.TRUE_CRITERIA)) {
                crits.remove();
                break;
            }
            if (pushCriteria(node, crit, crits, metadata)) {
                treeChanged = true;
            }
        }
        // degrade the join if there is no criteria left
        if (criteria.isEmpty() && joinType == JoinType.JOIN_INNER) {
            node.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_CROSS);
            treeChanged = true;
        }
        if (removeCopiedFlag) {
            // allow the criteria above the join to be eligible for pushing and copying
            PlanNode parent = node.getParent();
            while (parent != null && parent.getType() == NodeConstants.Types.SELECT) {
                parent.setProperty(NodeConstants.Info.IS_COPIED, Boolean.FALSE);
                parent = parent.getParent();
            }
        }
    }
    if (treeChanged) {
        rules.push(RuleConstants.PUSH_SELECT_CRITERIA);
    }
    if (pushRuleRaiseNull) {
        rules.push(RuleConstants.RAISE_NULL);
    }
    return plan;
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) Iterator(java.util.Iterator) JoinType(org.teiid.query.sql.lang.JoinType) ArrayList(java.util.ArrayList) List(java.util.List) IsNullCriteria(org.teiid.query.sql.lang.IsNullCriteria) Criteria(org.teiid.query.sql.lang.Criteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria)

Example 8 with JoinType

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

the class RuleRemoveOptionalJoins method removeJoin.

/**
 * remove the optional node if possible
 * @throws QueryPlannerException
 * @throws TeiidComponentException
 * @throws QueryMetadataException
 */
private List<PlanNode> removeJoin(Set<GroupSymbol> required, Set<GroupSymbol> requiredForOptional, PlanNode joinNode, PlanNode optionalNode, AnalysisRecord record, QueryMetadataInterface metadata) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
    boolean correctFrame = false;
    boolean isOptional = optionalNode.hasBooleanProperty(NodeConstants.Info.IS_OPTIONAL);
    if (isOptional) {
        required = requiredForOptional;
        correctFrame = true;
    }
    if (!Collections.disjoint(optionalNode.getGroups(), required)) {
        return null;
    }
    if (isOptional) {
        // prevent bridge table removal
        HashSet<GroupSymbol> joinGroups = new HashSet<GroupSymbol>();
        PlanNode parentNode = joinNode;
        while (parentNode.getType() != NodeConstants.Types.PROJECT) {
            PlanNode current = parentNode;
            parentNode = parentNode.getParent();
            if (current.getType() != NodeConstants.Types.SELECT && current.getType() != NodeConstants.Types.JOIN) {
                continue;
            }
            Set<GroupSymbol> currentGroups = current.getGroups();
            if (current.getType() == NodeConstants.Types.JOIN) {
                currentGroups = GroupsUsedByElementsVisitor.getGroups((List<Criteria>) current.getProperty(NodeConstants.Info.JOIN_CRITERIA));
            }
            if (!Collections.disjoint(currentGroups, optionalNode.getGroups()) && !optionalNode.getGroups().containsAll(currentGroups)) {
                // we're performing a join
                boolean wasEmpty = joinGroups.isEmpty();
                boolean modified = joinGroups.addAll(current.getGroups());
                if (!wasEmpty && modified) {
                    return null;
                }
            }
        }
    }
    JoinType jt = (JoinType) joinNode.getProperty(NodeConstants.Info.JOIN_TYPE);
    boolean usesKey = false;
    boolean isRight = optionalNode == joinNode.getLastChild();
    if (!isOptional && (jt == JoinType.JOIN_INNER || (jt == JoinType.JOIN_LEFT_OUTER && isRight))) {
        usesKey = isOptionalUsingKey(joinNode, optionalNode, metadata, isRight);
    }
    if (!isOptional && !usesKey && (jt != JoinType.JOIN_LEFT_OUTER || !isRight || useNonDistinctRows(joinNode.getParent()))) {
        return null;
    }
    // remove the parent node and move the sibling node upward
    PlanNode parentNode = joinNode.getParent();
    joinNode.removeChild(optionalNode);
    joinNode.getFirstChild().setProperty(NodeConstants.Info.OUTPUT_COLS, joinNode.getProperty(NodeConstants.Info.OUTPUT_COLS));
    NodeEditor.removeChildNode(parentNode, joinNode);
    // $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    joinNode.recordDebugAnnotation((isOptional ? "node was marked as optional " : "node will not affect the results"), null, "Removing join node", record, null);
    while (parentNode.getType() != NodeConstants.Types.PROJECT) {
        PlanNode current = parentNode;
        parentNode = parentNode.getParent();
        if (correctFrame) {
            if (current.getType() == NodeConstants.Types.SELECT) {
                if (!Collections.disjoint(current.getGroups(), optionalNode.getGroups())) {
                    current.getFirstChild().setProperty(NodeConstants.Info.OUTPUT_COLS, current.getProperty(NodeConstants.Info.OUTPUT_COLS));
                    NodeEditor.removeChildNode(parentNode, current);
                }
            } else if (current.getType() == NodeConstants.Types.JOIN) {
                if (!Collections.disjoint(current.getGroups(), optionalNode.getGroups())) {
                    List<Criteria> crits = (List<Criteria>) current.getProperty(NodeConstants.Info.JOIN_CRITERIA);
                    if (crits != null && !crits.isEmpty()) {
                        for (Iterator<Criteria> iterator = crits.iterator(); iterator.hasNext(); ) {
                            Criteria criteria = iterator.next();
                            if (!Collections.disjoint(GroupsUsedByElementsVisitor.getGroups(criteria), optionalNode.getGroups())) {
                                iterator.remove();
                            }
                        }
                        if (crits.isEmpty()) {
                            JoinType joinType = (JoinType) current.getProperty(NodeConstants.Info.JOIN_TYPE);
                            if (joinType == JoinType.JOIN_INNER) {
                                current.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_CROSS);
                            }
                        }
                    }
                }
            }
        } else if (current.getType() != NodeConstants.Types.JOIN) {
            break;
        }
        if (current.getType() == NodeConstants.Types.JOIN) {
            current.getGroups().removeAll(optionalNode.getGroups());
        }
    }
    return NodeEditor.findAllNodes(optionalNode, NodeConstants.Types.JOIN);
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) Iterator(java.util.Iterator) JoinType(org.teiid.query.sql.lang.JoinType) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) List(java.util.List) Criteria(org.teiid.query.sql.lang.Criteria) HashSet(java.util.HashSet)

Example 9 with JoinType

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

the class RuleCopyCriteria method tryToCopy.

/**
 * Recursively tries to copy criteria across join nodes.  toCopy will contain only the single group criteria
 * that has not yet been copied.  allCriteria will contain all criteria present at the join that can effect
 * copying.
 *
 * @param node
 * @return true if criteria has been created
 */
private boolean tryToCopy(PlanNode node, Set<Criteria>[] criteriaInfo, QueryMetadataInterface metadata, boolean underAccess) {
    boolean changedTree = false;
    if (node == null) {
        return false;
    }
    // visit join nodes in order
    if (node.getType() == NodeConstants.Types.JOIN) {
        JoinType jt = (JoinType) node.getProperty(NodeConstants.Info.JOIN_TYPE);
        if (jt == JoinType.JOIN_FULL_OUTER) {
            return visitChildern(node, criteriaInfo, changedTree, metadata, underAccess);
        }
        Set<Criteria>[] leftChildCriteria = new Set[2];
        Set<Criteria>[] rightChildCriteria = new Set[2];
        changedTree |= tryToCopy(node.getFirstChild(), leftChildCriteria, metadata, underAccess);
        changedTree |= tryToCopy(node.getLastChild(), rightChildCriteria, metadata, underAccess);
        List<Criteria> joinCrits = (List<Criteria>) node.getProperty(NodeConstants.Info.JOIN_CRITERIA);
        Set<Criteria> combinedCriteria = null;
        if (joinCrits != null) {
            combinedCriteria = new LinkedHashSet<Criteria>(joinCrits);
            combinedCriteria.addAll(leftChildCriteria[1]);
            combinedCriteria.addAll(rightChildCriteria[1]);
        }
        // combine the criteria
        leftChildCriteria[0].addAll(rightChildCriteria[0]);
        leftChildCriteria[1].addAll(rightChildCriteria[1]);
        // set the applicable criteria
        criteriaInfo[0] = leftChildCriteria[0];
        // set the all criteria
        criteriaInfo[1] = leftChildCriteria[1];
        // there's no join criteria here, so just let the criteria go up
        if (jt == JoinType.JOIN_CROSS) {
            return changedTree;
        }
        Set<Criteria> toCopy = criteriaInfo[0];
        Set<Criteria> allCriteria = criteriaInfo[1];
        if (joinCrits != null && !joinCrits.isEmpty()) {
            List<Criteria> newJoinCrits = new LinkedList<Criteria>();
            // we don't want to continue discovery since that could be recursive
            Map<Expression, Expression> srcToTgt = buildElementMap(joinCrits, node.hasBooleanProperty(NodeConstants.Info.IS_COPIED) ? null : newJoinCrits, combinedCriteria, metadata, underAccess);
            changedTree |= !newJoinCrits.isEmpty();
            if (!toCopy.isEmpty()) {
                changedTree |= createCriteria(false, toCopy, combinedCriteria, srcToTgt, newJoinCrits, metadata, underAccess);
                srcToTgt = buildElementMap(allCriteria, null, null, metadata, underAccess);
                changedTree |= createCriteria(true, joinCrits, combinedCriteria, srcToTgt, newJoinCrits, metadata, underAccess);
            }
            joinCrits.addAll(newJoinCrits);
        }
        // before returning, filter out criteria that cannot go above the join node
        if (jt == JoinType.JOIN_RIGHT_OUTER || jt == JoinType.JOIN_ANTI_SEMI || jt == JoinType.JOIN_SEMI || jt == JoinType.JOIN_UNION) {
            // $NON-NLS-1$
            throw new AssertionError("Unexpected join type");
        } else if (jt == JoinType.JOIN_LEFT_OUTER) {
            criteriaInfo[0].removeAll(rightChildCriteria[0]);
            criteriaInfo[1].removeAll(rightChildCriteria[1]);
        } else if (node.getSubqueryContainers().isEmpty()) {
            if (!node.hasBooleanProperty(NodeConstants.Info.IS_COPIED)) {
                toCopy.addAll(combinedCriteria);
            }
            allCriteria.addAll(joinCrits);
        }
        return changedTree;
    }
    changedTree = visitChildern(node, criteriaInfo, changedTree, metadata, underAccess);
    // visit select nodes on the way back up
    switch(node.getType()) {
        case NodeConstants.Types.SELECT:
            {
                if (criteriaInfo[0] != null) {
                    visitSelectNode(node, criteriaInfo[0], criteriaInfo[1]);
                }
                break;
            }
        // clear the criteria when hitting the following
        case NodeConstants.Types.NULL:
        case NodeConstants.Types.SOURCE:
        case NodeConstants.Types.GROUP:
        case NodeConstants.Types.SET_OP:
        case NodeConstants.Types.PROJECT:
            {
                if (criteriaInfo[0] == null) {
                    criteriaInfo[0] = new LinkedHashSet<Criteria>();
                    criteriaInfo[1] = new LinkedHashSet<Criteria>();
                } else {
                    criteriaInfo[0].clear();
                    criteriaInfo[1].clear();
                }
                break;
            }
    }
    return changedTree;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) LinkedHashSet(java.util.LinkedHashSet) Set(java.util.Set) JoinType(org.teiid.query.sql.lang.JoinType) IsNullCriteria(org.teiid.query.sql.lang.IsNullCriteria) Criteria(org.teiid.query.sql.lang.Criteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria) LinkedList(java.util.LinkedList) Expression(org.teiid.query.sql.symbol.Expression) LinkedList(java.util.LinkedList) List(java.util.List)

Example 10 with JoinType

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

the class RuleDecomposeJoin method decomposeJoin.

public PlanNode decomposeJoin(PlanNode joinNode, PlanNode root, QueryMetadataInterface metadata, CommandContext context) throws TeiidComponentException, QueryPlannerException {
    if (joinNode.getParent() == null) {
        // already processed
        return root;
    }
    JoinType joinType = (JoinType) joinNode.getProperty(Info.JOIN_TYPE);
    if (joinType == JoinType.JOIN_ANTI_SEMI || joinType == JoinType.JOIN_CROSS) {
        return root;
    }
    PlanNode left = joinNode.getFirstChild();
    while (left.getType() != NodeConstants.Types.SOURCE) {
        if (left.getType() == NodeConstants.Types.SELECT && left.hasBooleanProperty(Info.IS_PHANTOM)) {
            left = left.getFirstChild();
        } else {
            return root;
        }
    }
    Map<ElementSymbol, List<Set<Constant>>> partitionInfo = (Map<ElementSymbol, List<Set<Constant>>>) left.getProperty(Info.PARTITION_INFO);
    if (partitionInfo == null) {
        return root;
    }
    PlanNode unionNode = left.getFirstChild();
    if (unionNode.getType() != NodeConstants.Types.SET_OP) {
        return root;
    }
    PlanNode right = joinNode.getLastChild();
    while (right.getType() != NodeConstants.Types.SOURCE) {
        if (right.getType() == NodeConstants.Types.SELECT && right.hasBooleanProperty(Info.IS_PHANTOM)) {
            right = right.getFirstChild();
        } else {
            return root;
        }
    }
    Map<ElementSymbol, List<Set<Constant>>> rightPartionInfo = (Map<ElementSymbol, List<Set<Constant>>>) right.getProperty(Info.PARTITION_INFO);
    if (rightPartionInfo == null) {
        return root;
    }
    List<Criteria> criteria = (List<Criteria>) joinNode.getProperty(Info.JOIN_CRITERIA);
    List<Expression> expr = new ArrayList<Expression>();
    List<Expression> exprOther = new ArrayList<Expression>();
    RuleChooseJoinStrategy.separateCriteria(unionNode.getParent().getGroups(), right.getGroups(), expr, exprOther, criteria, new LinkedList<Criteria>());
    // if implicit, we assume that partitions match
    ElementSymbol es = getImplicitPartitionColumn(metadata, left);
    ElementSymbol esOther = getImplicitPartitionColumn(metadata, right);
    if (es != null && esOther != null && getEffectiveModelId(metadata, es.getGroupSymbol()) == getEffectiveModelId(metadata, esOther.getGroupSymbol())) {
        expr.add(es);
        exprOther.add(esOther);
    }
    if (expr.isEmpty()) {
        // no equi-join
        return root;
    }
    List<int[]> matches = findMatches(partitionInfo, rightPartionInfo, expr, exprOther);
    if (matches == null) {
        // no non-overlapping partitions
        return root;
    }
    int branchSize = partitionInfo.values().iterator().next().size();
    int otherBranchSize = rightPartionInfo.values().iterator().next().size();
    if (matches.isEmpty()) {
        if (joinType == JoinType.JOIN_INNER || joinType == JoinType.JOIN_SEMI) {
            // no matches mean that we can just insert a null node (false criteria) and be done with it
            PlanNode critNode = NodeFactory.getNewNode(NodeConstants.Types.SELECT);
            critNode.setProperty(Info.SELECT_CRITERIA, QueryRewriter.FALSE_CRITERIA);
            unionNode.addAsParent(critNode);
        } else if (joinType == JoinType.JOIN_LEFT_OUTER) {
            joinNode.getParent().replaceChild(joinNode, left);
        } else if (joinType == JoinType.JOIN_FULL_OUTER) {
            joinNode.setProperty(Info.JOIN_CRITERIA, QueryRewriter.FALSE_CRITERIA);
        }
        return root;
    }
    List<PlanNode> branches = new ArrayList<PlanNode>();
    // TODO: find union children from RulePushAggregates
    RulePushSelectCriteria.collectUnionChildren(unionNode, branches);
    if (branches.size() != branchSize) {
        // sanity check
        return root;
    }
    List<PlanNode> otherBranches = new ArrayList<PlanNode>();
    RulePushSelectCriteria.collectUnionChildren(right.getFirstChild(), otherBranches);
    if (otherBranches.size() != otherBranchSize) {
        // sanity check
        return root;
    }
    PlanNode newUnion = buildUnion(unionNode, right, criteria, matches, branches, otherBranches, joinType);
    GroupSymbol leftGroup = left.getGroups().iterator().next();
    PlanNode view = rebuild(leftGroup, joinNode, newUnion, metadata, context, left, right);
    // preserve the model of the virtual group as we'll look for this when checking for implicit behavior
    ((TempMetadataID) (view.getGroups().iterator().next().getMetadataID())).getTableData().setModel(getEffectiveModelId(metadata, leftGroup));
    SymbolMap symbolmap = (SymbolMap) view.getProperty(Info.SYMBOL_MAP);
    HashMap<ElementSymbol, List<Set<Constant>>> newPartitionInfo = new LinkedHashMap<ElementSymbol, List<Set<Constant>>>();
    Map<Expression, ElementSymbol> inverse = symbolmap.inserseMapping();
    for (int[] match : matches) {
        updatePartitionInfo(partitionInfo, matches, inverse, newPartitionInfo, match[0]);
        updatePartitionInfo(rightPartionInfo, matches, inverse, newPartitionInfo, match[1]);
    }
    view.setProperty(Info.PARTITION_INFO, newPartitionInfo);
    // since we've created a new union node, there's a chance we can decompose again
    if (view.getParent().getType() == NodeConstants.Types.JOIN) {
        return decomposeJoin(view.getParent(), root, metadata, context);
    }
    return root;
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) Set(java.util.Set) Constant(org.teiid.query.sql.symbol.Constant) ArrayList(java.util.ArrayList) JoinType(org.teiid.query.sql.lang.JoinType) SymbolMap(org.teiid.query.sql.util.SymbolMap) Criteria(org.teiid.query.sql.lang.Criteria) LinkedHashMap(java.util.LinkedHashMap) 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) LinkedList(java.util.LinkedList) List(java.util.List) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) SymbolMap(org.teiid.query.sql.util.SymbolMap)

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