use of io.crate.analyze.WindowDefinition in project crate by crate.
the class MoveFilterBeneathWindowAgg method apply.
@Override
public LogicalPlan apply(Filter filter, Captures captures, TableStats tableStats, TransactionContext txnCtx, NodeContext nodeCtx) {
WindowAgg windowAgg = captures.get(windowAggCapture);
WindowDefinition windowDefinition = windowAgg.windowDefinition();
List<WindowFunction> windowFunctions = windowAgg.windowFunctions();
Predicate<Symbol> containsWindowFunction = symbol -> symbol instanceof WindowFunction && windowFunctions.contains(symbol);
Symbol predicate = filter.query();
List<Symbol> filterParts = AndOperator.split(predicate);
ArrayList<Symbol> remainingFilterSymbols = new ArrayList<>();
ArrayList<Symbol> windowPartitionedBasedFilters = new ArrayList<>();
for (Symbol part : filterParts) {
if (SymbolVisitors.any(containsWindowFunction, part) == false && windowDefinition.partitions().containsAll(extractColumns(part))) {
windowPartitionedBasedFilters.add(part);
} else {
remainingFilterSymbols.add(part);
}
}
assert remainingFilterSymbols.size() > 0 || windowPartitionedBasedFilters.size() > 0 : "Splitting the filter symbol must result in at least one group";
/* SELECT ROW_NUMBER() OVER(PARTITION BY id)
* WHERE `x = 1`
*
* `x` is not the window partition column.
* We cannot push down the filter as it would change the window aggregation value
*
*/
if (windowPartitionedBasedFilters.isEmpty()) {
return null;
}
/* SELECT ROW_NUMBER() OVER(PARTITION BY id)
* WHERE `id = 1`
* remainingFilterSymbols: []
* windowPartitionedBasedFilters: [id = 1]
*
* Filter
* |
* WindowsAgg
*
* transforms to
*
* WindowAgg
* |
* Filter (id = 1)
*/
if (remainingFilterSymbols.isEmpty()) {
return transpose(filter, windowAgg);
}
/* WHERE `ROW_NUMBER() OVER(PARTITION BY id) = 2 AND id = 1`
* remainingFilterSymbols: [ROW_NUMBER() OVER(PARTITION BY id) = 2]
* windowPartitionedBasedFilters: [id = 1]
*
* Filter
* |
* WindowsAgg
*
* transforms to
*
* Filter (ROW_NUMBER() OVER(PARTITION BY id) = 2)
* |
* WindowAgg
* |
* Filter (id = 1)
*/
LogicalPlan newWindowAgg = windowAgg.replaceSources(List.of(new Filter(windowAgg.source(), AndOperator.join(windowPartitionedBasedFilters))));
return new Filter(newWindowAgg, AndOperator.join(remainingFilterSymbols));
}
use of io.crate.analyze.WindowDefinition in project crate by crate.
the class DefaultTraversalSymbolVisitor method visitWindowFunction.
@Override
public R visitWindowFunction(WindowFunction symbol, C context) {
for (Symbol arg : symbol.arguments()) {
arg.accept(this, context);
}
Symbol filter = symbol.filter();
if (filter != null) {
filter.accept(this, context);
}
WindowDefinition windowDefinition = symbol.windowDefinition();
OrderBy orderBy = windowDefinition.orderBy();
if (orderBy != null) {
for (Symbol orderBySymbol : orderBy.orderBySymbols()) {
orderBySymbol.accept(this, context);
}
}
for (Symbol partition : windowDefinition.partitions()) {
partition.accept(this, context);
}
Symbol frameStartValueSymbol = windowDefinition.windowFrameDefinition().start().value();
if (frameStartValueSymbol != null) {
frameStartValueSymbol.accept(this, context);
}
FrameBoundDefinition end = windowDefinition.windowFrameDefinition().end();
if (end != null) {
Symbol frameEndValueSymbol = end.value();
if (frameEndValueSymbol != null) {
frameEndValueSymbol.accept(this, context);
}
}
return null;
}
use of io.crate.analyze.WindowDefinition in project crate by crate.
the class WindowProjector method createUpdateProbeValueFunction.
private static BiFunction<Object[], Object[], Object[]> createUpdateProbeValueFunction(WindowDefinition windowDefinition, BiFunction<DataType<?>, DataType<?>, BiFunction> getOffsetApplicationFunction, Object offsetValue, DataType<?> offsetType) {
OrderBy windowOrdering = windowDefinition.orderBy();
assert windowOrdering != null : "The window definition must be ordered if custom offsets are specified";
List<Symbol> orderBySymbols = windowOrdering.orderBySymbols();
if (orderBySymbols.size() != 1) {
throw new IllegalArgumentException("Must have exactly 1 ORDER BY expression if using <offset> FOLLOWING/PRECEDING");
}
int offsetColumnPosition;
Symbol orderSymbol = orderBySymbols.get(0);
BiFunction applyOffsetOnOrderingValue = getOffsetApplicationFunction.apply(orderSymbol.valueType(), offsetType);
if (orderSymbol.symbolType() == SymbolType.LITERAL) {
offsetColumnPosition = -1;
} else {
assert orderSymbol instanceof InputColumn : "ORDER BY expression must resolve to an InputColumn, but got: " + orderSymbol;
offsetColumnPosition = ((InputColumn) orderSymbol).index();
}
var finalOffsetValue = offsetType.id() == IntervalType.ID ? offsetType.sanitizeValue(offsetValue) : orderSymbol.valueType().sanitizeValue(offsetValue);
return (currentRow, x) -> {
// `null`)
if (offsetColumnPosition != -1) {
x[offsetColumnPosition] = applyOffsetOnOrderingValue.apply(currentRow[offsetColumnPosition], finalOffsetValue);
}
return x;
};
}
use of io.crate.analyze.WindowDefinition in project crate by crate.
the class WindowProjector method fromProjection.
public static Projector fromProjection(WindowAggProjection projection, NodeContext nodeCtx, InputFactory inputFactory, TransactionContext txnCtx, RamAccounting ramAccounting, MemoryManager memoryManager, Version minNodeVersion, Version indexVersionCreated, IntSupplier numThreads, Executor executor) {
var windowFunctionSymbols = projection.windowFunctions();
var numWindowFunctions = windowFunctionSymbols.size();
assert numWindowFunctions > 0 : "WindowAggProjection must have at least 1 window function.";
ArrayList<WindowFunction> windowFunctions = new ArrayList<>(numWindowFunctions);
ArrayList<CollectExpression<Row, ?>> windowFuncArgsExpressions = new ArrayList<>(numWindowFunctions);
Input[][] windowFuncArgsInputs = new Input[numWindowFunctions][];
Boolean[] ignoreNulls = new Boolean[numWindowFunctions];
for (int idx = 0; idx < numWindowFunctions; idx++) {
var windowFunctionSymbol = windowFunctionSymbols.get(idx);
InputFactory.Context<CollectExpression<Row, ?>> ctx = inputFactory.ctxForInputColumns(txnCtx);
ctx.add(windowFunctionSymbol.arguments());
FunctionImplementation impl = nodeCtx.functions().getQualified(windowFunctionSymbol, txnCtx.sessionSettings().searchPath());
assert impl != null : "Function implementation not found using full qualified lookup";
if (impl instanceof AggregationFunction) {
var filterInputFactoryCtx = inputFactory.ctxForInputColumns(txnCtx);
var filterSymbol = windowFunctionSymbol.filter();
// noinspection unchecked
Input<Boolean> filterInput = filterSymbol == null ? Literal.BOOLEAN_TRUE : (Input<Boolean>) filterInputFactoryCtx.add(filterSymbol);
ExpressionsInput<Row, Boolean> filter = new ExpressionsInput<>(filterInput, filterInputFactoryCtx.expressions());
windowFunctions.add(new AggregateToWindowFunctionAdapter((AggregationFunction) impl, filter, indexVersionCreated, ramAccounting, memoryManager, minNodeVersion));
} else if (impl instanceof WindowFunction) {
windowFunctions.add((WindowFunction) impl);
} else {
throw new AssertionError("Function needs to be either a window or an aggregate function");
}
windowFuncArgsExpressions.addAll(ctx.expressions());
windowFuncArgsInputs[idx] = ctx.topLevelInputs().toArray(new Input[0]);
ignoreNulls[idx] = windowFunctionSymbol.ignoreNulls();
}
var windowDefinition = projection.windowDefinition();
var partitions = windowDefinition.partitions();
Supplier<InputFactory.Context<CollectExpression<Row, ?>>> createInputFactoryContext = () -> inputFactory.ctxForInputColumns(txnCtx);
int arrayListElementOverHead = 32;
RowAccountingWithEstimators accounting = new RowAccountingWithEstimators(Symbols.typeView(projection.standalone()), ramAccounting, arrayListElementOverHead);
Comparator<Object[]> cmpPartitionBy = partitions.isEmpty() ? null : createComparator(createInputFactoryContext, new OrderBy(windowDefinition.partitions()));
Comparator<Object[]> cmpOrderBy = createComparator(createInputFactoryContext, windowDefinition.orderBy());
int numCellsInSourceRow = projection.standalone().size();
ComputeFrameBoundary<Object[]> computeFrameStart = createComputeStartFrameBoundary(numCellsInSourceRow, txnCtx, nodeCtx, windowDefinition, cmpOrderBy);
ComputeFrameBoundary<Object[]> computeFrameEnd = createComputeEndFrameBoundary(numCellsInSourceRow, txnCtx, nodeCtx, windowDefinition, cmpOrderBy);
return sourceRows -> WindowFunctionBatchIterator.of(sourceRows, accounting, computeFrameStart, computeFrameEnd, cmpPartitionBy, cmpOrderBy, numCellsInSourceRow, numThreads, executor, windowFunctions, windowFuncArgsExpressions, ignoreNulls, windowFuncArgsInputs);
}
use of io.crate.analyze.WindowDefinition in project crate by crate.
the class ExpressionAnalyzer method getWindowDefinition.
@Nullable
private WindowDefinition getWindowDefinition(Optional<Window> maybeWindow, ExpressionAnalysisContext context) {
if (!maybeWindow.isPresent()) {
return null;
}
var unresolvedWindow = maybeWindow.get();
final Window window;
if (unresolvedWindow.windowRef() != null) {
var refWindow = resolveWindowRef(unresolvedWindow.windowRef(), context.windows());
window = unresolvedWindow.merge(refWindow);
} else {
window = unresolvedWindow;
}
List<Symbol> partitionSymbols = new ArrayList<>(window.getPartitions().size());
for (Expression partition : window.getPartitions()) {
Symbol symbol = convert(partition, context);
SemanticSortValidator.validate(symbol, "PARTITION BY");
partitionSymbols.add(symbol);
}
OrderBy orderBy = OrderyByAnalyzer.analyzeSortItems(window.getOrderBy(), sortKey -> {
Symbol symbol = convert(sortKey, context);
SemanticSortValidator.validate(symbol);
return symbol;
});
WindowFrameDefinition windowFrameDefinition = WindowDefinition.RANGE_UNBOUNDED_PRECEDING_CURRENT_ROW;
if (window.getWindowFrame().isPresent()) {
WindowFrame windowFrame = window.getWindowFrame().get();
validateFrame(window, windowFrame);
FrameBound start = windowFrame.getStart();
FrameBoundDefinition startBound = convertToAnalyzedFrameBound(context, start);
FrameBoundDefinition endBound = windowFrame.getEnd().map(end -> convertToAnalyzedFrameBound(context, end)).orElse(new FrameBoundDefinition(FrameBound.Type.CURRENT_ROW, Literal.NULL));
windowFrameDefinition = new WindowFrameDefinition(windowFrame.mode(), startBound, endBound);
}
return new WindowDefinition(partitionSymbols, orderBy, windowFrameDefinition);
}
Aggregations