Search in sources :

Example 6 with OrderByItem

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

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

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

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

use of org.teiid.query.sql.lang.OrderByItem 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)

Aggregations

OrderByItem (org.teiid.query.sql.lang.OrderByItem)13 Expression (org.teiid.query.sql.symbol.Expression)12 ElementSymbol (org.teiid.query.sql.symbol.ElementSymbol)8 List (java.util.List)7 OrderBy (org.teiid.query.sql.lang.OrderBy)7 ArrayList (java.util.ArrayList)6 PlanNode (org.teiid.query.optimizer.relational.plantree.PlanNode)5 LinkedList (java.util.LinkedList)3 GroupSymbol (org.teiid.query.sql.symbol.GroupSymbol)3 SymbolMap (org.teiid.query.sql.util.SymbolMap)3 LinkedHashSet (java.util.LinkedHashSet)2 QueryPlannerException (org.teiid.api.exception.query.QueryPlannerException)2 Criteria (org.teiid.query.sql.lang.Criteria)2 JoinType (org.teiid.query.sql.lang.JoinType)2 Select (org.teiid.query.sql.lang.Select)2 AggregateSymbol (org.teiid.query.sql.symbol.AggregateSymbol)2 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Set (java.util.Set)1 FunctionExecutionException (org.teiid.api.exception.query.FunctionExecutionException)1