Skip to content

Commit f1e3b5b

Browse files
authored
Support decimal literal with Calcite (opensearch-project#3673)
1 parent f2365b4 commit f1e3b5b

37 files changed

Lines changed: 461 additions & 156 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: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import lombok.RequiredArgsConstructor;
1010
import org.opensearch.sql.data.type.ExprCoreType;
1111

12-
/** The DataType defintion in AST. Question, could we use {@link ExprCoreType} directly in AST? */
12+
/** The DataType definition in AST. Question, could we use {@link ExprCoreType} directly in AST? */
1313
@RequiredArgsConstructor
1414
public enum DataType {
1515
TYPE_ERROR(ExprCoreType.UNKNOWN),
@@ -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
@@ -122,6 +122,8 @@ public RexNode visitLiteral(Literal node, CalcitePlanContext context) {
122122
return rexBuilder.makeApproxLiteral(
123123
new BigDecimal(Double.toString((Double) value)),
124124
typeFactory.createSqlType(SqlTypeName.DOUBLE));
125+
case DECIMAL:
126+
return rexBuilder.makeExactLiteral((BigDecimal) value);
125127
case BOOLEAN:
126128
return rexBuilder.makeLiteral((Boolean) value);
127129
case DATE:
@@ -132,9 +134,6 @@ public RexNode visitLiteral(Literal node, CalcitePlanContext context) {
132134
case TIMESTAMP:
133135
return rexBuilder.makeTimestampLiteral(
134136
new TimestampString(value.toString()), RelDataType.PRECISION_NOT_SPECIFIED);
135-
case INTERVAL:
136-
// return rexBuilder.makeIntervalLiteral(BigDecimal.valueOf((long)
137-
// node.getValue()));
138137
default:
139138
throw new UnsupportedOperationException("Unsupported literal type: " + node.getType());
140139
}

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/executor/OpenSearchTypeSystem.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,33 @@ private OpenSearchTypeSystem() {}
1818

1919
@Override
2020
public RelDataType deriveAvgAggType(RelDataTypeFactory typeFactory, RelDataType argumentType) {
21-
if (SqlTypeName.INT_TYPES.contains(argumentType.getSqlTypeName())) {
21+
if (SqlTypeName.DECIMAL == argumentType.getSqlTypeName()) {
22+
return typeFactory.createTypeWithNullability(highPrecision(typeFactory, argumentType), false);
23+
} else if (SqlTypeName.INT_TYPES.contains(argumentType.getSqlTypeName())) {
2224
return typeFactory.createTypeWithNullability(
2325
typeFactory.createSqlType(SqlTypeName.DOUBLE), false);
2426
} else {
2527
return argumentType;
2628
}
2729
}
30+
31+
/**
32+
* Compute a higher precision version of a type.
33+
*
34+
* @return If type is a DECIMAL type, return a type with the precision and scale +4, to align the
35+
* behaviour with Apache Spark.
36+
*/
37+
public static RelDataType highPrecision(
38+
final RelDataTypeFactory typeFactory, final RelDataType type) {
39+
if (type.getSqlTypeName() == SqlTypeName.DECIMAL) {
40+
return typeFactory.createSqlType(
41+
type.getSqlTypeName(),
42+
Math.min(
43+
type.getPrecision() + 4,
44+
typeFactory.getTypeSystem().getMaxPrecision(SqlTypeName.DECIMAL)),
45+
Math.min(
46+
type.getScale() + 4, typeFactory.getTypeSystem().getMaxScale(SqlTypeName.DECIMAL)));
47+
}
48+
return type;
49+
}
2850
}

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
@@ -196,7 +196,7 @@ void populate() {
196196
registerOperator(ADD, SqlStdOperatorTable.PLUS);
197197
registerOperator(SUBTRACT, SqlStdOperatorTable.MINUS);
198198
registerOperator(MULTIPLY, SqlStdOperatorTable.MULTIPLY);
199-
// registerOperator(DIVIDE, SqlStdOperatorTable.DIVIDE);
199+
registerOperator(TRUNCATE, SqlStdOperatorTable.TRUNCATE);
200200
registerOperator(ASCII, SqlStdOperatorTable.ASCII);
201201
registerOperator(LENGTH, SqlStdOperatorTable.CHAR_LENGTH);
202202
registerOperator(LOWER, SqlStdOperatorTable.LOWER);

0 commit comments

Comments
 (0)