Search in sources :

Example 11 with OrderBy

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

the class RuleImplementJoinStrategy method createSortNode.

private static PlanNode createSortNode(List<Expression> orderSymbols, Collection<Expression> outputElements) {
    PlanNode sortNode = NodeFactory.getNewNode(NodeConstants.Types.SORT);
    OrderBy order = new OrderBy(orderSymbols);
    sortNode.setProperty(NodeConstants.Info.SORT_ORDER, order);
    sortNode.setProperty(NodeConstants.Info.OUTPUT_COLS, new ArrayList<Expression>(outputElements));
    return sortNode;
}
Also used : OrderBy(org.teiid.query.sql.lang.OrderBy) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) Expression(org.teiid.query.sql.symbol.Expression)

Example 12 with OrderBy

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

the class RulePushLimit method pushOrderByAndLimit.

private void pushOrderByAndLimit(PlanNode limitNode, List<PlanNode> limitNodes, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, CommandContext context, PlanNode child, Expression parentLimit, Expression parentOffset, PlanNode branch) throws QueryMetadataException, TeiidComponentException {
    // push both the limit and order by
    OrderBy parentOrderBy = (OrderBy) child.getProperty(NodeConstants.Info.SORT_ORDER);
    PlanNode newSort = NodeFactory.getNewNode(NodeConstants.Types.SORT);
    OrderBy newOrderBy = parentOrderBy.clone();
    newSort.setProperty(Info.SORT_ORDER, newOrderBy);
    newSort.addGroups(child.getGroups());
    newSort.setProperty(NodeConstants.Info.OUTPUT_COLS, branch.getProperty(NodeConstants.Info.OUTPUT_COLS));
    branch.addAsParent(newSort);
    addBranchLimit(limitNode, limitNodes, metadata, parentLimit, parentOffset, newSort);
    if (limitNode.hasBooleanProperty(Info.IS_PUSHED)) {
        // remove the intermediate ordering/limit
        NodeEditor.removeChildNode(limitNode, limitNode.getFirstChild());
        NodeEditor.removeChildNode(limitNode.getParent(), limitNode);
    }
}
Also used : OrderBy(org.teiid.query.sql.lang.OrderBy) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode)

Example 13 with OrderBy

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

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

the class FrameUtil method convertNode.

// If newGroup == null, this will be performing a straight symbol swap - that is,
// an oldGroup is undergoing a name change and that is the only difference in the
// symbols.  In that case, some additional work can be done because we can assume
// that an oldElement isn't being replaced by an expression using elements from
// multiple new groups.
static void convertNode(PlanNode node, GroupSymbol oldGroup, Set<GroupSymbol> newGroups, Map symbolMap, QueryMetadataInterface metadata, boolean rewrite) throws QueryPlannerException {
    if (node.getType() == NodeConstants.Types.GROUP) {
        correctSymbolMap(symbolMap, node);
    }
    // Convert expressions from correlated subquery references;
    List<SymbolMap> refMaps = node.getAllReferences();
    LinkedList<Expression> correlatedExpression = new LinkedList<Expression>();
    for (SymbolMap refs : refMaps) {
        for (Map.Entry<ElementSymbol, Expression> ref : refs.asUpdatableMap().entrySet()) {
            Expression expr = ref.getValue();
            Expression convertedExpr = convertExpression(expr, symbolMap);
            ref.setValue(convertedExpr);
            correlatedExpression.add(convertedExpr);
        }
    }
    // Update groups for current node
    Set<GroupSymbol> groups = node.getGroups();
    boolean hasOld = groups.remove(oldGroup);
    int type = node.getType();
    boolean singleMapping = newGroups != null && newGroups.size() == 1;
    if (singleMapping) {
        if (!hasOld) {
            return;
        }
        groups.addAll(newGroups);
    } else if ((type & (NodeConstants.Types.ACCESS | NodeConstants.Types.JOIN | NodeConstants.Types.SOURCE)) == type) {
        if (newGroups != null) {
            groups.addAll(newGroups);
        }
    } else {
        groups.clear();
    }
    groups.addAll(GroupsUsedByElementsVisitor.getGroups(correlatedExpression));
    if (type == NodeConstants.Types.SELECT) {
        Criteria crit = (Criteria) node.getProperty(NodeConstants.Info.SELECT_CRITERIA);
        crit = convertCriteria(crit, symbolMap, metadata, rewrite);
        node.setProperty(NodeConstants.Info.SELECT_CRITERIA, crit);
        if (!singleMapping) {
            GroupsUsedByElementsVisitor.getGroups(crit, groups);
        }
    } else if (type == NodeConstants.Types.PROJECT) {
        List<Expression> projectedSymbols = (List<Expression>) node.getProperty(NodeConstants.Info.PROJECT_COLS);
        Select select = new Select(projectedSymbols);
        ExpressionMappingVisitor.mapExpressions(select, symbolMap);
        if (rewrite) {
            for (LanguageObject expr : select.getSymbols()) {
                rewriteSingleElementSymbol(metadata, (Expression) expr);
            }
        }
        node.setProperty(NodeConstants.Info.PROJECT_COLS, select.getSymbols());
        if (!singleMapping) {
            GroupsUsedByElementsVisitor.getGroups(select, groups);
        }
    } else if (type == NodeConstants.Types.JOIN) {
        // Convert join criteria property
        List<Criteria> joinCrits = (List<Criteria>) node.getProperty(NodeConstants.Info.JOIN_CRITERIA);
        if (joinCrits != null && !joinCrits.isEmpty()) {
            Criteria crit = new CompoundCriteria(joinCrits);
            crit = convertCriteria(crit, symbolMap, metadata, rewrite);
            if (crit instanceof CompoundCriteria && ((CompoundCriteria) crit).getOperator() == CompoundCriteria.AND) {
                node.setProperty(NodeConstants.Info.JOIN_CRITERIA, ((CompoundCriteria) crit).getCriteria());
            } else {
                joinCrits = new ArrayList<Criteria>();
                joinCrits.add(crit);
                node.setProperty(NodeConstants.Info.JOIN_CRITERIA, joinCrits);
            }
        }
        convertAccessPatterns(symbolMap, node);
    } else if (type == NodeConstants.Types.SORT) {
        OrderBy orderBy = (OrderBy) node.getProperty(NodeConstants.Info.SORT_ORDER);
        ExpressionMappingVisitor.mapExpressions(orderBy, symbolMap);
        if (rewrite) {
            for (OrderByItem item : orderBy.getOrderByItems()) {
                rewriteSingleElementSymbol(metadata, item.getSymbol());
            }
        }
        if (!singleMapping) {
            GroupsUsedByElementsVisitor.getGroups(orderBy, groups);
        }
    } else if (type == NodeConstants.Types.GROUP) {
        List<Expression> groupCols = (List<Expression>) node.getProperty(NodeConstants.Info.GROUP_COLS);
        if (groupCols != null) {
            GroupBy groupBy = new GroupBy(groupCols);
            ExpressionMappingVisitor.mapExpressions(groupBy, symbolMap);
            node.setProperty(NodeConstants.Info.GROUP_COLS, groupBy.getSymbols());
            if (!singleMapping) {
                GroupsUsedByElementsVisitor.getGroups(groupBy, groups);
            }
        }
        if (!singleMapping) {
            // add back the anon group
            SymbolMap property = (SymbolMap) node.getProperty(Info.SYMBOL_MAP);
            if (!property.asMap().isEmpty()) {
                groups.add(property.asMap().keySet().iterator().next().getGroupSymbol());
            }
        }
    } else if (type == NodeConstants.Types.SOURCE || type == NodeConstants.Types.ACCESS) {
        convertAccessPatterns(symbolMap, node);
    }
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) OrderBy(org.teiid.query.sql.lang.OrderBy) GroupBy(org.teiid.query.sql.lang.GroupBy) SymbolMap(org.teiid.query.sql.util.SymbolMap) CompoundCriteria(org.teiid.query.sql.lang.CompoundCriteria) Criteria(org.teiid.query.sql.lang.Criteria) OrderByItem(org.teiid.query.sql.lang.OrderByItem) Expression(org.teiid.query.sql.symbol.Expression) CompoundCriteria(org.teiid.query.sql.lang.CompoundCriteria) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) Select(org.teiid.query.sql.lang.Select) SymbolMap(org.teiid.query.sql.util.SymbolMap) LanguageObject(org.teiid.query.sql.LanguageObject)

Example 15 with OrderBy

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

the class RuleAssignOutputElements method determineSourceOutput.

/**
 * A special case to consider is when the virtual group is defined by a
 * UNION (no ALL) or a SELECT DISTINCT.  In this case, the dup removal means
 * that all columns need to be used to determine duplicates.  So, filtering the
 * columns at all will alter the number of rows flowing through the frame.
 * So, in this case filtering should not occur.  In fact the output columns
 * that were set on root above are filtered, but we actually want all the
 * virtual elements - so just reset it and proceed as before
 * @throws TeiidComponentException
 * @throws QueryMetadataException
 * @throws QueryPlannerException
 */
static List<? extends Expression> determineSourceOutput(PlanNode root, List<Expression> outputElements, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
    PlanNode virtualRoot = root.getLastChild();
    if (hasDupRemoval(virtualRoot)) {
        // Reset the outputColumns for this source node to be all columns for the virtual group
        SymbolMap symbolMap = (SymbolMap) root.getProperty(NodeConstants.Info.SYMBOL_MAP);
        if (!symbolMap.asMap().keySet().containsAll(outputElements)) {
            outputElements.removeAll(symbolMap.asMap().keySet());
            throw new QueryPlannerException(QueryPlugin.Event.TEIID30259, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30259, outputElements));
        }
        return symbolMap.getKeys();
    }
    PlanNode limit = NodeEditor.findNodePreOrder(root, NodeConstants.Types.TUPLE_LIMIT, NodeConstants.Types.PROJECT);
    if (limit == null) {
        return outputElements;
    }
    // reset the output elements to be the output columns + what's required by the sort
    PlanNode sort = NodeEditor.findNodePreOrder(limit, NodeConstants.Types.SORT, NodeConstants.Types.PROJECT);
    if (sort == null) {
        return outputElements;
    }
    PlanNode access = NodeEditor.findParent(sort, NodeConstants.Types.ACCESS);
    if (sort.hasBooleanProperty(NodeConstants.Info.UNRELATED_SORT) || (access != null && capFinder != null && CapabilitiesUtil.supports(Capability.QUERY_ORDERBY_UNRELATED, RuleRaiseAccess.getModelIDFromAccess(access, metadata), metadata, capFinder))) {
        return outputElements;
    }
    OrderBy sortOrder = (OrderBy) sort.getProperty(NodeConstants.Info.SORT_ORDER);
    List<Expression> topCols = FrameUtil.findTopCols(sort);
    SymbolMap symbolMap = (SymbolMap) root.getProperty(NodeConstants.Info.SYMBOL_MAP);
    List<ElementSymbol> symbolOrder = symbolMap.getKeys();
    for (OrderByItem item : sortOrder.getOrderByItems()) {
        final Expression expr = item.getSymbol();
        int index = topCols.indexOf(expr);
        if (index < 0) {
            continue;
        }
        ElementSymbol symbol = symbolOrder.get(index);
        if (!outputElements.contains(symbol)) {
            outputElements.add(symbol);
        }
    }
    return outputElements;
}
Also used : OrderBy(org.teiid.query.sql.lang.OrderBy) ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) OrderByItem(org.teiid.query.sql.lang.OrderByItem) Expression(org.teiid.query.sql.symbol.Expression) SymbolMap(org.teiid.query.sql.util.SymbolMap) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException)

Aggregations

OrderBy (org.teiid.query.sql.lang.OrderBy)23 ElementSymbol (org.teiid.query.sql.symbol.ElementSymbol)15 List (java.util.List)13 ArrayList (java.util.ArrayList)12 Expression (org.teiid.query.sql.symbol.Expression)12 PlanNode (org.teiid.query.optimizer.relational.plantree.PlanNode)10 AggregateSymbol (org.teiid.query.sql.symbol.AggregateSymbol)9 OrderByItem (org.teiid.query.sql.lang.OrderByItem)7 CommandContext (org.teiid.query.util.CommandContext)7 SymbolMap (org.teiid.query.sql.util.SymbolMap)6 AliasSymbol (org.teiid.query.sql.symbol.AliasSymbol)4 ExpressionSymbol (org.teiid.query.sql.symbol.ExpressionSymbol)4 LinkedHashSet (java.util.LinkedHashSet)3 LinkedList (java.util.LinkedList)3 BufferManager (org.teiid.common.buffer.BufferManager)3 Criteria (org.teiid.query.sql.lang.Criteria)3 GroupSymbol (org.teiid.query.sql.symbol.GroupSymbol)3 BigDecimal (java.math.BigDecimal)2 HashMap (java.util.HashMap)2 HashSet (java.util.HashSet)2