@Override public String visitWindowFrame(WindowFrame node, Void context) { StringBuilder builder = new StringBuilder(); builder.append(node.getType().toString()).append(' '); if (node.getEnd().isPresent()) { builder.append("BETWEEN ") .append(process(node.getStart(), null)) .append(" AND ") .append(process(node.getEnd().get(), null)); } else { builder.append(process(node.getStart(), null)); } return builder.toString(); }
@Override public String visitWindow(Window node, Void context) { List<String> parts = new ArrayList<>(); if (!node.getPartitionBy().isEmpty()) { parts.add("PARTITION BY " + joinExpressions(node.getPartitionBy())); } if (!node.getOrderBy().isEmpty()) { parts.add("ORDER BY " + formatSortItems(node.getOrderBy())); } if (node.getFrame().isPresent()) { parts.add(process(node.getFrame().get(), null)); } else { if (!windowFunctionName.equalsIgnoreCase("rank")) { if (!node.getOrderBy().isEmpty()) { // Redshift needs to specify frame explicitly if there is order by and the function is not rank() FrameBound fb = new FrameBound(FrameBound.Type.UNBOUNDED_PRECEDING); WindowFrame wf = new WindowFrame(WindowFrame.Type.ROWS, fb, null); parts.add(process(wf, null)); } } } return '(' + Joiner.on(' ').join(parts) + ')'; }
@Override public String visitWindowFrame(WindowFrame node, StackableAstVisitorContext<Integer> indent) { StringBuilder builder = new StringBuilder(); builder.append(node.getType().toString()).append(' '); if (node.getEnd().isPresent()) { builder.append("BETWEEN ") .append(process(node.getStart(), indent)) .append(" AND ") .append(process(node.getEnd().get(), indent)); } else { builder.append(process(node.getStart(), indent)); } return builder.toString(); }
@Override public Boolean visitWindowFrame(WindowFrame node, Void context) { Optional<Expression> start = node.getStart().getValue(); if (start.isPresent()) { if (!process(start.get(), context)) { throw new SemanticException(MUST_BE_AGGREGATE_OR_GROUP_BY, start.get(), "Window frame start must be an aggregate expression or appear in GROUP BY clause"); } } if (node.getEnd().isPresent() && node.getEnd().get().getValue().isPresent()) { Expression endValue = node.getEnd().get().getValue().get(); if (!process(endValue, context)) { throw new SemanticException(MUST_BE_AGGREGATE_OR_GROUP_BY, endValue, "Window frame end must be an aggregate expression or appear in GROUP BY clause"); } } return true; }
@Override public String visitWindowFrame(WindowFrame node, Boolean unmangleNames) { StringBuilder builder = new StringBuilder(); builder.append(node.getType().toString()).append(' '); if (node.getEnd().isPresent()) { builder.append("BETWEEN ") .append(process(node.getStart(), unmangleNames)) .append(" AND ") .append(process(node.getEnd().get(), unmangleNames)); } else { builder.append(process(node.getStart(), unmangleNames)); } return builder.toString(); }
public FrameInfo( WindowFrame.Type type, FrameBound.Type startType, Optional<Integer> startChannel, FrameBound.Type endType, Optional<Integer> endChannel) { this.type = requireNonNull(type, "type is null"); this.startType = requireNonNull(startType, "startType is null"); this.startChannel = requireNonNull(startChannel, "startChannel is null").orElse(-1); this.endType = requireNonNull(endType, "endType is null"); this.endChannel = requireNonNull(endChannel, "endChannel is null").orElse(-1); }
@JsonCreator public Frame( @JsonProperty("type") WindowFrame.Type type, @JsonProperty("startType") FrameBound.Type startType, @JsonProperty("startValue") Optional<Symbol> startValue, @JsonProperty("endType") FrameBound.Type endType, @JsonProperty("endValue") Optional<Symbol> endValue) { this.startType = requireNonNull(startType, "startType is null"); this.startValue = requireNonNull(startValue, "startValue is null"); this.endType = requireNonNull(endType, "endType is null"); this.endValue = requireNonNull(endValue, "endValue is null"); this.type = requireNonNull(type, "type is null"); }
private static void analyzeWindowFrame(WindowFrame frame) { FrameBound.Type startType = frame.getStart().getType(); FrameBound.Type endType = frame.getEnd().orElse(new FrameBound(CURRENT_ROW)).getType(); if (startType == UNBOUNDED_FOLLOWING) { throw new SemanticException(INVALID_WINDOW_FRAME, frame, "Window frame start cannot be UNBOUNDED FOLLOWING"); } if (endType == UNBOUNDED_PRECEDING) { throw new SemanticException(INVALID_WINDOW_FRAME, frame, "Window frame end cannot be UNBOUNDED PRECEDING"); } if ((startType == CURRENT_ROW) && (endType == PRECEDING)) { throw new SemanticException(INVALID_WINDOW_FRAME, frame, "Window frame starting from CURRENT ROW cannot end with PRECEDING"); } if ((startType == FOLLOWING) && (endType == PRECEDING)) { throw new SemanticException(INVALID_WINDOW_FRAME, frame, "Window frame starting from FOLLOWING cannot end with PRECEDING"); } if ((startType == FOLLOWING) && (endType == CURRENT_ROW)) { throw new SemanticException(INVALID_WINDOW_FRAME, frame, "Window frame starting from FOLLOWING cannot end with CURRENT ROW"); } if ((frame.getType() == RANGE) && ((startType == PRECEDING) || (endType == PRECEDING))) { throw new SemanticException(INVALID_WINDOW_FRAME, frame, "Window frame RANGE PRECEDING is only supported with UNBOUNDED"); } if ((frame.getType() == RANGE) && ((startType == FOLLOWING) || (endType == FOLLOWING))) { throw new SemanticException(INVALID_WINDOW_FRAME, frame, "Window frame RANGE FOLLOWING is only supported with UNBOUNDED"); } }
@Test public void testWindow() throws Exception { PlanNode node = new WindowNode(newId(), filter(baseTableScan, and( equals(AE, BE), equals(BE, CE), lessThan(CE, number(10)))), ImmutableList.of(A), ImmutableList.of(A), ImmutableMap.of(A, SortOrder.ASC_NULLS_LAST), new WindowNode.Frame(WindowFrame.Type.RANGE, FrameBound.Type.UNBOUNDED_PRECEDING, Optional.empty(), FrameBound.Type.CURRENT_ROW, Optional.empty()), ImmutableMap.<Symbol, FunctionCall>of(), ImmutableMap.<Symbol, Signature>of(), Optional.empty(), ImmutableSet.of(), 0); Expression effectivePredicate = EffectivePredicateExtractor.extract(node, TYPES); // Pass through Assert.assertEquals(normalizeConjuncts(effectivePredicate), normalizeConjuncts( equals(AE, BE), equals(BE, CE), lessThan(CE, number(10)))); }
@Override public Node visitOver(SqlBaseParser.OverContext context) { return new Window( getLocation(context), visit(context.partition, Expression.class), visit(context.sortItem(), SortItem.class), visitIfPresent(context.windowFrame(), WindowFrame.class)); }
@Override public Node visitWindowFrame(SqlBaseParser.WindowFrameContext context) { return new WindowFrame( getLocation(context), getFrameType(context.frameType), (FrameBound) visit(context.start), visitIfPresent(context.end, FrameBound.class)); }
private static WindowFrame.Type getFrameType(Token type) { switch (type.getType()) { case SqlBaseLexer.RANGE: return WindowFrame.Type.RANGE; case SqlBaseLexer.ROWS: return WindowFrame.Type.ROWS; } throw new IllegalArgumentException("Unsupported frame type: " + type.getText()); }
public WindowFrame.Type getType() { return type; }
@JsonProperty public WindowFrame.Type getType() { return type; }