Search in sources :

Example 26 with Criteria

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

the class RulePushSelectCriteria method pushAcrossSetOp.

boolean pushAcrossSetOp(PlanNode critNode, PlanNode setOp, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, CommandContext context) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
    // Find source node above union and grab the symbol map
    PlanNode sourceNode = NodeEditor.findParent(setOp, NodeConstants.Types.SOURCE);
    GroupSymbol virtualGroup = sourceNode.getGroups().iterator().next();
    if (createdNodes == null) {
        satisfyConditions(critNode, sourceNode, metadata);
    }
    SymbolMap symbolMap = (SymbolMap) sourceNode.getProperty(NodeConstants.Info.SYMBOL_MAP);
    SymbolMap childMap = symbolMap;
    // Move criteria to first child of union - names are the same, so no symbol mapping
    LinkedList<PlanNode> unionChildren = new LinkedList<PlanNode>();
    collectUnionChildren(setOp, unionChildren);
    int movedCount = 0;
    for (PlanNode planNode : unionChildren) {
        // Find first project node
        PlanNode projectNode = NodeEditor.findNodePreOrder(planNode, NodeConstants.Types.PROJECT);
        if (childMap == null) {
            childMap = SymbolMap.createSymbolMap(symbolMap.getKeys(), (List) projectNode.getProperty(NodeConstants.Info.PROJECT_COLS));
        }
        // we cannot simply move the node in the case where placing above or below the access would be invalid
        boolean handleSetOp = false;
        PlanNode accessNode = NodeEditor.findNodePreOrder(planNode, NodeConstants.Types.ACCESS, NodeConstants.Types.PROJECT);
        if (accessNode != null && NodeEditor.findParent(projectNode, NodeConstants.Types.SET_OP, NodeConstants.Types.ACCESS) != null) {
            handleSetOp = true;
        }
        // Move the node
        if (placeConvertedSelectNode(critNode, virtualGroup, projectNode, childMap, metadata)) {
            if (handleSetOp) {
                PlanNode newSelect = projectNode.getFirstChild();
                projectNode.replaceChild(newSelect, newSelect.getFirstChild());
                Object modelID = RuleRaiseAccess.getModelIDFromAccess(accessNode, metadata);
                Criteria crit = (Criteria) newSelect.getProperty(NodeConstants.Info.SELECT_CRITERIA);
                if (newSelect.hasBooleanProperty(NodeConstants.Info.IS_DEPENDENT_SET) && context != null && CapabilitiesUtil.supportsInlineView(modelID, metadata, capFinder) && CriteriaCapabilityValidatorVisitor.canPushLanguageObject(crit, modelID, metadata, capFinder, null)) {
                    accessNode.getFirstChild().addAsParent(newSelect);
                    List<Expression> old = (List<Expression>) projectNode.getProperty(NodeConstants.Info.PROJECT_COLS);
                    // create a project node based upon the created group and add it as the parent of the select
                    PlanNode project = RelationalPlanner.createProjectNode(LanguageObject.Util.deepClone(old, Expression.class));
                    newSelect.addAsParent(project);
                    // $NON-NLS-1$
                    PlanNode newSourceNode = RuleDecomposeJoin.rebuild(new GroupSymbol("intermediate"), null, newSelect.getFirstChild(), metadata, context, projectNode);
                    newSourceNode.setProperty(NodeConstants.Info.INLINE_VIEW, true);
                    accessNode.addGroups(newSourceNode.getGroups());
                    markDependent(newSelect, accessNode, metadata, capFinder);
                } else {
                    // or an inline view could be used similar to the above
                    if (createdNodes != null) {
                        createdNodes.remove(newSelect);
                    }
                    childMap = null;
                    continue;
                }
            }
            movedCount++;
        }
        // create a new symbol map for the other children
        childMap = null;
    }
    // TODO - the logic here could be made more intelligent about EXCEPT and INTERSECT.
    if (movedCount == unionChildren.size()) {
        critNode.setProperty(NodeConstants.Info.IS_PHANTOM, Boolean.TRUE);
        return true;
    }
    // otherwise mark it as pushed so we don't consider it again
    critNode.setProperty(NodeConstants.Info.IS_PUSHED, Boolean.TRUE);
    // if any moved, then we need to continue
    return movedCount != 0;
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) Expression(org.teiid.query.sql.symbol.Expression) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) SymbolMap(org.teiid.query.sql.util.SymbolMap) LanguageObject(org.teiid.query.sql.LanguageObject) 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)

Example 27 with Criteria

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

the class RuleRemoveOptionalJoins method isOptionalUsingKey.

private boolean isOptionalUsingKey(PlanNode joinNode, PlanNode optionalNode, QueryMetadataInterface metadata, boolean isRight) throws TeiidComponentException, QueryMetadataException {
    // for now we just look for a single group
    if (optionalNode.getGroups().size() != 1) {
        return false;
    }
    PlanNode left = isRight ? joinNode.getFirstChild() : joinNode.getLastChild();
    LinkedList<Expression> leftExpressions = new LinkedList<Expression>();
    LinkedList<Expression> rightExpressions = new LinkedList<Expression>();
    LinkedList<Criteria> nonEquiJoinCriteria = new LinkedList<Criteria>();
    RuleChooseJoinStrategy.separateCriteria(left.getGroups(), optionalNode.getGroups(), leftExpressions, rightExpressions, (List<Criteria>) joinNode.getProperty(NodeConstants.Info.JOIN_CRITERIA), nonEquiJoinCriteria);
    if (!nonEquiJoinCriteria.isEmpty()) {
        for (Criteria crit : nonEquiJoinCriteria) {
            if (!Collections.disjoint(GroupsUsedByElementsVisitor.getGroups(crit), optionalNode.getGroups())) {
                // additional predicates still need to be applied, or ignored via hint
                return false;
            }
        }
    }
    ArrayList<Object> leftIds = new ArrayList<Object>(leftExpressions.size());
    ArrayList<Object> rightIds = new ArrayList<Object>(rightExpressions.size());
    for (Expression expr : leftExpressions) {
        if (expr instanceof ElementSymbol) {
            leftIds.add(((ElementSymbol) expr).getMetadataID());
        }
    }
    for (Expression expr : rightExpressions) {
        if (expr instanceof ElementSymbol) {
            rightIds.add(((ElementSymbol) expr).getMetadataID());
        } else {
            // only allow a key join
            return false;
        }
    }
    outer: for (GroupSymbol group : left.getGroups()) {
        Collection fks = metadata.getForeignKeysInGroup(group.getMetadataID());
        for (Object fk : fks) {
            List fkColumns = metadata.getElementIDsInKey(fk);
            if (!leftIds.containsAll(fkColumns)) {
                continue;
            }
            Object pk = metadata.getPrimaryKeyIDForForeignKeyID(fk);
            List pkColumns = metadata.getElementIDsInKey(pk);
            if ((rightIds.size() != pkColumns.size()) || !rightIds.containsAll(pkColumns)) {
                continue;
            }
            if (!isRight) {
                // match up to the replacement logic below
                JoinUtil.swapJoinChildren(joinNode);
            }
            return true;
        }
    }
    return false;
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) ArrayList(java.util.ArrayList) Criteria(org.teiid.query.sql.lang.Criteria) LinkedList(java.util.LinkedList) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) Expression(org.teiid.query.sql.symbol.Expression) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) Collection(java.util.Collection) LanguageObject(org.teiid.query.sql.LanguageObject) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) List(java.util.List)

Example 28 with Criteria

use of org.teiid.query.sql.lang.Criteria 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 29 with Criteria

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

the class RuleChooseJoinStrategy method separateCriteria.

public static void separateCriteria(Collection<GroupSymbol> leftGroups, Collection<GroupSymbol> rightGroups, List<Expression> leftExpressions, List<Expression> rightExpressions, List<Criteria> crits, Collection<Criteria> nonEquiJoinCriteria) {
    for (Criteria theCrit : crits) {
        Set<GroupSymbol> critGroups = GroupsUsedByElementsVisitor.getGroups(theCrit);
        if (leftGroups.containsAll(critGroups) || rightGroups.containsAll(critGroups)) {
            nonEquiJoinCriteria.add(theCrit);
            continue;
        }
        if (!(theCrit instanceof CompareCriteria)) {
            nonEquiJoinCriteria.add(theCrit);
            continue;
        }
        CompareCriteria crit = (CompareCriteria) theCrit;
        if (crit.getOperator() != CompareCriteria.EQ) {
            nonEquiJoinCriteria.add(theCrit);
            continue;
        }
        Expression leftExpr = crit.getLeftExpression();
        Expression rightExpr = crit.getRightExpression();
        Set<GroupSymbol> leftExprGroups = GroupsUsedByElementsVisitor.getGroups(leftExpr);
        Set<GroupSymbol> rightExprGroups = GroupsUsedByElementsVisitor.getGroups(rightExpr);
        if (leftGroups.isEmpty() || rightGroups.isEmpty()) {
            nonEquiJoinCriteria.add(theCrit);
        } else if (leftGroups.containsAll(leftExprGroups) && rightGroups.containsAll(rightExprGroups)) {
            leftExpressions.add(leftExpr);
            rightExpressions.add(rightExpr);
        } else if (rightGroups.containsAll(leftExprGroups) && leftGroups.containsAll(rightExprGroups)) {
            leftExpressions.add(rightExpr);
            rightExpressions.add(leftExpr);
        } else {
            nonEquiJoinCriteria.add(theCrit);
        }
    }
}
Also used : Expression(org.teiid.query.sql.symbol.Expression) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) Criteria(org.teiid.query.sql.lang.Criteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria)

Example 30 with Criteria

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

the class RuleCopyCriteria method copyCriteria.

/**
 * Given a criteria and a map of elements to values try to create a new single group criteria
 *
 * If the new criteria does not have exactly one group or already exists in the combined criteria,
 * it will not be added.
 *
 * @param crit
 * @param tgtMap
 * @param joinCriteria
 * @param combinedCriteria
 * @return number of remaining groups if the copy was successful
 */
private Integer copyCriteria(Criteria crit, Map<Expression, Expression> tgtMap, List<Criteria> joinCriteria, Set<Criteria> combinedCriteria, boolean checkForGroupReduction, QueryMetadataInterface metadata, boolean underAccess) {
    int startGroups = GroupsUsedByElementsVisitor.getGroups(crit).size();
    Criteria tgtCrit = (Criteria) crit.clone();
    try {
        tgtCrit = FrameUtil.convertCriteria(tgtCrit, tgtMap, metadata, true);
    } catch (QueryPlannerException err) {
        // $NON-NLS-1$
        LogManager.logDetail(LogConstants.CTX_QUERY_PLANNER, err, "Could not remap target criteria in RuleCopyCriteria");
        return null;
    }
    if (tgtCrit instanceof IsNullCriteria && ((IsNullCriteria) tgtCrit).isNegated()) {
        return null;
    }
    int endGroups = GroupsUsedByElementsVisitor.getGroups(tgtCrit).size();
    if (checkForGroupReduction) {
        if (endGroups >= startGroups) {
            return null;
        }
    } else if (endGroups > startGroups) {
        return null;
    }
    boolean isNew = combinedCriteria.add(tgtCrit);
    if (underAccess) {
        if (!isNew || checkForGroupReduction || endGroups > 1) {
            return null;
        }
        if (!COPY_ALL) {
            boolean use = false;
            Collection<ElementSymbol> cols = ElementCollectorVisitor.getElements(tgtCrit, true);
            // use only if it could be used to further rewrite predicates
            for (Criteria existing : combinedCriteria) {
                if (existing.equals(tgtCrit)) {
                    continue;
                }
                Collection<ElementSymbol> elements = ElementCollectorVisitor.getElements(existing, true);
                if (GroupsUsedByElementsVisitor.getGroups(elements).size() > 1) {
                    continue;
                }
                if (elements.containsAll(cols)) {
                    use = true;
                    break;
                }
            }
            if (!use) {
                return null;
            }
        }
    }
    // if this is unique or it a duplicate but reduced a current join conjunct, return true
    if (isNew) {
        joinCriteria.add(tgtCrit);
        if (tgtCrit instanceof CompareCriteria) {
            CompareCriteria cc = (CompareCriteria) tgtCrit;
            if (!EvaluatableVisitor.willBecomeConstant(cc.getRightExpression()) && !EvaluatableVisitor.willBecomeConstant(cc.getRightExpression())) {
                ((CompareCriteria) tgtCrit).setOptional(true);
            }
        }
        return endGroups;
    } else if (checkForGroupReduction && endGroups < 2) {
        return endGroups;
    }
    return null;
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) IsNullCriteria(org.teiid.query.sql.lang.IsNullCriteria) Criteria(org.teiid.query.sql.lang.Criteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria) IsNullCriteria(org.teiid.query.sql.lang.IsNullCriteria)

Aggregations

Criteria (org.teiid.query.sql.lang.Criteria)67 CompareCriteria (org.teiid.query.sql.lang.CompareCriteria)40 PlanNode (org.teiid.query.optimizer.relational.plantree.PlanNode)35 ElementSymbol (org.teiid.query.sql.symbol.ElementSymbol)22 Expression (org.teiid.query.sql.symbol.Expression)22 GroupSymbol (org.teiid.query.sql.symbol.GroupSymbol)22 CompoundCriteria (org.teiid.query.sql.lang.CompoundCriteria)19 ArrayList (java.util.ArrayList)16 List (java.util.List)15 DependentSetCriteria (org.teiid.query.sql.lang.DependentSetCriteria)13 IsNullCriteria (org.teiid.query.sql.lang.IsNullCriteria)12 Constant (org.teiid.query.sql.symbol.Constant)11 SymbolMap (org.teiid.query.sql.util.SymbolMap)11 JoinType (org.teiid.query.sql.lang.JoinType)10 SetCriteria (org.teiid.query.sql.lang.SetCriteria)10 LinkedList (java.util.LinkedList)7 Reference (org.teiid.query.sql.symbol.Reference)6 LinkedHashSet (java.util.LinkedHashSet)5 LanguageObject (org.teiid.query.sql.LanguageObject)5 Collection (java.util.Collection)4