Uploaded image for project: 'Calcite'
  1. Calcite
  2. CALCITE-5960

CAST failed if SqlTypeFamily of targetType is NULL

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 1.35.0
    • 1.36.0
    • core
    • None

    Description

      current RexToLixTranslator#translateCast#scaleIntervalToNumber will scale interval to number. but it throws NPE when family is null.

      It will cause some types such as row type (family is null) raise a NPE.

      e.g. If we call

      CAST(row(1, 2) as row(a integer, b tinyint))

      it will cause NPE:

      java.sql.SQLException: Error while executing SQL "values (CAST(row(1, 2) as row(a integer, b tinyint)))": Unable to implement EnumerableCalc(expr#0=[\{inputs}], expr#1=[1], expr#2=[2], expr#3=[ROW($t1, $t2)], expr#4=[CAST($t3):RecordType(INTEGER NOT NULL A, TINYINT NOT NULL B) NOT NULL], EXPR$0=[$t4]): rowcount = 1.0, cumulative cost = \{2.0 rows, 7.0 cpu, 0.0 io}, id = 20
        EnumerableValues(tuples=[[\{ 0 }]]): rowcount = 1.0, cumulative cost = \{1.0 rows, 1.0 cpu, 0.0 io}, id = 13
      at org.apache.calcite.avatica.Helper.createException(Helper.java:56)
      at org.apache.calcite.avatica.Helper.createException(Helper.java:41)
      at org.apache.calcite.avatica.AvaticaStatement.executeInternal(AvaticaStatement.java:164)
      at org.apache.calcite.avatica.AvaticaStatement.executeQuery(AvaticaStatement.java:228)
      at org.apache.calcite.test.SqlOperatorTest$TesterImpl.check(SqlOperatorTest.java:12684)
      at org.apache.calcite.sql.test.SqlTester.check(SqlTester.java:160)
      at org.apache.calcite.test.SqlOperatorFixtureImpl.lambda$checkScalar$2(SqlOperatorFixtureImpl.java:224)
      at org.apache.calcite.sql.test.AbstractSqlTester.forEachQuery(AbstractSqlTester.java:446)
      at org.apache.calcite.test.SqlOperatorFixtureImpl.checkScalar(SqlOperatorFixtureImpl.java:223)
      at org.apache.calcite.sql.test.SqlOperatorFixture.checkScalar(SqlOperatorFixture.java:238)
      at org.apache.calcite.test.SqlOperatorTest.testCastRow(SqlOperatorTest.java:6103)
      at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.base/java.lang.reflect.Method.invoke(Method.java:566)
      at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:727)
      at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
      at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
      at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
      at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
      at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
      at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)
      at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93)
      at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
      at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
      at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
      at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
      at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92)
      at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86)
      at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:217)
      at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
      at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:213)
      at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:138)
      at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
      at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
      at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
      at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
      at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
      at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
      at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
      at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
      at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
      at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
      at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
      at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
      at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
      at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
      at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
      at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
      at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
      at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:147)
      at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:127)
      at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:90)
      at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:55)
      at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:102)
      at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:54)
      at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
      at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
      at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
      at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
      at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)
      at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
      at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
      at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
      at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
      at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
      Caused by: java.lang.IllegalStateException: Unable to implement EnumerableCalc(expr#0=[\{inputs}], expr#1=[1], expr#2=[2], expr#3=[ROW($t1, $t2)], expr#4=[CAST($t3):RecordType(INTEGER NOT NULL A, TINYINT NOT NULL B) NOT NULL], EXPR$0=[$t4]): rowcount = 1.0, cumulative cost = \{2.0 rows, 7.0 cpu, 0.0 io}, id = 20
        EnumerableValues(tuples=[[\{ 0 }]]): rowcount = 1.0, cumulative cost = \{1.0 rows, 1.0 cpu, 0.0 io}, id = 13
       
      at org.apache.calcite.adapter.enumerable.EnumerableRelImplementor.implementRoot(EnumerableRelImplementor.java:117)
      at org.apache.calcite.adapter.enumerable.EnumerableInterpretable.toBindable(EnumerableInterpretable.java:112)
      at org.apache.calcite.prepare.CalcitePrepareImpl$CalcitePreparingStmt.implement(CalcitePrepareImpl.java:1169)
      at org.apache.calcite.prepare.Prepare.prepareSql(Prepare.java:324)
      at org.apache.calcite.prepare.Prepare.prepareSql(Prepare.java:220)
      at org.apache.calcite.prepare.CalcitePrepareImpl.prepare2_(CalcitePrepareImpl.java:665)
      at org.apache.calcite.prepare.CalcitePrepareImpl.prepare_(CalcitePrepareImpl.java:519)
      at org.apache.calcite.prepare.CalcitePrepareImpl.prepareSql(CalcitePrepareImpl.java:487)
      at org.apache.calcite.jdbc.CalciteConnectionImpl.parseQuery(CalciteConnectionImpl.java:236)
      at org.apache.calcite.jdbc.CalciteMetaImpl.prepareAndExecute(CalciteMetaImpl.java:630)
      at org.apache.calcite.avatica.AvaticaConnection.prepareAndExecuteInternal(AvaticaConnection.java:677)
      at org.apache.calcite.avatica.AvaticaStatement.executeInternal(AvaticaStatement.java:157)
      ... 78 more
      Suppressed: java.lang.NullPointerException: SqlTypeFamily for RecordType(INTEGER A, TINYINT B)
      at java.base/java.util.Objects.requireNonNull(Objects.java:347)
      at org.apache.calcite.adapter.enumerable.RexToLixTranslator.scaleIntervalToNumber(RexToLixTranslator.java:976)
      at org.apache.calcite.adapter.enumerable.RexToLixTranslator.translateCast(RexToLixTranslator.java:293)
      at org.apache.calcite.adapter.enumerable.RexImpTable$CastImplementor.implementSafe(RexImpTable.java:3200)
      at org.apache.calcite.adapter.enumerable.RexImpTable$AbstractRexCallImplementor.genValueStatement(RexImpTable.java:3768)
      at org.apache.calcite.adapter.enumerable.RexImpTable$AbstractRexCallImplementor.implement(RexImpTable.java:3730)
      at org.apache.calcite.adapter.enumerable.RexToLixTranslator.visitCall(RexToLixTranslator.java:1184)
      at org.apache.calcite.adapter.enumerable.RexToLixTranslator.visitCall(RexToLixTranslator.java:101)
      at org.apache.calcite.rex.RexCall.accept(RexCall.java:189)
      at org.apache.calcite.adapter.enumerable.RexToLixTranslator.visitLocalRef(RexToLixTranslator.java:1060)
      at org.apache.calcite.adapter.enumerable.RexToLixTranslator.visitLocalRef(RexToLixTranslator.java:101)
      at org.apache.calcite.rex.RexLocalRef.accept(RexLocalRef.java:77)
      at org.apache.calcite.adapter.enumerable.RexToLixTranslator.translate(RexToLixTranslator.java:253)
      at org.apache.calcite.adapter.enumerable.RexToLixTranslator.translate(RexToLixTranslator.java:247)
      at org.apache.calcite.adapter.enumerable.RexToLixTranslator.translateList(RexToLixTranslator.java:899)
      at org.apache.calcite.adapter.enumerable.RexToLixTranslator.translateProjects(RexToLixTranslator.java:201)
      at org.apache.calcite.adapter.enumerable.EnumerableCalc.implement(EnumerableCalc.java:192)
      at org.apache.calcite.adapter.enumerable.EnumerableRelImplementor.implementRoot(EnumerableRelImplementor.java:114)
      ... 89 more
      
      

      however, the right result should be (1,2).

      In fact this function should do its logic for expected type, otherwise just return the original operand is ok.

      Expression translateCast(
          RelDataType sourceType,
          RelDataType targetType,
          Expression operand,
          boolean safe) {
        Expression convert = getConvertExpression(sourceType, targetType, operand);
        Expression convert2 = checkExpressionPadTruncate(convert, sourceType, targetType);
        Expression convert3 = expressionHandlingSafe(convert2, safe);
        return scaleIntervalToNumber(sourceType, targetType, convert3);
      }
      
      private static Expression scaleIntervalToNumber(          --> inner private method
          RelDataType sourceType,
          RelDataType targetType,
          Expression operand) {
        switch (requireNonNull(targetType.getSqlTypeName().getFamily(),  --> error
            () -> "SqlTypeFamily for " + targetType)) {
        case NUMERIC:
          switch (sourceType.getSqlTypeName()) {
          case INTERVAL_YEAR:
          // omit some code
          default:
            break;
          }
          break;
        default:
          break;
        }
        return operand;
      } 

      Attachments

        Issue Links

          Activity

            People

              taoran Ran Tao
              taoran Ran Tao
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: