Search in sources :

Example 6 with OrderBy

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

the class RuleAssignOutputElements method collectRequiredInputSymbols.

/**
 * Collect all required input symbols for a given node.  Input symbols
 * are any symbols that are required in the processing of this node,
 * for instance to create a new element symbol or sort on it, etc.
 * @param node Node to collect for
 * @param metadata
 * @param capFinder
 * @throws TeiidComponentException
 * @throws QueryMetadataException
 */
private List<Expression> collectRequiredInputSymbols(PlanNode node, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryMetadataException, TeiidComponentException {
    Set<Expression> requiredSymbols = new LinkedHashSet<Expression>();
    Set<Expression> createdSymbols = new HashSet<Expression>();
    List<Expression> outputCols = (List<Expression>) node.getProperty(NodeConstants.Info.OUTPUT_COLS);
    switch(node.getType()) {
        case NodeConstants.Types.PROJECT:
            {
                List<Expression> projectCols = (List<Expression>) node.getProperty(NodeConstants.Info.PROJECT_COLS);
                PlanNode accessParent = NodeEditor.findParent(node, NodeConstants.Types.ACCESS);
                PlanNode accessNode = null;
                if (accessParent == null) {
                    // find the direct access node
                    accessNode = NodeEditor.findNodePreOrder(node, NodeConstants.Types.ACCESS, NodeConstants.Types.SOURCE | NodeConstants.Types.JOIN | NodeConstants.Types.SET_OP | NodeConstants.Types.GROUP);
                }
                for (Expression ss : projectCols) {
                    if (ss instanceof AliasSymbol) {
                        createdSymbols.add(ss);
                        ss = ((AliasSymbol) ss).getSymbol();
                    }
                    if (ss instanceof WindowFunction || ss instanceof ExpressionSymbol) {
                        createdSymbols.add(ss);
                    }
                    if (!pushProjection(node, metadata, capFinder, requiredSymbols, accessParent, accessNode, ss)) {
                        ElementCollectorVisitor.getElements(ss, requiredSymbols);
                    }
                }
                break;
            }
        case NodeConstants.Types.SELECT:
            Criteria selectCriteria = (Criteria) node.getProperty(NodeConstants.Info.SELECT_CRITERIA);
            ElementCollectorVisitor.getElements(selectCriteria, requiredSymbols);
            break;
        case NodeConstants.Types.JOIN:
            List<Criteria> crits = (List) node.getProperty(NodeConstants.Info.JOIN_CRITERIA);
            if (crits != null) {
                for (Criteria joinCriteria : crits) {
                    ElementCollectorVisitor.getElements(joinCriteria, requiredSymbols);
                }
            }
            break;
        case NodeConstants.Types.GROUP:
            List<Expression> groupCols = (List<Expression>) node.getProperty(NodeConstants.Info.GROUP_COLS);
            PlanNode accessParent = NodeEditor.findParent(node, NodeConstants.Types.ACCESS);
            PlanNode accessNode = null;
            if (accessParent == null) {
                // find the direct access node
                accessNode = NodeEditor.findNodePreOrder(node.getFirstChild(), NodeConstants.Types.ACCESS, NodeConstants.Types.SOURCE | NodeConstants.Types.JOIN | NodeConstants.Types.SET_OP | NodeConstants.Types.GROUP);
            }
            if (groupCols != null) {
                for (Expression expression : groupCols) {
                    if (!pushProjection(node, metadata, capFinder, requiredSymbols, accessParent, accessNode, expression)) {
                        ElementCollectorVisitor.getElements(expression, requiredSymbols);
                    }
                }
            }
            SymbolMap symbolMap = (SymbolMap) node.getProperty(NodeConstants.Info.SYMBOL_MAP);
            Set<ElementSymbol> usedAggregates = new HashSet<ElementSymbol>();
            // Take credit for creating any aggregates that are needed above
            for (Expression outputSymbol : outputCols) {
                if (!(outputSymbol instanceof ElementSymbol)) {
                    continue;
                }
                createdSymbols.add(outputSymbol);
                Expression ex = symbolMap.getMappedExpression((ElementSymbol) outputSymbol);
                if (ex instanceof AggregateSymbol) {
                    AggregateSymbol agg = (AggregateSymbol) ex;
                    Expression[] aggExprs = agg.getArgs();
                    for (Expression expression : aggExprs) {
                        if (!pushProjection(node, metadata, capFinder, requiredSymbols, accessParent, accessNode, expression)) {
                            ElementCollectorVisitor.getElements(expression, requiredSymbols);
                        }
                    }
                    OrderBy orderBy = agg.getOrderBy();
                    if (orderBy != null) {
                        ElementCollectorVisitor.getElements(orderBy, requiredSymbols);
                    }
                    Expression condition = agg.getCondition();
                    if (condition != null) {
                        ElementCollectorVisitor.getElements(condition, requiredSymbols);
                    }
                    usedAggregates.add((ElementSymbol) outputSymbol);
                }
            }
            // update the aggs in the symbolmap
            for (Map.Entry<ElementSymbol, Expression> entry : new ArrayList<Map.Entry<ElementSymbol, Expression>>(symbolMap.asMap().entrySet())) {
                if (entry.getValue() instanceof AggregateSymbol && !usedAggregates.contains(entry.getKey())) {
                    symbolMap.asUpdatableMap().remove(entry.getKey());
                }
            }
            if (requiredSymbols.isEmpty() && usedAggregates.isEmpty()) {
                node.setProperty(Info.IS_OPTIONAL, true);
            }
            break;
    }
    // Gather elements from correlated subquery references;
    for (SymbolMap refs : node.getAllReferences()) {
        for (Expression expr : refs.asMap().values()) {
            ElementCollectorVisitor.getElements(expr, requiredSymbols);
        }
    }
    // Add any columns to required that are in this node's output but were not created here
    for (Expression currentOutputSymbol : outputCols) {
        if (!createdSymbols.contains(currentOutputSymbol) && (finalRun || node.getType() != NodeConstants.Types.PROJECT || currentOutputSymbol instanceof ElementSymbol)) {
            requiredSymbols.add(currentOutputSymbol);
        }
    }
    // TODO: this should depend upon whether the expressions are deterministic
    if (node.getType() == NodeConstants.Types.PROJECT) {
        Set<Expression> expressions = new HashSet<Expression>();
        for (Iterator<Expression> iterator = requiredSymbols.iterator(); iterator.hasNext(); ) {
            Expression ses = iterator.next();
            if (!expressions.add(SymbolMap.getExpression(ses))) {
                iterator.remove();
            }
        }
    }
    return new ArrayList<Expression>(requiredSymbols);
}
Also used : LinkedHashSet(java.util.LinkedHashSet) ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) OrderBy(org.teiid.query.sql.lang.OrderBy) AggregateSymbol(org.teiid.query.sql.symbol.AggregateSymbol) ArrayList(java.util.ArrayList) SymbolMap(org.teiid.query.sql.util.SymbolMap) ExpressionSymbol(org.teiid.query.sql.symbol.ExpressionSymbol) Criteria(org.teiid.query.sql.lang.Criteria) WindowFunction(org.teiid.query.sql.symbol.WindowFunction) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) AliasSymbol(org.teiid.query.sql.symbol.AliasSymbol) Expression(org.teiid.query.sql.symbol.Expression) List(java.util.List) ArrayList(java.util.ArrayList) Map(java.util.Map) SymbolMap(org.teiid.query.sql.util.SymbolMap) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 7 with OrderBy

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

the class RuleAssignOutputElements method assignOutputElements.

/**
 * <p>Assign the output elements at a particular node and recurse the tree.  The
 * outputElements needed from above the node have been collected in
 * outputElements.</p>
 *
 * <p>SOURCE nodes:  If we find a SOURCE node, this must define the top
 * of a virtual group.  Physical groups can be identified by ACCESS nodes
 * at this point in the planning stage.  So, we filter the virtual elements
 * in the virtual source based on the required output elements.</p>
 *
 * <p>SET_OP nodes:  If we hit a SET_OP node, this must be a union.  Unions
 * require a lot of special care.  Unions have many branches and the projected
 * elements in each branch are "equivalent" in terms of nodes above the union.
 * This means that any filtering must occur in an identical way in all branches
 * of a union.</p>
 *
 * @param root Node to assign
 * @param outputElements Output elements needed for this node
 * @param metadata Metadata implementation
 */
private void assignOutputElements(PlanNode root, List<Expression> outputElements, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, RuleStack rules, AnalysisRecord analysisRecord, CommandContext context) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
    int nodeType = root.getType();
    // Update this node's output columns based on parent's columns
    List<Expression> oldOutput = (List<Expression>) root.setProperty(NodeConstants.Info.OUTPUT_COLS, outputElements);
    if (root.getChildCount() == 0) {
        // update temp access
        if (root.getType() == NodeConstants.Types.SOURCE && root.getGroups().size() == 1) {
            GroupSymbol gs = root.getGroups().iterator().next();
            if (gs.getMetadataID() instanceof TempMetadataID) {
                for (Expression ex : outputElements) {
                    if (ex instanceof ElementSymbol) {
                        Object id = ((ElementSymbol) ex).getMetadataID();
                        if (id instanceof TempMetadataID) {
                            ((TempMetadataID) id).setAccessed(true);
                        }
                    }
                }
            }
        }
        return;
    }
    switch(nodeType) {
        case NodeConstants.Types.ACCESS:
            Command command = FrameUtil.getNonQueryCommand(root);
            if (command instanceof StoredProcedure) {
                // if the access node represents a stored procedure, then we can't actually change the output symbols
                root.setProperty(NodeConstants.Info.OUTPUT_COLS, command.getProjectedSymbols());
            } else {
                ProcessorPlan plan = FrameUtil.getNestedPlan(root);
                if (plan != null && (command == null || !RelationalNodeUtil.isUpdate(command))) {
                    // nested with clauses are handled as sub plans, which have a fixed set of output symbols
                    root.setProperty(NodeConstants.Info.OUTPUT_COLS, ResolverUtil.resolveElementsInGroup(root.getGroups().iterator().next(), metadata));
                }
                if (checkSymbols) {
                    Object modelId = RuleRaiseAccess.getModelIDFromAccess(root, metadata);
                    for (Expression symbol : outputElements) {
                        if (!RuleRaiseAccess.canPushSymbol(symbol, true, modelId, metadata, capFinder, analysisRecord)) {
                            throw new QueryPlannerException(QueryPlugin.Event.TEIID30258, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30258, symbol, modelId));
                        }
                    }
                }
                if (NodeEditor.findParent(root, NodeConstants.Types.PROJECT, NodeConstants.Types.SOURCE) != null) {
                    // there's a chance that partial projection was used.  we are not a defacto project node
                    // take credit for creating anything that is not an element symbol
                    LinkedHashSet<Expression> filteredElements = new LinkedHashSet<Expression>();
                    for (Expression element : outputElements) {
                        if (element instanceof ElementSymbol) {
                            filteredElements.add(element);
                        } else {
                            filteredElements.addAll(ElementCollectorVisitor.getElements(element, false));
                        }
                    }
                    outputElements = new ArrayList<Expression>(filteredElements);
                }
            }
            assignOutputElements(root.getLastChild(), outputElements, metadata, capFinder, rules, analysisRecord, context);
            break;
        case NodeConstants.Types.DUP_REMOVE:
            // targeted optimization based upon swapping the dup remove for a limit 1
            // TODO: may need to also check for grouping over constants
            boolean allConstants = true;
            for (Expression ex : outputElements) {
                if (!(EvaluatableVisitor.willBecomeConstant(SymbolMap.getExpression(ex)))) {
                    allConstants = false;
                    break;
                }
            }
            if (allConstants && addLimit(rules, root, metadata, capFinder)) {
                // TODO we could more gracefully handle the !addLimit case
                PlanNode parent = root.getParent();
                if (parent != null) {
                    NodeEditor.removeChildNode(root.getParent(), root);
                    execute(parent, metadata, capFinder, rules, analysisRecord, context);
                    return;
                }
            }
        case NodeConstants.Types.SORT:
            // correct expression positions and update the unrelated flag
            OrderBy order = (OrderBy) root.getProperty(NodeConstants.Info.SORT_ORDER);
            if (order != null && (oldOutput == null || !oldOutput.equals(outputElements))) {
                outputElements = new ArrayList<Expression>(outputElements);
                boolean hasUnrelated = false;
                for (OrderByItem item : order.getOrderByItems()) {
                    int index = outputElements.indexOf(item.getSymbol());
                    if (index != -1) {
                        item.setExpressionPosition(index);
                    } else {
                        hasUnrelated = true;
                        outputElements.add(item.getSymbol());
                    }
                }
                if (!hasUnrelated) {
                    root.setProperty(NodeConstants.Info.UNRELATED_SORT, false);
                } else {
                    root.setProperty(NodeConstants.Info.UNRELATED_SORT, true);
                }
            }
            assignOutputElements(root.getLastChild(), outputElements, metadata, capFinder, rules, analysisRecord, context);
            break;
        case NodeConstants.Types.TUPLE_LIMIT:
            assignOutputElements(root.getLastChild(), outputElements, metadata, capFinder, rules, analysisRecord, context);
            break;
        case NodeConstants.Types.SOURCE:
            {
                outputElements = (List<Expression>) determineSourceOutput(root, outputElements, metadata, capFinder);
                if (!finalRun && root.getProperty(Info.PARTITION_INFO) != null && NodeEditor.findParent(root, NodeConstants.Types.JOIN) != null) {
                    GroupSymbol group = root.getGroups().iterator().next();
                    Object modelId = RuleDecomposeJoin.getEffectiveModelId(metadata, group);
                    String name = metadata.getExtensionProperty(modelId, RuleDecomposeJoin.IMPLICIT_PARTITION_COLUMN_NAME, true);
                    if (name != null) {
                        // keep projecting the implicit partitioning column through the source so that it can
                        // be used in the decomposition logic
                        ElementSymbol es = new ElementSymbol(name, group);
                        if (!outputElements.contains(es)) {
                            es.setMetadataID(metadata.getElementID(es.getName()));
                            outputElements.add(es);
                        }
                    }
                }
                root.setProperty(NodeConstants.Info.OUTPUT_COLS, outputElements);
                List<Expression> childElements = filterVirtualElements(root, outputElements, metadata);
                assignOutputElements(root.getFirstChild(), childElements, metadata, capFinder, rules, analysisRecord, context);
                break;
            }
        case NodeConstants.Types.SET_OP:
            {
                for (PlanNode childNode : root.getChildren()) {
                    PlanNode projectNode = NodeEditor.findNodePreOrder(childNode, NodeConstants.Types.PROJECT);
                    List<Expression> projectCols = (List<Expression>) projectNode.getProperty(NodeConstants.Info.PROJECT_COLS);
                    assignOutputElements(childNode, projectCols, metadata, capFinder, rules, analysisRecord, context);
                }
                break;
            }
        default:
            {
                PlanNode sortNode = null;
                if (root.getType() == NodeConstants.Types.PROJECT) {
                    GroupSymbol intoGroup = (GroupSymbol) root.getProperty(NodeConstants.Info.INTO_GROUP);
                    if (intoGroup != null) {
                        // if this is a project into, treat the nodes under the source as a new plan root
                        PlanNode intoRoot = NodeEditor.findNodePreOrder(root, NodeConstants.Types.SOURCE);
                        execute(intoRoot.getFirstChild(), metadata, capFinder, rules, analysisRecord, context);
                        return;
                    }
                    List<Expression> projectCols = outputElements;
                    sortNode = NodeEditor.findParent(root, NodeConstants.Types.SORT, NodeConstants.Types.SOURCE);
                    if (finalRun && sortNode != null && sortNode.hasBooleanProperty(NodeConstants.Info.UNRELATED_SORT)) {
                        root.getGroups().clear();
                        root.addGroups(GroupsUsedByElementsVisitor.getGroups(projectCols));
                        root.addGroups(GroupsUsedByElementsVisitor.getGroups(root.getCorrelatedReferenceElements()));
                    }
                    root.setProperty(NodeConstants.Info.PROJECT_COLS, projectCols);
                    if (root.hasBooleanProperty(Info.HAS_WINDOW_FUNCTIONS)) {
                        Set<WindowFunction> windowFunctions = getWindowFunctions(projectCols);
                        if (windowFunctions.isEmpty()) {
                            root.setProperty(Info.HAS_WINDOW_FUNCTIONS, false);
                        }
                    }
                }
                List<Expression> requiredInput = collectRequiredInputSymbols(root, metadata, capFinder);
                // targeted optimization for unnecessary aggregation
                if (root.getType() == NodeConstants.Types.GROUP && root.hasBooleanProperty(Info.IS_OPTIONAL) && NodeEditor.findParent(root, NodeConstants.Types.ACCESS) == null) {
                    PlanNode parent = removeGroupBy(root, metadata);
                    if (!root.hasCollectionProperty(Info.GROUP_COLS)) {
                        // just lob off everything under the projection
                        PlanNode project = NodeEditor.findNodePreOrder(parent, NodeConstants.Types.PROJECT);
                        project.removeAllChildren();
                    } else if (!addLimit(rules, parent, metadata, capFinder)) {
                        // $NON-NLS-1$
                        throw new AssertionError("expected limit node to be added");
                    }
                    execute(parent, metadata, capFinder, rules, analysisRecord, context);
                    return;
                }
                // Call children recursively
                if (root.getChildCount() == 1) {
                    assignOutputElements(root.getLastChild(), requiredInput, metadata, capFinder, rules, analysisRecord, context);
                    if (!finalRun && root.getType() == NodeConstants.Types.PROJECT && sortNode != null && sortNode.hasBooleanProperty(NodeConstants.Info.UNRELATED_SORT)) {
                        // if this is the initial rule run, remove unrelated order to preserve the original projection
                        OrderBy elements = (OrderBy) sortNode.getProperty(NodeConstants.Info.SORT_ORDER);
                        outputElements = new ArrayList<Expression>(outputElements);
                        for (OrderByItem item : elements.getOrderByItems()) {
                            if (item.getExpressionPosition() == -1) {
                                outputElements.remove(item.getSymbol());
                            }
                        }
                        root.setProperty(NodeConstants.Info.PROJECT_COLS, outputElements);
                    }
                } else {
                    // determine which elements go to each side of the join
                    for (PlanNode childNode : root.getChildren()) {
                        Set<GroupSymbol> filterGroups = FrameUtil.findJoinSourceNode(childNode).getGroups();
                        List<Expression> filteredElements = filterElements(requiredInput, filterGroups);
                        // Call child recursively
                        assignOutputElements(childNode, filteredElements, metadata, capFinder, rules, analysisRecord, context);
                    }
                }
            }
    }
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) LinkedHashSet(java.util.LinkedHashSet) OrderBy(org.teiid.query.sql.lang.OrderBy) Set(java.util.Set) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) TempMetadataID(org.teiid.query.metadata.TempMetadataID) ArrayList(java.util.ArrayList) StoredProcedure(org.teiid.query.sql.lang.StoredProcedure) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) OrderByItem(org.teiid.query.sql.lang.OrderByItem) Expression(org.teiid.query.sql.symbol.Expression) Command(org.teiid.query.sql.lang.Command) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) List(java.util.List) ArrayList(java.util.ArrayList) ProcessorPlan(org.teiid.query.processor.ProcessorPlan) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException)

Example 8 with OrderBy

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

the class RuleMergeVirtual method correctOrderBy.

/**
 * special handling is needed since we are retaining the child aliases
 */
private static void correctOrderBy(PlanNode frame, PlanNode sort, List<Expression> selectSymbols, PlanNode parentProject) {
    if (sort == null || NodeEditor.findNodePreOrder(sort, NodeConstants.Types.PROJECT, NodeConstants.Types.SOURCE) != parentProject) {
        return;
    }
    List<Expression> childProject = (List<Expression>) NodeEditor.findNodePreOrder(frame, NodeConstants.Types.PROJECT).getProperty(NodeConstants.Info.PROJECT_COLS);
    OrderBy elements = (OrderBy) sort.getProperty(NodeConstants.Info.SORT_ORDER);
    for (OrderByItem item : elements.getOrderByItems()) {
        item.setSymbol(childProject.get(selectSymbols.indexOf(item.getSymbol())));
    }
    sort.getGroups().clear();
    sort.addGroups(GroupsUsedByElementsVisitor.getGroups(elements));
}
Also used : OrderBy(org.teiid.query.sql.lang.OrderBy) OrderByItem(org.teiid.query.sql.lang.OrderByItem) Expression(org.teiid.query.sql.symbol.Expression) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) List(java.util.List)

Example 9 with OrderBy

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

the class RulePlanSorts method checkForProjectOptimization.

static PlanNode checkForProjectOptimization(PlanNode node, PlanNode root, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord record, CommandContext context) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
    PlanNode projectNode = node.getFirstChild();
    PlanNode parent = node.getParent();
    boolean raiseAccess = false;
    // special check for unrelated order by compensation
    if (projectNode.getType() == NodeConstants.Types.ACCESS && RuleRaiseAccess.canRaiseOverSort(projectNode, metadata, capFinder, node, record, true, context)) {
        projectNode = NodeEditor.findNodePreOrder(projectNode, NodeConstants.Types.PROJECT, NodeConstants.Types.SOURCE | NodeConstants.Types.SET_OP);
        if (projectNode == null) {
            // no interviening project
            return root;
        }
        raiseAccess = true;
    } else if (projectNode.getType() == NodeConstants.Types.PROJECT && projectNode.getFirstChild() != null) {
        raiseAccess = projectNode.getFirstChild().getType() == NodeConstants.Types.ACCESS && RuleRaiseAccess.canRaiseOverSort(projectNode.getFirstChild(), metadata, capFinder, node, record, false, context);
        // if we can't raise the access node and this doesn't have a limit, there's no point in optimizing
        if (!raiseAccess && (parent == null || parent.getType() != NodeConstants.Types.TUPLE_LIMIT)) {
            return root;
        }
    } else {
        return root;
    }
    List<Expression> childOutputCols = (List<Expression>) projectNode.getFirstChild().getProperty(Info.OUTPUT_COLS);
    OrderBy orderBy = (OrderBy) node.getProperty(Info.SORT_ORDER);
    List<Expression> orderByKeys = orderBy.getSortKeys();
    LinkedHashSet<Expression> toProject = new LinkedHashSet();
    for (Expression ss : orderByKeys) {
        Expression original = ss;
        if (ss instanceof AliasSymbol) {
            ss = ((AliasSymbol) ss).getSymbol();
        }
        if (ss instanceof ExpressionSymbol) {
            if (!raiseAccess) {
                // TODO: insert a new project node to handle this case
                return root;
            }
        }
        if (!childOutputCols.contains(ss)) {
            if (!raiseAccess) {
                return root;
            }
            toProject.add(original);
        }
    }
    PlanNode toRepair = projectNode.getParent();
    if (!toProject.isEmpty()) {
        PlanNode intermediateProject = NodeFactory.getNewNode(NodeConstants.Types.PROJECT);
        toProject.addAll(childOutputCols);
        List<Expression> projectCols = new ArrayList<Expression>(toProject);
        childOutputCols = projectCols;
        intermediateProject.setProperty(NodeConstants.Info.PROJECT_COLS, projectCols);
        intermediateProject.setProperty(NodeConstants.Info.OUTPUT_COLS, new ArrayList<Expression>(projectCols));
        toRepair.getFirstChild().addAsParent(intermediateProject);
    }
    NodeEditor.removeChildNode(projectNode.getParent(), projectNode);
    if (parent != null && parent.getType() == NodeConstants.Types.TUPLE_LIMIT && parent.getParent() != null) {
        parent.addAsParent(projectNode);
    } else {
        if (parent == null) {
            root = projectNode;
        }
        if (parent != null && parent.getType() == NodeConstants.Types.TUPLE_LIMIT) {
            if (root == parent) {
                root = projectNode;
            }
            projectNode.addFirstChild(parent);
        } else {
            projectNode.addFirstChild(node);
        }
    }
    List<Expression> orderByOutputSymbols = (List<Expression>) node.getProperty(Info.OUTPUT_COLS);
    boolean unrelated = false;
    if (node.hasBooleanProperty(Info.UNRELATED_SORT)) {
        node.setProperty(Info.UNRELATED_SORT, false);
        unrelated = true;
    }
    for (OrderByItem item : orderBy.getOrderByItems()) {
        if (unrelated || !toProject.isEmpty()) {
            // update sort order
            int index = childOutputCols.indexOf(item.getSymbol());
            item.setExpressionPosition(index);
        }
        if (toProject.isEmpty()) {
            // strip alias as project was raised
            if (item.getSymbol() instanceof AliasSymbol) {
                item.setSymbol(((AliasSymbol) item.getSymbol()).getSymbol());
            }
        }
    }
    while (toRepair != node) {
        toRepair.setProperty(Info.OUTPUT_COLS, childOutputCols);
        toRepair = toRepair.getParent();
    }
    projectNode.setProperty(Info.OUTPUT_COLS, orderByOutputSymbols);
    projectNode.setProperty(Info.PROJECT_COLS, orderByOutputSymbols);
    node.setProperty(Info.OUTPUT_COLS, childOutputCols);
    if (parent != null) {
        parent.setProperty(Info.OUTPUT_COLS, childOutputCols);
    }
    if (raiseAccess) {
        PlanNode accessNode = NodeEditor.findNodePreOrder(node, NodeConstants.Types.ACCESS);
        // instead of just calling ruleraiseaccess, we're more selective
        // we do not want to raise the access node over a project that is handling an unrelated sort
        PlanNode newRoot = RuleRaiseAccess.raiseAccessNode(root, accessNode, metadata, capFinder, true, record, context);
        if (newRoot != null) {
            accessNode.setProperty(NodeConstants.Info.OUTPUT_COLS, childOutputCols);
            root = newRoot;
            if (!toProject.isEmpty()) {
                newRoot = RuleRaiseAccess.raiseAccessNode(root, accessNode, metadata, capFinder, true, record, context);
            }
            if (newRoot != null) {
                root = newRoot;
                if (accessNode.getParent().getType() == NodeConstants.Types.TUPLE_LIMIT) {
                    newRoot = RulePushLimit.raiseAccessOverLimit(root, accessNode, metadata, capFinder, accessNode.getParent(), record);
                }
                if (newRoot != null) {
                    root = newRoot;
                }
            }
        }
    }
    return root;
}
Also used : OrderBy(org.teiid.query.sql.lang.OrderBy) LinkedHashSet(java.util.LinkedHashSet) ArrayList(java.util.ArrayList) ExpressionSymbol(org.teiid.query.sql.symbol.ExpressionSymbol) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) AliasSymbol(org.teiid.query.sql.symbol.AliasSymbol) OrderByItem(org.teiid.query.sql.lang.OrderByItem) Expression(org.teiid.query.sql.symbol.Expression) ArrayList(java.util.ArrayList) List(java.util.List)

Example 10 with OrderBy

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

the class RulePushAggregates method addUnionGroupBy.

private void addUnionGroupBy(List<Expression> groupingExpressions, LinkedHashSet<AggregateSymbol> aggregates, SymbolMap parentMap, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, GroupSymbol group, boolean first, PlanNode planNode, boolean viewOnly, boolean partitioned) throws QueryMetadataException, TeiidComponentException, QueryPlannerException, QueryResolverException {
    List<Expression> groupingColumns = LanguageObject.Util.deepClone(groupingExpressions, Expression.class);
    // branches other than the first need to have their projected column names updated
    if (!first) {
        PlanNode sortNode = NodeEditor.findNodePreOrder(planNode, NodeConstants.Types.SORT, NodeConstants.Types.SOURCE);
        List<Expression> sortOrder = null;
        OrderBy orderBy = null;
        if (sortNode != null) {
            orderBy = (OrderBy) sortNode.getProperty(Info.SORT_ORDER);
            sortOrder = orderBy.getSortKeys();
        }
        List<Expression> projectCols = FrameUtil.findTopCols(planNode);
        List<ElementSymbol> virtualElements = parentMap.getKeys();
        for (int i = 0; i < virtualElements.size(); i++) {
            ElementSymbol virtualElem = virtualElements.get(i);
            Expression projectedSymbol = projectCols.get(i);
            if (!Symbol.getShortName(projectedSymbol).equals(Symbol.getShortName(virtualElem))) {
                if (sortOrder != null) {
                    int sortIndex = sortOrder.indexOf(projectedSymbol);
                    if (sortIndex > -1) {
                        updateSymbolName(sortOrder, sortIndex, virtualElem, sortOrder.get(sortIndex));
                        orderBy.getOrderByItems().get(sortIndex).setSymbol(sortOrder.get(sortIndex));
                    }
                }
                updateSymbolName(projectCols, i, virtualElem, projectedSymbol);
            }
        }
    }
    PlanNode view = RuleDecomposeJoin.createSource(group, planNode, parentMap);
    PlanNode projectPlanNode = NodeFactory.getNewNode(NodeConstants.Types.PROJECT);
    Select allSymbols = new Select();
    for (Expression expr : groupingColumns) {
        // $NON-NLS-1$
        allSymbols.addSymbol(new ExpressionSymbol("expr", expr));
    }
    if (viewOnly) {
        for (AggregateSymbol agg : aggregates) {
            agg = (AggregateSymbol) agg.clone();
            if (agg.getAggregateFunction() == Type.COUNT) {
                if (isCountStar(agg)) {
                    // $NON-NLS-1$
                    allSymbols.addSymbol(new ExpressionSymbol("stagedAgg", new Constant(1)));
                } else {
                    SearchedCaseExpression count = new SearchedCaseExpression(Arrays.asList(new IsNullCriteria(agg.getArg(0))), Arrays.asList(new Constant(Integer.valueOf(0))));
                    count.setElseExpression(new Constant(Integer.valueOf(1)));
                    count.setType(DataTypeManager.DefaultDataClasses.INTEGER);
                    // $NON-NLS-1$
                    allSymbols.addSymbol(new ExpressionSymbol("stagedAgg", count));
                }
            } else {
                // prior canStage should ensure this is true
                assert agg.getArgs().length == 1;
                Expression ex = agg.getArg(0);
                ex = ResolverUtil.convertExpression(ex, DataTypeManager.getDataTypeName(agg.getType()), metadata);
                // $NON-NLS-1$
                allSymbols.addSymbol(new ExpressionSymbol("stagedAgg", ex));
            }
        }
    } else {
        allSymbols.addSymbols(aggregates);
    }
    if (first) {
        QueryRewriter.makeSelectUnique(allSymbols, false);
    }
    projectPlanNode.setProperty(NodeConstants.Info.PROJECT_COLS, allSymbols.getSymbols());
    projectPlanNode.addGroups(view.getGroups());
    view.addAsParent(projectPlanNode);
    if (!viewOnly) {
        addGroupBy(view, groupingColumns, aggregates, metadata, projectPlanNode.getParent(), capFinder, true, groupingColumns.isEmpty() && (partitioned || containsNullDependent(aggregates)));
    }
}
Also used : OrderBy(org.teiid.query.sql.lang.OrderBy) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) Select(org.teiid.query.sql.lang.Select) IsNullCriteria(org.teiid.query.sql.lang.IsNullCriteria)

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