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]