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);
     }
 }

Reply via email to