Skip to content

Commit

Permalink
feat: support new IntervalCompound and updated IntervalDay types (#288)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: IntervalDay now has "subsecond" and "precision" fields instead
of "microseconds". Old protobufs should be still read correctly.
  • Loading branch information
Blizzara authored Sep 20, 2024
1 parent c8c31ec commit e24ce6f
Show file tree
Hide file tree
Showing 40 changed files with 492 additions and 42 deletions.
5 changes: 3 additions & 2 deletions core/src/main/antlr/SubstraitType.g4
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Date : D A T E;
Time : T I M E;
IntervalYear: I N T E R V A L '_' Y E A R;
IntervalDay: I N T E R V A L '_' D A Y;
IntervalCompound: I N T E R V A L '_' C O M P O U N D;
UUID : U U I D;
Decimal : D E C I M A L;
PrecisionTimestamp: P R E C I S I O N '_' T I M E S T A M P;
Expand Down Expand Up @@ -158,7 +159,6 @@ scalarType
| TimestampTZ #timestampTz
| Date #date
| Time #time
| IntervalDay #intervalDay
| IntervalYear #intervalYear
| UUID #uuid
| UserDefined Identifier #userDefined
Expand All @@ -169,6 +169,8 @@ parameterizedType
| VarChar isnull='?'? Lt len=numericParameter Gt #varChar
| FixedBinary isnull='?'? Lt len=numericParameter Gt #fixedBinary
| Decimal isnull='?'? Lt precision=numericParameter Comma scale=numericParameter Gt #decimal
| IntervalDay isnull='?'? Lt precision=numericParameter Gt #intervalDay
| IntervalCompound isnull='?'? Lt precision=numericParameter Gt #intervalCompound
| PrecisionTimestamp isnull='?'? Lt precision=numericParameter Gt #precisionTimestamp
| PrecisionTimestampTZ isnull='?'? Lt precision=numericParameter Gt #precisionTimestampTZ
| Struct isnull='?'? Lt expr (Comma expr)* Gt #struct
Expand Down Expand Up @@ -205,4 +207,3 @@ expr
| (Bang) expr #NotExpr
| ifExpr=expr QMark thenExpr=expr Colon elseExpr=expr #Ternary
;
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ public OUTPUT visit(Expression.IntervalDayLiteral expr) throws EXCEPTION {
return visitFallback(expr);
}

@Override
public OUTPUT visit(Expression.IntervalCompoundLiteral expr) throws EXCEPTION {
return visitFallback(expr);
}

@Override
public OUTPUT visit(Expression.UUIDLiteral expr) throws EXCEPTION {
return visitFallback(expr);
Expand Down
35 changes: 33 additions & 2 deletions core/src/main/java/io/substrait/expression/Expression.java
Original file line number Diff line number Diff line change
Expand Up @@ -333,10 +333,12 @@ abstract static class IntervalDayLiteral implements Literal {

public abstract int seconds();

public abstract int microseconds();
public abstract long subseconds();

public abstract int precision();

public Type getType() {
return Type.withNullability(nullable()).INTERVAL_DAY;
return Type.withNullability(nullable()).intervalDay(precision());
}

public static ImmutableExpression.IntervalDayLiteral.Builder builder() {
Expand All @@ -348,6 +350,35 @@ public <R, E extends Throwable> R accept(ExpressionVisitor<R, E> visitor) throws
}
}

@Value.Immutable
abstract static class IntervalCompoundLiteral implements Literal {
// Flattened IntervalYearLiteral
public abstract int years();

public abstract int months();

// Flattened IntervalDayLiteral
public abstract int days();

public abstract int seconds();

public abstract long subseconds();

public abstract int precision();

public Type getType() {
return Type.withNullability(nullable()).intervalCompound(precision());
}

public static ImmutableExpression.IntervalCompoundLiteral.Builder builder() {
return ImmutableExpression.IntervalCompoundLiteral.builder();
}

public <R, E extends Throwable> R accept(ExpressionVisitor<R, E> visitor) throws E {
return visitor.visit(this);
}
}

@Value.Immutable
abstract static class UUIDLiteral implements Literal {
public abstract UUID value();
Expand Down
26 changes: 23 additions & 3 deletions core/src/main/java/io/substrait/expression/ExpressionCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -161,16 +161,36 @@ public static Expression.IntervalYearLiteral intervalYear(
}

public static Expression.IntervalDayLiteral intervalDay(boolean nullable, int days, int seconds) {
return intervalDay(nullable, days, seconds, 0);
return intervalDay(nullable, days, seconds, 0, 0);
}

public static Expression.IntervalDayLiteral intervalDay(
boolean nullable, int days, int seconds, int microseconds) {
boolean nullable, int days, int seconds, long subseconds, int precision) {
return Expression.IntervalDayLiteral.builder()
.nullable(nullable)
.days(days)
.seconds(seconds)
.microseconds(microseconds)
.subseconds(subseconds)
.precision(precision)
.build();
}

public static Expression.IntervalCompoundLiteral intervalCompound(
boolean nullable,
int years,
int months,
int days,
int seconds,
long subseconds,
int precision) {
return Expression.IntervalCompoundLiteral.builder()
.nullable(nullable)
.years(years)
.months(months)
.days(days)
.seconds(seconds)
.subseconds(subseconds)
.precision(precision)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public interface ExpressionVisitor<R, E extends Throwable> {

R visit(Expression.IntervalDayLiteral expr) throws E;

R visit(Expression.IntervalCompoundLiteral expr) throws E;

R visit(Expression.UUIDLiteral expr) throws E;

R visit(Expression.FixedCharLiteral expr) throws E;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,27 @@ public Expression visit(io.substrait.expression.Expression.IntervalDayLiteral ex
Expression.Literal.IntervalDayToSecond.newBuilder()
.setDays(expr.days())
.setSeconds(expr.seconds())
.setMicroseconds(expr.microseconds())));
.setSubseconds(expr.subseconds())
.setPrecision(expr.precision())));
}

@Override
public Expression visit(io.substrait.expression.Expression.IntervalCompoundLiteral expr) {
return lit(
bldr ->
bldr.setNullable(expr.nullable())
.setIntervalCompound(
Expression.Literal.IntervalCompound.newBuilder()
.setIntervalYearToMonth(
Expression.Literal.IntervalYearToMonth.newBuilder()
.setYears(expr.years())
.setMonths(expr.months()))
.setIntervalDayToSecond(
Expression.Literal.IntervalDayToSecond.newBuilder()
.setDays(expr.days())
.setSeconds(expr.seconds())
.setSubseconds(expr.subseconds())
.setPrecision(expr.precision()))));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,11 +340,38 @@ public Expression.Literal from(io.substrait.proto.Expression.Literal literal) {
literal.getNullable(),
literal.getIntervalYearToMonth().getYears(),
literal.getIntervalYearToMonth().getMonths());
case INTERVAL_DAY_TO_SECOND -> ExpressionCreator.intervalDay(
literal.getNullable(),
literal.getIntervalDayToSecond().getDays(),
literal.getIntervalDayToSecond().getSeconds(),
literal.getIntervalDayToSecond().getMicroseconds());
case INTERVAL_DAY_TO_SECOND -> {
// Handle deprecated version that doesn't provide precision and that uses microseconds
// instead of subseconds, for backwards compatibility
int precision =
literal.getIntervalDayToSecond().hasPrecision()
? literal.getIntervalDayToSecond().getPrecision()
: 6; // microseconds
long subseconds =
literal.getIntervalDayToSecond().hasPrecision()
? literal.getIntervalDayToSecond().getSubseconds()
: literal.getIntervalDayToSecond().getMicroseconds();
yield ExpressionCreator.intervalDay(
literal.getNullable(),
literal.getIntervalDayToSecond().getDays(),
literal.getIntervalDayToSecond().getSeconds(),
subseconds,
precision);
}
case INTERVAL_COMPOUND -> {
if (!literal.getIntervalCompound().getIntervalDayToSecond().hasPrecision()) {
throw new RuntimeException(
"Interval compound with deprecated version of interval day (ie. no precision) is not supported");
}
yield ExpressionCreator.intervalCompound(
literal.getNullable(),
literal.getIntervalCompound().getIntervalYearToMonth().getYears(),
literal.getIntervalCompound().getIntervalYearToMonth().getMonths(),
literal.getIntervalCompound().getIntervalDayToSecond().getDays(),
literal.getIntervalCompound().getIntervalDayToSecond().getSeconds(),
literal.getIntervalCompound().getIntervalDayToSecond().getSubseconds(),
literal.getIntervalCompound().getIntervalDayToSecond().getPrecision());
}
case FIXED_CHAR -> ExpressionCreator.fixedChar(literal.getNullable(), literal.getFixedChar());
case VAR_CHAR -> ExpressionCreator.varChar(
literal.getNullable(), literal.getVarChar().getValue(), literal.getVarChar().getLength());
Expand Down
30 changes: 30 additions & 0 deletions core/src/main/java/io/substrait/function/ParameterizedType.java
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,36 @@ public static ImmutableParameterizedType.Decimal.Builder builder() {
}
}

@Value.Immutable
abstract static class IntervalDay extends BaseParameterizedType implements NullableType {
public abstract StringLiteral precision();

@Override
<R, E extends Throwable> R accept(final ParameterizedTypeVisitor<R, E> parameterizedTypeVisitor)
throws E {
return parameterizedTypeVisitor.visit(this);
}

public static ImmutableParameterizedType.IntervalDay.Builder builder() {
return ImmutableParameterizedType.IntervalDay.builder();
}
}

@Value.Immutable
abstract static class IntervalCompound extends BaseParameterizedType implements NullableType {
public abstract StringLiteral precision();

@Override
<R, E extends Throwable> R accept(final ParameterizedTypeVisitor<R, E> parameterizedTypeVisitor)
throws E {
return parameterizedTypeVisitor.visit(this);
}

public static ImmutableParameterizedType.IntervalCompound.Builder builder() {
return ImmutableParameterizedType.IntervalCompound.builder();
}
}

@Value.Immutable
abstract static class PrecisionTimestamp extends BaseParameterizedType implements NullableType {
public abstract StringLiteral precision();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ public ParameterizedType decimalE(String precision, String scale) {
.build();
}

public ParameterizedType intervalDayE(String precision) {
return ParameterizedType.IntervalDay.builder()
.nullable(nullable)
.precision(parameter(precision, false))
.build();
}

public ParameterizedType intervalCompoundE(String precision) {
return ParameterizedType.IntervalCompound.builder()
.nullable(nullable)
.precision(parameter(precision, false))
.build();
}

public ParameterizedType precisionTimestampE(String precision) {
return ParameterizedType.PrecisionTimestamp.builder()
.nullable(nullable)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ public interface ParameterizedTypeVisitor<R, E extends Throwable> extends TypeVi

R visit(ParameterizedType.Decimal expr) throws E;

R visit(ParameterizedType.IntervalDay expr) throws E;

R visit(ParameterizedType.IntervalCompound expr) throws E;

R visit(ParameterizedType.PrecisionTimestamp expr) throws E;

R visit(ParameterizedType.PrecisionTimestampTZ expr) throws E;
Expand Down Expand Up @@ -60,6 +64,16 @@ public R visit(ParameterizedType.PrecisionTimestampTZ expr) throws E {
throw t();
}

@Override
public R visit(ParameterizedType.IntervalDay expr) throws E {
throw t();
}

@Override
public R visit(ParameterizedType.IntervalCompound expr) throws E {
throw t();
}

@Override
public R visit(ParameterizedType.Struct expr) throws E {
throw t();
Expand Down
15 changes: 15 additions & 0 deletions core/src/main/java/io/substrait/function/ToTypeString.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ public String visit(final Type.IntervalDay expr) {
return "iday";
}

@Override
public String visit(final Type.IntervalCompound expr) {
return "icompound";
}

@Override
public String visit(final Type.UUID expr) {
return "uuid";
Expand Down Expand Up @@ -165,6 +170,16 @@ public String visit(ParameterizedType.Decimal expr) throws RuntimeException {
return "dec";
}

@Override
public String visit(ParameterizedType.IntervalDay expr) throws RuntimeException {
return "iday";
}

@Override
public String visit(ParameterizedType.IntervalCompound expr) throws RuntimeException {
return "icompound";
}

@Override
public String visit(ParameterizedType.PrecisionTimestamp expr) throws RuntimeException {
return "pts";
Expand Down
30 changes: 30 additions & 0 deletions core/src/main/java/io/substrait/function/TypeExpression.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,36 @@ public static ImmutableTypeExpression.Decimal.Builder builder() {
}
}

@Value.Immutable
abstract static class IntervalDay extends BaseTypeExpression implements NullableType {

public abstract TypeExpression precision();

@Override
<R, E extends Throwable> R acceptE(final TypeExpressionVisitor<R, E> visitor) throws E {
return visitor.visit(this);
}

public static ImmutableTypeExpression.IntervalDay.Builder builder() {
return ImmutableTypeExpression.IntervalDay.builder();
}
}

@Value.Immutable
abstract static class IntervalCompound extends BaseTypeExpression implements NullableType {

public abstract TypeExpression precision();

@Override
<R, E extends Throwable> R acceptE(final TypeExpressionVisitor<R, E> visitor) throws E {
return visitor.visit(this);
}

public static ImmutableTypeExpression.IntervalCompound.Builder builder() {
return ImmutableTypeExpression.IntervalCompound.builder();
}
}

@Value.Immutable
abstract static class PrecisionTimestamp extends BaseTypeExpression implements NullableType {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ public TypeExpression decimalE(TypeExpression precision, TypeExpression scale) {
.build();
}

public TypeExpression intervalDayE(TypeExpression precision) {
return TypeExpression.IntervalDay.builder().nullable(nullable).precision(precision).build();
}

public TypeExpression intervalCompoundE(TypeExpression precision) {
return TypeExpression.IntervalCompound.builder()
.nullable(nullable)
.precision(precision)
.build();
}

public TypeExpression precisionTimestampE(TypeExpression precision) {
return TypeExpression.PrecisionTimestamp.builder()
.nullable(nullable)
Expand Down
Loading

0 comments on commit e24ce6f

Please sign in to comment.