blob: 5f61ed60b45ec839c3ae5fd7f2dc52bba81d8cdd [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.parquet.schema;
import org.apache.parquet.Preconditions;
import org.apache.yetus.audience.InterfaceAudience;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
import static java.util.Arrays.asList;
import static java.util.Optional.empty;
import static org.apache.parquet.schema.ColumnOrder.ColumnOrderName.TYPE_DEFINED_ORDER;
import static org.apache.parquet.schema.ColumnOrder.ColumnOrderName.UNDEFINED;
import static org.apache.parquet.schema.PrimitiveStringifier.TIMESTAMP_MICROS_STRINGIFIER;
import static org.apache.parquet.schema.PrimitiveStringifier.TIMESTAMP_MICROS_UTC_STRINGIFIER;
import static org.apache.parquet.schema.PrimitiveStringifier.TIMESTAMP_MILLIS_STRINGIFIER;
import static org.apache.parquet.schema.PrimitiveStringifier.TIMESTAMP_MILLIS_UTC_STRINGIFIER;
import static org.apache.parquet.schema.PrimitiveStringifier.TIMESTAMP_NANOS_STRINGIFIER;
import static org.apache.parquet.schema.PrimitiveStringifier.TIMESTAMP_NANOS_UTC_STRINGIFIER;
import static org.apache.parquet.schema.PrimitiveStringifier.TIME_NANOS_STRINGIFIER;
import static org.apache.parquet.schema.PrimitiveStringifier.TIME_NANOS_UTC_STRINGIFIER;
import static org.apache.parquet.schema.PrimitiveStringifier.TIME_STRINGIFIER;
import static org.apache.parquet.schema.PrimitiveStringifier.TIME_UTC_STRINGIFIER;
public abstract class LogicalTypeAnnotation {
enum LogicalTypeToken {
MAP {
@Override
protected LogicalTypeAnnotation fromString(List<String> params) {
return mapType();
}
},
LIST {
@Override
protected LogicalTypeAnnotation fromString(List<String> params) {
return listType();
}
},
STRING {
@Override
protected LogicalTypeAnnotation fromString(List<String> params) {
return stringType();
}
},
MAP_KEY_VALUE {
@Override
protected LogicalTypeAnnotation fromString(List<String> params) {
return MapKeyValueTypeAnnotation.getInstance();
}
},
ENUM {
@Override
protected LogicalTypeAnnotation fromString(List<String> params) {
return enumType();
}
},
DECIMAL {
@Override
protected LogicalTypeAnnotation fromString(List<String> params) {
if (params.size() != 2) {
throw new RuntimeException("Expecting 2 parameters for decimal logical type, got " + params.size());
}
return decimalType(Integer.valueOf(params.get(1)), Integer.valueOf(params.get(0)));
}
},
DATE {
@Override
protected LogicalTypeAnnotation fromString(List<String> params) {
return dateType();
}
},
TIME {
@Override
protected LogicalTypeAnnotation fromString(List<String> params) {
if (params.size() != 2) {
throw new RuntimeException("Expecting 2 parameters for time logical type, got " + params.size());
}
return timeType(Boolean.parseBoolean(params.get(1)), TimeUnit.valueOf(params.get(0)));
}
},
TIMESTAMP {
@Override
protected LogicalTypeAnnotation fromString(List<String> params) {
if (params.size() != 2) {
throw new RuntimeException("Expecting 2 parameters for timestamp logical type, got " + params.size());
}
return timestampType(Boolean.parseBoolean(params.get(1)), TimeUnit.valueOf(params.get(0)));
}
},
INTEGER {
@Override
protected LogicalTypeAnnotation fromString(List<String> params) {
if (params.size() != 2) {
throw new RuntimeException("Expecting 2 parameters for integer logical type, got " + params.size());
}
return intType(Integer.valueOf(params.get(0)), Boolean.parseBoolean(params.get(1)));
}
},
JSON {
@Override
protected LogicalTypeAnnotation fromString(List<String> params) {
return jsonType();
}
},
BSON {
@Override
protected LogicalTypeAnnotation fromString(List<String> params) {
return bsonType();
}
},
INTERVAL {
@Override
protected LogicalTypeAnnotation fromString(List<String> params) {
return IntervalLogicalTypeAnnotation.getInstance();
}
};
protected abstract LogicalTypeAnnotation fromString(List<String> params);
}
/**
* Convert this logical type to old logical type representation in parquet-mr (if there's any).
* Those logical type implementations, which don't have a corresponding mapping should return null.
*
* @return the OriginalType representation of the new logical type, or null if there's none
*/
@InterfaceAudience.Private
public abstract OriginalType toOriginalType();
/**
* Visits this logical type with the given visitor
*
* @param logicalTypeAnnotationVisitor the visitor to visit this type
*/
public abstract <T> Optional<T> accept(LogicalTypeAnnotationVisitor<T> logicalTypeAnnotationVisitor);
abstract LogicalTypeToken getType();
String typeParametersAsString() {
return "";
}
boolean isValidColumnOrder(ColumnOrder columnOrder) {
return columnOrder.getColumnOrderName() == UNDEFINED || columnOrder.getColumnOrderName() == TYPE_DEFINED_ORDER;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getType());
sb.append(typeParametersAsString());
return sb.toString();
}
PrimitiveStringifier valueStringifier(PrimitiveType primitiveType) {
throw new UnsupportedOperationException("Stringifier is not supported for the logical type: " + this);
}
/**
* Helper method to convert the old representation of logical types (OriginalType) to new logical type.
*/
@InterfaceAudience.Private
public static LogicalTypeAnnotation fromOriginalType(OriginalType originalType, DecimalMetadata decimalMetadata) {
if (originalType == null) {
return null;
}
switch (originalType) {
case UTF8:
return stringType();
case MAP:
return mapType();
case DECIMAL:
int scale = (decimalMetadata == null ? 0 : decimalMetadata.getScale());
int precision = (decimalMetadata == null ? 0 : decimalMetadata.getPrecision());
return decimalType(scale, precision);
case LIST:
return listType();
case DATE:
return dateType();
case INTERVAL:
return IntervalLogicalTypeAnnotation.getInstance();
case TIMESTAMP_MILLIS:
return timestampType(true, LogicalTypeAnnotation.TimeUnit.MILLIS);
case TIMESTAMP_MICROS:
return timestampType(true, LogicalTypeAnnotation.TimeUnit.MICROS);
case TIME_MILLIS:
return timeType(true, LogicalTypeAnnotation.TimeUnit.MILLIS);
case TIME_MICROS:
return timeType(true, LogicalTypeAnnotation.TimeUnit.MICROS);
case UINT_8:
return intType(8, false);
case UINT_16:
return intType(16, false);
case UINT_32:
return intType(32, false);
case UINT_64:
return intType(64, false);
case INT_8:
return intType(8, true);
case INT_16:
return intType(16, true);
case INT_32:
return intType(32, true);
case INT_64:
return intType(64, true);
case ENUM:
return enumType();
case JSON:
return jsonType();
case BSON:
return bsonType();
case MAP_KEY_VALUE:
return MapKeyValueTypeAnnotation.getInstance();
default:
throw new RuntimeException("Can't convert original type to logical type, unknown original type " + originalType);
}
}
public static StringLogicalTypeAnnotation stringType() {
return StringLogicalTypeAnnotation.INSTANCE;
}
public static MapLogicalTypeAnnotation mapType() {
return MapLogicalTypeAnnotation.INSTANCE;
}
public static ListLogicalTypeAnnotation listType() {
return ListLogicalTypeAnnotation.INSTANCE;
}
public static EnumLogicalTypeAnnotation enumType() {
return EnumLogicalTypeAnnotation.INSTANCE;
}
public static DecimalLogicalTypeAnnotation decimalType(final int scale, final int precision) {
return new DecimalLogicalTypeAnnotation(scale, precision);
}
public static DateLogicalTypeAnnotation dateType() {
return DateLogicalTypeAnnotation.INSTANCE;
}
public static TimeLogicalTypeAnnotation timeType(final boolean isAdjustedToUTC, final TimeUnit unit) {
return new TimeLogicalTypeAnnotation(isAdjustedToUTC, unit);
}
public static TimestampLogicalTypeAnnotation timestampType(final boolean isAdjustedToUTC, final TimeUnit unit) {
return new TimestampLogicalTypeAnnotation(isAdjustedToUTC, unit);
}
public static IntLogicalTypeAnnotation intType(final int bitWidth, final boolean isSigned) {
Preconditions.checkArgument(
bitWidth == 8 || bitWidth == 16 || bitWidth == 32 || bitWidth == 64,
"Invalid bit width for integer logical type, " + bitWidth + " is not allowed, " +
"valid bit width values: 8, 16, 32, 64");
return new IntLogicalTypeAnnotation(bitWidth, isSigned);
}
public static JsonLogicalTypeAnnotation jsonType() {
return JsonLogicalTypeAnnotation.INSTANCE;
}
public static BsonLogicalTypeAnnotation bsonType() {
return BsonLogicalTypeAnnotation.INSTANCE;
}
public static class StringLogicalTypeAnnotation extends LogicalTypeAnnotation {
private static final StringLogicalTypeAnnotation INSTANCE = new StringLogicalTypeAnnotation();
private StringLogicalTypeAnnotation() {
}
@Override
@InterfaceAudience.Private
public OriginalType toOriginalType() {
return OriginalType.UTF8;
}
@Override
public <T> Optional<T> accept(LogicalTypeAnnotationVisitor<T> logicalTypeAnnotationVisitor) {
return logicalTypeAnnotationVisitor.visit(this);
}
@Override
LogicalTypeToken getType() {
return LogicalTypeToken.STRING;
}
@Override
public boolean equals(Object obj) {
return obj instanceof StringLogicalTypeAnnotation;
}
@Override
public int hashCode() {
// This type doesn't have any parameters, thus using class hashcode
return getClass().hashCode();
}
@Override
PrimitiveStringifier valueStringifier(PrimitiveType primitiveType) {
return PrimitiveStringifier.UTF8_STRINGIFIER;
}
}
public static class MapLogicalTypeAnnotation extends LogicalTypeAnnotation {
private static final MapLogicalTypeAnnotation INSTANCE = new MapLogicalTypeAnnotation();
private MapLogicalTypeAnnotation() {
}
@Override
@InterfaceAudience.Private
public OriginalType toOriginalType() {
return OriginalType.MAP;
}
@Override
public <T> Optional<T> accept(LogicalTypeAnnotationVisitor<T> logicalTypeAnnotationVisitor) {
return logicalTypeAnnotationVisitor.visit(this);
}
@Override
LogicalTypeToken getType() {
return LogicalTypeToken.MAP;
}
@Override
public boolean equals(Object obj) {
return obj instanceof MapLogicalTypeAnnotation;
}
@Override
public int hashCode() {
// This type doesn't have any parameters, thus using class hashcode
return getClass().hashCode();
}
}
public static class ListLogicalTypeAnnotation extends LogicalTypeAnnotation {
private static final ListLogicalTypeAnnotation INSTANCE = new ListLogicalTypeAnnotation();
private ListLogicalTypeAnnotation() {
}
@Override
@InterfaceAudience.Private
public OriginalType toOriginalType() {
return OriginalType.LIST;
}
@Override
public <T> Optional<T> accept(LogicalTypeAnnotationVisitor<T> logicalTypeAnnotationVisitor) {
return logicalTypeAnnotationVisitor.visit(this);
}
@Override
LogicalTypeToken getType() {
return LogicalTypeToken.LIST;
}
@Override
public boolean equals(Object obj) {
return obj instanceof ListLogicalTypeAnnotation;
}
@Override
public int hashCode() {
// This type doesn't have any parameters, thus using class hashcode
return getClass().hashCode();
}
}
public static class EnumLogicalTypeAnnotation extends LogicalTypeAnnotation {
private static final EnumLogicalTypeAnnotation INSTANCE = new EnumLogicalTypeAnnotation();
private EnumLogicalTypeAnnotation() {
}
@Override
@InterfaceAudience.Private
public OriginalType toOriginalType() {
return OriginalType.ENUM;
}
@Override
public <T> Optional<T> accept(LogicalTypeAnnotationVisitor<T> logicalTypeAnnotationVisitor) {
return logicalTypeAnnotationVisitor.visit(this);
}
@Override
LogicalTypeToken getType() {
return LogicalTypeToken.ENUM;
}
@Override
public boolean equals(Object obj) {
return obj instanceof EnumLogicalTypeAnnotation;
}
@Override
public int hashCode() {
// This type doesn't have any parameters, thus using class hashcode
return getClass().hashCode();
}
@Override
PrimitiveStringifier valueStringifier(PrimitiveType primitiveType) {
return PrimitiveStringifier.UTF8_STRINGIFIER;
}
}
public static class DecimalLogicalTypeAnnotation extends LogicalTypeAnnotation {
private final PrimitiveStringifier stringifier;
private final int scale;
private final int precision;
private DecimalLogicalTypeAnnotation(int scale, int precision) {
this.scale = scale;
this.precision = precision;
stringifier = PrimitiveStringifier.createDecimalStringifier(scale);
}
public int getPrecision() {
return precision;
}
public int getScale() {
return scale;
}
@Override
@InterfaceAudience.Private
public OriginalType toOriginalType() {
return OriginalType.DECIMAL;
}
@Override
public <T> Optional<T> accept(LogicalTypeAnnotationVisitor<T> logicalTypeAnnotationVisitor) {
return logicalTypeAnnotationVisitor.visit(this);
}
@Override
LogicalTypeToken getType() {
return LogicalTypeToken.DECIMAL;
}
@Override
protected String typeParametersAsString() {
StringBuilder sb = new StringBuilder();
sb.append("(");
sb.append(precision);
sb.append(",");
sb.append(scale);
sb.append(")");
return sb.toString();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof DecimalLogicalTypeAnnotation)) {
return false;
}
DecimalLogicalTypeAnnotation other = (DecimalLogicalTypeAnnotation) obj;
return scale == other.scale && precision == other.precision;
}
@Override
public int hashCode() {
return Objects.hash(scale, precision);
}
@Override
PrimitiveStringifier valueStringifier(PrimitiveType primitiveType) {
return stringifier;
}
}
public static class DateLogicalTypeAnnotation extends LogicalTypeAnnotation {
private static final DateLogicalTypeAnnotation INSTANCE = new DateLogicalTypeAnnotation();
private DateLogicalTypeAnnotation() {
}
@Override
@InterfaceAudience.Private
public OriginalType toOriginalType() {
return OriginalType.DATE;
}
@Override
public <T> Optional<T> accept(LogicalTypeAnnotationVisitor<T> logicalTypeAnnotationVisitor) {
return logicalTypeAnnotationVisitor.visit(this);
}
@Override
LogicalTypeToken getType() {
return LogicalTypeToken.DATE;
}
@Override
public boolean equals(Object obj) {
return obj instanceof DateLogicalTypeAnnotation;
}
@Override
public int hashCode() {
// This type doesn't have any parameters, thus using class hashcode
return getClass().hashCode();
}
@Override
PrimitiveStringifier valueStringifier(PrimitiveType primitiveType) {
return PrimitiveStringifier.DATE_STRINGIFIER;
}
}
public enum TimeUnit {
MILLIS,
MICROS,
NANOS
}
public static class TimeLogicalTypeAnnotation extends LogicalTypeAnnotation {
private final boolean isAdjustedToUTC;
private final TimeUnit unit;
private TimeLogicalTypeAnnotation(boolean isAdjustedToUTC, TimeUnit unit) {
this.isAdjustedToUTC = isAdjustedToUTC;
this.unit = unit;
}
@Override
@InterfaceAudience.Private
public OriginalType toOriginalType() {
switch (unit) {
case MILLIS:
return OriginalType.TIME_MILLIS;
case MICROS:
return OriginalType.TIME_MICROS;
default:
return null;
}
}
@Override
public <T> Optional<T> accept(LogicalTypeAnnotationVisitor<T> logicalTypeAnnotationVisitor) {
return logicalTypeAnnotationVisitor.visit(this);
}
@Override
LogicalTypeToken getType() {
return LogicalTypeToken.TIME;
}
@Override
protected String typeParametersAsString() {
StringBuilder sb = new StringBuilder();
sb.append("(");
sb.append(unit);
sb.append(",");
sb.append(isAdjustedToUTC);
sb.append(")");
return sb.toString();
}
public TimeUnit getUnit() {
return unit;
}
public boolean isAdjustedToUTC() {
return isAdjustedToUTC;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof TimeLogicalTypeAnnotation)) {
return false;
}
TimeLogicalTypeAnnotation other = (TimeLogicalTypeAnnotation) obj;
return isAdjustedToUTC == other.isAdjustedToUTC && unit == other.unit;
}
@Override
public int hashCode() {
return Objects.hash(isAdjustedToUTC, unit);
}
@Override
PrimitiveStringifier valueStringifier(PrimitiveType primitiveType) {
switch (unit) {
case MICROS:
case MILLIS:
return isAdjustedToUTC ? TIME_UTC_STRINGIFIER : TIME_STRINGIFIER;
case NANOS:
return isAdjustedToUTC ? TIME_NANOS_UTC_STRINGIFIER : TIME_NANOS_STRINGIFIER;
default:
return super.valueStringifier(primitiveType);
}
}
}
public static class TimestampLogicalTypeAnnotation extends LogicalTypeAnnotation {
private final boolean isAdjustedToUTC;
private final TimeUnit unit;
private TimestampLogicalTypeAnnotation(boolean isAdjustedToUTC, TimeUnit unit) {
this.isAdjustedToUTC = isAdjustedToUTC;
this.unit = unit;
}
@Override
@InterfaceAudience.Private
public OriginalType toOriginalType() {
switch (unit) {
case MILLIS:
return OriginalType.TIMESTAMP_MILLIS;
case MICROS:
return OriginalType.TIMESTAMP_MICROS;
default:
return null;
}
}
@Override
public <T> Optional<T> accept(LogicalTypeAnnotationVisitor<T> logicalTypeAnnotationVisitor) {
return logicalTypeAnnotationVisitor.visit(this);
}
@Override
LogicalTypeToken getType() {
return LogicalTypeToken.TIMESTAMP;
}
@Override
protected String typeParametersAsString() {
StringBuilder sb = new StringBuilder();
sb.append("(");
sb.append(unit);
sb.append(",");
sb.append(isAdjustedToUTC);
sb.append(")");
return sb.toString();
}
public TimeUnit getUnit() {
return unit;
}
public boolean isAdjustedToUTC() {
return isAdjustedToUTC;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof TimestampLogicalTypeAnnotation)) {
return false;
}
TimestampLogicalTypeAnnotation other = (TimestampLogicalTypeAnnotation) obj;
return (isAdjustedToUTC == other.isAdjustedToUTC) && (unit == other.unit);
}
@Override
public int hashCode() {
return Objects.hash(isAdjustedToUTC, unit);
}
@Override
PrimitiveStringifier valueStringifier(PrimitiveType primitiveType) {
switch (unit) {
case MICROS:
return isAdjustedToUTC ? TIMESTAMP_MICROS_UTC_STRINGIFIER : TIMESTAMP_MICROS_STRINGIFIER;
case MILLIS:
return isAdjustedToUTC ? TIMESTAMP_MILLIS_UTC_STRINGIFIER : TIMESTAMP_MILLIS_STRINGIFIER;
case NANOS:
return isAdjustedToUTC ? TIMESTAMP_NANOS_UTC_STRINGIFIER : TIMESTAMP_NANOS_STRINGIFIER;
default:
return super.valueStringifier(primitiveType);
}
}
}
public static class IntLogicalTypeAnnotation extends LogicalTypeAnnotation {
private static final Set<Integer> VALID_BIT_WIDTH = Collections.unmodifiableSet(
new HashSet<>(asList(8, 16, 32, 64)));
private final int bitWidth;
private final boolean isSigned;
private IntLogicalTypeAnnotation(int bitWidth, boolean isSigned) {
if (!VALID_BIT_WIDTH.contains(bitWidth)) {
throw new IllegalArgumentException("Invalid integer bit width: " + bitWidth);
}
this.bitWidth = bitWidth;
this.isSigned = isSigned;
}
@Override
@InterfaceAudience.Private
public OriginalType toOriginalType() {
switch (bitWidth) {
case 8:
return isSigned ? OriginalType.INT_8 : OriginalType.UINT_8;
case 16:
return isSigned ? OriginalType.INT_16 : OriginalType.UINT_16;
case 32:
return isSigned ? OriginalType.INT_32 : OriginalType.UINT_32;
case 64:
return isSigned ? OriginalType.INT_64 : OriginalType.UINT_64;
default:
return null;
}
}
@Override
public <T> Optional<T> accept(LogicalTypeAnnotationVisitor<T> logicalTypeAnnotationVisitor) {
return logicalTypeAnnotationVisitor.visit(this);
}
@Override
LogicalTypeToken getType() {
return LogicalTypeToken.INTEGER;
}
@Override
protected String typeParametersAsString() {
StringBuilder sb = new StringBuilder();
sb.append("(");
sb.append(bitWidth);
sb.append(",");
sb.append(isSigned);
sb.append(")");
return sb.toString();
}
public int getBitWidth() {
return bitWidth;
}
public boolean isSigned() {
return isSigned;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof IntLogicalTypeAnnotation)) {
return false;
}
IntLogicalTypeAnnotation other = (IntLogicalTypeAnnotation) obj;
return (bitWidth == other.bitWidth) && (isSigned == other.isSigned);
}
@Override
public int hashCode() {
return Objects.hash(bitWidth, isSigned);
}
@Override
PrimitiveStringifier valueStringifier(PrimitiveType primitiveType) {
return isSigned ? PrimitiveStringifier.DEFAULT_STRINGIFIER : PrimitiveStringifier.UNSIGNED_STRINGIFIER;
}
}
public static class JsonLogicalTypeAnnotation extends LogicalTypeAnnotation {
private static final JsonLogicalTypeAnnotation INSTANCE = new JsonLogicalTypeAnnotation();
private JsonLogicalTypeAnnotation() {
}
@Override
@InterfaceAudience.Private
public OriginalType toOriginalType() {
return OriginalType.JSON;
}
@Override
public <T> Optional<T> accept(LogicalTypeAnnotationVisitor<T> logicalTypeAnnotationVisitor) {
return logicalTypeAnnotationVisitor.visit(this);
}
@Override
LogicalTypeToken getType() {
return LogicalTypeToken.JSON;
}
@Override
public boolean equals(Object obj) {
return obj instanceof JsonLogicalTypeAnnotation;
}
@Override
public int hashCode() {
// This type doesn't have any parameters, thus using class hashcode
return getClass().hashCode();
}
@Override
PrimitiveStringifier valueStringifier(PrimitiveType primitiveType) {
return PrimitiveStringifier.UTF8_STRINGIFIER;
}
}
public static class BsonLogicalTypeAnnotation extends LogicalTypeAnnotation {
private static final BsonLogicalTypeAnnotation INSTANCE = new BsonLogicalTypeAnnotation();
private BsonLogicalTypeAnnotation() {
}
@Override
@InterfaceAudience.Private
public OriginalType toOriginalType() {
return OriginalType.BSON;
}
@Override
public <T> Optional<T> accept(LogicalTypeAnnotationVisitor<T> logicalTypeAnnotationVisitor) {
return logicalTypeAnnotationVisitor.visit(this);
}
@Override
LogicalTypeToken getType() {
return LogicalTypeToken.BSON;
}
@Override
public boolean equals(Object obj) {
return obj instanceof BsonLogicalTypeAnnotation;
}
@Override
public int hashCode() {
// This type doesn't have any parameters, thus using class hashcode
return getClass().hashCode();
}
@Override
PrimitiveStringifier valueStringifier(PrimitiveType primitiveType) {
return PrimitiveStringifier.DEFAULT_STRINGIFIER;
}
}
// This logical type annotation is implemented to support backward compatibility with ConvertedType.
// The new logical type representation in parquet-format doesn't have any interval type,
// thus this annotation is mapped to UNKNOWN.
public static class IntervalLogicalTypeAnnotation extends LogicalTypeAnnotation {
private static IntervalLogicalTypeAnnotation INSTANCE = new IntervalLogicalTypeAnnotation();
public static LogicalTypeAnnotation getInstance() {
return INSTANCE;
}
private IntervalLogicalTypeAnnotation() {
}
@Override
@InterfaceAudience.Private
public OriginalType toOriginalType() {
return OriginalType.INTERVAL;
}
@Override
public <T> Optional<T> accept(LogicalTypeAnnotationVisitor<T> logicalTypeAnnotationVisitor) {
return logicalTypeAnnotationVisitor.visit(this);
}
@Override
LogicalTypeToken getType() {
return LogicalTypeToken.INTERVAL;
}
@Override
public boolean equals(Object obj) {
return obj instanceof IntervalLogicalTypeAnnotation;
}
@Override
public int hashCode() {
// This type doesn't have any parameters, thus using class hashcode
return getClass().hashCode();
}
@Override
PrimitiveStringifier valueStringifier(PrimitiveType primitiveType) {
return PrimitiveStringifier.INTERVAL_STRINGIFIER;
}
@Override
boolean isValidColumnOrder(ColumnOrder columnOrder) {
return columnOrder.getColumnOrderName() == UNDEFINED;
}
}
// This logical type annotation is implemented to support backward compatibility with ConvertedType.
// The new logical type representation in parquet-format doesn't have any key-value type,
// thus this annotation is mapped to UNKNOWN. This type shouldn't be used.
public static class MapKeyValueTypeAnnotation extends LogicalTypeAnnotation {
private static MapKeyValueTypeAnnotation INSTANCE = new MapKeyValueTypeAnnotation();
public static MapKeyValueTypeAnnotation getInstance() {
return INSTANCE;
}
private MapKeyValueTypeAnnotation() {
}
@Override
@InterfaceAudience.Private
public OriginalType toOriginalType() {
return OriginalType.MAP_KEY_VALUE;
}
@Override
public <T> Optional<T> accept(LogicalTypeAnnotationVisitor<T> logicalTypeAnnotationVisitor) {
return logicalTypeAnnotationVisitor.visit(this);
}
@Override
LogicalTypeToken getType() {
return LogicalTypeToken.MAP_KEY_VALUE;
}
@Override
public boolean equals(Object obj) {
return obj instanceof MapKeyValueTypeAnnotation;
}
@Override
public int hashCode() {
// This type doesn't have any parameters, thus using class hashcode
return getClass().hashCode();
}
}
/**
* Implement this interface to visit a logical type annotation in the schema.
* The default implementation for each logical type specific visitor method is empty.
* <p>
* Example usage: logicalTypeAnnotation.accept(new LogicalTypeAnnotationVisitor() { ... });
*
* Every visit method returns {@link Optional#empty()} by default.
* It means that for the given logical type no specific action is needed.
* Client code can use {@link Optional#orElse(Object)} to return a default value for unhandled types,
* or {@link Optional#orElseThrow(Supplier)} to throw exception if omitting a type is not allowed.
*/
public interface LogicalTypeAnnotationVisitor<T> {
default Optional<T> visit(StringLogicalTypeAnnotation stringLogicalType) {
return empty();
}
default Optional<T> visit(MapLogicalTypeAnnotation mapLogicalType) {
return empty();
}
default Optional<T> visit(ListLogicalTypeAnnotation listLogicalType) {
return empty();
}
default Optional<T> visit(EnumLogicalTypeAnnotation enumLogicalType) {
return empty();
}
default Optional<T> visit(DecimalLogicalTypeAnnotation decimalLogicalType) {
return empty();
}
default Optional<T> visit(DateLogicalTypeAnnotation dateLogicalType) {
return empty();
}
default Optional<T> visit(TimeLogicalTypeAnnotation timeLogicalType) {
return empty();
}
default Optional<T> visit(TimestampLogicalTypeAnnotation timestampLogicalType) {
return empty();
}
default Optional<T> visit(IntLogicalTypeAnnotation intLogicalType) {
return empty();
}
default Optional<T> visit(JsonLogicalTypeAnnotation jsonLogicalType) {
return empty();
}
default Optional<T> visit(BsonLogicalTypeAnnotation bsonLogicalType) {
return empty();
}
default Optional<T> visit(IntervalLogicalTypeAnnotation intervalLogicalType) {
return empty();
}
default Optional<T> visit(MapKeyValueTypeAnnotation mapKeyValueLogicalType) {
return empty();
}
}
}