in nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/util/DataTypeUtils.java [1680:1791]
public static Optional<DataType> getWiderType(final DataType thisDataType, final DataType otherDataType) {
if (thisDataType == null) {
return Optional.ofNullable(otherDataType);
}
if (otherDataType == null) {
return Optional.of(thisDataType);
}
final RecordFieldType thisFieldType = thisDataType.getFieldType();
final RecordFieldType otherFieldType = otherDataType.getFieldType();
if (thisFieldType == RecordFieldType.ARRAY && otherFieldType == RecordFieldType.ARRAY) {
// Check for array<null> and return the other (or empty if they are both array<null>). This happens if at some point we inferred an element type of null which
// indicates an empty array, and then we inferred a non-null type for the same field in a different record. The non-null type should be used in that case.
ArrayDataType thisArrayType = (ArrayDataType) thisDataType;
ArrayDataType otherArrayType = (ArrayDataType) otherDataType;
if (thisArrayType.getElementType() == null) {
if (otherArrayType.getElementType() == null) {
return Optional.empty();
} else {
return Optional.of(otherDataType);
}
} else {
if (otherArrayType.getElementType() == null) {
return Optional.of(thisDataType);
} else {
final Optional<DataType> widerElementType = getWiderType(thisArrayType.getElementType(), otherArrayType.getElementType());
if (widerElementType.isPresent()) {
return Optional.of(RecordFieldType.ARRAY.getArrayDataType(widerElementType.get()));
}
return Optional.empty();
}
}
}
final int thisIntTypeValue = getIntegerTypeValue(thisFieldType);
final int otherIntTypeValue = getIntegerTypeValue(otherFieldType);
final boolean thisIsInt = thisIntTypeValue > -1;
final boolean otherIsInt = otherIntTypeValue > -1;
if (thisIsInt && otherIsInt) {
if (thisIntTypeValue > otherIntTypeValue) {
return Optional.of(thisDataType);
}
return Optional.of(otherDataType);
}
final boolean otherIsDecimal = isDecimalType(otherFieldType);
switch (thisFieldType) {
case BYTE:
case SHORT:
case INT:
case LONG:
if (otherIsDecimal) {
return Optional.of(otherDataType);
}
break;
case FLOAT:
if (otherFieldType == RecordFieldType.DOUBLE || otherFieldType == RecordFieldType.DECIMAL) {
return Optional.of(otherDataType);
}
if (otherFieldType == RecordFieldType.BYTE || otherFieldType == RecordFieldType.SHORT || otherFieldType == RecordFieldType.INT || otherFieldType == RecordFieldType.LONG) {
return Optional.of(thisDataType);
}
break;
case DOUBLE:
if (otherFieldType == RecordFieldType.DECIMAL) {
return Optional.of(otherDataType);
}
if (otherFieldType == RecordFieldType.BYTE || otherFieldType == RecordFieldType.SHORT || otherFieldType == RecordFieldType.INT || otherFieldType == RecordFieldType.LONG
|| otherFieldType == RecordFieldType.FLOAT) {
return Optional.of(thisDataType);
}
break;
case DECIMAL:
if (otherFieldType == RecordFieldType.DOUBLE || otherFieldType == RecordFieldType.FLOAT || otherIsInt) {
return Optional.of(thisDataType);
} else if (otherFieldType == RecordFieldType.DECIMAL) {
final DecimalDataType thisDecimalDataType = (DecimalDataType) thisDataType;
final DecimalDataType otherDecimalDataType = (DecimalDataType) otherDataType;
final int precision = Math.max(thisDecimalDataType.getPrecision(), otherDecimalDataType.getPrecision());
final int scale = Math.max(thisDecimalDataType.getScale(), otherDecimalDataType.getScale());
return Optional.of(RecordFieldType.DECIMAL.getDecimalDataType(precision, scale));
}
break;
case CHAR:
case UUID:
if (otherFieldType == RecordFieldType.STRING) {
return Optional.of(otherDataType);
}
break;
case STRING:
if (otherFieldType == RecordFieldType.CHAR || otherFieldType == RecordFieldType.UUID) {
return Optional.of(thisDataType);
}
break;
case RECORD:
if (otherFieldType != RecordFieldType.RECORD) {
return Optional.empty();
}
final RecordDataType thisRecordDataType = (RecordDataType) thisDataType;
final RecordDataType otherRecordDataType = (RecordDataType) otherDataType;
return getWiderRecordType(thisRecordDataType, otherRecordDataType);
}
return Optional.empty();
}