Search in sources :

Example 1 with OrderByItem

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

the class AccessNode method minimizeProject.

public void minimizeProject(Command atomicCommand) {
    if (!(atomicCommand instanceof Query)) {
        return;
    }
    Query query = (Query) atomicCommand;
    Select select = query.getSelect();
    List<Expression> symbols = select.getSymbols();
    if (symbols.size() == 1) {
        return;
    }
    boolean shouldProject = false;
    LinkedHashMap<Expression, Integer> uniqueSymbols = new LinkedHashMap<Expression, Integer>();
    projection = new Object[symbols.size()];
    this.originalSelect = new ArrayList<Expression>(query.getSelect().getSymbols());
    int i = 0;
    int j = 0;
    for (Iterator<Expression> iter = symbols.iterator(); iter.hasNext(); ) {
        Expression ss = iter.next();
        Expression ex = SymbolMap.getExpression(ss);
        if (ex instanceof Constant) {
            projection[i] = ex;
            if (iter.hasNext() || j != 0) {
                iter.remove();
                shouldProject = true;
            } else {
                projection[i] = j++;
            }
        } else {
            Integer index = uniqueSymbols.get(ex);
            if (index == null) {
                uniqueSymbols.put(ex, j);
                index = j++;
            } else {
                iter.remove();
                shouldProject = true;
            }
            projection[i] = index;
        }
        i++;
    }
    if (!shouldProject) {
        this.projection = NO_PROJECTION;
    } else if (query.getOrderBy() != null) {
        for (OrderByItem item : query.getOrderBy().getOrderByItems()) {
            Integer index = uniqueSymbols.get(SymbolMap.getExpression(item.getSymbol()));
            if (index != null) {
                item.setExpressionPosition(index);
                item.setSymbol(select.getSymbols().get(index));
            }
        }
    }
}
Also used : Query(org.teiid.query.sql.lang.Query) Constant(org.teiid.query.sql.symbol.Constant) OrderByItem(org.teiid.query.sql.lang.OrderByItem) Expression(org.teiid.query.sql.symbol.Expression) Select(org.teiid.query.sql.lang.Select)

Example 2 with OrderByItem

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

the class GroupingNode method initAccumulator.

static AggregateFunction initAccumulator(AggregateSymbol aggSymbol, RelationalNode node, LinkedHashMap<Expression, Integer> expressionIndexes) {
    int[] argIndexes = new int[aggSymbol.getArgs().length];
    AggregateFunction result = null;
    Expression[] args = aggSymbol.getArgs();
    Class<?>[] inputTypes = new Class[args.length];
    for (int j = 0; j < args.length; j++) {
        inputTypes[j] = args[j].getType();
        argIndexes[j] = getIndex(args[j], expressionIndexes);
    }
    Type function = aggSymbol.getAggregateFunction();
    switch(function) {
        case RANK:
        case DENSE_RANK:
            result = new RankingFunction(function);
            break;
        // same as count(*)
        case ROW_NUMBER:
        case COUNT:
            result = new Count();
            break;
        case SUM:
            result = new Sum();
            break;
        case AVG:
            result = new Avg();
            break;
        case MIN:
            result = new Min();
            break;
        case MAX:
            result = new Max();
            break;
        case XMLAGG:
            result = new XMLAgg();
            break;
        case ARRAY_AGG:
            result = new ArrayAgg();
            break;
        case JSONARRAY_AGG:
            result = new JSONArrayAgg();
            break;
        case TEXTAGG:
            result = new TextAgg((TextLine) args[0]);
            break;
        case STRING_AGG:
            result = new StringAgg(aggSymbol.getType() == DataTypeManager.DefaultDataClasses.BLOB);
            break;
        case FIRST_VALUE:
            result = new FirstLastValue(aggSymbol.getType(), true);
            break;
        case LAST_VALUE:
            result = new FirstLastValue(aggSymbol.getType(), false);
            break;
        case LEAD:
        case LAG:
            result = new LeadLagValue();
            break;
        case USER_DEFINED:
            try {
                result = new UserDefined(aggSymbol.getFunctionDescriptor());
            } catch (FunctionExecutionException e) {
                throw new TeiidRuntimeException(e);
            }
            break;
        default:
            result = new StatsFunction(function);
    }
    if (aggSymbol.getOrderBy() != null) {
        int numOrderByItems = aggSymbol.getOrderBy().getOrderByItems().size();
        List<OrderByItem> orderByItems = new ArrayList<OrderByItem>(numOrderByItems);
        List<ElementSymbol> schema = createSortSchema(result, inputTypes);
        argIndexes = Arrays.copyOf(argIndexes, argIndexes.length + numOrderByItems);
        for (ListIterator<OrderByItem> iterator = aggSymbol.getOrderBy().getOrderByItems().listIterator(); iterator.hasNext(); ) {
            OrderByItem item = iterator.next();
            argIndexes[args.length + iterator.previousIndex()] = getIndex(item.getSymbol(), expressionIndexes);
            ElementSymbol element = new ElementSymbol(String.valueOf(iterator.previousIndex()));
            element.setType(item.getSymbol().getType());
            schema.add(element);
            OrderByItem newItem = item.clone();
            newItem.setSymbol(element);
            orderByItems.add(newItem);
        }
        SortingFilter filter = new SortingFilter(result, node.getBufferManager(), node.getConnectionID(), aggSymbol.isDistinct());
        filter.setElements(schema);
        filter.setSortItems(orderByItems);
        result = filter;
    } else if (aggSymbol.isDistinct()) {
        SortingFilter filter = new SortingFilter(result, node.getBufferManager(), node.getConnectionID(), true);
        List<ElementSymbol> elements = createSortSchema(result, inputTypes);
        filter.setElements(elements);
        result = filter;
    }
    result.setArgIndexes(argIndexes);
    if (aggSymbol.getCondition() != null) {
        result.setConditionIndex(getIndex(aggSymbol.getCondition(), expressionIndexes));
    }
    result.initialize(aggSymbol.getType(), inputTypes);
    return result;
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) ArrayList(java.util.ArrayList) TeiidRuntimeException(org.teiid.core.TeiidRuntimeException) FunctionExecutionException(org.teiid.api.exception.query.FunctionExecutionException) OrderByItem(org.teiid.query.sql.lang.OrderByItem) ArrayList(java.util.ArrayList) List(java.util.List) TextLine(org.teiid.query.sql.symbol.TextLine) Type(org.teiid.query.sql.symbol.AggregateSymbol.Type) Expression(org.teiid.query.sql.symbol.Expression)

Example 3 with OrderByItem

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

the class GroupingNode method initialize.

@Override
public void initialize(CommandContext context, BufferManager bufferManager, ProcessorDataManager dataMgr) {
    super.initialize(context, bufferManager, dataMgr);
    if (this.functions != null) {
        return;
    }
    // Incoming elements and lookup map for evaluating expressions
    List<? extends Expression> sourceElements = this.getChildren()[0].getElements();
    this.elementMap = createLookupMap(sourceElements);
    this.collectedExpressions = new LinkedHashMap<Expression, Integer>();
    // List should contain all grouping columns / expressions as we need those for sorting
    if (this.orderBy != null) {
        for (OrderByItem item : this.orderBy) {
            Expression ex = SymbolMap.getExpression(item.getSymbol());
            getIndex(ex, this.collectedExpressions);
        }
        if (removeDuplicates) {
            for (Expression ses : sourceElements) {
                getIndex(ses, collectedExpressions);
            }
            distinctCols = collectedExpressions.size();
        }
    }
    // Construct aggregate function state accumulators
    functions = new AggregateFunction[getElements().size()][];
    for (int i = 0; i < getElements().size(); i++) {
        Expression symbol = getElements().get(i);
        if (this.outputMapping != null) {
            symbol = outputMapping.getMappedExpression((ElementSymbol) symbol);
        }
        Class<?> outputType = symbol.getType();
        if (symbol instanceof AggregateSymbol) {
            AggregateSymbol aggSymbol = (AggregateSymbol) symbol;
            functions[i] = new AggregateFunction[rollup ? orderBy.size() + 1 : 1];
            for (int j = 0; j < functions[i].length; j++) {
                functions[i][j] = initAccumulator(aggSymbol, this, this.collectedExpressions);
            }
        } else {
            AggregateFunction af = new ConstantFunction();
            af.setArgIndexes(new int[] { this.collectedExpressions.get(symbol) });
            af.initialize(outputType, new Class<?>[] { symbol.getType() });
            functions[i] = new AggregateFunction[] { af };
        }
    }
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) AggregateSymbol(org.teiid.query.sql.symbol.AggregateSymbol) OrderByItem(org.teiid.query.sql.lang.OrderByItem) Expression(org.teiid.query.sql.symbol.Expression)

Example 4 with OrderByItem

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

the class BaseIndexInfo method useIndexForOrderBy.

/**
 * Return a non-null direction if the index can be used, otherwise null.
 * @param orderBy
 * @return
 */
private Boolean useIndexForOrderBy(OrderBy orderBy) {
    Boolean direction = null;
    int size = orderBy.getOrderByItems().size();
    if (size > table.getPkLength()) {
        return null;
    }
    for (int i = 0; i < size; i++) {
        OrderByItem item = orderBy.getOrderByItems().get(i);
        if (!Boolean.TRUE.equals(table.matchesPkColumn(i, item.getSymbol())) || !table.supportsOrdering(i, item.getSymbol())) {
            return null;
        }
        if (item.getNullOrdering() != null && ((item.isAscending() && item.getNullOrdering() == NullOrdering.LAST) || (!item.isAscending() && item.getNullOrdering() == NullOrdering.FIRST))) {
            // assumes nulls low
            return null;
        }
        if (item.isAscending()) {
            if (direction == null) {
                direction = OrderBy.ASC;
            } else if (direction != OrderBy.ASC) {
                return null;
            }
        } else if (direction == null) {
            direction = OrderBy.DESC;
        } else if (direction != OrderBy.DESC) {
            return null;
        }
    }
    return direction;
}
Also used : OrderByItem(org.teiid.query.sql.lang.OrderByItem)

Example 5 with OrderByItem

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

the class RuleMergeVirtual method doMerge.

static PlanNode doMerge(PlanNode frame, PlanNode root, boolean beforeDecomposeJoin, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
    if (frame.hasBooleanProperty(Info.NO_UNNEST)) {
        return root;
    }
    GroupSymbol virtualGroup = frame.getGroups().iterator().next();
    // check to see if frame represents a proc relational query.
    if (virtualGroup.isProcedure()) {
        return root;
    }
    List<PlanNode> sources = NodeEditor.findAllNodes(frame.getFirstChild(), NodeConstants.Types.SOURCE, NodeConstants.Types.SOURCE);
    SymbolMap references = (SymbolMap) frame.getProperty(NodeConstants.Info.CORRELATED_REFERENCES);
    if (references != null) {
        if (!sources.isEmpty()) {
            // correlated nested table commands should not be merged
            return root;
        }
        // this is ok only if all of the references go above the correlating join
        // currently this check is simplistic - just look at the parent join more nested scenarios won't work
        PlanNode parentJoin = NodeEditor.findParent(frame, NodeConstants.Types.JOIN, NodeConstants.Types.SOURCE | NodeConstants.Types.GROUP);
        if (parentJoin != null && !parentJoin.getGroups().containsAll(GroupsUsedByElementsVisitor.getGroups(references.getValues()))) {
            return root;
        }
    }
    PlanNode parentProject = NodeEditor.findParent(frame, NodeConstants.Types.PROJECT);
    // Check whether the upper frame is a SELECT INTO
    if (parentProject.getProperty(NodeConstants.Info.INTO_GROUP) != null) {
        return root;
    }
    if (!FrameUtil.canConvertAccessPatterns(frame)) {
        return root;
    }
    PlanNode projectNode = frame.getFirstChild();
    // Check if lower frame has only a stored procedure execution - this cannot be merged to parent frame
    if (FrameUtil.isProcedure(projectNode)) {
        return root;
    }
    SymbolMap symbolMap = (SymbolMap) frame.getProperty(NodeConstants.Info.SYMBOL_MAP);
    PlanNode sortNode = NodeEditor.findParent(parentProject, NodeConstants.Types.SORT, NodeConstants.Types.SOURCE);
    if (sortNode != null && sortNode.hasBooleanProperty(NodeConstants.Info.UNRELATED_SORT)) {
        OrderBy sortOrder = (OrderBy) sortNode.getProperty(NodeConstants.Info.SORT_ORDER);
        boolean unrelated = false;
        for (OrderByItem item : sortOrder.getOrderByItems()) {
            if (!item.isUnrelated()) {
                continue;
            }
            Collection<ElementSymbol> elements = ElementCollectorVisitor.getElements(item.getSymbol(), true);
            for (ElementSymbol elementSymbol : elements) {
                if (virtualGroup.equals(elementSymbol.getGroupSymbol())) {
                    unrelated = true;
                }
            }
        }
        // the lower frame cannot contain DUP_REMOVE, GROUP, UNION if unrelated
        if (unrelated && NodeEditor.findNodePreOrder(frame, NodeConstants.Types.DUP_REMOVE, NodeConstants.Types.PROJECT) != null || NodeEditor.findNodePreOrder(frame, NodeConstants.Types.SET_OP, NodeConstants.Types.SOURCE) != null || NodeEditor.findNodePreOrder(frame, NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE) != null) {
            return root;
        }
    }
    PlanNode parentJoin = NodeEditor.findParent(frame, NodeConstants.Types.JOIN, NodeConstants.Types.SOURCE | NodeConstants.Types.GROUP);
    // 3. if the frame has no sources
    if (projectNode.getType() != NodeConstants.Types.PROJECT || NodeEditor.findNodePreOrder(frame.getFirstChild(), NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE | NodeConstants.Types.JOIN) != null || sources.isEmpty()) {
        PlanNode parentSource = NodeEditor.findParent(parentProject, NodeConstants.Types.SOURCE);
        if (beforeDecomposeJoin && parentSource != null && parentSource.hasProperty(Info.PARTITION_INFO) && !NodeEditor.findAllNodes(frame.getFirstChild(), NodeConstants.Types.SET_OP, NodeConstants.Types.SOURCE).isEmpty()) {
            // don't bother to merge until after
            return root;
        }
        root = checkForSimpleProjection(frame, root, parentProject, metadata, capFinder);
        if (frame.getParent() == null || !sources.isEmpty() || projectNode.getType() != NodeConstants.Types.PROJECT || parentJoin == null) {
            // only consider no sources when the frame is simple and there is a parent join
            return root;
        }
        if (sources.isEmpty() && parentJoin != null) {
            JoinType jt = (JoinType) parentJoin.getProperty(Info.JOIN_TYPE);
            if (jt.isOuter()) {
                // cannot remove if the no source side is an outer side, or if it can change the meaning of the plan
                return root;
            }
            PlanNode joinToTest = parentJoin;
            while (joinToTest != null) {
                if (FrameUtil.findJoinSourceNode(joinToTest.getFirstChild()).getGroups().contains(virtualGroup)) {
                    // scan all sources under the other side as there could be a join structure
                    for (PlanNode node : NodeEditor.findAllNodes(joinToTest.getLastChild(), NodeConstants.Types.SOURCE, NodeConstants.Types.SOURCE)) {
                        SymbolMap map = (SymbolMap) node.getProperty(NodeConstants.Info.CORRELATED_REFERENCES);
                        if (map != null && GroupsUsedByElementsVisitor.getGroups(map.getValues()).contains(virtualGroup)) {
                            // TODO: we don't have the logic yet to then replace the correlated references
                            return root;
                        }
                    }
                }
                joinToTest = NodeEditor.findParent(joinToTest, NodeConstants.Types.JOIN, NodeConstants.Types.SOURCE | NodeConstants.Types.GROUP);
            }
        }
    }
    if (!checkJoinCriteria(frame.getFirstChild(), virtualGroup, parentJoin)) {
        return root;
    }
    // we don't have to check for null dependent with no source without criteria since there must be a row
    if (!checkProjectedSymbols(projectNode, virtualGroup, parentJoin, metadata, sources, !sources.isEmpty() || frame.getParent() != parentJoin, parentProject)) {
        // TODO: propagate constants if just inhibited by subquery/non-deterministic expressions
        return root;
    }
    // Otherwise merge should work
    // Convert parent frame before merge
    Set<GroupSymbol> groups = Collections.emptySet();
    if (!sources.isEmpty()) {
        groups = FrameUtil.findJoinSourceNode(projectNode).getGroups();
    } else if (references != null) {
        // convert from correlated form to regular references
        RuleMergeCriteria.ReferenceReplacementVisitor rrv = new RuleMergeCriteria.ReferenceReplacementVisitor(references);
        for (Map.Entry<ElementSymbol, Expression> entry : symbolMap.asUpdatableMap().entrySet()) {
            if (entry.getValue() instanceof Reference) {
                Expression ex = rrv.replaceExpression(entry.getValue());
                entry.setValue(ex);
            } else {
                PreOrPostOrderNavigator.doVisit(entry.getValue(), rrv, PreOrPostOrderNavigator.PRE_ORDER);
            }
        }
    }
    FrameUtil.convertFrame(frame, virtualGroup, groups, symbolMap.asMap(), metadata);
    PlanNode parentBottom = frame.getParent();
    prepareFrame(frame);
    if (sources.isEmpty() && parentJoin != null) {
        // special handling for no sources
        PlanNode parent = frame;
        List<PlanNode> criteriaNodes = new ArrayList<PlanNode>();
        while (parent.getParent() != parentJoin) {
            parent = parent.getParent();
            if (!parent.hasBooleanProperty(Info.IS_PHANTOM)) {
                criteriaNodes.add(parent);
            }
        }
        PlanNode parentNode = parentJoin.getParent();
        parentJoin.removeChild(parent);
        PlanNode other = parentJoin.getFirstChild();
        NodeEditor.removeChildNode(parentNode, parentJoin);
        JoinType jt = (JoinType) parentJoin.getProperty(Info.JOIN_TYPE);
        if (!jt.isOuter()) {
            // if we are not an outer join then the join/parent criteria is effectively
            // applied to the other side
            List<Criteria> joinCriteria = (List<Criteria>) parentJoin.getProperty(Info.JOIN_CRITERIA);
            if (joinCriteria != null) {
                for (Criteria crit : joinCriteria) {
                    PlanNode critNode = RelationalPlanner.createSelectNode(crit, false);
                    criteriaNodes.add(critNode);
                }
            }
            if (!criteriaNodes.isEmpty()) {
                for (PlanNode selectNode : criteriaNodes) {
                    selectNode.removeAllChildren();
                    selectNode.removeFromParent();
                    other.addAsParent(selectNode);
                }
            }
        }
    } else {
        // Remove top 2 nodes (SOURCE, PROJECT) of virtual group - they're no longer needed
        NodeEditor.removeChildNode(parentBottom, frame);
        NodeEditor.removeChildNode(parentBottom, projectNode);
    }
    return root;
}
Also used : OrderBy(org.teiid.query.sql.lang.OrderBy) ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) Reference(org.teiid.query.sql.symbol.Reference) ArrayList(java.util.ArrayList) JoinType(org.teiid.query.sql.lang.JoinType) SymbolMap(org.teiid.query.sql.util.SymbolMap) Criteria(org.teiid.query.sql.lang.Criteria) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) OrderByItem(org.teiid.query.sql.lang.OrderByItem) Expression(org.teiid.query.sql.symbol.Expression) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) List(java.util.List)

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