Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Add temporal interval data type and support interval clause as function #687

Merged
merged 12 commits into from
Aug 20, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
import com.amazon.opendistroforelasticsearch.sql.analysis.symbol.Symbol;
import com.amazon.opendistroforelasticsearch.sql.ast.AbstractNodeVisitor;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.AggregateFunction;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Alias;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.And;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Compare;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.EqualTo;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Field;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Function;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Interval;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.IntervalUnit;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Literal;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Not;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Or;
Expand Down Expand Up @@ -86,6 +87,13 @@ public Expression visitLiteral(Literal node, AnalysisContext context) {
.literal(ExprValueUtils.fromObjectValue(node.getValue(), node.getType().getCoreType()));
}

@Override
public Expression visitInterval(Interval node, AnalysisContext context) {
Expression value = node.getValue().accept(this, context);
Expression unit = DSL.literal(node.getUnit().name());
return dsl.interval(value, unit);
}

@Override
public Expression visitAnd(And node, AnalysisContext context) {
Expression left = node.getLeft().accept(this, context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Field;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Function;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.In;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Interval;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Let;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Literal;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Map;
Expand Down Expand Up @@ -188,4 +189,8 @@ public T visitAlias(Alias node, C context) {
public T visitAllFields(AllFields node, C context) {
return visitChildren(node, context);
}

public T visitInterval(Interval node, C context) {
return visitChildren(node, context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Field;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Function;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.In;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Interval;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.IntervalUnit;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Let;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Literal;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Map;
Expand Down Expand Up @@ -148,6 +150,10 @@ public static Literal booleanLiteral(Boolean value) {
return literal(value, DataType.BOOLEAN);
}

public static Interval intervalLiteral(Object value, DataType type, String unit) {
return new Interval(literal(value, type), unit);
}

public static Literal nullLiteral() {
return literal(null, DataType.NULL);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ public enum DataType {
NULL(ExprCoreType.UNKNOWN),

INTEGER(ExprCoreType.INTEGER),
LONG(ExprCoreType.LONG),
DOUBLE(ExprCoreType.DOUBLE),
STRING(ExprCoreType.STRING),
BOOLEAN(ExprCoreType.BOOLEAN),

DATE(ExprCoreType.DATE),
TIME(ExprCoreType.TIME),
TIMESTAMP(ExprCoreType.TIMESTAMP);
TIMESTAMP(ExprCoreType.TIMESTAMP),
chloe-zh marked this conversation as resolved.
Show resolved Hide resolved
INTERVAL(ExprCoreType.INTERVAL);

@Getter
private final ExprCoreType coreType;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package com.amazon.opendistroforelasticsearch.sql.ast.expression;

import com.amazon.opendistroforelasticsearch.sql.ast.AbstractNodeVisitor;
import com.google.common.collect.ImmutableList;
import java.util.Collections;
import java.util.List;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;

@Getter
@ToString
@EqualsAndHashCode(callSuper = false)
@RequiredArgsConstructor
public class Interval extends UnresolvedExpression {

private final UnresolvedExpression value;
private final IntervalUnit unit;

public Interval(UnresolvedExpression value, String unit) {
this.value = value;
this.unit = IntervalUnit.of(unit);
}

@Override
public List<UnresolvedExpression> getChild() {
return Collections.singletonList(value);
}

@Override
public <R, C> R accept(AbstractNodeVisitor<R, C> nodeVisitor, C context) {
return nodeVisitor.visitInterval(this, context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package com.amazon.opendistroforelasticsearch.sql.ast.expression;

import com.google.common.collect.ImmutableList;
import java.util.List;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum IntervalUnit {
UNKNOWN,

MICROSECOND,
SECOND,
MINUTE,
HOUR,
DAY,
WEEK,
MONTH,
QUARTER,
YEAR,
SECOND_MICROSECOND,
MINUTE_MICROSECOND,
MINUTE_SECOND,
HOUR_MICROSECOND,
HOUR_SECOND,
HOUR_MINUTE,
DAY_MICROSECOND,
DAY_SECOND,
DAY_MINUTE,
DAY_HOUR,
YEAR_MONTH;

private static final List<IntervalUnit> INTERVAL_UNITS;

static {
ImmutableList.Builder<IntervalUnit> builder = new ImmutableList.Builder<>();
INTERVAL_UNITS = builder.add(IntervalUnit.values()).build();
}

/**
* Util method to get interval unit given the unit name.
*/
public static IntervalUnit of(String unit) {
return INTERVAL_UNITS.stream()
.filter(v -> unit.equalsIgnoreCase(v.name()))
.findFirst()
.orElse(IntervalUnit.UNKNOWN);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package com.amazon.opendistroforelasticsearch.sql.data.model;

import com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType;
import com.amazon.opendistroforelasticsearch.sql.data.type.ExprType;
import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalUnit;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class ExprIntervalValue extends AbstractExprValue {
private final TemporalAmount interval;

@Override
public TemporalAmount intervalValue() {
return interval;
}

@Override
public int compare(ExprValue other) {
TemporalAmount otherInterval = other.intervalValue();
if (!interval.getClass().equals(other.intervalValue().getClass())) {
throw new ExpressionEvaluationException(
String.format("invalid to compare intervals with units %s and %s",
unit(), ((ExprIntervalValue) other).unit()));
}
return Long.compare(
interval.get(unit()), otherInterval.get(((ExprIntervalValue) other).unit()));
}

@Override
public boolean equal(ExprValue other) {
return interval.equals(other.intervalValue());
}

@Override
public TemporalAmount value() {
return interval;
}

@Override
public ExprType type() {
return ExprCoreType.INTERVAL;
}

/**
* Util method to get temporal unit stored locally.
*/
public TemporalUnit unit() {
return interval.getUnits()
.stream()
.filter(v -> interval.get(v) != 0)
.findAny()
.orElse(interval.getUnits().get(0));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.time.Instant;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAmount;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -146,6 +147,14 @@ default ZonedDateTime dateValue() {
"invalid to get dateValue from value of type " + type());
}

/**
* Get interval value.
*/
default TemporalAmount intervalValue() {
throw new ExpressionEvaluationException(
"invalid to get intervalValue from value of type " + type());
}

/**
* Get map value.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,10 @@

package com.amazon.opendistroforelasticsearch.sql.data.model;

import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.ARRAY;
import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.BOOLEAN;
import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.STRING;
import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.STRUCT;

import com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType;
import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException;
import com.google.common.annotations.VisibleForTesting;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAmount;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
Expand Down Expand Up @@ -64,6 +59,10 @@ public static ExprValue stringValue(String value) {
return new ExprStringValue(value);
}

public static ExprValue intervalValue(TemporalAmount value) {
return new ExprIntervalValue(value);
}

/**
* {@link ExprTupleValue} constructor.
*/
Expand Down Expand Up @@ -172,4 +171,8 @@ public static Boolean getBooleanValue(ExprValue exprValue) {
public static ZonedDateTime getDateValue(ExprValue exprValue) {
return exprValue.dateValue();
}

public static TemporalAmount getIntervalValue(ExprValue exprValue) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this method?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, i've also added getTimeValue, getDatetimeValue, getTimestampValue in the other PR #694 to stay consistent. We can also remove all these methods including the getDateValue actually

return exprValue.intervalValue();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public enum ExprCoreType implements ExprType {
TIMESTAMP,
DATE,
TIME,
INTERVAL,

/**
* Struct.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,4 +325,9 @@ public FunctionExpression isnull(Expression... expressions) {
public FunctionExpression isnotnull(Expression... expressions) {
return function(BuiltinFunctionName.IS_NOT_NULL, expressions);
}

public FunctionExpression interval(Expression value, Expression unit) {
return (FunctionExpression) repository.compile(
BuiltinFunctionName.INTERVAL.getName(), Arrays.asList(value, unit));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.amazon.opendistroforelasticsearch.sql.expression.DSL;
import com.amazon.opendistroforelasticsearch.sql.expression.aggregation.AggregatorFunction;
import com.amazon.opendistroforelasticsearch.sql.expression.datetime.DateTimeFunction;
import com.amazon.opendistroforelasticsearch.sql.expression.datetime.IntervalClause;
import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionRepository;
import com.amazon.opendistroforelasticsearch.sql.expression.operator.arthmetic.ArithmeticFunction;
import com.amazon.opendistroforelasticsearch.sql.expression.operator.arthmetic.MathematicalFunction;
Expand Down Expand Up @@ -45,6 +46,7 @@ public BuiltinFunctionRepository functionRepository() {
UnaryPredicateOperator.register(builtinFunctionRepository);
AggregatorFunction.register(builtinFunctionRepository);
DateTimeFunction.register(builtinFunctionRepository);
IntervalClause.register(builtinFunctionRepository);
return builtinFunctionRepository;
}

Expand Down
Loading