This is an automated email from the ASF dual-hosted git repository.
alexpl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new ffb07dbb3c7 IGNITE-23804 SQL Calcite: Fix numeric to interval cast -
Fixes #11707.
ffb07dbb3c7 is described below
commit ffb07dbb3c769eceb302da6a114e4d0914087a6e
Author: Aleksey Plekhanov <[email protected]>
AuthorDate: Thu Dec 5 18:25:12 2024 +0300
IGNITE-23804 SQL Calcite: Fix numeric to interval cast - Fixes #11707.
Signed-off-by: Aleksey Plekhanov <[email protected]>
---
.../query/calcite/exec/exp/IgniteRexBuilder.java | 11 +++++-
.../query/calcite/exec/exp/RexToLixTranslator.java | 39 +++++++++++-----------
.../query/calcite/util/IgniteMethod.java | 6 +++-
.../query/calcite/integration/IntervalTest.java | 16 ++++++---
4 files changed, 47 insertions(+), 25 deletions(-)
diff --git
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/IgniteRexBuilder.java
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/IgniteRexBuilder.java
index e26d249437c..d22c9079fe1 100644
---
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/IgniteRexBuilder.java
+++
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/IgniteRexBuilder.java
@@ -23,7 +23,9 @@ import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rex.RexBuilder;
import org.apache.calcite.rex.RexLiteral;
+import org.apache.calcite.sql.type.IntervalSqlType;
import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.sql.type.SqlTypeUtil;
import org.apache.ignite.internal.processors.query.IgniteSQLException;
import org.apache.ignite.internal.processors.query.calcite.util.TypeUtils;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -49,7 +51,14 @@ public class IgniteRexBuilder extends RexBuilder {
}
}
- if (TypeUtils.hasScale(type))
+ if (type instanceof IntervalSqlType) {
+ // TODO Workaround for
https://issues.apache.org/jira/browse/CALCITE-6714
+ bd =
bd.multiply(((IntervalSqlType)type).getIntervalQualifier().getUnit().multiplier);
+
+ return super.makeLiteral(bd, type, type.getSqlTypeName());
+ }
+
+ if (TypeUtils.hasScale(type) && SqlTypeUtil.isNumeric(type))
return super.makeLiteral(bd.setScale(type.getScale(),
RoundingMode.HALF_UP), type, typeName);
}
diff --git
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/RexToLixTranslator.java
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/RexToLixTranslator.java
index 5de08f2f0e3..8df2261e8b5 100644
---
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/RexToLixTranslator.java
+++
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/RexToLixTranslator.java
@@ -64,6 +64,7 @@ import org.apache.calcite.sql.SqlIntervalQualifier;
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.sql.type.SqlTypeUtil;
import org.apache.calcite.sql.validate.SqlConformance;
import org.apache.calcite.util.BuiltInMethod;
@@ -543,6 +544,25 @@ public class RexToLixTranslator implements
RexVisitor<RexToLixTranslator.Result>
Expressions.field(null, SqlParserPos.class,
"ZERO")
)
);
+ break;
+ case NUMERIC:
+ BigDecimal multiplier =
targetType.getSqlTypeName().getEndUnit().multiplier;
+
+ if
(SqlTypeName.FRACTIONAL_TYPES.contains(sourceType.getSqlTypeName())) {
+ convert = sourceType.getSqlTypeName() ==
SqlTypeName.DECIMAL
+ ? operand
+ : ConverterUtils.convertToDecimal(operand,
typeFactory.createSqlType(SqlTypeName.DECIMAL));
+
+ convert = Expressions.call(
+ convert,
+ IgniteMethod.BIG_DECIMAL_MULTIPLY.method(),
+ Expressions.constant(multiplier));
+ }
+ else
+ convert = IgniteExpressions.multiplyExact(operand,
Expressions.constant(multiplier.longValue()));
+
+ convert = ConverterUtils.convert(convert, targetType);
+ break;
}
break;
case BINARY:
@@ -612,25 +632,6 @@ public class RexToLixTranslator implements
RexVisitor<RexToLixTranslator.Result>
(long)Math.pow(10, 3 - targetScale)));
}
break;
- case INTERVAL_YEAR:
- case INTERVAL_YEAR_MONTH:
- case INTERVAL_MONTH:
- case INTERVAL_DAY:
- case INTERVAL_DAY_HOUR:
- case INTERVAL_DAY_MINUTE:
- case INTERVAL_DAY_SECOND:
- case INTERVAL_HOUR:
- case INTERVAL_HOUR_MINUTE:
- case INTERVAL_HOUR_SECOND:
- case INTERVAL_MINUTE:
- case INTERVAL_MINUTE_SECOND:
- case INTERVAL_SECOND:
- switch (sourceType.getSqlTypeName().getFamily()) {
- case NUMERIC:
- final BigDecimal multiplier =
targetType.getSqlTypeName().getEndUnit().multiplier;
- final BigDecimal divider = BigDecimal.ONE;
- convert = RexImpTable.multiplyDivide(convert,
multiplier, divider);
- }
}
return scaleIntervalToNumber(sourceType, targetType, convert);
}
diff --git
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/IgniteMethod.java
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/IgniteMethod.java
index 5b48750adfb..4fe07c2149b 100644
---
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/IgniteMethod.java
+++
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/IgniteMethod.java
@@ -19,6 +19,7 @@ package
org.apache.ignite.internal.processors.query.calcite.util;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
+import java.math.BigDecimal;
import java.util.Objects;
import org.apache.calcite.avatica.util.ByteString;
import org.apache.calcite.linq4j.tree.Types;
@@ -98,7 +99,10 @@ public enum IgniteMethod {
IS_NOT_DISTINCT_FROM(Objects.class, "equals", Object.class, Object.class),
/** See {@link IgniteSqlFunctions#skipFirstArgument(Object, Object)}. **/
- SKIP_FIRST_ARGUMENT(IgniteSqlFunctions.class, "skipFirstArgument",
Object.class, Object.class);
+ SKIP_FIRST_ARGUMENT(IgniteSqlFunctions.class, "skipFirstArgument",
Object.class, Object.class),
+
+ /** See {@link BigDecimal#multiply(BigDecimal)}. */
+ BIG_DECIMAL_MULTIPLY(BigDecimal.class, "multiply", BigDecimal.class);
/** */
private final Method method;
diff --git
a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/IntervalTest.java
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/IntervalTest.java
index 11f9c66605c..12cc2133837 100644
---
a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/IntervalTest.java
+++
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/IntervalTest.java
@@ -54,10 +54,10 @@ public class IntervalTest extends
AbstractBasicIntegrationTest {
}
/**
- * Test cast interval types to integer and integer to interval.
+ * Test cast interval types to numeric and numeric to interval.
*/
@Test
- public void testIntervalIntCast() {
+ public void testIntervalNumCast() {
assertNull(eval("CAST(NULL::INTERVAL SECONDS AS INT)"));
assertNull(eval("CAST(NULL::INTERVAL MONTHS AS INT)"));
assertEquals(1, eval("CAST(INTERVAL 1 SECONDS AS INT)"));
@@ -77,6 +77,14 @@ public class IntervalTest extends
AbstractBasicIntegrationTest {
assertEquals(Duration.ofDays(4), eval("CAST(4 AS INTERVAL DAYS)"));
assertEquals(Period.ofMonths(5), eval("CAST(5 AS INTERVAL MONTHS)"));
assertEquals(Period.ofYears(6), eval("CAST(6 AS INTERVAL YEARS)"));
+ assertEquals(Duration.ofDays(1), eval("CAST(1::INT AS INTERVAL
DAYS)"));
+ assertEquals(Period.ofMonths(1), eval("CAST(1::INT AS INTERVAL
MONTHS)"));
+ assertEquals(Duration.ofHours(36), eval("CAST(1.5 AS INTERVAL DAYS)"));
+ assertEquals(Period.of(1, 6, 0), eval("CAST(1.5 AS INTERVAL YEARS)"));
+ assertEquals(Duration.ofHours(36), eval("CAST(f AS INTERVAL DAYS) FROM
(VALUES(1.5)) AS t(f)"));
+ assertEquals(Period.of(1, 6, 0), eval("CAST(f AS INTERVAL YEARS) FROM
(VALUES(1.5)) AS t(f)"));
+ assertEquals(Duration.ofHours(36), eval("CAST(1.5::DECIMAL AS INTERVAL
DAYS)"));
+ assertEquals(Period.of(1, 6, 0), eval("CAST(1.5::DECIMAL AS INTERVAL
YEARS)"));
// Compound interval types cannot be cast.
assertThrows("SELECT CAST(INTERVAL '1-2' YEAR TO MONTH AS INT)",
IgniteSQLException.class, "cannot convert");
@@ -388,7 +396,7 @@ public class IntervalTest extends
AbstractBasicIntegrationTest {
}
/** */
- public Object eval(String exp) {
- return executeSql("SELECT " + exp).get(0).get(0);
+ public Object eval(String exp, Object... params) {
+ return executeSql("SELECT " + exp, params).get(0).get(0);
}
}