use of io.prestosql.spi.plan.WindowNode in project hetu-core by openlookeng.
the class WindowMatcher method detailMatches.
@Override
public MatchResult detailMatches(PlanNode node, StatsProvider stats, Session session, Metadata metadata, SymbolAliases symbolAliases) {
checkState(shapeMatches(node), "Plan testing framework error: shapeMatches returned false in detailMatches in %s", this.getClass().getName());
WindowNode windowNode = (WindowNode) node;
if (!prePartitionedInputs.map(expectedInputs -> expectedInputs.stream().map(alias -> alias.toSymbol(symbolAliases)).collect(toImmutableSet()).equals(windowNode.getPrePartitionedInputs())).orElse(true)) {
return NO_MATCH;
}
if (!specification.map(expectedSpecification -> expectedSpecification.getExpectedValue(symbolAliases).equals(windowNode.getSpecification())).orElse(true)) {
return NO_MATCH;
}
if (!preSortedOrderPrefix.map(Integer.valueOf(windowNode.getPreSortedOrderPrefix())::equals).orElse(true)) {
return NO_MATCH;
}
if (!hashSymbol.map(expectedHashSymbol -> expectedHashSymbol.map(alias -> alias.toSymbol(symbolAliases)).equals(windowNode.getHashSymbol())).orElse(true)) {
return NO_MATCH;
}
/*
* Window functions produce a symbol (the result of the function call) that we might
* want to bind to an alias so we can reference it further up the tree. As such,
* they need to be matched with an Alias matcher so we can bind the symbol if desired.
*/
return match();
}
use of io.prestosql.spi.plan.WindowNode in project hetu-core by openlookeng.
the class QueryPlanner method window.
private PlanBuilder window(PlanBuilder inputSubPlan, List<FunctionCall> windowFunctions) {
PlanBuilder subPlan = inputSubPlan;
if (windowFunctions.isEmpty()) {
return subPlan;
}
for (FunctionCall windowFunction : windowFunctions) {
Window window = windowFunction.getWindow().get();
// Extract frame
WindowFrameType frameType = RANGE;
FrameBoundType frameStartType = UNBOUNDED_PRECEDING;
FrameBoundType frameEndType = CURRENT_ROW;
Expression frameStart = null;
Expression frameEnd = null;
if (window.getFrame().isPresent()) {
WindowFrame frame = window.getFrame().get();
frameType = frame.getType();
frameStartType = frame.getStart().getType();
frameStart = frame.getStart().getValue().orElse(null);
if (frame.getEnd().isPresent()) {
frameEndType = frame.getEnd().get().getType();
frameEnd = frame.getEnd().get().getValue().orElse(null);
}
}
// Pre-project inputs
ImmutableList.Builder<Expression> inputs = ImmutableList.<Expression>builder().addAll(windowFunction.getArguments()).addAll(window.getPartitionBy()).addAll(Iterables.transform(getSortItemsFromOrderBy(window.getOrderBy()), SortItem::getSortKey));
if (frameStart != null) {
inputs.add(frameStart);
}
if (frameEnd != null) {
inputs.add(frameEnd);
}
subPlan = subPlan.appendProjections(inputs.build(), planSymbolAllocator, idAllocator);
// Rewrite PARTITION BY in terms of pre-projected inputs
ImmutableList.Builder<Symbol> partitionBySymbols = ImmutableList.builder();
for (Expression expression : window.getPartitionBy()) {
partitionBySymbols.add(subPlan.translate(expression));
}
// Rewrite ORDER BY in terms of pre-projected inputs
LinkedHashMap<Symbol, SortOrder> orderings = new LinkedHashMap<>();
for (SortItem item : getSortItemsFromOrderBy(window.getOrderBy())) {
Symbol symbol = subPlan.translate(item.getSortKey());
// don't override existing keys, i.e. when "ORDER BY a ASC, a DESC" is specified
orderings.putIfAbsent(symbol, sortItemToSortOrder(item));
}
// Rewrite frame bounds in terms of pre-projected inputs
Optional<Symbol> frameStartSymbol = Optional.empty();
Optional<Symbol> frameEndSymbol = Optional.empty();
if (frameStart != null) {
frameStartSymbol = Optional.of(subPlan.translate(frameStart));
}
if (frameEnd != null) {
frameEndSymbol = Optional.of(subPlan.translate(frameEnd));
}
WindowNode.Frame frame = new WindowNode.Frame(frameType, frameStartType, frameStartSymbol, frameEndType, frameEndSymbol, Optional.ofNullable(frameStart).map(Expression::toString), Optional.ofNullable(frameEnd).map(Expression::toString));
TranslationMap outputTranslations = subPlan.copyTranslations();
// Rewrite function call in terms of pre-projected inputs
Expression rewritten = subPlan.rewrite(windowFunction);
boolean needCoercion = rewritten instanceof Cast;
// Strip out the cast and add it back as a post-projection
if (rewritten instanceof Cast) {
rewritten = ((Cast) rewritten).getExpression();
}
// If refers to existing symbol, don't create another PlanNode
if (rewritten instanceof SymbolReference) {
if (needCoercion) {
subPlan = explicitCoercionSymbols(subPlan, subPlan.getRoot().getOutputSymbols(), ImmutableList.of(windowFunction));
}
continue;
}
Type returnType = analysis.getType(windowFunction);
Symbol newSymbol = planSymbolAllocator.newSymbol(rewritten, analysis.getType(windowFunction));
outputTranslations.put(windowFunction, newSymbol);
List<RowExpression> arguments = new ArrayList<>();
for (int i = 0; i < ((FunctionCall) rewritten).getArguments().size(); i++) {
arguments.add(castToRowExpression(((FunctionCall) rewritten).getArguments().get(i)));
}
WindowNode.Function function = new WindowNode.Function(call(windowFunction.getName().toString(), analysis.getFunctionHandle(windowFunction), returnType, ((FunctionCall) rewritten).getArguments().stream().map(OriginalExpressionUtils::castToRowExpression).collect(toImmutableList())), arguments, frame);
List<Symbol> sourceSymbols = subPlan.getRoot().getOutputSymbols();
ImmutableList.Builder<Symbol> orderBySymbols = ImmutableList.builder();
orderBySymbols.addAll(orderings.keySet());
Optional<OrderingScheme> orderingScheme = Optional.empty();
if (!orderings.isEmpty()) {
orderingScheme = Optional.of(new OrderingScheme(orderBySymbols.build(), orderings));
}
// create window node
subPlan = new PlanBuilder(outputTranslations, new WindowNode(idAllocator.getNextId(), subPlan.getRoot(), new WindowNode.Specification(partitionBySymbols.build(), orderingScheme), ImmutableMap.of(newSymbol, function), Optional.empty(), ImmutableSet.of(), 0));
if (needCoercion) {
subPlan = explicitCoercionSymbols(subPlan, sourceSymbols, ImmutableList.of(windowFunction));
}
}
return subPlan;
}
use of io.prestosql.spi.plan.WindowNode in project hetu-core by openlookeng.
the class TestWindowNode method testSerializationRoundtrip.
@Test
public void testSerializationRoundtrip() throws Exception {
Symbol windowSymbol = planSymbolAllocator.newSymbol("sum", BIGINT);
FunctionHandle functionHandle = createTestMetadataManager().getFunctionAndTypeManager().lookupFunction("sum", fromTypes(BIGINT));
WindowNode.Frame frame = new WindowNode.Frame(Types.WindowFrameType.RANGE, Types.FrameBoundType.UNBOUNDED_PRECEDING, Optional.empty(), Types.FrameBoundType.UNBOUNDED_FOLLOWING, Optional.empty(), Optional.empty(), Optional.empty());
PlanNodeId id = newId();
WindowNode.Specification specification = new WindowNode.Specification(ImmutableList.of(columnA), Optional.of(new OrderingScheme(ImmutableList.of(columnB), ImmutableMap.of(columnB, SortOrder.ASC_NULLS_FIRST))));
CallExpression call = call("sum", functionHandle, BIGINT, ImmutableList.of(new VariableReferenceExpression(columnC.getName(), BIGINT)));
Map<Symbol, WindowNode.Function> functions = ImmutableMap.of(windowSymbol, new WindowNode.Function(call, ImmutableList.of(new VariableReferenceExpression(columnC.getName(), BIGINT)), frame));
Optional<Symbol> hashSymbol = Optional.of(columnB);
Set<Symbol> prePartitionedInputs = ImmutableSet.of(columnA);
WindowNode windowNode = new WindowNode(id, sourceNode, specification, functions, hashSymbol, prePartitionedInputs, 0);
String json = codec.toJson(windowNode);
WindowNode actualNode = codec.fromJson(json);
assertEquals(actualNode.getId(), windowNode.getId());
assertEquals(actualNode.getSpecification(), windowNode.getSpecification());
assertEquals(actualNode.getWindowFunctions(), windowNode.getWindowFunctions());
assertEquals(actualNode.getFrames(), windowNode.getFrames());
assertEquals(actualNode.getHashSymbol(), windowNode.getHashSymbol());
assertEquals(actualNode.getPrePartitionedInputs(), windowNode.getPrePartitionedInputs());
assertEquals(actualNode.getPreSortedOrderPrefix(), windowNode.getPreSortedOrderPrefix());
}
use of io.prestosql.spi.plan.WindowNode in project hetu-core by openlookeng.
the class TestWindowNode method getJsonCodec.
private JsonCodec<WindowNode> getJsonCodec() throws Exception {
Module module = binder -> {
SqlParser sqlParser = new SqlParser();
TypeManager typeManager = new TestingTypeManager();
binder.install(new JsonModule());
binder.install(new HandleJsonModule());
binder.bind(SqlParser.class).toInstance(sqlParser);
binder.bind(TypeManager.class).toInstance(typeManager);
configBinder(binder).bindConfig(FeaturesConfig.class);
newSetBinder(binder, Type.class);
jsonBinder(binder).addSerializerBinding(Slice.class).to(SliceSerializer.class);
jsonBinder(binder).addDeserializerBinding(Slice.class).to(SliceDeserializer.class);
jsonBinder(binder).addDeserializerBinding(Type.class).to(TestingTypeDeserializer.class);
jsonBinder(binder).addSerializerBinding(Expression.class).to(Serialization.ExpressionSerializer.class);
jsonBinder(binder).addDeserializerBinding(Expression.class).to(Serialization.ExpressionDeserializer.class);
jsonBinder(binder).addDeserializerBinding(FunctionCall.class).to(Serialization.FunctionCallDeserializer.class);
jsonBinder(binder).addKeySerializerBinding(VariableReferenceExpression.class).to(Serialization.VariableReferenceExpressionSerializer.class);
jsonBinder(binder).addKeyDeserializerBinding(VariableReferenceExpression.class).to(Serialization.VariableReferenceExpressionDeserializer.class);
jsonCodecBinder(binder).bindJsonCodec(WindowNode.class);
};
Bootstrap app = new Bootstrap(ImmutableList.of(module));
Injector injector = app.strictConfig().doNotInitializeLogging().quiet().initialize();
return injector.getInstance(new Key<JsonCodec<WindowNode>>() {
});
}
use of io.prestosql.spi.plan.WindowNode in project hetu-core by openlookeng.
the class TestTypeValidator method testInvalidWindowFunctionCall.
@Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "type of symbol 'sum(_[0-9]+)?' is expected to be double, but the actual type is bigint")
public void testInvalidWindowFunctionCall() {
Symbol windowSymbol = planSymbolAllocator.newSymbol("sum", DOUBLE);
FunctionHandle functionHandle = FUNCTION_MANAGER.lookupFunction("sum", fromTypes(DOUBLE));
WindowNode.Frame frame = new WindowNode.Frame(WindowFrameType.RANGE, FrameBoundType.UNBOUNDED_PRECEDING, Optional.empty(), FrameBoundType.UNBOUNDED_FOLLOWING, Optional.empty(), Optional.empty(), Optional.empty());
WindowNode.Function function = new WindowNode.Function(call("sum", functionHandle, BIGINT, ImmutableList.of(VariableReferenceSymbolConverter.toVariableReference(columnA, BIGINT))), ImmutableList.of(VariableReferenceSymbolConverter.toVariableReference(columnA, BIGINT)), frame);
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);
assertTypesValid(node);
}
Aggregations