in core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java [906:1001]
public static boolean canCastFrom(
RelDataType toType,
RelDataType fromType,
SqlTypeMappingRule typeMappingRule) {
if (toType.equals(fromType)) {
return true;
}
// If fromType is a measure, you should compare the inner type otherwise it will
// always return TRUE because the SqlTypeFamily of MEASURE is ANY
if (isMeasure(fromType)) {
return canCastFrom(toType, requireNonNull(fromType.getMeasureElementType()),
typeMappingRule);
}
if (isAny(toType) || isAny(fromType) || isVariant(toType) || isVariant(fromType)) {
return true;
}
final SqlTypeName fromTypeName = fromType.getSqlTypeName();
final SqlTypeName toTypeName = toType.getSqlTypeName();
if (toTypeName == SqlTypeName.UNKNOWN) {
return true;
}
if (toType.getSqlTypeName() == SqlTypeName.UUID) {
return fromType.getSqlTypeName() == SqlTypeName.UUID
|| fromType.getFamily() == SqlTypeFamily.CHARACTER
|| fromType.getFamily() == SqlTypeFamily.BINARY;
}
if (toType.isStruct() || fromType.isStruct()) {
if (toTypeName == SqlTypeName.DISTINCT) {
if (fromTypeName == SqlTypeName.DISTINCT) {
// can't cast between different distinct types
return false;
}
return canCastFrom(
toType.getFieldList().get(0).getType(), fromType, typeMappingRule);
} else if (fromTypeName == SqlTypeName.DISTINCT) {
return canCastFrom(
toType, fromType.getFieldList().get(0).getType(), typeMappingRule);
} else if (toTypeName == SqlTypeName.ROW) {
if (fromTypeName != SqlTypeName.ROW) {
return fromTypeName == SqlTypeName.NULL;
}
int n = toType.getFieldCount();
if (fromType.getFieldCount() != n) {
return false;
}
for (int i = 0; i < n; ++i) {
RelDataTypeField toField = toType.getFieldList().get(i);
RelDataTypeField fromField = fromType.getFieldList().get(i);
if (!canCastFrom(
toField.getType(),
fromField.getType(),
typeMappingRule)) {
return false;
}
}
return true;
} else if (toTypeName == SqlTypeName.MULTISET) {
if (!fromType.isStruct()) {
return false;
}
if (fromTypeName != SqlTypeName.MULTISET) {
return false;
}
return canCastFrom(
getComponentTypeOrThrow(toType),
getComponentTypeOrThrow(fromType),
typeMappingRule);
} else if (fromTypeName == SqlTypeName.MULTISET) {
return false;
} else {
return toType.getFamily() == fromType.getFamily();
}
}
RelDataType c1 = toType.getComponentType();
if (c1 != null) {
RelDataType c2 = fromType.getComponentType();
if (c2 != null) {
return canCastFrom(c1, c2, typeMappingRule);
}
}
if ((isInterval(fromType) && isExactNumeric(toType))
|| (isInterval(toType) && isExactNumeric(fromType))) {
IntervalSqlType intervalType =
(IntervalSqlType) (isInterval(fromType) ? fromType : toType);
if (!intervalType.getIntervalQualifier().isSingleDatetimeField()) {
// Casts between intervals and exact numerics must involve
// intervals with a single datetime field.
return false;
}
}
if (toTypeName == null || fromTypeName == null) {
return false;
}
return typeMappingRule.canApplyFrom(toTypeName, fromTypeName);
}