Search in sources :

Example 1 with WindowSpecification

use of org.teiid.query.sql.symbol.WindowSpecification in project teiid by teiid.

the class WindowFunctionProjectNode method buildResults.

/**
 * Build the results by maintaining indexes that either map
 * rowid->values
 * or
 * rowid->partitionid and partitionid->values
 *
 * TODO use the size hint for tree balancing
 */
private void buildResults() throws TeiidComponentException, TeiidProcessingException, FunctionExecutionException, ExpressionEvaluationException {
    List<Map.Entry<WindowSpecification, WindowSpecificationInfo>> specs = new ArrayList<Map.Entry<WindowSpecification, WindowSpecificationInfo>>(windows.entrySet());
    for (int specIndex = 0; specIndex < specs.size(); specIndex++) {
        Map.Entry<WindowSpecification, WindowSpecificationInfo> entry = specs.get(specIndex);
        WindowSpecificationInfo info = entry.getValue();
        IndexedTupleSource specificationTs = tb.createIndexedTupleSource();
        boolean multiGroup = false;
        int[] partitionIndexes = null;
        int[] orderIndexes = null;
        // if there is partitioning or ordering, then sort
        if (!info.orderType.isEmpty()) {
            multiGroup = true;
            int[] sortKeys = new int[info.orderType.size()];
            int i = 0;
            if (!info.groupIndexes.isEmpty()) {
                for (Integer sortIndex : info.groupIndexes) {
                    sortKeys[i++] = sortIndex;
                }
                partitionIndexes = Arrays.copyOf(sortKeys, info.groupIndexes.size());
            }
            if (!info.sortIndexes.isEmpty()) {
                for (Integer sortIndex : info.sortIndexes) {
                    sortKeys[i++] = sortIndex;
                }
                orderIndexes = Arrays.copyOfRange(sortKeys, info.groupIndexes.size(), info.groupIndexes.size() + info.sortIndexes.size());
            }
            if (!info.functions.isEmpty()) {
                // $NON-NLS-1$
                ElementSymbol key = new ElementSymbol("rowId");
                key.setType(DataTypeManager.DefaultDataClasses.INTEGER);
                // $NON-NLS-1$
                ElementSymbol value = new ElementSymbol("partitionId");
                value.setType(DataTypeManager.DefaultDataClasses.INTEGER);
                List<ElementSymbol> elements = Arrays.asList(key, value);
                partitionMapping[specIndex] = this.getBufferManager().createSTree(elements, this.getConnectionID(), 1);
            }
            SortUtility su = new SortUtility(null, Mode.SORT, this.getBufferManager(), this.getConnectionID(), tb.getSchema(), info.orderType, info.nullOrderings, sortKeys);
            su.setWorkingBuffer(tb);
            su.setNonBlocking(true);
            TupleBuffer sorted = su.sort();
            specificationTs = sorted.createIndexedTupleSource(true);
        }
        List<AggregateFunction> aggs = initializeAccumulators(info.functions, specIndex, false);
        List<AggregateFunction> rowValueAggs = initializeAccumulators(info.rowValuefunctions, specIndex, true);
        int groupId = 0;
        List<?> lastRow = null;
        while (specificationTs.hasNext()) {
            List<?> tuple = specificationTs.nextTuple();
            if (multiGroup) {
                if (lastRow != null) {
                    boolean samePartition = GroupingNode.sameGroup(partitionIndexes, tuple, lastRow) == -1;
                    if (!aggs.isEmpty() && (!samePartition || GroupingNode.sameGroup(orderIndexes, tuple, lastRow) != -1)) {
                        saveValues(specIndex, aggs, groupId, samePartition, false);
                        groupId++;
                    }
                    saveValues(specIndex, rowValueAggs, lastRow.get(lastRow.size() - 1), samePartition, true);
                }
                if (!aggs.isEmpty()) {
                    List<Object> partitionTuple = Arrays.asList(tuple.get(tuple.size() - 1), groupId);
                    partitionMapping[specIndex].insert(partitionTuple, InsertMode.NEW, -1);
                }
            }
            for (AggregateFunction function : aggs) {
                function.addInput(tuple, getContext());
            }
            for (AggregateFunction function : rowValueAggs) {
                function.addInput(tuple, getContext());
            }
            lastRow = tuple;
        }
        if (lastRow != null) {
            saveValues(specIndex, aggs, groupId, true, false);
            saveValues(specIndex, rowValueAggs, lastRow.get(lastRow.size() - 1), true, true);
        }
    }
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) ArrayList(java.util.ArrayList) TupleBuffer(org.teiid.common.buffer.TupleBuffer) WindowSpecification(org.teiid.query.sql.symbol.WindowSpecification) IndexedTupleSource(org.teiid.common.buffer.IndexedTupleSource) AggregateFunction(org.teiid.query.function.aggregate.AggregateFunction) LanguageObject(org.teiid.query.sql.LanguageObject) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) SymbolMap(org.teiid.query.sql.util.SymbolMap)

Example 2 with WindowSpecification

use of org.teiid.query.sql.symbol.WindowSpecification in project teiid by teiid.

the class RulePushSelectCriteria method createConvertedSelectNode.

private PlanNode createConvertedSelectNode(PlanNode critNode, GroupSymbol sourceGroup, PlanNode projectNode, SymbolMap symbolMap, QueryMetadataInterface metadata) throws QueryPlannerException {
    // If projectNode has children, then it is from a SELECT without a FROM and the criteria should not be pushed
    if (projectNode.getChildCount() == 0) {
        return null;
    }
    Criteria crit = (Criteria) critNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
    Collection<ElementSymbol> cols = ElementCollectorVisitor.getElements(crit, true);
    if (projectNode.hasBooleanProperty(Info.HAS_WINDOW_FUNCTIONS)) {
        // we can push iff the predicate is against partitioning columns in all projected window functions
        Set<WindowFunction> windowFunctions = RuleAssignOutputElements.getWindowFunctions((List<Expression>) projectNode.getProperty(Info.PROJECT_COLS));
        for (WindowFunction windowFunction : windowFunctions) {
            WindowSpecification spec = windowFunction.getWindowSpecification();
            if (spec.getPartition() == null) {
                return null;
            }
            for (ElementSymbol col : cols) {
                if (!spec.getPartition().contains(symbolMap.getMappedExpression(col))) {
                    return null;
                }
            }
        }
    }
    Boolean conversionResult = checkConversion(symbolMap, cols);
    if (conversionResult == Boolean.FALSE) {
        // not convertable
        return null;
    }
    if (!critNode.getSubqueryContainers().isEmpty() && checkConversion(symbolMap, critNode.getCorrelatedReferenceElements()) != null) {
        // not convertable, or has an aggregate for a correlated reference
        return null;
    }
    PlanNode copyNode = copyNode(critNode);
    if (conversionResult == Boolean.TRUE) {
        copyNode.setProperty(NodeConstants.Info.IS_HAVING, Boolean.TRUE);
    }
    FrameUtil.convertNode(copyNode, sourceGroup, null, symbolMap.asMap(), metadata, true);
    // any proc relational criteria that is not input criteria should stay above the source
    if (sourceGroup.isProcedure() && !copyNode.getGroups().isEmpty()) {
        if (this.createdNodes != null) {
            this.createdNodes.remove(this.createdNodes.size() - 1);
        }
        return null;
    }
    return copyNode;
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) WindowFunction(org.teiid.query.sql.symbol.WindowFunction) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) Expression(org.teiid.query.sql.symbol.Expression) WindowSpecification(org.teiid.query.sql.symbol.WindowSpecification) CompoundCriteria(org.teiid.query.sql.lang.CompoundCriteria) DependentSetCriteria(org.teiid.query.sql.lang.DependentSetCriteria) Criteria(org.teiid.query.sql.lang.Criteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria)

Example 3 with WindowSpecification

use of org.teiid.query.sql.symbol.WindowSpecification in project teiid by teiid.

the class WindowFunctionProjectNode method init.

/**
 * This state can be determined prior to initialize and is the same for all nodes,
 * so it is moved into it's own init routine
 */
public void init() {
    expressionIndexes = new LinkedHashMap<Expression, Integer>();
    for (int i = 0; i < getElements().size(); i++) {
        Expression ex = SymbolMap.getExpression(getElements().get(i));
        if (ex instanceof WindowFunction) {
            WindowFunction wf = (WindowFunction) ex;
            WindowSpecification ws = wf.getWindowSpecification();
            WindowSpecificationInfo wsi = windows.get(ws);
            if (wsi == null) {
                wsi = new WindowSpecificationInfo();
                windows.put(wf.getWindowSpecification(), wsi);
                if (ws.getPartition() != null) {
                    for (Expression ex1 : ws.getPartition()) {
                        Integer index = GroupingNode.getIndex(ex1, expressionIndexes);
                        wsi.groupIndexes.add(index);
                        wsi.orderType.add(OrderBy.ASC);
                        wsi.nullOrderings.add(null);
                    }
                }
                if (ws.getOrderBy() != null) {
                    for (OrderByItem item : ws.getOrderBy().getOrderByItems()) {
                        Expression ex1 = SymbolMap.getExpression(item.getSymbol());
                        Integer index = GroupingNode.getIndex(ex1, expressionIndexes);
                        wsi.sortIndexes.add(index);
                        wsi.orderType.add(item.isAscending());
                        wsi.nullOrderings.add(item.getNullOrdering());
                    }
                }
            }
            WindowFunctionInfo wfi = new WindowFunctionInfo();
            wfi.function = wf;
            // collect the agg expressions
            for (Expression e : wf.getFunction().getArgs()) {
                GroupingNode.getIndex(e, expressionIndexes);
            }
            if (wf.getFunction().getOrderBy() != null) {
                for (OrderByItem item : wf.getFunction().getOrderBy().getOrderByItems()) {
                    GroupingNode.getIndex(item.getSymbol(), expressionIndexes);
                }
            }
            if (wf.getFunction().getCondition() != null) {
                GroupingNode.getIndex(wf.getFunction().getCondition(), expressionIndexes);
            }
            wfi.outputIndex = i;
            if (wf.getFunction().isRowValueFunction()) {
                wsi.rowValuefunctions.add(wfi);
            } else {
                wsi.functions.add(wfi);
            }
        } else {
            int index = GroupingNode.getIndex(ex, expressionIndexes);
            passThrough.add(new int[] { i, index });
        }
    }
}
Also used : WindowFunction(org.teiid.query.sql.symbol.WindowFunction) OrderByItem(org.teiid.query.sql.lang.OrderByItem) Expression(org.teiid.query.sql.symbol.Expression) WindowSpecification(org.teiid.query.sql.symbol.WindowSpecification)

Example 4 with WindowSpecification

use of org.teiid.query.sql.symbol.WindowSpecification in project teiid by teiid.

the class WindowFunctionProjectNode method nextBatchDirect.

@Override
protected TupleBatch nextBatchDirect() throws BlockedException, TeiidComponentException, TeiidProcessingException {
    if (phase == Phase.COLLECT) {
        saveInput();
        phase = Phase.PROCESS;
        partitionMapping = new STree[this.windows.size()];
        valueMapping = new STree[this.windows.size()];
        rowValueMapping = new STree[this.windows.size()];
    }
    if (phase == Phase.PROCESS) {
        buildResults();
        phase = Phase.OUTPUT;
    }
    if (phase == Phase.OUTPUT) {
        if (outputTs == null) {
            outputTs = tb.createIndexedTupleSource(true);
        }
        while (outputTs.hasNext()) {
            List<?> tuple = outputTs.nextTuple();
            Integer rowId = (Integer) tuple.get(tuple.size() - 1);
            int size = getElements().size();
            ArrayList<Object> outputRow = new ArrayList<Object>(size);
            for (int i = 0; i < size; i++) {
                outputRow.add(null);
            }
            for (int[] entry : passThrough) {
                outputRow.set(entry[0], tuple.get(entry[1]));
            }
            List<Map.Entry<WindowSpecification, WindowSpecificationInfo>> specs = new ArrayList<Map.Entry<WindowSpecification, WindowSpecificationInfo>>(windows.entrySet());
            for (int specIndex = 0; specIndex < specs.size(); specIndex++) {
                Map.Entry<WindowSpecification, WindowSpecificationInfo> entry = specs.get(specIndex);
                List<?> idRow = Arrays.asList(rowId);
                List<WindowFunctionInfo> functions = entry.getValue().rowValuefunctions;
                if (!functions.isEmpty()) {
                    List<?> valueRow = rowValueMapping[specIndex].find(idRow);
                    for (int i = 0; i < functions.size(); i++) {
                        WindowFunctionInfo wfi = functions.get(i);
                        Object value = valueRow.get(i + 1);
                        // the offset, default, and partition
                        if (wfi.function.getFunction().getAggregateFunction() == Type.LEAD || wfi.function.getFunction().getAggregateFunction() == Type.LAG) {
                            ArrayImpl array = (ArrayImpl) value;
                            Object[] args = array.getValues();
                            int offset = 1;
                            Object defaultValue = null;
                            if (args.length > 2) {
                                offset = (int) args[1];
                                if (args.length > 3) {
                                    defaultValue = args[2];
                                }
                            }
                            List<?> newIdRow = Arrays.asList(rowId + (wfi.function.getFunction().getAggregateFunction() == Type.LAG ? -offset : offset));
                            List<?> newValueRow = rowValueMapping[specIndex].find(newIdRow);
                            if (newValueRow == null) {
                                value = defaultValue;
                            } else {
                                Object[] newArgs = ((ArrayImpl) newValueRow.get(i + 1)).getValues();
                                // make sure it's the same partition
                                if (args[args.length - 1].equals(newArgs[newArgs.length - 1])) {
                                    value = newArgs[0];
                                } else {
                                    value = defaultValue;
                                }
                            }
                        }
                        outputRow.set(wfi.outputIndex, value);
                    }
                }
                functions = entry.getValue().functions;
                if (!functions.isEmpty()) {
                    if (partitionMapping[specIndex] != null) {
                        idRow = partitionMapping[specIndex].find(idRow);
                        idRow = idRow.subList(1, 2);
                    } else {
                        idRow = SINGLE_VALUE_ID;
                    }
                    List<?> valueRow = valueMapping[specIndex].find(idRow);
                    for (int i = 0; i < functions.size(); i++) {
                        WindowFunctionInfo wfi = functions.get(i);
                        outputRow.set(wfi.outputIndex, valueRow.get(i + 1));
                    }
                }
            }
            this.addBatchRow(outputRow);
            if (this.isBatchFull()) {
                return pullBatch();
            }
        }
        terminateBatches();
    }
    return this.pullBatch();
}
Also used : ArrayImpl(org.teiid.core.types.ArrayImpl) ArrayList(java.util.ArrayList) WindowSpecification(org.teiid.query.sql.symbol.WindowSpecification) LanguageObject(org.teiid.query.sql.LanguageObject) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) SymbolMap(org.teiid.query.sql.util.SymbolMap)

Aggregations

WindowSpecification (org.teiid.query.sql.symbol.WindowSpecification)4 ArrayList (java.util.ArrayList)2 LinkedHashMap (java.util.LinkedHashMap)2 Map (java.util.Map)2 LanguageObject (org.teiid.query.sql.LanguageObject)2 ElementSymbol (org.teiid.query.sql.symbol.ElementSymbol)2 Expression (org.teiid.query.sql.symbol.Expression)2 WindowFunction (org.teiid.query.sql.symbol.WindowFunction)2 SymbolMap (org.teiid.query.sql.util.SymbolMap)2 IndexedTupleSource (org.teiid.common.buffer.IndexedTupleSource)1 TupleBuffer (org.teiid.common.buffer.TupleBuffer)1 ArrayImpl (org.teiid.core.types.ArrayImpl)1 AggregateFunction (org.teiid.query.function.aggregate.AggregateFunction)1 PlanNode (org.teiid.query.optimizer.relational.plantree.PlanNode)1 CompareCriteria (org.teiid.query.sql.lang.CompareCriteria)1 CompoundCriteria (org.teiid.query.sql.lang.CompoundCriteria)1 Criteria (org.teiid.query.sql.lang.Criteria)1 DependentSetCriteria (org.teiid.query.sql.lang.DependentSetCriteria)1 OrderByItem (org.teiid.query.sql.lang.OrderByItem)1