This is an automated email from the ASF dual-hosted git repository.
xiong pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push:
new 6c7685cb56 [CALCITE-4838] Add RoundingMode in RelDataTypeSystem to
specify the rounding behavior
6c7685cb56 is described below
commit 6c7685cb568494cfe927420a157eae414d80f5e3
Author: Xiong Duan <[email protected]>
AuthorDate: Fri Aug 16 20:07:53 2024 +0800
[CALCITE-4838] Add RoundingMode in RelDataTypeSystem to specify the
rounding behavior
---
.../adapter/enumerable/RexToLixTranslator.java | 34 +-
.../calcite/rel/type/DelegatingTypeSystem.java | 6 +
.../apache/calcite/rel/type/RelDataTypeSystem.java | 5 +
.../calcite/rel/type/RelDataTypeSystemImpl.java | 6 +
.../org/apache/calcite/util/BuiltInMethod.java | 21 +-
.../org/apache/calcite/test/CoreQuidemTest.java | 9 +
.../calcite/test/CustomRelDataTypeSystem.java | 40 ++
core/src/test/resources/sql/misc.iq | 426 +++++++++++++++++++++
.../apache/calcite/linq4j/tree/Expressions.java | 12 +-
.../org/apache/calcite/linq4j/tree/Primitive.java | 105 ++++-
.../calcite/linq4j/tree/UnaryExpression.java | 4 +-
11 files changed, 626 insertions(+), 42 deletions(-)
diff --git
a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
index 39014391da..aedee05227 100644
---
a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
+++
b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
@@ -456,45 +456,51 @@ public class RexToLixTranslator implements
RexVisitor<RexToLixTranslator.Result>
&& scale != RelDataType.SCALE_NOT_SPECIFIED) {
if (sourceType.getFamily() == SqlTypeFamily.CHARACTER) {
return Expressions.call(
- BuiltInMethod.CHAR_DECIMAL_CAST.method,
+ BuiltInMethod.CHAR_DECIMAL_CAST_ROUNDING_MODE.method,
operand,
Expressions.constant(precision),
- Expressions.constant(scale));
+ Expressions.constant(scale),
+
Expressions.constant(typeFactory.getTypeSystem().roundingMode()));
} else if (sourceType.getFamily() == SqlTypeFamily.INTERVAL_DAY_TIME) {
return Expressions.call(
- BuiltInMethod.SHORT_INTERVAL_DECIMAL_CAST.method,
+ BuiltInMethod.SHORT_INTERVAL_DECIMAL_CAST_ROUNDING_MODE.method,
operand,
Expressions.constant(precision),
Expressions.constant(scale),
-
Expressions.constant(sourceType.getSqlTypeName().getEndUnit().multiplier));
+
Expressions.constant(sourceType.getSqlTypeName().getEndUnit().multiplier),
+
Expressions.constant(typeFactory.getTypeSystem().roundingMode()));
} else if (sourceType.getFamily() ==
SqlTypeFamily.INTERVAL_YEAR_MONTH) {
return Expressions.call(
- BuiltInMethod.LONG_INTERVAL_DECIMAL_CAST.method,
+ BuiltInMethod.LONG_INTERVAL_DECIMAL_CAST_ROUNDING_MODE.method,
operand,
Expressions.constant(precision),
Expressions.constant(scale),
-
Expressions.constant(sourceType.getSqlTypeName().getEndUnit().multiplier));
+
Expressions.constant(sourceType.getSqlTypeName().getEndUnit().multiplier),
+
Expressions.constant(typeFactory.getTypeSystem().roundingMode()));
} else if (sourceType.getSqlTypeName() == SqlTypeName.DECIMAL) {
// Cast from DECIMAL to DECIMAL, may adjust scale and precision.
return Expressions.call(
- BuiltInMethod.DECIMAL_DECIMAL_CAST.method,
+ BuiltInMethod.DECIMAL_DECIMAL_CAST_ROUNDING_MODE.method,
operand,
Expressions.constant(precision),
- Expressions.constant(scale));
+ Expressions.constant(scale),
+
Expressions.constant(typeFactory.getTypeSystem().roundingMode()));
} else if
(SqlTypeName.INT_TYPES.contains(sourceType.getSqlTypeName())) {
// Cast from INTEGER to DECIMAL, check for overflow
return Expressions.call(
- BuiltInMethod.INTEGER_DECIMAL_CAST.method,
+ BuiltInMethod.INTEGER_DECIMAL_CAST_ROUNDING_MODE.method,
operand,
Expressions.constant(precision),
- Expressions.constant(scale));
+ Expressions.constant(scale),
+
Expressions.constant(typeFactory.getTypeSystem().roundingMode()));
} else if
(SqlTypeName.APPROX_TYPES.contains(sourceType.getSqlTypeName())) {
// Cast from FLOAT/DOUBLE to DECIMAL
return Expressions.call(
- BuiltInMethod.FP_DECIMAL_CAST.method,
+ BuiltInMethod.FP_DECIMAL_CAST_ROUNDING_MODE.method,
operand,
Expressions.constant(precision),
- Expressions.constant(scale));
+ Expressions.constant(scale),
+
Expressions.constant(typeFactory.getTypeSystem().roundingMode()));
}
}
return defaultExpression.get();
@@ -505,9 +511,9 @@ public class RexToLixTranslator implements
RexVisitor<RexToLixTranslator.Result>
case SMALLINT: {
if (SqlTypeName.NUMERIC_TYPES.contains(sourceType.getSqlTypeName())) {
return Expressions.call(
- BuiltInMethod.INTEGER_CAST.method,
+ BuiltInMethod.INTEGER_CAST_ROUNDING_MODE.method,
Expressions.constant(Primitive.of(typeFactory.getJavaClass(targetType))),
- operand);
+ operand,
Expressions.constant(typeFactory.getTypeSystem().roundingMode()));
}
return defaultExpression.get();
}
diff --git
a/core/src/main/java/org/apache/calcite/rel/type/DelegatingTypeSystem.java
b/core/src/main/java/org/apache/calcite/rel/type/DelegatingTypeSystem.java
index 96b8628a9b..edc8d16d50 100644
--- a/core/src/main/java/org/apache/calcite/rel/type/DelegatingTypeSystem.java
+++ b/core/src/main/java/org/apache/calcite/rel/type/DelegatingTypeSystem.java
@@ -20,6 +20,8 @@ import org.apache.calcite.sql.type.SqlTypeName;
import org.checkerframework.checker.nullness.qual.Nullable;
+import java.math.RoundingMode;
+
/** Implementation of {@link org.apache.calcite.rel.type.RelDataTypeSystem}
* that sends all methods to an underlying object. */
public class DelegatingTypeSystem implements RelDataTypeSystem {
@@ -50,6 +52,10 @@ public class DelegatingTypeSystem implements
RelDataTypeSystem {
return typeSystem.getMaxNumericPrecision();
}
+ @Override public RoundingMode roundingMode() {
+ return typeSystem.roundingMode();
+ }
+
@Override public @Nullable String getLiteral(SqlTypeName typeName, boolean
isPrefix) {
return typeSystem.getLiteral(typeName, isPrefix);
}
diff --git
a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystem.java
b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystem.java
index ba2b0e6f60..ebe900650e 100644
--- a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystem.java
+++ b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystem.java
@@ -22,6 +22,8 @@ import org.apache.calcite.util.Glossary;
import org.checkerframework.checker.nullness.qual.Nullable;
+import java.math.RoundingMode;
+
/**
* Type system.
*
@@ -60,6 +62,9 @@ public interface RelDataTypeSystem {
/** Returns the maximum precision of a NUMERIC or DECIMAL type. */
int getMaxNumericPrecision();
+ /** Returns the rounding behavior for numerical operations capable of
discarding precision. */
+ RoundingMode roundingMode();
+
/** Returns the LITERAL string for the type, either PREFIX/SUFFIX. */
@Nullable String getLiteral(SqlTypeName typeName, boolean isPrefix);
diff --git
a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java
b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java
index d4a9cac0f8..1b057909e3 100644
--- a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java
+++ b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java
@@ -22,6 +22,8 @@ import org.apache.calcite.sql.type.SqlTypeName;
import org.checkerframework.checker.nullness.qual.Nullable;
+import java.math.RoundingMode;
+
/** Default implementation of
* {@link org.apache.calcite.rel.type.RelDataTypeSystem},
* providing parameters from the SQL standard.
@@ -160,6 +162,10 @@ public abstract class RelDataTypeSystemImpl implements
RelDataTypeSystem {
return 19;
}
+ @Override public RoundingMode roundingMode() {
+ return RoundingMode.DOWN;
+ }
+
@Override public @Nullable String getLiteral(SqlTypeName typeName, boolean
isPrefix) {
switch (typeName) {
case VARBINARY:
diff --git a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
index 7d74ccd37a..bd94cad2f2 100644
--- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
+++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
@@ -125,6 +125,7 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
+import java.math.RoundingMode;
import java.nio.charset.Charset;
import java.sql.ResultSet;
import java.sql.Time;
@@ -159,10 +160,16 @@ public enum BuiltInMethod {
AS_QUERYABLE(Enumerable.class, "asQueryable"),
ABSTRACT_ENUMERABLE_CTOR(AbstractEnumerable.class),
CHAR_DECIMAL_CAST(Primitive.class, "charToDecimalCast", String.class,
int.class, int.class),
+ CHAR_DECIMAL_CAST_ROUNDING_MODE(Primitive.class, "charToDecimalCast",
+ String.class, int.class, int.class, RoundingMode.class),
SHORT_INTERVAL_DECIMAL_CAST(Primitive.class, "shortIntervalToDecimalCast",
Long.class, int.class, int.class, BigDecimal.class),
+ SHORT_INTERVAL_DECIMAL_CAST_ROUNDING_MODE(Primitive.class,
"shortIntervalToDecimalCast",
+ Long.class, int.class, int.class, BigDecimal.class, RoundingMode.class),
LONG_INTERVAL_DECIMAL_CAST(Primitive.class, "longIntervalToDecimalCast",
Integer.class, int.class, int.class, BigDecimal.class),
+ LONG_INTERVAL_DECIMAL_CAST_ROUNDING_MODE(Primitive.class,
"longIntervalToDecimalCast",
+ Integer.class, int.class, int.class, BigDecimal.class,
RoundingMode.class),
INTO(ExtendedEnumerable.class, "into", Collection.class),
REMOVE_ALL(ExtendedEnumerable.class, "removeAll", Collection.class),
SCHEMA_GET_SUB_SCHEMA(Schema.class, "getSubSchema", String.class),
@@ -310,11 +317,17 @@ public enum BuiltInMethod {
AS_LIST(Primitive.class, "asList", Object.class),
DECIMAL_DECIMAL_CAST(Primitive.class, "decimalDecimalCast",
BigDecimal.class, int.class, int.class),
- INTEGER_DECIMAL_CAST(Primitive.class, "integerDecimalCast",
- Number.class, int.class, int.class),
- FP_DECIMAL_CAST(Primitive.class, "fpDecimalCast",
- Number.class, int.class, int.class),
+ DECIMAL_DECIMAL_CAST_ROUNDING_MODE(Primitive.class, "decimalDecimalCast",
+ BigDecimal.class, int.class, int.class, RoundingMode.class),
+ INTEGER_DECIMAL_CAST(Primitive.class, "integerDecimalCast", Number.class,
int.class, int.class),
+ INTEGER_DECIMAL_CAST_ROUNDING_MODE(Primitive.class, "integerDecimalCast",
+ Number.class, int.class, int.class, RoundingMode.class),
+ FP_DECIMAL_CAST(Primitive.class, "fpDecimalCast", Number.class, int.class,
int.class),
+ FP_DECIMAL_CAST_ROUNDING_MODE(Primitive.class, "fpDecimalCast",
+ Number.class, int.class, int.class, RoundingMode.class),
INTEGER_CAST(Primitive.class, "integerCast", Primitive.class, Object.class),
+ INTEGER_CAST_ROUNDING_MODE(Primitive.class, "integerCast",
+ Primitive.class, Object.class, RoundingMode.class),
MEMORY_GET0(MemoryFactory.Memory.class, "get"),
MEMORY_GET1(MemoryFactory.Memory.class, "get", int.class),
ENUMERATOR_CURRENT(Enumerator.class, "current"),
diff --git a/core/src/test/java/org/apache/calcite/test/CoreQuidemTest.java
b/core/src/test/java/org/apache/calcite/test/CoreQuidemTest.java
index 8fbbf3d6ab..5b325e1a54 100644
--- a/core/src/test/java/org/apache/calcite/test/CoreQuidemTest.java
+++ b/core/src/test/java/org/apache/calcite/test/CoreQuidemTest.java
@@ -68,6 +68,15 @@ class CoreQuidemTest extends QuidemTest {
.with(CalciteConnectionProperty.FUN, SqlLibrary.CALCITE.fun)
.with(CalciteAssert.Config.SCOTT)
.connect();
+ case "scott-rounding-half-up":
+ return CalciteAssert.that()
+ .with(CalciteConnectionProperty.PARSER_FACTORY,
+ ExtensionDdlExecutor.class.getName() + "#PARSER_FACTORY")
+ .with(CalciteConnectionProperty.FUN, SqlLibrary.CALCITE.fun)
+ .with(CalciteConnectionProperty.TYPE_SYSTEM,
+ CustomRelDataTypeSystem.class.getName() +
"#ROUNDING_MODE_HALF_UP")
+ .with(CalciteAssert.Config.SCOTT)
+ .connect();
case "scott-lenient":
// Same as "scott", but uses LENIENT conformance.
// TODO: add a way to change conformance without defining a new
diff --git
a/core/src/test/java/org/apache/calcite/test/CustomRelDataTypeSystem.java
b/core/src/test/java/org/apache/calcite/test/CustomRelDataTypeSystem.java
new file mode 100644
index 0000000000..a230d18ae4
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/test/CustomRelDataTypeSystem.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 org.apache.calcite.test;
+
+import org.apache.calcite.rel.type.RelDataTypeSystem;
+import org.apache.calcite.rel.type.RelDataTypeSystemImpl;
+
+import java.math.RoundingMode;
+
+/**
+ * Custom type system only for Quidem test.
+ *
+ * <p> Specify the rounding behaviour. In the default implementation,
+ * the rounding mode is {@link RoundingMode#DOWN}, but here is {@link
RoundingMode#HALF_UP}
+ *
+ * <p>The default implementation is {@link #DEFAULT}.
+ */
+
+public class CustomRelDataTypeSystem extends RelDataTypeSystemImpl {
+
+ public static final RelDataTypeSystem ROUNDING_MODE_HALF_UP = new
CustomRelDataTypeSystem();
+
+ @Override public RoundingMode roundingMode() {
+ return RoundingMode.HALF_UP;
+ }
+}
diff --git a/core/src/test/resources/sql/misc.iq
b/core/src/test/resources/sql/misc.iq
index 224d6a1d13..fdc8802bab 100644
--- a/core/src/test/resources/sql/misc.iq
+++ b/core/src/test/resources/sql/misc.iq
@@ -2658,4 +2658,430 @@ FROM "hr"."emps";
!ok
+# [CALCITE-4838] Add RoundingMode in RelDataTypeSystem to specify the rounding
behavior
+!use scott-rounding-half-up
+
+# Test cast approximate numeric to int when rounding mode is HALF-UP
+select cast(5.5 as int),
+ cast(3.5 as int),
+ cast(1.6 as int),
+ cast(1.1 as int),
+ cast(1.0 as int),
+ cast(-1.0 as int),
+ cast(-1.1 as int),
+ cast(-1.6 as int),
+ cast(-2.5 as int),
+ cast(15.5 as int)
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 6 | 4 | 2 | 1 | 1 | -1 | -1 | -2 |
-3 | 16 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+# Test cast approximate numeric to tinyint when rounding mode is HALF-UP
+select cast(5.5 as tinyint),
+ cast(3.5 as tinyint),
+ cast(1.6 as tinyint),
+ cast(1.1 as tinyint),
+ cast(1.0 as tinyint),
+ cast(-1.0 as tinyint),
+ cast(-1.1 as tinyint),
+ cast(-1.6 as tinyint),
+ cast(-2.5 as tinyint),
+ cast(15.5 as tinyint)
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 6 | 4 | 2 | 1 | 1 | -1 | -1 | -2 |
-3 | 16 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+# Test cast approximate numeric to smallint when rounding mode is HALF-UP
+select cast(5.5 as smallint),
+ cast(3.5 as smallint),
+ cast(1.6 as smallint),
+ cast(1.1 as smallint),
+ cast(1.0 as smallint),
+ cast(-1.0 as smallint),
+ cast(-1.1 as smallint),
+ cast(-1.6 as smallint),
+ cast(-2.5 as smallint),
+ cast(15.5 as smallint)
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 6 | 4 | 2 | 1 | 1 | -1 | -1 | -2 |
-3 | 16 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+# Test cast approximate numeric to bigint when rounding mode is HALF-UP
+select cast(5.5 as bigint),
+ cast(3.5 as bigint),
+ cast(1.6 as bigint),
+ cast(1.1 as bigint),
+ cast(1.0 as bigint),
+ cast(-1.0 as bigint),
+ cast(-1.1 as bigint),
+ cast(-1.6 as bigint),
+ cast(-2.5 as bigint),
+ cast(15.5 as bigint)
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 6 | 4 | 2 | 1 | 1 | -1 | -1 | -2 |
-3 | 16 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+# Test cast decimal to decimal when rounding mode is HALF-UP
+select cast(cast(5.55 as decimal(3,2)) as decimal(2,1)),
+ cast(cast(3.55 as decimal(3,2)) as decimal(2,1)),
+ cast(cast(1.66 as decimal(3,2)) as decimal(2,1)),
+ cast(cast(1.11 as decimal(3,2)) as decimal(2,1)),
+ cast(cast(1.00 as decimal(3,2)) as decimal(2,1)),
+ cast(cast(-1.00 as decimal(3,2)) as decimal(2,1)),
+ cast(cast(-1.11 as decimal(3,2)) as decimal(2,1)),
+ cast(cast(-1.66 as decimal(3,2)) as decimal(2,1)),
+ cast(cast(-2.55 as decimal(3,2)) as decimal(2,1)),
+ cast(cast(15.55 as decimal(4,2)) as decimal(3,1))
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 5.6 | 3.6 | 1.7 | 1.1 | 1.0 | -1.0 | -1.1 | -1.7 |
-2.6 | 15.6 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+# Test cast varchar to decimal when rounding mode is HALF-UP
+select cast('5.5' as decimal(2, 0)),
+ cast('3.5' as decimal(2, 0)),
+ cast('1.6' as decimal(2, 0)),
+ cast('1.1' as decimal(2, 0)),
+ cast('1.0' as decimal(2, 0)),
+ cast('-1.0' as decimal(2, 0)),
+ cast('-1.1' as decimal(2, 0)),
+ cast('-1.6' as decimal(2, 0)),
+ cast('-2.5' as decimal(2, 0)),
+ cast('15.5' as decimal(2, 0))
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 6 | 4 | 2 | 1 | 1 | -1 | -1 | -2 |
-3 | 16 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+# Test cast float to decimal when rounding mode is HALF-UP
+select cast(cast(5.5 as float) as decimal(2,0)),
+ cast(cast(3.5 as float) as decimal(2,0)),
+ cast(cast(1.6 as float) as decimal(2,0)),
+ cast(cast(1.1 as float) as decimal(2,0)),
+ cast(cast(1.0 as float) as decimal(2,0)),
+ cast(cast(-1.0 as float) as decimal(2,0)),
+ cast(cast(-1.1 as float) as decimal(2,0)),
+ cast(cast(-1.6 as float) as decimal(2,0)),
+ cast(cast(-2.5 as float) as decimal(2,0)),
+ cast(cast(15.5 as float) as decimal(2,0))
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 6 | 4 | 2 | 1 | 1 | -1 | -1 | -2 |
-3 | 16 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+# Test cast float to decimal but rounding behavior happens in scala when
rounding mode is HALF-UP
+select cast(cast(5.55 as float) as decimal(2,1)),
+ cast(cast(3.55 as float) as decimal(2,1)),
+ cast(cast(1.66 as float) as decimal(2,1)),
+ cast(cast(1.11 as float) as decimal(2,1)),
+ cast(cast(1.00 as float) as decimal(2,1)),
+ cast(cast(-1.00 as float) as decimal(2,1)),
+ cast(cast(-1.11 as float) as decimal(2,1)),
+ cast(cast(-1.66 as float) as decimal(2,1)),
+ cast(cast(-2.55 as float) as decimal(2,1)),
+ cast(cast(15.55 as float) as decimal(3,1))
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 5.6 | 3.6 | 1.7 | 1.1 | 1.0 | -1.0 | -1.1 | -1.7 |
-2.6 | 15.6 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+# Test cast double to decimal when rounding mode is HALF-UP
+select cast(cast(5.5 as double) as decimal(2,0)),
+ cast(cast(3.5 as double) as decimal(2,0)),
+ cast(cast(1.6 as double) as decimal(2,0)),
+ cast(cast(1.1 as double) as decimal(2,0)),
+ cast(cast(1.0 as double) as decimal(2,0)),
+ cast(cast(-1.0 as double) as decimal(2,0)),
+ cast(cast(-1.1 as double) as decimal(2,0)),
+ cast(cast(-1.6 as double) as decimal(2,0)),
+ cast(cast(-2.5 as double) as decimal(2,0)),
+ cast(cast(15.5 as double) as decimal(2,0))
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 6 | 4 | 2 | 1 | 1 | -1 | -1 | -2 |
-3 | 16 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+# Test cast double to decimal but rounding behavior happens in scala when
rounding mode is HALF-UP
+select cast(cast(5.55 as double) as decimal(2,1)),
+ cast(cast(3.55 as double) as decimal(2,1)),
+ cast(cast(1.66 as double) as decimal(2,1)),
+ cast(cast(1.11 as double) as decimal(2,1)),
+ cast(cast(1.00 as double) as decimal(2,1)),
+ cast(cast(-1.00 as double) as decimal(2,1)),
+ cast(cast(-1.11 as double) as decimal(2,1)),
+ cast(cast(-1.66 as double) as decimal(2,1)),
+ cast(cast(-2.55 as double) as decimal(2,1)),
+ cast(cast(15.55 as double) as decimal(3,1))
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 5.6 | 3.6 | 1.7 | 1.1 | 1.0 | -1.0 | -1.1 | -1.7 |
-2.6 | 15.6 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+
+!use scott
+
+# Test cast approximate numeric to int when rounding mode is DOWN
+select cast(5.5 as int),
+ cast(3.5 as int),
+ cast(1.6 as int),
+ cast(1.1 as int),
+ cast(1.0 as int),
+ cast(-1.0 as int),
+ cast(-1.1 as int),
+ cast(-1.6 as int),
+ cast(-2.5 as int),
+ cast(15.5 as int)
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 5 | 3 | 1 | 1 | 1 | -1 | -1 | -1 |
-2 | 15 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+# Test cast approximate numeric to tinyint when rounding mode is DOWN
+select cast(5.5 as tinyint),
+ cast(3.5 as tinyint),
+ cast(1.6 as tinyint),
+ cast(1.1 as tinyint),
+ cast(1.0 as tinyint),
+ cast(-1.0 as tinyint),
+ cast(-1.1 as tinyint),
+ cast(-1.6 as tinyint),
+ cast(-2.5 as tinyint),
+ cast(15.5 as tinyint)
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 5 | 3 | 1 | 1 | 1 | -1 | -1 | -1 |
-2 | 15 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+# Test cast approximate numeric to smallint when rounding mode is DOWN
+select cast(5.5 as smallint),
+ cast(3.5 as smallint),
+ cast(1.6 as smallint),
+ cast(1.1 as smallint),
+ cast(1.0 as smallint),
+ cast(-1.0 as smallint),
+ cast(-1.1 as smallint),
+ cast(-1.6 as smallint),
+ cast(-2.5 as smallint),
+ cast(15.5 as smallint)
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 5 | 3 | 1 | 1 | 1 | -1 | -1 | -1 |
-2 | 15 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+# Test cast approximate numeric to bigint when rounding mode is DOWN
+select cast(5.5 as bigint),
+ cast(3.5 as bigint),
+ cast(1.6 as bigint),
+ cast(1.1 as bigint),
+ cast(1.0 as bigint),
+ cast(-1.0 as bigint),
+ cast(-1.1 as bigint),
+ cast(-1.6 as bigint),
+ cast(-2.5 as bigint),
+ cast(15.5 as bigint)
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 5 | 3 | 1 | 1 | 1 | -1 | -1 | -1 |
-2 | 15 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+# Test cast decimal to decimal when rounding mode is DOWN
+select cast(cast(5.55 as decimal(3,2)) as decimal(2,1)),
+ cast(cast(3.55 as decimal(3,2)) as decimal(2,1)),
+ cast(cast(1.66 as decimal(3,2)) as decimal(2,1)),
+ cast(cast(1.11 as decimal(3,2)) as decimal(2,1)),
+ cast(cast(1.00 as decimal(3,2)) as decimal(2,1)),
+ cast(cast(-1.00 as decimal(3,2)) as decimal(2,1)),
+ cast(cast(-1.11 as decimal(3,2)) as decimal(2,1)),
+ cast(cast(-1.66 as decimal(3,2)) as decimal(2,1)),
+ cast(cast(-2.55 as decimal(3,2)) as decimal(2,1)),
+ cast(cast(15.55 as decimal(4,2)) as decimal(3,1))
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 5.5 | 3.5 | 1.6 | 1.1 | 1.0 | -1.0 | -1.1 | -1.6 |
-2.5 | 15.5 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+# Test cast varchar to decimal when rounding mode is DOWN
+select cast('5.5' as decimal(2, 0)),
+ cast('3.5' as decimal(2, 0)),
+ cast('1.6' as decimal(2, 0)),
+ cast('1.1' as decimal(2, 0)),
+ cast('1.0' as decimal(2, 0)),
+ cast('-1.0' as decimal(2, 0)),
+ cast('-1.1' as decimal(2, 0)),
+ cast('-1.6' as decimal(2, 0)),
+ cast('-2.5' as decimal(2, 0)),
+ cast('15.5' as decimal(2, 0))
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 5 | 3 | 1 | 1 | 1 | -1 | -1 | -1 |
-2 | 15 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+# Test cast float to decimal when rounding mode is DOWN
+select cast(cast(5.5 as float) as decimal(2,0)),
+ cast(cast(3.5 as float) as decimal(2,0)),
+ cast(cast(1.6 as float) as decimal(2,0)),
+ cast(cast(1.1 as float) as decimal(2,0)),
+ cast(cast(1.0 as float) as decimal(2,0)),
+ cast(cast(-1.0 as float) as decimal(2,0)),
+ cast(cast(-1.1 as float) as decimal(2,0)),
+ cast(cast(-1.6 as float) as decimal(2,0)),
+ cast(cast(-2.5 as float) as decimal(2,0)),
+ cast(cast(15.5 as float) as decimal(2,0))
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 5 | 3 | 1 | 1 | 1 | -1 | -1 | -1 |
-2 | 15 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+# Test cast float to decimal but rounding behavior happens in scala when
rounding mode is DOWN
+select cast(cast(5.55 as float) as decimal(2,1)),
+ cast(cast(3.55 as float) as decimal(2,1)),
+ cast(cast(1.66 as float) as decimal(2,1)),
+ cast(cast(1.11 as float) as decimal(2,1)),
+ cast(cast(1.00 as float) as decimal(2,1)),
+ cast(cast(-1.00 as float) as decimal(2,1)),
+ cast(cast(-1.11 as float) as decimal(2,1)),
+ cast(cast(-1.66 as float) as decimal(2,1)),
+ cast(cast(-2.55 as float) as decimal(2,1)),
+ cast(cast(15.55 as float) as decimal(3,1))
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 5.5 | 3.5 | 1.6 | 1.1 | 1.0 | -1.0 | -1.1 | -1.6 |
-2.5 | 15.5 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+# Test cast double to decimal when rounding mode is DOWN
+select cast(cast(5.5 as double) as decimal(2,0)),
+ cast(cast(3.5 as double) as decimal(2,0)),
+ cast(cast(1.6 as double) as decimal(2,0)),
+ cast(cast(1.1 as double) as decimal(2,0)),
+ cast(cast(1.0 as double) as decimal(2,0)),
+ cast(cast(-1.0 as double) as decimal(2,0)),
+ cast(cast(-1.1 as double) as decimal(2,0)),
+ cast(cast(-1.6 as double) as decimal(2,0)),
+ cast(cast(-2.5 as double) as decimal(2,0)),
+ cast(cast(15.5 as double) as decimal(2,0))
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 5 | 3 | 1 | 1 | 1 | -1 | -1 | -1 |
-2 | 15 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
+# Test cast double to decimal but rounding behavior happens in scala when
rounding mode is DOWN
+select cast(cast(5.55 as double) as decimal(2,1)),
+ cast(cast(3.55 as double) as decimal(2,1)),
+ cast(cast(1.66 as double) as decimal(2,1)),
+ cast(cast(1.11 as double) as decimal(2,1)),
+ cast(cast(1.00 as double) as decimal(2,1)),
+ cast(cast(-1.00 as double) as decimal(2,1)),
+ cast(cast(-1.11 as double) as decimal(2,1)),
+ cast(cast(-1.66 as double) as decimal(2,1)),
+ cast(cast(-2.55 as double) as decimal(2,1)),
+ cast(cast(15.55 as double) as decimal(3,1))
+from (values 0) as t(x);
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 | EXPR$4 | EXPR$5 | EXPR$6 | EXPR$7 |
EXPR$8 | EXPR$9 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+| 5.5 | 3.5 | 1.6 | 1.1 | 1.0 | -1.0 | -1.1 | -1.6 |
-2.5 | 15.5 |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
+(1 row)
+
+!ok
+
# End misc.iq
diff --git
a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java
b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java
index ebde1a4d3e..e41a07cc01 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java
@@ -35,6 +35,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
+import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -550,6 +551,15 @@ public abstract class Expressions {
* properties set to the specified values.
*/
public static ConstantExpression constant(@Nullable Object value, Type type)
{
+ return constant(value, type, RoundingMode.DOWN);
+ }
+
+ /**
+ * Creates a ConstantExpression that has the Value 、Type 、RoundingMode
+ * properties set to the specified values.
+ */
+ public static ConstantExpression constant(@Nullable Object value, Type type,
+ RoundingMode roundingMode) {
if (value != null && type instanceof Class) {
// Fix up value so that it matches type.
Class<?> clazz = (Class<?>) type;
@@ -572,7 +582,7 @@ public abstract class Expressions {
if (primitive != null) {
if (value instanceof Number) {
Number valueNumber = (Number) value;
- value = primitive.numberValue(valueNumber);
+ value = primitive.numberValue(valueNumber, roundingMode);
if (value == null) {
value = primitive.parse(stringValue);
}
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Primitive.java
b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Primitive.java
index 71e7d5aae1..34f40e83f6 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Primitive.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Primitive.java
@@ -386,21 +386,24 @@ public enum Primitive {
/** Called from BuiltInMethod.INTEGER_CAST */
public static @Nullable Object integerCast(Primitive primitive, final Object
value) {
- return requireNonNull(primitive, "primitive").numberValue((Number) value);
+ return requireNonNull(primitive, "primitive").numberValue((Number) value,
RoundingMode.DOWN);
}
- static BigDecimal checkOverflow(BigDecimal value, int precision, int scale) {
- // The rounding mode is not specified in any Calcite docs,
- // but elsewhere Calcite is rounding down. For example, Calcite is
frequently
- // calling BigDecimal.longValue(), which is rounding down, by ignoring all
- // digits after the decimal point.
- BigDecimal result = value.setScale(scale, RoundingMode.DOWN);
+ /** Called from BuiltInMethod.INTEGER_CAST_ROUNDING_MODE */
+ public static @Nullable Object integerCast(Primitive primitive, final Object
value,
+ RoundingMode roundingMode) {
+ return requireNonNull(primitive, "primitive").numberValue((Number) value,
roundingMode);
+ }
+
+ static BigDecimal checkOverflow(BigDecimal value, int precision, int scale,
+ RoundingMode roundingMode) {
+ BigDecimal result = value.setScale(scale, roundingMode);
result = result.stripTrailingZeros();
if (result.scale() < scale) {
// stripTrailingZeros also removes zeros if there is no
// decimal point, converting 1000 to 1e+3, using a negative scale.
// Here we undo this change.
- result = result.setScale(scale, RoundingMode.DOWN);
+ result = result.setScale(scale, roundingMode);
}
int actualPrecision = result.precision();
if (actualPrecision > precision) {
@@ -413,11 +416,17 @@ public enum Primitive {
/** Called from BuiltInMethod.CHAR_DECIMAL_CAST */
public static @Nullable Object charToDecimalCast(
@Nullable String value, int precision, int scale) {
+ return charToDecimalCast(value, precision, scale, RoundingMode.DOWN);
+ }
+
+ /** Called from BuiltInMethod.CHAR_DECIMAL_CAST_ROUNDING_MODE */
+ public static @Nullable Object charToDecimalCast(
+ @Nullable String value, int precision, int scale, RoundingMode
roundingMode) {
if (value == null) {
return null;
}
BigDecimal result = new BigDecimal(value.trim());
- return checkOverflow(result, precision, scale);
+ return checkOverflow(result, precision, scale, roundingMode);
}
/**
@@ -425,13 +434,24 @@ public enum Primitive {
* Called from BuiltInMethod.SHORT_INTERVAL_DECIMAL_CAST.
* @param unitScale Scale describing source interval type */
public static @Nullable Object shortIntervalToDecimalCast(
- @Nullable Long value, int precision, int scale, BigDecimal unitScale) {
+ @Nullable Long value, int precision, int scale,
+ BigDecimal unitScale) {
+ return shortIntervalToDecimalCast(value, precision, scale, unitScale,
RoundingMode.DOWN);
+ }
+
+ /**
+ * Convert a short time interval to a decimal value.
+ * Called from BuiltInMethod.SHORT_INTERVAL_DECIMAL_CAST_ROUNDING_MODE.
+ * @param unitScale Scale describing source interval type */
+ public static @Nullable Object shortIntervalToDecimalCast(
+ @Nullable Long value, int precision, int scale,
+ BigDecimal unitScale, RoundingMode roundingMode) {
if (value == null) {
return null;
}
// Divide with the scale expected of the result
- BigDecimal result = new BigDecimal(value).divide(unitScale, scale,
RoundingMode.DOWN);
- return checkOverflow(result, precision, scale);
+ BigDecimal result = new BigDecimal(value).divide(unitScale, scale,
roundingMode);
+ return checkOverflow(result, precision, scale, roundingMode);
}
/**
@@ -439,42 +459,75 @@ public enum Primitive {
* Called from BuiltInMethod.LONG_INTERVAL_DECIMAL_CAST.
* @param unitScale Scale describing source interval type */
public static @Nullable Object longIntervalToDecimalCast(
- @Nullable Integer value, int precision, int scale, BigDecimal unitScale)
{
+ @Nullable Integer value, int precision, int scale,
+ BigDecimal unitScale) {
+ return longIntervalToDecimalCast(value, precision, scale, unitScale,
RoundingMode.DOWN);
+ }
+
+ /**
+ * Convert a long time interval to a decimal value.
+ * Called from BuiltInMethod.LONG_INTERVAL_DECIMAL_CAST_ROUNDING_MODE.
+ * @param unitScale Scale describing source interval type */
+ public static @Nullable Object longIntervalToDecimalCast(
+ @Nullable Integer value, int precision, int scale,
+ BigDecimal unitScale, RoundingMode roundingMode) {
if (value == null) {
return null;
}
// Divide with the scale expected of the result
- BigDecimal result = new BigDecimal(value).divide(unitScale, scale,
RoundingMode.DOWN);
- return checkOverflow(result, precision, scale);
+ BigDecimal result = new BigDecimal(value).divide(unitScale, scale,
roundingMode);
+ return checkOverflow(result, precision, scale, roundingMode);
}
/** Called from BuiltInMethod.DECIMAL_DECIMAL_CAST */
public static @Nullable Object decimalDecimalCast(
@Nullable BigDecimal value, int precision, int scale) {
+ return decimalDecimalCast(value, precision, scale, RoundingMode.DOWN);
+ }
+
+ /** Called from BuiltInMethod.DECIMAL_DECIMAL_CAST_ROUNDING_MODE */
+ public static @Nullable Object decimalDecimalCast(
+ @Nullable BigDecimal value, int precision, int scale, RoundingMode
roundingMode) {
if (value == null) {
return null;
}
- return checkOverflow(value, precision, scale);
+ return checkOverflow(value, precision, scale, roundingMode);
}
/** Called from BuiltInMethod.INTEGER_DECIMAL_CAST */
public static @Nullable Object integerDecimalCast(
@Nullable Number value, int precision, int scale) {
+ return integerDecimalCast(value, precision, scale, RoundingMode.DOWN);
+ }
+
+ /** Called from BuiltInMethod.INTEGER_DECIMAL_CAST_ROUNDING_MODE */
+ public static @Nullable Object integerDecimalCast(
+ @Nullable Number value, int precision, int scale, RoundingMode
roundingMode) {
if (value == null) {
return null;
}
final BigDecimal decimal = new BigDecimal(value.longValue());
- return checkOverflow(decimal, precision, scale);
+ return checkOverflow(decimal, precision, scale, roundingMode);
}
/** Called from BuiltInMethod.FP_DECIMAL_CAST */
public static @Nullable Object fpDecimalCast(
@Nullable Number value, int precision, int scale) {
+ return fpDecimalCast(value, precision, scale, RoundingMode.DOWN);
+ }
+
+ /** Called from BuiltInMethod.FP_DECIMAL_CAST_ROUNDING_MODE */
+ public static @Nullable Object fpDecimalCast(
+ @Nullable Number value, int precision, int scale, RoundingMode
roundingMode) {
if (value == null) {
return null;
}
final BigDecimal decimal = BigDecimal.valueOf(value.doubleValue());
- return checkOverflow(decimal, precision, scale);
+ return checkOverflow(decimal, precision, scale, roundingMode);
+ }
+
+ public @Nullable Object numberValueRoundDown(Number value) {
+ return numberValue(value, RoundingMode.DOWN);
}
/**
@@ -483,12 +536,16 @@ public enum Primitive {
* an exception is thrown.
*
* @param value Value to convert.
+ * @param roundingMode Rounding behavior.
* @return The converted value, or null if the type of the result is
not a number.
*/
- public @Nullable Object numberValue(Number value) {
+ public @Nullable Object numberValue(Number value, RoundingMode roundingMode)
{
switch (this) {
case BYTE:
checkRoundedRange(value, Byte.MIN_VALUE, Byte.MAX_VALUE);
+ if (value instanceof BigDecimal) {
+ return ((BigDecimal) value).setScale(0, roundingMode).byteValue();
+ }
return value.byteValue();
case CHAR:
// No overflow checks for char values.
@@ -496,9 +553,15 @@ public enum Primitive {
return (char) value.intValue();
case SHORT:
checkRoundedRange(value, Short.MIN_VALUE, Short.MAX_VALUE);
+ if (value instanceof BigDecimal) {
+ return ((BigDecimal) value).setScale(0, roundingMode).shortValue();
+ }
return value.shortValue();
case INT:
checkRoundedRange(value, Integer.MIN_VALUE, Integer.MAX_VALUE);
+ if (value instanceof BigDecimal) {
+ return ((BigDecimal) value).setScale(0, roundingMode).intValue();
+ }
return value.intValue();
case LONG:
if (value instanceof Byte
@@ -513,14 +576,14 @@ public enum Primitive {
// so we cannot use checkRoundedRange.
BigDecimal decimal = BigDecimal.valueOf(value.doubleValue())
// Round to an integer
- .setScale(0, RoundingMode.DOWN);
+ .setScale(0, roundingMode);
// longValueExact will throw ArithmeticException if out of range
return decimal.longValueExact();
}
if (value instanceof BigDecimal) {
BigDecimal decimal = ((BigDecimal) value)
// Round to an integer
- .setScale(0, RoundingMode.DOWN);
+ .setScale(0, roundingMode);
// longValueExact will throw ArithmeticException if out of range
return decimal.longValueExact();
}
diff --git
a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/UnaryExpression.java
b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/UnaryExpression.java
index 09d3bc5212..4c08ab60b1 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/UnaryExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/UnaryExpression.java
@@ -59,12 +59,12 @@ public class UnaryExpression extends Expression {
if (!writer.requireParentheses(this, lprec, rprec)) {
// Generate Java code that looks like e.g.,
// ((Number)org.apache.calcite.linq4j.tree.Primitive.of(int.class)
- // .numberValue(literal_value)).intValue();
+ // .numberValueRoundDown(literal_value)).intValue();
writer.append("((Number)")
.append("org.apache.calcite.linq4j.tree.Primitive.of(")
.append(type)
.append(".class)")
- .append(".numberValue(");
+ .append(".numberValueRoundDown(");
expression.accept(writer, nodeType.rprec, rprec);
writer.append(")).").append(type).append("Value()");
}