Skip to content

Commit 91309af

Browse files
committed
Support decimal literal with Calcite
Signed-off-by: Lantao Jin <ltjin@amazon.com>
1 parent 730f066 commit 91309af

31 files changed

Lines changed: 372 additions & 66 deletions

core/src/main/java/org/opensearch/sql/ast/dsl/AstDSL.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package org.opensearch.sql.ast.dsl;
77

88
import com.google.common.collect.ImmutableList;
9+
import java.math.BigDecimal;
910
import java.util.ArrayList;
1011
import java.util.Arrays;
1112
import java.util.List;
@@ -213,6 +214,14 @@ public static Literal doubleLiteral(Double value) {
213214
return literal(value, DataType.DOUBLE);
214215
}
215216

217+
public static Literal decimalLiteral(Double value) {
218+
return literal(BigDecimal.valueOf(value), DataType.DECIMAL);
219+
}
220+
221+
public static Literal decimalLiteral(BigDecimal value) {
222+
return literal(value, DataType.DECIMAL);
223+
}
224+
216225
public static Literal stringLiteral(String value) {
217226
return literal(value, DataType.STRING);
218227
}

core/src/main/java/org/opensearch/sql/ast/expression/DataType.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ public enum DataType {
2828
TIMESTAMP(ExprCoreType.TIMESTAMP),
2929
INTERVAL(ExprCoreType.INTERVAL),
3030

31+
// the decimal DataType is only used for building decimal literal,
32+
// so it still maps to double core type until we support decimal type.
33+
// ref https://github.com/opensearch-project/sql/issues/3619
34+
DECIMAL(ExprCoreType.DOUBLE),
35+
3136
IP(ExprCoreType.IP);
3237

3338
@Getter private final ExprCoreType coreType;

core/src/main/java/org/opensearch/sql/ast/expression/Literal.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
package org.opensearch.sql.ast.expression;
77

88
import com.google.common.collect.ImmutableList;
9+
import java.math.BigDecimal;
910
import java.util.List;
1011
import lombok.EqualsAndHashCode;
1112
import lombok.Getter;
12-
import lombok.RequiredArgsConstructor;
1313
import org.opensearch.sql.ast.AbstractNodeVisitor;
1414

1515
/**
@@ -18,12 +18,20 @@
1818
*/
1919
@Getter
2020
@EqualsAndHashCode(callSuper = false)
21-
@RequiredArgsConstructor
2221
public class Literal extends UnresolvedExpression {
2322

2423
private final Object value;
2524
private final DataType type;
2625

26+
public Literal(Object value, DataType dataType) {
27+
if (dataType == DataType.DECIMAL && value instanceof Double) {
28+
this.value = BigDecimal.valueOf((Double) value);
29+
} else {
30+
this.value = value;
31+
}
32+
this.type = dataType;
33+
}
34+
2735
@Override
2836
public List<UnresolvedExpression> getChild() {
2937
return ImmutableList.of();

core/src/main/java/org/opensearch/sql/ast/tree/AD.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
@Getter
2121
@Setter
2222
@ToString
23-
@EqualsAndHashCode(callSuper = true)
23+
@EqualsAndHashCode(callSuper = false)
2424
@RequiredArgsConstructor
2525
@AllArgsConstructor
2626
public class AD extends UnresolvedPlan {

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ public RexNode visitLiteral(Literal node, CalcitePlanContext context) {
118118
return rexBuilder.makeApproxLiteral(
119119
new BigDecimal(Double.toString((Double) value)),
120120
typeFactory.createSqlType(SqlTypeName.DOUBLE));
121+
case DECIMAL:
122+
return rexBuilder.makeExactLiteral((BigDecimal) value);
121123
case BOOLEAN:
122124
return rexBuilder.makeLiteral((Boolean) value);
123125
case DATE:
@@ -128,9 +130,6 @@ public RexNode visitLiteral(Literal node, CalcitePlanContext context) {
128130
case TIMESTAMP:
129131
return rexBuilder.makeTimestampLiteral(
130132
new TimestampString(value.toString()), RelDataType.PRECISION_NOT_SPECIFIED);
131-
case INTERVAL:
132-
// return rexBuilder.makeIntervalLiteral(BigDecimal.valueOf((long)
133-
// node.getValue()));
134133
default:
135134
throw new UnsupportedOperationException("Unsupported literal type: " + node.getType());
136135
}

core/src/main/java/org/opensearch/sql/calcite/utils/MathUtils.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,17 @@
55

66
package org.opensearch.sql.calcite.utils;
77

8+
import java.math.BigDecimal;
9+
810
public class MathUtils {
911
public static boolean isIntegral(Number n) {
1012
return n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof Long;
1113
}
1214

15+
public static boolean isDecimal(Number n) {
16+
return n instanceof BigDecimal;
17+
}
18+
1319
/**
1420
* Converts a long value to the least restrictive integral type based on the types of two input
1521
* numbers.

core/src/main/java/org/opensearch/sql/calcite/utils/OpenSearchTypeFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ public static ExprType convertSqlTypeNameToExprType(SqlTypeName sqlTypeName) {
223223
case INTEGER -> INTEGER;
224224
case BIGINT -> LONG;
225225
case FLOAT, REAL -> FLOAT;
226-
case DOUBLE -> DOUBLE;
226+
case DOUBLE, DECIMAL -> DOUBLE; // TODO the decimal is only used for literal
227227
case CHAR, VARCHAR -> STRING;
228228
case BOOLEAN -> BOOLEAN;
229229
case DATE -> DATE;

core/src/main/java/org/opensearch/sql/data/model/ExprValueUtils.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import static org.opensearch.sql.utils.ExpressionUtils.PATH_SEP;
1010

1111
import inet.ipaddr.IPAddress;
12+
import java.math.BigDecimal;
1213
import java.sql.Date;
1314
import java.sql.Time;
1415
import java.sql.Timestamp;
@@ -134,6 +135,10 @@ public static ExprValue fromObjectValue(Object o) {
134135
return LITERAL_NULL;
135136
}
136137
return doubleValue(d);
138+
} else if (o instanceof BigDecimal d) {
139+
// TODO fallback decimal to double in v2
140+
// until https://github.com/opensearch-project/sql/issues/3619 fixed.
141+
return new ExprDoubleValue(d);
137142
} else if (o instanceof String) {
138143
return stringValue((String) o);
139144
} else if (o instanceof Float f) {

core/src/main/java/org/opensearch/sql/expression/function/PPLFuncImpTable.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ void populate() {
166166
registerOperator(ADD, SqlStdOperatorTable.PLUS);
167167
registerOperator(SUBTRACT, SqlStdOperatorTable.MINUS);
168168
registerOperator(MULTIPLY, SqlStdOperatorTable.MULTIPLY);
169-
// registerOperator(DIVIDE, SqlStdOperatorTable.DIVIDE);
169+
registerOperator(TRUNCATE, SqlStdOperatorTable.TRUNCATE);
170170
registerOperator(ASCII, SqlStdOperatorTable.ASCII);
171171
registerOperator(LENGTH, SqlStdOperatorTable.CHAR_LENGTH);
172172
registerOperator(LOWER, SqlStdOperatorTable.LOWER);

core/src/main/java/org/opensearch/sql/expression/function/udf/math/DivideFunction.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
package org.opensearch.sql.expression.function.udf.math;
77

8+
import java.math.BigDecimal;
9+
import java.math.RoundingMode;
810
import java.util.List;
911
import org.apache.calcite.adapter.enumerable.NotNullImplementor;
1012
import org.apache.calcite.adapter.enumerable.NullPolicy;
@@ -24,6 +26,7 @@
2426
* PPL. Therefore, we implement our versions
2527
*/
2628
public class DivideFunction extends ImplementorUDF {
29+
public static final int MAX_SCALE = 38;
2730

2831
public DivideFunction() {
2932
super(new DivideImplementor(), NullPolicy.ANY);
@@ -54,6 +57,12 @@ public static Number divide(Number dividend, Number divisor) {
5457
if (MathUtils.isIntegral(dividend) && MathUtils.isIntegral(divisor)) {
5558
long result = dividend.longValue() / divisor.longValue();
5659
return MathUtils.coerceToWidestIntegralType(dividend, divisor, result);
60+
} else if (MathUtils.isDecimal(dividend) && MathUtils.isIntegral(divisor)) {
61+
return ((BigDecimal) dividend)
62+
.divide(BigDecimal.valueOf(divisor.longValue()), MAX_SCALE + 1, RoundingMode.HALF_UP);
63+
} else if (MathUtils.isIntegral(dividend) && MathUtils.isDecimal(divisor)) {
64+
return (BigDecimal.valueOf(dividend.longValue()))
65+
.divide((BigDecimal) divisor, MAX_SCALE + 1, RoundingMode.HALF_UP);
5766
}
5867
double result = dividend.doubleValue() / divisor.doubleValue();
5968
return MathUtils.coerceToWidestFloatingType(dividend, divisor, result);

0 commit comments

Comments
 (0)