MasseGuillaume commented on PR #3324:
URL: https://github.com/apache/calcite/pull/3324#issuecomment-1816845557

   This PR introduce a regression when building an array with structs.
   
   I defined in my codebase `named_struct` that can return a struct type:
   
   ```java
   public class NamedStructUtils {
   
     private NamedStructUtils() {
       throw new UnsupportedOperationException("This is a utility class and 
cannot be instantiated");
     }
   
     public static SqlBasicFunction create() {
       return SqlBasicFunction.create(
         "NAMED_STRUCT",
         NamedStructUtils::returnType,
         OPERAND_TYPE_CHECKER);
     }
   
     private static String namedStructRequiresLiteralStringKeysGotExpression() {
       return "named_struct key is not a string literal, got an expression";
     }
   
     private static String 
namedStructRequiresLiteralStringKeysGotOtherType(String tpe) {
       return String.format("named_struct key is not a string literal, found 
type '%s'", tpe);
     }
   
     private static String namedStructRequiresEvenNumberOfArgs() {
       return "named_struct requires an even number for arguments";
     }
     
     private static RelDataType returnType(SqlOperatorBinding operatorBinding) {
       final List<String> keys = new ArrayList<String>();
       final List<RelDataType> values = new ArrayList<RelDataType>();
       int i = 0;
       for (RelDataType type : operatorBinding.collectOperandTypes()) {
         if (i % 2 == 0) {
           Object key = operatorBinding.getOperandLiteralValue(i, Object.class);
           if (key == null) {
             throw new CalciteException(
               namedStructRequiresLiteralStringKeysGotExpression(), null);
           }
           if (key instanceof NlsString) {
             keys.add(((NlsString) key).getValue());
           } else {
             String tpe = key.getClass().getSimpleName();
             throw new CalciteException(
               namedStructRequiresLiteralStringKeysGotOtherType(tpe), null);
           }
   
         } else {
           values.add(type);
         }
         i++;
       }
       final RelDataTypeFactory typeFactory = operatorBinding.getTypeFactory();
       return typeFactory.createStructType(values, keys);
     }
   
     private static final SqlOperandTypeChecker TWO_OR_MORE =
         OperandTypes.variadic(SqlOperandCountRanges.from(2));
   
     private static final SqlOperandTypeChecker OPERAND_TYPE_CHECKER =
         new SqlOperandTypeChecker() {
           @Override public boolean checkOperandTypes(
               SqlCallBinding callBinding,
               boolean throwOnFailure) {
             final boolean isRangeOk = 
TWO_OR_MORE.checkOperandTypes(callBinding, throwOnFailure);
             final int operandCount = callBinding.operands().size();
             final boolean isEvenNumberOfArgs = operandCount % 2 != 0;
   
             if (throwOnFailure && isEvenNumberOfArgs) {
               throw new 
CalciteException(namedStructRequiresEvenNumberOfArgs(), null);
             }
   
             return isRangeOk && isEvenNumberOfArgs;
           }
   
           @Override public SqlOperandCountRange getOperandCountRange() {
             return TWO_OR_MORE.getOperandCountRange();
           }
   
           @Override public String getAllowedSignatures(SqlOperator op, String 
opName) {
             return opName + "(...)";
           }
         };
   }
   ```
   
   Since `SqlTypeName.ROW` has type family null: `ROW(PrecScale.NO_NO, false, 
Types.STRUCT, null),`
   it fails the check `requireNonNull(family, "array element type family");`
   
   eg 
   ```
   array(named_struct('k', 'v'))
   ```
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to