public static boolean canCastFrom()

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);
  }