Search in sources :

Example 31 with CompareCriteria

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

the class RulePlanJoins method groupJoinsForPushing.

/**
 * This is a heuristic that checks for joins that may be pushed so they can be removed
 * before considering the joins that must be evaluated in MetaMatrix.
 *
 * By running this, we eliminate the need for running RuleRaiseAccess during join ordering
 *
 * @param metadata
 * @param joinRegion
 * @throws QueryMetadataException
 * @throws TeiidComponentException
 * @throws QueryPlannerException
 */
private void groupJoinsForPushing(QueryMetadataInterface metadata, CapabilitiesFinder capFinder, JoinRegion joinRegion, CommandContext context) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
    // TODO: consider moving select criteria if it is preventing a join from being pushed down
    // TODO: make the criteria checks based upon a guess at selectivity
    Map accessMap = getAccessMap(metadata, capFinder, joinRegion);
    boolean structureChanged = false;
    // search for combinations of join sources that should be pushed down
    for (Iterator accessNodeIter = accessMap.entrySet().iterator(); accessNodeIter.hasNext(); ) {
        Map.Entry entry = (Map.Entry) accessNodeIter.next();
        List<PlanNode> accessNodes = (List) entry.getValue();
        if (accessNodes.size() < 2) {
            continue;
        }
        int secondPass = -1;
        for (int i = accessNodes.size() - 1; i >= 0; i--) {
            PlanNode accessNode1 = accessNodes.get(i);
            Object modelId = RuleRaiseAccess.getModelIDFromAccess(accessNode1, metadata);
            SupportedJoinCriteria sjc = CapabilitiesUtil.getSupportedJoinCriteria(modelId, metadata, capFinder);
            int discoveredJoin = -1;
            for (int k = (secondPass == -1 ? accessNodes.size() - 1 : secondPass); k >= 0; k--) {
                if (k == i) {
                    continue;
                }
                PlanNode accessNode2 = accessNodes.get(k);
                List<PlanNode> criteriaNodes = joinRegion.getCriteriaNodes();
                List<PlanNode> joinCriteriaNodes = new LinkedList<PlanNode>();
                /* hasJoinCriteria will be true if
                     *  1. there is criteria between accessNode1 and accessNode2 exclusively
                     *  2. there is criteria between some other source (not the same logical connector) and accessNode1 or accessNode2
                     *  
                     *  Ideally we should be a little smarter in case 2 
                     *    - pushing down a same source cross join can be done if we know that a dependent join will be performed 
                     */
                boolean hasJoinCriteria = false;
                LinkedList<Criteria> joinCriteria = new LinkedList<Criteria>();
                for (PlanNode critNode : criteriaNodes) {
                    Set<PlanNode> sources = joinRegion.getCritieriaToSourceMap().get(critNode);
                    if (sources == null) {
                        continue;
                    }
                    if (sources.contains(accessNode1)) {
                        if (sources.contains(accessNode2) && sources.size() == 2) {
                            Criteria crit = (Criteria) critNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
                            if (RuleRaiseAccess.isSupportedJoinCriteria(sjc, crit, modelId, metadata, capFinder, null)) {
                                joinCriteriaNodes.add(critNode);
                                joinCriteria.add(crit);
                            }
                        } else if (!accessNodes.containsAll(sources)) {
                            hasJoinCriteria = true;
                        }
                    } else if (sources.contains(accessNode2) && !accessNodes.containsAll(sources)) {
                        hasJoinCriteria = true;
                    }
                }
                /*
                     * If we failed to find direct criteria, a cross join may still be acceptable
                     */
                if (joinCriteriaNodes.isEmpty() && (hasJoinCriteria || !canPushCrossJoin(metadata, accessNode1, accessNode2))) {
                    continue;
                }
                List<PlanNode> toTest = Arrays.asList(accessNode1, accessNode2);
                JoinType joinType = joinCriteria.isEmpty() ? JoinType.JOIN_CROSS : JoinType.JOIN_INNER;
                /*
                     * We need to limit the heuristic grouping as we don't want to create larger source queries than necessary
                     */
                boolean shouldPush = true;
                int sourceCount = NodeEditor.findAllNodes(accessNode1, NodeConstants.Types.SOURCE, NodeConstants.Types.SOURCE).size();
                sourceCount += NodeEditor.findAllNodes(accessNode2, NodeConstants.Types.SOURCE, NodeConstants.Types.SOURCE).size();
                if (!context.getOptions().isAggressiveJoinGrouping() && accessMap.size() > 1 && joinType == JoinType.JOIN_INNER && (sourceCount > 2 && (accessNode1.hasProperty(Info.MAKE_DEP) || accessNode2.hasProperty(Info.MAKE_DEP)) || sourceCount > 3) && !canPushCrossJoin(metadata, accessNode1, accessNode2)) {
                    Collection<GroupSymbol> leftGroups = accessNode1.getGroups();
                    Collection<GroupSymbol> rightGroups = accessNode2.getGroups();
                    List<Expression> leftExpressions = new ArrayList<Expression>();
                    List<Expression> rightExpressions = new ArrayList<Expression>();
                    List<Criteria> nonEquiJoinCriteria = new ArrayList<Criteria>();
                    RuleChooseJoinStrategy.separateCriteria(leftGroups, rightGroups, leftExpressions, rightExpressions, joinCriteria, nonEquiJoinCriteria);
                    // allow a 1-1 join
                    if (!NewCalculateCostUtil.usesKey(accessNode1, leftExpressions, metadata) || !NewCalculateCostUtil.usesKey(accessNode2, rightExpressions, metadata)) {
                        // don't push heuristically
                        shouldPush = false;
                    }
                }
                // try to push to the source
                if (!shouldPush || RuleRaiseAccess.canRaiseOverJoin(toTest, metadata, capFinder, joinCriteria, joinType, null, context, secondPass != -1, false) == null) {
                    if (secondPass == -1 && sjc != SupportedJoinCriteria.KEY && discoveredJoin == -1) {
                        for (Criteria criteria : joinCriteria) {
                            if (criteria instanceof CompareCriteria && ((CompareCriteria) criteria).isOptional()) {
                                discoveredJoin = k;
                            }
                        }
                    }
                    continue;
                }
                secondPass = -1;
                discoveredJoin = -1;
                structureChanged = true;
                // remove the information that is no longer relevant to the join region
                joinRegion.getCritieriaToSourceMap().keySet().removeAll(joinCriteriaNodes);
                joinRegion.getCriteriaNodes().removeAll(joinCriteriaNodes);
                joinRegion.getJoinSourceNodes().remove(accessNode1);
                joinRegion.getJoinSourceNodes().remove(accessNode2);
                accessNodes.remove(i);
                accessNodes.remove(k < i ? k : k - 1);
                // build a new join node
                PlanNode joinNode = createJoinNode(accessNode1, accessNode2, joinCriteria, joinType);
                PlanNode newAccess = RuleRaiseAccess.raiseAccessOverJoin(joinNode, joinNode.getFirstChild(), entry.getKey(), capFinder, metadata, false);
                for (PlanNode critNode : joinCriteriaNodes) {
                    critNode.removeFromParent();
                    critNode.removeAllChildren();
                }
                for (Set<PlanNode> source : joinRegion.getCritieriaToSourceMap().values()) {
                    if (source.remove(accessNode1) || source.remove(accessNode2)) {
                        source.add(newAccess);
                    }
                }
                joinRegion.getJoinSourceNodes().put(newAccess, newAccess);
                accessNodes.add(newAccess);
                i = accessNodes.size();
                k = accessNodes.size();
                break;
            }
            if (discoveredJoin != -1) {
                // rerun with the discoveredJoin criteria
                i++;
                secondPass = discoveredJoin;
            }
        }
    }
    if (structureChanged) {
        joinRegion.reconstructJoinRegoin();
    }
}
Also used : JoinType(org.teiid.query.sql.lang.JoinType) Criteria(org.teiid.query.sql.lang.Criteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria) SupportedJoinCriteria(org.teiid.translator.ExecutionFactory.SupportedJoinCriteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) SupportedJoinCriteria(org.teiid.translator.ExecutionFactory.SupportedJoinCriteria) Expression(org.teiid.query.sql.symbol.Expression) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) SymbolMap(org.teiid.query.sql.util.SymbolMap)

Example 32 with CompareCriteria

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

the class RulePlanProcedures method findInputNodes.

private void findInputNodes(final HashSet<ElementSymbol> inputs, PlanNode critNode, final List<Criteria> conjuncts, final Set<ElementSymbol> params) {
    while (critNode.getType() == NodeConstants.Types.SELECT) {
        final PlanNode currentNode = critNode;
        final Criteria crit = (Criteria) currentNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
        critNode = currentNode.getParent();
        if (!currentNode.getGroups().isEmpty()) {
            continue;
        }
        LanguageVisitor visitor = new LanguageVisitor() {

            public void visit(CompareCriteria compCrit) {
                if (compCrit.getOperator() == CompareCriteria.EQ && checkForInput(compCrit.getLeftExpression()) && !checkForAnyInput(compCrit.getRightExpression())) {
                    addInputNode((Reference) compCrit.getLeftExpression());
                }
            }

            private void addInputNode(Reference param) {
                params.add(param.getExpression());
                conjuncts.add(crit);
                NodeEditor.removeChildNode(currentNode.getParent(), currentNode);
            }

            public void visit(IsNullCriteria isNull) {
                if (!isNull.isNegated() && checkForInput(isNull.getExpression())) {
                    addInputNode((Reference) isNull.getExpression());
                }
            }

            public void visit(SetCriteria obj) {
                if (!obj.isNegated() && checkForInput(obj.getExpression()) && !checkForAnyInput(obj.getValues())) {
                    addInputNode((Reference) obj.getExpression());
                }
            }

            public void visit(DependentSetCriteria obj) {
                if (obj.isNegated()) {
                    // just a sanity check
                    return;
                }
                if (obj.hasMultipleAttributes()) {
                    for (AttributeComparison comp : obj.getAttributes()) {
                        if (!checkForInput(comp.dep)) {
                            return;
                        }
                    }
                    for (AttributeComparison comp : obj.getAttributes()) {
                        params.add(((Reference) comp.dep).getExpression());
                    }
                    conjuncts.add(crit);
                    NodeEditor.removeChildNode(currentNode.getParent(), currentNode);
                } else if (checkForInput(obj.getExpression())) {
                    addInputNode((Reference) obj.getExpression());
                }
            }

            boolean checkForInput(Expression expr) {
                if (!(expr instanceof Reference)) {
                    return false;
                }
                // if the expr is a function containing a reference should give a warning
                Reference ref = (Reference) expr;
                return inputs.contains(ref.getExpression());
            }

            boolean checkForAnyInput(LanguageObject expr) {
                for (Reference ref : ReferenceCollectorVisitor.getReferences(expr)) {
                    if (checkForInput(ref)) {
                        return true;
                    }
                }
                return false;
            }

            boolean checkForAnyInput(Collection<Expression> expressions) {
                for (Expression expr : expressions) {
                    if (checkForAnyInput(expr)) {
                        return true;
                    }
                }
                return false;
            }
        };
        for (Criteria conjunct : Criteria.separateCriteriaByAnd(crit)) {
            conjunct.acceptVisitor(visitor);
        }
    }
}
Also used : LanguageVisitor(org.teiid.query.sql.LanguageVisitor) DependentSetCriteria(org.teiid.query.sql.lang.DependentSetCriteria) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) Expression(org.teiid.query.sql.symbol.Expression) Reference(org.teiid.query.sql.symbol.Reference) DependentSetCriteria(org.teiid.query.sql.lang.DependentSetCriteria) SetCriteria(org.teiid.query.sql.lang.SetCriteria) Collection(java.util.Collection) 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) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria) AttributeComparison(org.teiid.query.sql.lang.DependentSetCriteria.AttributeComparison) LanguageObject(org.teiid.query.sql.LanguageObject) IsNullCriteria(org.teiid.query.sql.lang.IsNullCriteria)

Example 33 with CompareCriteria

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

the class RuleCopyCriteria method createCriteria.

private boolean createCriteria(boolean copyingJoinCriteria, Collection<Criteria> toCopy, Set<Criteria> combinedCriteria, Map<Expression, Expression> srcToTgt, List<Criteria> newJoinCrits, QueryMetadataInterface metadata, boolean underAccess) {
    boolean changedTree = false;
    if (srcToTgt.size() == 0) {
        return changedTree;
    }
    Iterator<Criteria> i = toCopy.iterator();
    while (i.hasNext()) {
        Criteria crit = i.next();
        Integer endGroups = copyCriteria(crit, srcToTgt, newJoinCrits, combinedCriteria, copyingJoinCriteria, metadata, underAccess);
        if (endGroups != null) {
            changedTree = true;
            if (copyingJoinCriteria && endGroups < 2) {
                if (crit instanceof CompareCriteria) {
                    CompareCriteria cc = (CompareCriteria) crit;
                    // don't remove theta criteria, just mark it as optional
                    cc.setOptional(null);
                    continue;
                }
                i.remove();
            }
        }
    }
    return changedTree;
}
Also used : IsNullCriteria(org.teiid.query.sql.lang.IsNullCriteria) Criteria(org.teiid.query.sql.lang.Criteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria)

Example 34 with CompareCriteria

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

the class RulePushSelectCriteria method satisfyConditions.

/**
 * @param critNode
 * @param sourceNode
 * @throws TeiidComponentException
 * @throws QueryMetadataException
 */
static void satisfyConditions(PlanNode critNode, PlanNode sourceNode, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
    List aps = (List) sourceNode.getProperty(NodeConstants.Info.ACCESS_PATTERNS);
    Criteria crit = (Criteria) critNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
    if (sourceNode.hasBooleanProperty(Info.IS_MULTI_SOURCE) && crit instanceof CompareCriteria) {
        CompareCriteria cc = (CompareCriteria) crit;
        if (cc.getLeftExpression() instanceof ElementSymbol && cc.getRightExpression() instanceof Constant) {
            ElementSymbol es = (ElementSymbol) cc.getLeftExpression();
            if (metadata.isMultiSourceElement(es.getMetadataID())) {
                sourceNode.setProperty(Info.IS_MULTI_SOURCE, false);
                sourceNode.setProperty(Info.SOURCE_NAME, ((Constant) cc.getRightExpression()).getValue());
            }
        }
    }
    if (aps == null) {
        return;
    }
    Collection<ElementSymbol> elements = getElementsIncriteria(crit);
    boolean removeAps = satisfyAccessPatterns(aps, elements);
    if (removeAps) {
        sourceNode.removeProperty(NodeConstants.Info.ACCESS_PATTERNS);
        return;
    }
    Collections.sort(aps);
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) Constant(org.teiid.query.sql.symbol.Constant) CompoundCriteria(org.teiid.query.sql.lang.CompoundCriteria) DependentSetCriteria(org.teiid.query.sql.lang.DependentSetCriteria) Criteria(org.teiid.query.sql.lang.Criteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria)

Example 35 with CompareCriteria

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

the class JoinRegion method getJoinCriteriaForGroups.

// TODO: this should be better than a linear search
protected List<PlanNode> getJoinCriteriaForGroups(Set<GroupSymbol> groups, Collection<PlanNode> nodes) {
    List<PlanNode> result = new LinkedList<PlanNode>();
    for (PlanNode critNode : nodes) {
        if (groups.containsAll(critNode.getGroups())) {
            Criteria crit = (Criteria) critNode.getProperty(Info.SELECT_CRITERIA);
            if (crit instanceof CompareCriteria && ((CompareCriteria) crit).isOptional()) {
                continue;
            }
            result.add(critNode);
        }
    }
    return result;
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) CompoundCriteria(org.teiid.query.sql.lang.CompoundCriteria) Criteria(org.teiid.query.sql.lang.Criteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria)

Aggregations

CompareCriteria (org.teiid.query.sql.lang.CompareCriteria)52 ElementSymbol (org.teiid.query.sql.symbol.ElementSymbol)25 Constant (org.teiid.query.sql.symbol.Constant)24 Criteria (org.teiid.query.sql.lang.Criteria)21 ArrayList (java.util.ArrayList)15 GroupSymbol (org.teiid.query.sql.symbol.GroupSymbol)11 Test (org.junit.Test)10 PlanNode (org.teiid.query.optimizer.relational.plantree.PlanNode)9 CompoundCriteria (org.teiid.query.sql.lang.CompoundCriteria)9 Expression (org.teiid.query.sql.symbol.Expression)9 IsNullCriteria (org.teiid.query.sql.lang.IsNullCriteria)8 List (java.util.List)7 HashMap (java.util.HashMap)6 Query (org.teiid.query.sql.lang.Query)6 SetCriteria (org.teiid.query.sql.lang.SetCriteria)6 From (org.teiid.query.sql.lang.From)5 Select (org.teiid.query.sql.lang.Select)5 DependentSetCriteria (org.teiid.query.sql.lang.DependentSetCriteria)4 Collection (java.util.Collection)3 JoinType (org.teiid.query.sql.lang.JoinType)3