[ 
https://issues.apache.org/jira/browse/CALCITE-5948?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Ran Tao updated CALCITE-5948:
-----------------------------
    Description: 
First, we need to reach a consensus to allow types of the same family to 
coexist in multiset such as array and map.

It means the form like `{*}array(1, cast(2 as tinyint)){*}` is correct(the 
LeastRestrictiveType is Integer).In fact, the most of mature engines such as 
spark/hive/flink just also support this behavior. However, this function 
validate success in calcite but it failed in runtime, exception stack is:
{code:java}
java.lang.ClassCastException: class java.lang.Byte cannot be cast to class 
java.lang.Integer
    at 
org.apache.calcite.avatica.util.AbstractCursor$IntAccessor.getInt(AbstractCursor.java:522)
    at 
org.apache.calcite.avatica.util.AbstractCursor$ArrayAccessor.convertValue(AbstractCursor.java:1396)
    at 
org.apache.calcite.avatica.util.AbstractCursor$ArrayAccessor.getObject(AbstractCursor.java:1377)
    at 
org.apache.calcite.avatica.util.AbstractCursor$ArrayAccessor.getArray(AbstractCursor.java:1432)
    at 
org.apache.calcite.avatica.util.AbstractCursor$ArrayAccessor.getString(AbstractCursor.java:1444)
    at 
org.apache.calcite.avatica.AvaticaResultSet.getString(AvaticaResultSet.java:241)
    at org.apache.calcite.util.JdbcTypeImpl$10.get(JdbcTypeImpl.java:112)
    at org.apache.calcite.util.JdbcTypeImpl$10.get(JdbcTypeImpl.java:109)
    at 
org.apache.calcite.sql.test.ResultCheckers.compareResultSetWithMatcher(ResultCheckers.java:248)
    at 
org.apache.calcite.sql.test.ResultCheckers$MatcherResultChecker.checkResult(ResultCheckers
 {code}
 

And `{*}map[1, 1, 2, cast(1 as tinyint)]{*}` is correct but calcite throw 
exception:
{code:java}
java.lang.AssertionError: Expected query to throw exception, but it did not; 
query [values (map[1, 1, 2, cast(1 as tinyint)])]; expected [Parameters must be 
of the same type]
        at org.apache.calcite.sql.test.SqlTests.checkEx(SqlTests.java:240)      
at 
org.apache.calcite.sql.test.AbstractSqlTester.assertExceptionIsThrown(AbstractSqlTester.java:111)
    at 
org.apache.calcite.test.SqlOperatorFixtureImpl.checkQueryFails(SqlOperatorFixtureImpl.java:174)
 {code}
 

std ArrayConstructor.
{code:java}
public class SqlArrayValueConstructor extends SqlMultisetValueConstructor {
  public SqlArrayValueConstructor() {
    super("ARRAY", SqlKind.ARRAY_VALUE_CONSTRUCTOR);
  }

  @Override public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
    RelDataType type =
        getComponentType(
            opBinding.getTypeFactory(),
            opBinding.collectOperandTypes());
    --> we need explicit cast here
    requireNonNull(type, "inferred array element type");
    return SqlTypeUtil.createArrayType(
        opBinding.getTypeFactory(), type, false);
  }
} {code}
std map constructor:
{code:java}
public class SqlMapValueConstructor extends SqlMultisetValueConstructor {
  public SqlMapValueConstructor() {
    super("MAP", SqlKind.MAP_VALUE_CONSTRUCTOR);
  }

  @Override public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
    Pair<@Nullable RelDataType, @Nullable RelDataType> type =
        getComponentTypes(
            opBinding.getTypeFactory(), opBinding.collectOperandTypes());
     --> we need explicit cast here   
     return SqlTypeUtil.createMapType(
        opBinding.getTypeFactory(),
        requireNonNull(type.left, "inferred key type"),
        requireNonNull(type.right, "inferred value type"),
        false);
  }
}{code}

  was:
First, we need to reach a consensus to allow types of the same family to 
coexist in multiset such as array and map.

It means the form like `{*}array(1, cast(2 as tinyint)){*}` is correct(the 
LeastRestrictiveType is Integer).In fact, the most of mature engines such as 
spark/hive/flink just also support this behavior. However, this function 
validate success in calcite but it failed in runtime, exception stack is:
{code:java}
java.lang.ClassCastException: class java.lang.Byte cannot be cast to class 
java.lang.Integer
    at 
org.apache.calcite.avatica.util.AbstractCursor$IntAccessor.getInt(AbstractCursor.java:522)
    at 
org.apache.calcite.avatica.util.AbstractCursor$ArrayAccessor.convertValue(AbstractCursor.java:1396)
    at 
org.apache.calcite.avatica.util.AbstractCursor$ArrayAccessor.getObject(AbstractCursor.java:1377)
    at 
org.apache.calcite.avatica.util.AbstractCursor$ArrayAccessor.getArray(AbstractCursor.java:1432)
    at 
org.apache.calcite.avatica.util.AbstractCursor$ArrayAccessor.getString(AbstractCursor.java:1444)
    at 
org.apache.calcite.avatica.AvaticaResultSet.getString(AvaticaResultSet.java:241)
    at org.apache.calcite.util.JdbcTypeImpl$10.get(JdbcTypeImpl.java:112)
    at org.apache.calcite.util.JdbcTypeImpl$10.get(JdbcTypeImpl.java:109)
    at 
org.apache.calcite.sql.test.ResultCheckers.compareResultSetWithMatcher(ResultCheckers.java:248)
    at 
org.apache.calcite.sql.test.ResultCheckers$MatcherResultChecker.checkResult(ResultCheckers
 {code}
 

And `{*}map[1, 1, 2, cast(1 as tinyint)]{*}` is correct but calcite throw 
exception:
{code:java}
java.lang.AssertionError: Expected query to throw exception, but it did not; 
query [values (map[1, 1, 2, cast(1 as tinyint)])]; expected [Parameters must be 
of the same type]
        at org.apache.calcite.sql.test.SqlTests.checkEx(SqlTests.java:240)      
at 
org.apache.calcite.sql.test.AbstractSqlTester.assertExceptionIsThrown(AbstractSqlTester.java:111)
    at 
org.apache.calcite.test.SqlOperatorFixtureImpl.checkQueryFails(SqlOperatorFixtureImpl.java:174)
 {code}
 

std ArrayConstructor.
{code:java}
public class SqlArrayValueConstructor extends SqlMultisetValueConstructor {
  public SqlArrayValueConstructor() {
    super("ARRAY", SqlKind.ARRAY_VALUE_CONSTRUCTOR);
  }

  @Override public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
    RelDataType type =
        getComponentType(
            opBinding.getTypeFactory(),
            opBinding.collectOperandTypes());
    --> we need explicit cast here
    requireNonNull(type, "inferred array element type");
    return SqlTypeUtil.createArrayType(
        opBinding.getTypeFactory(), type, false);
  }
} {code}

std map constructor:
{code:java}
public class SqlMapValueConstructor extends SqlMultisetValueConstructor {
  public SqlMapValueConstructor() {
    super("MAP", SqlKind.MAP_VALUE_CONSTRUCTOR);
  }

  @Override public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
    Pair<@Nullable RelDataType, @Nullable RelDataType> type =
        getComponentTypes(
            opBinding.getTypeFactory(), opBinding.collectOperandTypes());
     --> we need explicit cast here   
     return SqlTypeUtil.createMapType(
        opBinding.getTypeFactory(),
        requireNonNull(type.left, "inferred key type"),
        requireNonNull(type.right, "inferred value type"),
        false);
  }
}{code}
 

 

spark library array
{code:java}
private static RelDataType arrayReturnType(SqlOperatorBinding opBinding) {
  RelDataType type =
      opBinding.getOperandCount() > 0
          ? ReturnTypes.LEAST_RESTRICTIVE.inferReturnType(opBinding)
          : opBinding.getTypeFactory().createUnknownType();    
  --> we need explicit cast here    
  requireNonNull(type, "inferred array element type");
  return SqlTypeUtil.createArrayType(opBinding.getTypeFactory(), type, false);
} {code}


> Explicit casting should be made if the type of an element in ARRAY/MAP not 
> equals with the derived component type
> -----------------------------------------------------------------------------------------------------------------
>
>                 Key: CALCITE-5948
>                 URL: https://issues.apache.org/jira/browse/CALCITE-5948
>             Project: Calcite
>          Issue Type: Bug
>          Components: core
>    Affects Versions: 1.35.0
>            Reporter: Ran Tao
>            Assignee: Ran Tao
>            Priority: Major
>
> First, we need to reach a consensus to allow types of the same family to 
> coexist in multiset such as array and map.
> It means the form like `{*}array(1, cast(2 as tinyint)){*}` is correct(the 
> LeastRestrictiveType is Integer).In fact, the most of mature engines such as 
> spark/hive/flink just also support this behavior. However, this function 
> validate success in calcite but it failed in runtime, exception stack is:
> {code:java}
> java.lang.ClassCastException: class java.lang.Byte cannot be cast to class 
> java.lang.Integer
>     at 
> org.apache.calcite.avatica.util.AbstractCursor$IntAccessor.getInt(AbstractCursor.java:522)
>     at 
> org.apache.calcite.avatica.util.AbstractCursor$ArrayAccessor.convertValue(AbstractCursor.java:1396)
>     at 
> org.apache.calcite.avatica.util.AbstractCursor$ArrayAccessor.getObject(AbstractCursor.java:1377)
>     at 
> org.apache.calcite.avatica.util.AbstractCursor$ArrayAccessor.getArray(AbstractCursor.java:1432)
>     at 
> org.apache.calcite.avatica.util.AbstractCursor$ArrayAccessor.getString(AbstractCursor.java:1444)
>     at 
> org.apache.calcite.avatica.AvaticaResultSet.getString(AvaticaResultSet.java:241)
>     at org.apache.calcite.util.JdbcTypeImpl$10.get(JdbcTypeImpl.java:112)
>     at org.apache.calcite.util.JdbcTypeImpl$10.get(JdbcTypeImpl.java:109)
>     at 
> org.apache.calcite.sql.test.ResultCheckers.compareResultSetWithMatcher(ResultCheckers.java:248)
>     at 
> org.apache.calcite.sql.test.ResultCheckers$MatcherResultChecker.checkResult(ResultCheckers
>  {code}
>  
> And `{*}map[1, 1, 2, cast(1 as tinyint)]{*}` is correct but calcite throw 
> exception:
> {code:java}
> java.lang.AssertionError: Expected query to throw exception, but it did not; 
> query [values (map[1, 1, 2, cast(1 as tinyint)])]; expected [Parameters must 
> be of the same type]
>       at org.apache.calcite.sql.test.SqlTests.checkEx(SqlTests.java:240)      
> at 
> org.apache.calcite.sql.test.AbstractSqlTester.assertExceptionIsThrown(AbstractSqlTester.java:111)
>     at 
> org.apache.calcite.test.SqlOperatorFixtureImpl.checkQueryFails(SqlOperatorFixtureImpl.java:174)
>  {code}
>  
> std ArrayConstructor.
> {code:java}
> public class SqlArrayValueConstructor extends SqlMultisetValueConstructor {
>   public SqlArrayValueConstructor() {
>     super("ARRAY", SqlKind.ARRAY_VALUE_CONSTRUCTOR);
>   }
>   @Override public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
>     RelDataType type =
>         getComponentType(
>             opBinding.getTypeFactory(),
>             opBinding.collectOperandTypes());
>     --> we need explicit cast here
>     requireNonNull(type, "inferred array element type");
>     return SqlTypeUtil.createArrayType(
>         opBinding.getTypeFactory(), type, false);
>   }
> } {code}
> std map constructor:
> {code:java}
> public class SqlMapValueConstructor extends SqlMultisetValueConstructor {
>   public SqlMapValueConstructor() {
>     super("MAP", SqlKind.MAP_VALUE_CONSTRUCTOR);
>   }
>   @Override public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
>     Pair<@Nullable RelDataType, @Nullable RelDataType> type =
>         getComponentTypes(
>             opBinding.getTypeFactory(), opBinding.collectOperandTypes());
>      --> we need explicit cast here   
>      return SqlTypeUtil.createMapType(
>         opBinding.getTypeFactory(),
>         requireNonNull(type.left, "inferred key type"),
>         requireNonNull(type.right, "inferred value type"),
>         false);
>   }
> }{code}



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to