in java/core/src/java/org/apache/orc/impl/SchemaEvolution.java [441:571]
void buildConversion(TypeDescription fileType,
TypeDescription readerType,
int positionalLevels) {
// if the column isn't included, don't map it
if (!includeReaderColumn(readerType.getId())) {
return;
}
boolean isOk = true;
// check the easy case first
if (fileType.getCategory() == readerType.getCategory()) {
switch (readerType.getCategory()) {
case BOOLEAN:
case BYTE:
case SHORT:
case INT:
case LONG:
case DOUBLE:
case FLOAT:
case STRING:
case TIMESTAMP:
case TIMESTAMP_INSTANT:
case BINARY:
case DATE:
// these are always a match
break;
case CHAR:
case VARCHAR:
// We do conversion when same CHAR/VARCHAR type but different
// maxLength.
if (fileType.getMaxLength() != readerType.getMaxLength()) {
hasConversion = true;
if (!typesAreImplicitConversion(fileType, readerType)) {
isOnlyImplicitConversion = false;
}
}
break;
case DECIMAL:
// We do conversion when same DECIMAL type but different
// precision/scale.
if (fileType.getPrecision() != readerType.getPrecision() ||
fileType.getScale() != readerType.getScale()) {
hasConversion = true;
isOnlyImplicitConversion = false;
}
break;
case UNION:
case MAP:
case LIST: {
// these must be an exact match
List<TypeDescription> fileChildren = fileType.getChildren();
List<TypeDescription> readerChildren = readerType.getChildren();
if (fileChildren.size() == readerChildren.size()) {
for(int i=0; i < fileChildren.size(); ++i) {
buildConversion(fileChildren.get(i),
readerChildren.get(i), positionalLevels - 1);
}
} else {
isOk = false;
}
break;
}
case STRUCT: {
List<TypeDescription> readerChildren = readerType.getChildren();
List<TypeDescription> fileChildren = fileType.getChildren();
if (fileChildren.size() != readerChildren.size()) {
hasConversion = true;
// UNDONE: Does LLAP detect fewer columns and NULL them out????
isOnlyImplicitConversion = false;
}
if (positionalLevels <= 0) {
List<String> readerFieldNames = readerType.getFieldNames();
List<String> fileFieldNames = fileType.getFieldNames();
final Map<String, TypeDescription> fileTypesIdx;
if (isSchemaEvolutionCaseAware) {
fileTypesIdx = new HashMap<>();
} else {
fileTypesIdx = new CaseInsensitiveMap<TypeDescription>();
}
for (int i = 0; i < fileFieldNames.size(); i++) {
final String fileFieldName = fileFieldNames.get(i);
fileTypesIdx.put(fileFieldName, fileChildren.get(i));
}
for (int i = 0; i < readerFieldNames.size(); i++) {
final String readerFieldName = readerFieldNames.get(i);
TypeDescription readerField = readerChildren.get(i);
TypeDescription fileField = fileTypesIdx.get(readerFieldName);
if (fileField == null) {
continue;
}
buildConversion(fileField, readerField, 0);
}
} else {
int jointSize = Math.min(fileChildren.size(),
readerChildren.size());
for (int i = 0; i < jointSize; ++i) {
buildConversion(fileChildren.get(i), readerChildren.get(i),
positionalLevels - 1);
}
}
break;
}
default:
throw new IllegalArgumentException("Unknown type " + readerType);
}
} else {
/*
* Check for the few cases where will not convert....
*/
isOk = ConvertTreeReaderFactory.canConvert(fileType, readerType);
hasConversion = true;
if (!typesAreImplicitConversion(fileType, readerType)) {
isOnlyImplicitConversion = false;
}
}
if (isOk) {
readerFileTypes[readerType.getId()] = fileType;
fileIncluded[fileType.getId()] = true;
} else {
throw new IllegalEvolutionException(
String.format("ORC does not support type conversion from file" +
" type %s (%d) to reader type %s (%d)",
fileType, fileType.getId(),
readerType, readerType.getId()));
}
}