use of io.trino.sql.planner.plan.WindowNode in project trino by trinodb.
the class TestTypeValidator method testInvalidWindowFunctionSignature.
@Test
public void testInvalidWindowFunctionSignature() {
Symbol windowSymbol = symbolAllocator.newSymbol("sum", BIGINT);
ResolvedFunction resolvedFunction = functionResolution.resolveFunction(QualifiedName.of("sum"), fromTypes(DOUBLE));
WindowNode.Frame frame = new WindowNode.Frame(WindowFrame.Type.RANGE, FrameBound.Type.UNBOUNDED_PRECEDING, Optional.empty(), Optional.empty(), FrameBound.Type.UNBOUNDED_FOLLOWING, Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty());
WindowNode.Function function = new WindowNode.Function(resolvedFunction, ImmutableList.of(columnC.toSymbolReference()), frame, false);
WindowNode.Specification specification = new WindowNode.Specification(ImmutableList.of(), Optional.empty());
PlanNode node = new WindowNode(newId(), baseTableScan, specification, ImmutableMap.of(windowSymbol, function), Optional.empty(), ImmutableSet.of(), 0);
assertThatThrownBy(() -> assertTypesValid(node)).isInstanceOf(IllegalArgumentException.class).hasMessageMatching("type of symbol 'sum(_[0-9]+)?' is expected to be bigint, but the actual type is double");
}
use of io.trino.sql.planner.plan.WindowNode in project trino by trinodb.
the class TestEffectivePredicateExtractor method testWindow.
@Test
public void testWindow() {
PlanNode node = new WindowNode(newId(), filter(baseTableScan, and(equals(AE, BE), equals(BE, CE), lessThan(CE, bigintLiteral(10)))), new WindowNode.Specification(ImmutableList.of(A), Optional.of(new OrderingScheme(ImmutableList.of(A), ImmutableMap.of(A, SortOrder.ASC_NULLS_LAST)))), ImmutableMap.of(), Optional.empty(), ImmutableSet.of(), 0);
Expression effectivePredicate = effectivePredicateExtractor.extract(SESSION, node, TypeProvider.empty(), typeAnalyzer);
// Pass through
assertEquals(normalizeConjuncts(effectivePredicate), normalizeConjuncts(equals(AE, BE), equals(BE, CE), lessThan(CE, bigintLiteral(10))));
}
use of io.trino.sql.planner.plan.WindowNode in project trino by trinodb.
the class TestPushdownLimitIntoWindow method testLimitWithPreSortedInputs.
@Test
public void testLimitWithPreSortedInputs() {
// We can push Limit with pre-sorted inputs into WindowNode if ordering scheme is satisfied
// We don't do it currently to avoid relying on LocalProperties outside of AddExchanges/AddLocalExchanges
ResolvedFunction ranking = tester().getMetadata().resolveFunction(tester().getSession(), QualifiedName.of("row_number"), fromTypes());
tester().assertThat(new PushdownLimitIntoWindow()).on(p -> {
Symbol a = p.symbol("a");
Symbol rowNumberSymbol = p.symbol("row_number_1");
OrderingScheme orderingScheme = new OrderingScheme(ImmutableList.of(a), ImmutableMap.of(a, SortOrder.ASC_NULLS_FIRST));
return p.limit(3, false, ImmutableList.of(a), p.window(new WindowNode.Specification(ImmutableList.of(), Optional.of(orderingScheme)), ImmutableMap.of(rowNumberSymbol, newWindowNodeFunction(ranking, a)), p.values(a)));
}).doesNotFire();
}
use of io.trino.sql.planner.plan.WindowNode in project trino by trinodb.
the class QueryPlanner method planWindow.
private PlanBuilder planWindow(PlanBuilder subPlan, FunctionCall windowFunction, ResolvedWindow window, PlanAndMappings coercions, Optional<Symbol> frameStartSymbol, Optional<Symbol> sortKeyCoercedForFrameStartComparison, Optional<Symbol> frameEndSymbol, Optional<Symbol> sortKeyCoercedForFrameEndComparison) {
WindowFrame.Type frameType = WindowFrame.Type.RANGE;
FrameBound.Type frameStartType = FrameBound.Type.UNBOUNDED_PRECEDING;
FrameBound.Type frameEndType = FrameBound.Type.CURRENT_ROW;
Optional<Expression> frameStartExpression = Optional.empty();
Optional<Expression> frameEndExpression = Optional.empty();
if (window.getFrame().isPresent()) {
WindowFrame frame = window.getFrame().get();
frameType = frame.getType();
frameStartType = frame.getStart().getType();
frameStartExpression = frame.getStart().getValue();
if (frame.getEnd().isPresent()) {
frameEndType = frame.getEnd().get().getType();
frameEndExpression = frame.getEnd().get().getValue();
}
}
WindowNode.Specification specification = planWindowSpecification(window.getPartitionBy(), window.getOrderBy(), coercions::get);
// Rewrite frame bounds in terms of pre-projected inputs
WindowNode.Frame frame = new WindowNode.Frame(frameType, frameStartType, frameStartSymbol, sortKeyCoercedForFrameStartComparison, frameEndType, frameEndSymbol, sortKeyCoercedForFrameEndComparison, frameStartExpression, frameEndExpression);
Symbol newSymbol = symbolAllocator.newSymbol(windowFunction, analysis.getType(windowFunction));
NullTreatment nullTreatment = windowFunction.getNullTreatment().orElse(NullTreatment.RESPECT);
WindowNode.Function function = new WindowNode.Function(analysis.getResolvedFunction(windowFunction), windowFunction.getArguments().stream().map(argument -> {
if (argument instanceof LambdaExpression) {
return subPlan.rewrite(argument);
}
return coercions.get(argument).toSymbolReference();
}).collect(toImmutableList()), frame, nullTreatment == NullTreatment.IGNORE);
// create window node
return new PlanBuilder(subPlan.getTranslations().withAdditionalMappings(ImmutableMap.of(scopeAwareKey(windowFunction, analysis, subPlan.getScope()), newSymbol)), new WindowNode(idAllocator.getNextId(), subPlan.getRoot(), specification, ImmutableMap.of(newSymbol, function), Optional.empty(), ImmutableSet.of(), 0));
}
use of io.trino.sql.planner.plan.WindowNode in project trino by trinodb.
the class WindowFunctionMatcher method getAssignedSymbol.
@Override
public Optional<Symbol> getAssignedSymbol(PlanNode node, Session session, Metadata metadata, SymbolAliases symbolAliases) {
Optional<Symbol> result = Optional.empty();
Map<Symbol, Function> assignments;
if (node instanceof WindowNode) {
assignments = ((WindowNode) node).getWindowFunctions();
} else if (node instanceof PatternRecognitionNode) {
assignments = ((PatternRecognitionNode) node).getWindowFunctions();
} else {
return result;
}
FunctionCall expectedCall = callMaker.getExpectedValue(symbolAliases);
Optional<WindowNode.Frame> expectedFrame = frameMaker.map(maker -> maker.getExpectedValue(symbolAliases));
for (Map.Entry<Symbol, Function> assignment : assignments.entrySet()) {
Function function = assignment.getValue();
boolean signatureMatches = resolvedFunction.map(assignment.getValue().getResolvedFunction()::equals).orElse(true);
if (signatureMatches && windowFunctionMatches(function, expectedCall, expectedFrame)) {
checkState(result.isEmpty(), "Ambiguous function calls in %s", node);
result = Optional.of(assignment.getKey());
}
}
return result;
}
Aggregations