private static Object tryTypedShred()

in common/variant/src/main/java/org/apache/spark/types/variant/VariantShreddingWriter.java [155:295]


  private static Object tryTypedShred(
          Variant v,
          VariantUtil.Type variantType,
          VariantSchema.ScalarType targetType,
          ShreddedResultBuilder builder) {
    switch (variantType) {
      case LONG:
        if (targetType instanceof VariantSchema.IntegralType integralType) {
          // Check that the target type can hold the actual value.
          VariantSchema.IntegralSize size = integralType.size;
          long value = v.getLong();
          switch (size) {
            case BYTE:
              if (value == (byte) value) {
                  return (byte) value;
              }
              break;
            case SHORT:
              if (value == (short) value) {
                  return (short) value;
              }
              break;
            case INT:
              if (value == (int) value) {
                  return (int) value;
              }
              break;
            case LONG:
              return value;
          }
        } else if (targetType instanceof VariantSchema.DecimalType decimalType &&
                   builder.allowNumericScaleChanges()) {
          // If the integer can fit in the given decimal precision, allow it.
          long value = v.getLong();
          // Set to the requested scale, and check if the precision is large enough.
          BigDecimal decimalValue = BigDecimal.valueOf(value);
          BigDecimal scaledValue = decimalValue.setScale(decimalType.scale);
          // The initial value should have scale 0, so rescaling shouldn't lose information.
          assert(decimalValue.compareTo(scaledValue) == 0);
          if (scaledValue.precision() <= decimalType.precision) {
            return scaledValue;
          }
        }
        break;
      case DECIMAL:
        if (targetType instanceof VariantSchema.DecimalType decimalType) {
          // Use getDecimalWithOriginalScale so that we retain scale information if
          // allowNumericScaleChanges() is false.
          BigDecimal value = VariantUtil.getDecimalWithOriginalScale(v.value, v.pos);
          if (value.precision() <= decimalType.precision &&
              value.scale() == decimalType.scale) {
            return value;
          }
          if (builder.allowNumericScaleChanges()) {
            // Convert to the target scale, and see if it fits. Rounding mode doesn't matter,
            // since we'll reject it if it turned out to require rounding.
            BigDecimal scaledValue = value.setScale(decimalType.scale, RoundingMode.FLOOR);
            if (scaledValue.compareTo(value) == 0 &&
                    scaledValue.precision() <= decimalType.precision) {
              return scaledValue;
            }
          }
        } else if (targetType instanceof VariantSchema.IntegralType integralType &&
          builder.allowNumericScaleChanges()) {
          // Check if the decimal happens to be an integer.
          BigDecimal value = v.getDecimal();
          VariantSchema.IntegralSize size = integralType.size;
          // Try to cast to the appropriate type, and check if any information is lost.
          switch (size) {
            case BYTE:
              if (value.compareTo(BigDecimal.valueOf(value.byteValue())) == 0) {
                return value.byteValue();
              }
              break;
            case SHORT:
              if (value.compareTo(BigDecimal.valueOf(value.shortValue())) == 0) {
                return value.shortValue();
              }
              break;
            case INT:
              if (value.compareTo(BigDecimal.valueOf(value.intValue())) == 0) {
                return value.intValue();
              }
              break;
            case LONG:
              if (value.compareTo(BigDecimal.valueOf(value.longValue())) == 0) {
                return value.longValue();
              }
          }
        }
        break;
      case BOOLEAN:
        if (targetType instanceof VariantSchema.BooleanType) {
          return v.getBoolean();
        }
        break;
      case STRING:
        if (targetType instanceof VariantSchema.StringType) {
          return v.getString();
        }
        break;
      case DOUBLE:
        if (targetType instanceof VariantSchema.DoubleType) {
          return v.getDouble();
        }
        break;
      case DATE:
        if (targetType instanceof VariantSchema.DateType) {
          return (int) v.getLong();
        }
        break;
      case TIMESTAMP:
        if (targetType instanceof VariantSchema.TimestampType) {
          return v.getLong();
        }
        break;
      case TIMESTAMP_NTZ:
        if (targetType instanceof VariantSchema.TimestampNTZType) {
          return v.getLong();
        }
        break;
      case FLOAT:
        if (targetType instanceof VariantSchema.FloatType) {
          return v.getFloat();
        }
        break;
      case BINARY:
        if (targetType instanceof VariantSchema.BinaryType) {
          return v.getBinary();
        }
        break;
      case UUID:
        if (targetType instanceof VariantSchema.UuidType) {
          return v.getUuid();
        }
        break;
    }
    // The stored type does not match the requested shredding type. Return null, and the caller
    // will store the result in untyped_value.
    return null;
  }