Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*-
* #%L
* JSQLParser library
* %%
* Copyright (C) 2004 - 2019 JSQLParser
* %%
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
* #L%
*/
package net.sf.jsqlparser.statement.select;

import java.io.Serializable;

import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.schema.Column;

/**
* Models one column entry of the ClickHouse {@code INTERPOLATE} clause, which computes the values
* of non-sorted columns for the rows generated by {@code ORDER BY ... WITH FILL} (see
* <a href="https://clickhouse.com/docs/en/sql-reference/statements/select/order-by">ClickHouse:
* ORDER BY</a>).
* <p>
* {@code col AS expr} evaluates {@code expr} for the generated rows, while a bare {@code col} (a
* {@code null} expression) repeats the previous value of the column.
*/
public class InterpolateElement implements Serializable {

private Column column;
private Expression expression;

public InterpolateElement() {
super();
}

public InterpolateElement(Column column, Expression expression) {
this.column = column;
this.expression = expression;
}

public Column getColumn() {
return column;
}

public void setColumn(Column column) {
this.column = column;
}

public InterpolateElement withColumn(Column column) {
setColumn(column);
return this;
}

public Expression getExpression() {
return expression;
}

public void setExpression(Expression expression) {
this.expression = expression;
}

public InterpolateElement withExpression(Expression expression) {
setExpression(expression);
return this;
}

@Override
public String toString() {
if (expression != null) {
return column + " AS " + expression;
}
return column.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class OrderByElement implements Serializable {
private boolean asc = true;
private boolean ascDescPresent = false;
private NullOrdering nullOrdering;
private WithFill withFill;

public boolean isAsc() {
return asc;
Expand All @@ -39,6 +40,20 @@ public void setNullOrdering(NullOrdering nullOrdering) {
this.nullOrdering = nullOrdering;
}

public WithFill getWithFill() {
return withFill;
}

public OrderByElement setWithFill(WithFill withFill) {
this.withFill = withFill;
return this;
}

public OrderByElement withWithFill(WithFill withFill) {
setWithFill(withFill);
return this;
}

public boolean isAscDescPresent() {
return ascDescPresent;
}
Expand Down Expand Up @@ -74,6 +89,9 @@ public String toString() {
b.append(' ');
b.append(nullOrdering == NullOrdering.NULLS_FIRST ? "NULLS FIRST" : "NULLS LAST");
}
if (withFill != null) {
b.append(' ').append(withFill);
}
if (isMysqlWithRollup()) {
b.append(" WITH ROLLUP");
}
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/net/sf/jsqlparser/statement/select/Select.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public abstract class Select extends ASTNodeAccessImpl implements Statement, Exp
ForClause forClause = null;

List<OrderByElement> orderByElements;
List<InterpolateElement> interpolate;
ForMode forMode = null;
private boolean skipLocked;
private Wait wait;
Expand All @@ -54,6 +55,16 @@ public static String orderByToString(boolean oracleSiblings,
return getFormattedList(orderByElements, oracleSiblings ? "ORDER SIBLINGS BY" : "ORDER BY");
}

public static String interpolateToString(List<InterpolateElement> interpolate) {
if (interpolate == null) {
return "";
}
if (interpolate.isEmpty()) {
return " INTERPOLATE";
}
return getFormattedList(interpolate, "INTERPOLATE", true, true);
}

public static String getFormattedList(List<?> list, String expression) {
return getFormattedList(list, expression, true, false);
}
Expand Down Expand Up @@ -192,6 +203,19 @@ public void setOrderByElements(List<OrderByElement> orderByElements) {
this.orderByElements = orderByElements;
}

public List<InterpolateElement> getInterpolate() {
return interpolate;
}

public void setInterpolate(List<InterpolateElement> interpolate) {
this.interpolate = interpolate;
}

public Select withInterpolate(List<InterpolateElement> interpolate) {
setInterpolate(interpolate);
return this;
}

public Select withOrderByElements(List<OrderByElement> orderByElements) {
this.setOrderByElements(orderByElements);
return this;
Expand Down Expand Up @@ -463,6 +487,7 @@ public StringBuilder appendTo(StringBuilder builder) {

if (!forUpdateBeforeOrderBy) {
builder.append(orderByToString(oracleSiblings, orderByElements));
builder.append(interpolateToString(interpolate));
}

if (forClause != null) {
Expand Down Expand Up @@ -512,6 +537,7 @@ public StringBuilder appendTo(StringBuilder builder) {

if (forUpdateBeforeOrderBy) {
builder.append(orderByToString(oracleSiblings, orderByElements));
builder.append(interpolateToString(interpolate));
}

return builder;
Expand Down
102 changes: 102 additions & 0 deletions src/main/java/net/sf/jsqlparser/statement/select/WithFill.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*-
* #%L
* JSQLParser library
* %%
* Copyright (C) 2004 - 2019 JSQLParser
* %%
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
* #L%
*/
package net.sf.jsqlparser.statement.select;

import java.io.Serializable;

import net.sf.jsqlparser.expression.Expression;

/**
* Models the ClickHouse {@code WITH FILL} modifier of an {@link OrderByElement}, which fills gaps
* in the sorted sequence of the order by expression (see
* <a href="https://clickhouse.com/docs/en/sql-reference/statements/select/order-by">ClickHouse:
* ORDER BY</a>).
* <p>
* The modifier takes optional {@code FROM}, {@code TO}, {@code STEP} and {@code STALENESS} bounds,
* where the step may be an {@code INTERVAL} literal. Its presence on an {@link OrderByElement}
* marks the element as filled.
*/
public class WithFill implements Serializable {

private Expression from;
private Expression to;
private Expression step;
private Expression staleness;

public Expression getFrom() {
return from;
}

public void setFrom(Expression from) {
this.from = from;
}

public WithFill withFrom(Expression from) {
setFrom(from);
return this;
}

public Expression getTo() {
return to;
}

public void setTo(Expression to) {
this.to = to;
}

public WithFill withTo(Expression to) {
setTo(to);
return this;
}

public Expression getStep() {
return step;
}

public void setStep(Expression step) {
this.step = step;
}

public WithFill withStep(Expression step) {
setStep(step);
return this;
}

public Expression getStaleness() {
return staleness;
}

public void setStaleness(Expression staleness) {
this.staleness = staleness;
}

public WithFill withStaleness(Expression staleness) {
setStaleness(staleness);
return this;
}

@Override
public String toString() {
StringBuilder b = new StringBuilder("WITH FILL");
if (from != null) {
b.append(" FROM ").append(from);
}
if (to != null) {
b.append(" TO ").append(to);
}
if (step != null) {
b.append(" STEP ").append(step);
}
if (staleness != null) {
b.append(" STALENESS ").append(staleness);
}
return b.toString();
}
}
25 changes: 25 additions & 0 deletions src/main/java/net/sf/jsqlparser/util/deparser/OrderByDeParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import net.sf.jsqlparser.expression.ExpressionVisitor;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.WithFill;

public class OrderByDeParser extends AbstractDeParser<List<OrderByElement>> {

Expand Down Expand Up @@ -64,11 +65,35 @@ public void deParseElement(OrderByElement orderBy) {
? "NULLS FIRST"
: "NULLS LAST");
}
if (orderBy.getWithFill() != null) {
builder.append(' ');
deParseWithFill(orderBy.getWithFill());
}
if (orderBy.isMysqlWithRollup()) {
builder.append(" WITH ROLLUP");
}
}

private void deParseWithFill(WithFill withFill) {
builder.append("WITH FILL");
if (withFill.getFrom() != null) {
builder.append(" FROM ");
withFill.getFrom().accept(expressionVisitor, null);
}
if (withFill.getTo() != null) {
builder.append(" TO ");
withFill.getTo().accept(expressionVisitor, null);
}
if (withFill.getStep() != null) {
builder.append(" STEP ");
withFill.getStep().accept(expressionVisitor, null);
}
if (withFill.getStaleness() != null) {
builder.append(" STALENESS ");
withFill.getStaleness().accept(expressionVisitor, null);
}
}

void setExpressionVisitor(ExpressionVisitor<StringBuilder> expressionVisitor) {
this.expressionVisitor = expressionVisitor;
}
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import net.sf.jsqlparser.statement.select.First;
import net.sf.jsqlparser.statement.select.FromItem;
import net.sf.jsqlparser.statement.select.FromItemVisitor;
import net.sf.jsqlparser.statement.select.InterpolateElement;
import net.sf.jsqlparser.statement.select.Join;
import net.sf.jsqlparser.statement.select.LateralSubSelect;
import net.sf.jsqlparser.statement.select.LateralView;
Expand Down Expand Up @@ -136,6 +137,7 @@ public <S> StringBuilder visit(ParenthesedSelect select, S context) {
if (select.getOrderByElements() != null) {
new OrderByDeParser(expressionVisitor, builder).deParse(select.isOracleSiblings(),
select.getOrderByElements());
deParseInterpolate(select.getInterpolate());
}

Alias alias = select.getAlias();
Expand Down Expand Up @@ -471,9 +473,33 @@ protected void deparseOrderByElementsClause(PlainSelect plainSelect,
if (orderByElements != null) {
new OrderByDeParser(expressionVisitor, builder).deParse(plainSelect.isOracleSiblings(),
orderByElements);
deParseInterpolate(plainSelect.getInterpolate());
}
}

private void deParseInterpolate(List<InterpolateElement> interpolate) {
if (interpolate == null) {
return;
}
if (interpolate.isEmpty()) {
builder.append(" INTERPOLATE");
return;
}
builder.append(" INTERPOLATE (");
for (Iterator<InterpolateElement> iter = interpolate.iterator(); iter.hasNext();) {
InterpolateElement element = iter.next();
element.getColumn().accept(expressionVisitor, null);
if (element.getExpression() != null) {
builder.append(" AS ");
element.getExpression().accept(expressionVisitor, null);
}
if (iter.hasNext()) {
builder.append(", ");
}
}
builder.append(")");
}

@Override
public <S> StringBuilder visit(SelectItem<?> selectItem, S context) {
selectItem.getExpression().accept(expressionVisitor, context);
Expand Down Expand Up @@ -729,6 +755,7 @@ public <S> StringBuilder visit(SetOperationList list, S context) {
}
if (list.getOrderByElements() != null) {
new OrderByDeParser(expressionVisitor, builder).deParse(list.getOrderByElements());
deParseInterpolate(list.getInterpolate());
}

if (list.getLimit() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ public <S> Void visit(OrderByElement orderBy, S context) {
validateOptionalFeature(c, orderBy.getNullOrdering(), Feature.orderByNullOrdering);
}
getValidator(ExpressionValidator.class).validate(orderBy.getExpression());
if (orderBy.getWithFill() != null) {
validateOptionalExpression(orderBy.getWithFill().getFrom());
validateOptionalExpression(orderBy.getWithFill().getTo());
validateOptionalExpression(orderBy.getWithFill().getStep());
validateOptionalExpression(orderBy.getWithFill().getStaleness());
}
return null;
}

Expand Down
Loading
Loading