| /* |
| * 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.drill.common.types; |
| |
| import static org.apache.drill.common.types.TypeProtos.DataMode.REPEATED; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.apache.drill.common.exceptions.DrillRuntimeException; |
| import org.apache.drill.common.types.TypeProtos.DataMode; |
| import org.apache.drill.common.types.TypeProtos.MajorType; |
| import org.apache.drill.common.types.TypeProtos.MinorType; |
| |
| import com.google.protobuf.TextFormat; |
| |
| public class Types { |
| |
| public static final int MAX_VARCHAR_LENGTH = 65535; |
| public static final int UNDEFINED = 0; |
| |
| public static final MajorType NULL = required(MinorType.NULL); |
| public static final MajorType LATE_BIND_TYPE = optional(MinorType.LATE); |
| public static final MajorType REQUIRED_BIT = required(MinorType.BIT); |
| public static final MajorType OPTIONAL_BIT = optional(MinorType.BIT); |
| public static final MajorType OPTIONAL_INT = optional(MinorType.INT); |
| |
| public static boolean isUnion(MajorType toType) { |
| return toType.getMinorType() == MinorType.UNION; |
| } |
| |
| public static boolean isComplex(final MajorType type) { |
| switch(type.getMinorType()) { |
| case LIST: |
| case MAP: |
| case DICT: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| public static boolean isRepeated(final MajorType type) { |
| return type.getMode() == REPEATED; |
| } |
| |
| public static boolean isNumericType(final MajorType type) { |
| if (type.getMode() == REPEATED) { |
| return false; |
| } |
| return isNumericType(type.getMinorType()); |
| } |
| |
| public static boolean isNumericType(final MinorType type) { |
| switch (type) { |
| case BIGINT: |
| case VARDECIMAL: |
| case DECIMAL38SPARSE: |
| case DECIMAL38DENSE: |
| case DECIMAL28SPARSE: |
| case DECIMAL28DENSE: |
| case DECIMAL18: |
| case DECIMAL9: |
| case FLOAT4: |
| case FLOAT8: |
| case INT: |
| case MONEY: |
| case SMALLINT: |
| case TINYINT: |
| case UINT1: |
| case UINT2: |
| case UINT4: |
| case UINT8: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| public static boolean isDateTimeType(MajorType type) { |
| if (type.getMode() == REPEATED) { |
| return false; |
| } |
| return isDateTimeType(type.getMinorType()); |
| } |
| |
| public static boolean isDateTimeType(MinorType type) { |
| switch (type) { |
| case TIME: |
| case TIMETZ: |
| case DATE: |
| case TIMESTAMP: |
| case TIMESTAMPTZ: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| public static boolean isIntervalType(MajorType type) { |
| if (type.getMode() == REPEATED) { |
| return false; |
| } |
| return isIntervalType(type.getMinorType()); |
| } |
| |
| public static boolean isIntervalType(MinorType type) { |
| switch (type) { |
| case INTERVAL: |
| case INTERVALDAY: |
| case INTERVALYEAR: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| /** |
| * Returns true if specified type is decimal data type. |
| * |
| * @param type type to check |
| * @return true if specified type is decimal data type. |
| */ |
| public static boolean isDecimalType(MajorType type) { |
| return isDecimalType(type.getMinorType()); |
| } |
| |
| /** |
| * Returns true if specified type is decimal data type. |
| * |
| * @param minorType type to check |
| * @return true if specified type is decimal data type. |
| */ |
| public static boolean isDecimalType(MinorType minorType) { |
| switch(minorType) { |
| case VARDECIMAL: |
| case DECIMAL38SPARSE: |
| case DECIMAL38DENSE: |
| case DECIMAL28SPARSE: |
| case DECIMAL28DENSE: |
| case DECIMAL18: |
| case DECIMAL9: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| /*** |
| * Gets SQL data type name for given Drill RPC-/protobuf-level data type. |
| * @return |
| * canonical keyword sequence for SQL data type (leading keywords in |
| * corresponding {@code <data type>}; what |
| * {@code INFORMATION_SCHEMA.COLUMNS.TYPE_NAME} would list) |
| */ |
| public static String getSqlTypeName(final MajorType type) { |
| if (type.getMode() == DataMode.REPEATED || type.getMinorType() == MinorType.LIST) { |
| return "ARRAY"; |
| } |
| return getBaseSqlTypeName(type); |
| } |
| |
| public static String getBaseSqlTypeName(final MajorType type) { |
| |
| switch (type.getMinorType()) { |
| |
| // Standard SQL atomic data types: |
| |
| case BIT: return "BOOLEAN"; |
| |
| case SMALLINT: return "SMALLINT"; |
| case INT: return "INTEGER"; |
| case BIGINT: return "BIGINT"; |
| |
| case FLOAT4: return "FLOAT"; |
| case FLOAT8: return "DOUBLE"; |
| |
| case VARDECIMAL: |
| case DECIMAL9: |
| case DECIMAL18: |
| case DECIMAL28DENSE: |
| case DECIMAL28SPARSE: |
| case DECIMAL38DENSE: |
| case DECIMAL38SPARSE: return "DECIMAL"; |
| |
| case VARCHAR: return "CHARACTER VARYING"; |
| case FIXEDCHAR: return "CHARACTER"; |
| |
| case VAR16CHAR: return "NATIONAL CHARACTER VARYING"; |
| case FIXED16CHAR: return "NATIONAL CHARACTER"; |
| |
| case VARBINARY: return "BINARY VARYING"; |
| case FIXEDBINARY: return "BINARY"; |
| |
| case DATE: return "DATE"; |
| case TIME: return "TIME"; |
| case TIMETZ: return "TIME WITH TIME ZONE"; |
| case TIMESTAMP: return "TIMESTAMP"; |
| case TIMESTAMPTZ: return "TIMESTAMP WITH TIME ZONE"; |
| |
| case INTERVALYEAR: return "INTERVAL YEAR TO MONTH"; |
| case INTERVALDAY: return "INTERVAL DAY TO SECOND"; |
| |
| // Non-standard SQL atomic data types: |
| |
| case INTERVAL: return "INTERVAL"; |
| case MONEY: return "DECIMAL"; |
| case TINYINT: return "TINYINT"; |
| |
| // Composite types and other types that are not atomic types (SQL standard |
| // or not) except ARRAY types (handled above): |
| |
| case MAP: return "STRUCT"; // Drill map represents struct |
| case DICT: return "MAP"; |
| case LATE: return "ANY"; |
| case NULL: return "NULL"; |
| case UNION: return "UNION"; |
| case GENERIC_OBJECT: return "JAVA_OBJECT"; |
| |
| // Internal types not actually used at level of SQL types(?): |
| |
| case UINT1: return "TINYINT"; |
| case UINT2: return "SMALLINT"; |
| case UINT4: return "INTEGER"; |
| case UINT8: return "BIGINT"; |
| |
| default: |
| throw new AssertionError( |
| "Unexpected/unhandled MinorType value " + type.getMinorType() ); |
| } |
| } |
| |
| /** |
| * Extend decimal type with precision and scale. |
| * |
| * @param type major type |
| * @return type name augmented with precision and scale, |
| * if type is a decimal |
| */ |
| public static String getExtendedSqlTypeName(MajorType type) { |
| |
| String typeName = getSqlTypeName(type); |
| switch (type.getMinorType()) { |
| case DECIMAL9: |
| case DECIMAL18: |
| case DECIMAL28SPARSE: |
| case DECIMAL28DENSE: |
| case DECIMAL38SPARSE: |
| case DECIMAL38DENSE: |
| case VARDECIMAL: |
| // Disabled for now. See DRILL-6378 |
| if (type.getPrecision() > 0) { |
| typeName += String.format("(%d, %d)", |
| type.getPrecision(), type.getScale()); |
| } |
| default: |
| } |
| return typeName; |
| } |
| |
| public static String getSqlModeName(final MajorType type) { |
| switch (type.getMode()) { |
| case REQUIRED: |
| return "NOT NULL"; |
| case OPTIONAL: |
| return "NULLABLE"; |
| case REPEATED: |
| return "ARRAY"; |
| default: |
| return "UNKNOWN"; |
| } |
| } |
| |
| /*** |
| * Gets JDBC type code for given SQL data type name. |
| */ |
| public static int getJdbcTypeCode(final String sqlTypeName) { |
| |
| switch (sqlTypeName) { |
| case "ANY": return java.sql.Types.OTHER; |
| case "ARRAY": return java.sql.Types.OTHER; // Drill doesn't support java.sql.Array |
| case "BIGINT": return java.sql.Types.BIGINT; |
| case "BINARY VARYING": return java.sql.Types.VARBINARY; |
| case "BINARY": return java.sql.Types.BINARY; |
| case "BOOLEAN": return java.sql.Types.BOOLEAN; |
| case "CHARACTER VARYING": return java.sql.Types.VARCHAR; |
| case "CHARACTER": return java.sql.Types.NCHAR; |
| case "DATE": return java.sql.Types.DATE; |
| case "DECIMAL": return java.sql.Types.DECIMAL; |
| case "DOUBLE": return java.sql.Types.DOUBLE; |
| case "FLOAT": return java.sql.Types.FLOAT; |
| case "INTEGER": return java.sql.Types.INTEGER; |
| case "INTERVAL": return java.sql.Types.OTHER; // JDBC (4.1) has nothing for INTERVAL |
| case "INTERVAL YEAR TO MONTH": return java.sql.Types.OTHER; |
| case "INTERVAL DAY TO SECOND": return java.sql.Types.OTHER; |
| case "STRUCT": return java.sql.Types.OTHER; // Drill doesn't support java.sql.Struct |
| case "MAP": return java.sql.Types.OTHER; |
| case "NATIONAL CHARACTER VARYING": return java.sql.Types.NVARCHAR; |
| case "NATIONAL CHARACTER": return java.sql.Types.NCHAR; |
| case "NULL": return java.sql.Types.NULL; |
| case "SMALLINT": return java.sql.Types.SMALLINT; |
| case "TIME WITH TIME ZONE": // fall through |
| case "TIME": return java.sql.Types.TIME; |
| case "TIMESTAMP WITH TIME ZONE": // fall through |
| case "TIMESTAMP": return java.sql.Types.TIMESTAMP; |
| case "TINYINT": return java.sql.Types.TINYINT; |
| case "UNION": return java.sql.Types.OTHER; |
| case "JAVA_OBJECT": return java.sql.Types.JAVA_OBJECT; |
| default: |
| // TODO: This isn't really an unsupported-operation/-type case; this |
| // is an unexpected, code-out-of-sync-with-itself case, so use an |
| // exception intended for that. |
| throw new UnsupportedOperationException( |
| "Unexpected/unhandled SqlType value " + sqlTypeName ); |
| } |
| } |
| |
| /** |
| * Reports whether given RPC-level type is a signed type (per semantics of |
| * {@link java.sql.ResultSetMetaData#isSigned(int)}). |
| */ |
| public static boolean isJdbcSignedType( final MajorType type ) { |
| final boolean isSigned; |
| switch ( type.getMode() ) { |
| case REPEATED: |
| isSigned = false; // SQL ARRAY |
| break; |
| case REQUIRED: |
| case OPTIONAL: |
| switch ( type.getMinorType() ) { |
| // Verified signed types: |
| case SMALLINT: |
| case INT: // SQL INTEGER |
| case BIGINT: |
| case FLOAT4: // SQL REAL / FLOAT(N) |
| case FLOAT8: // SQL DOUBLE PRECISION / FLOAT(N) |
| case INTERVALYEAR: // SQL INTERVAL w/YEAR and/or MONTH |
| case INTERVALDAY: // SQL INTERVAL w/DAY, HOUR, MINUTE and/or SECOND |
| // Not-yet seen/verified signed types: |
| case VARDECIMAL: // SQL DECIMAL (if used) |
| case DECIMAL9: // SQL DECIMAL (if used) |
| case DECIMAL18: // SQL DECIMAL (if used) |
| case DECIMAL28SPARSE: // SQL DECIMAL (if used) |
| case DECIMAL38SPARSE: // SQL DECIMAL (if used) |
| case DECIMAL28DENSE: // SQL DECIMAL (if used) |
| case DECIMAL38DENSE: // SQL DECIMAL (if used) |
| case TINYINT: // (not standard SQL) |
| case MONEY: // (not standard SQL) |
| case INTERVAL: // unknown (given INTERVALYEAR and INTERVALDAY) |
| isSigned = true; |
| break; |
| // Verified unsigned types: |
| case BIT: // SQL BOOLEAN |
| case VARCHAR: |
| case FIXEDCHAR: // SQL CHARACTER |
| case VARBINARY: |
| case FIXEDBINARY: // SQL BINARY |
| case DATE: |
| case TIME: // SQL TIME WITHOUT TIME ZONE |
| case TIMESTAMP: // SQL TIMESTAMP WITHOUT TIME ZONE |
| // Not-yet seen/verified unsigned types: |
| case UINT1: |
| case UINT2: |
| case UINT4: |
| case UINT8: |
| case FIXED16CHAR: |
| case VAR16CHAR: |
| case GENERIC_OBJECT: |
| case LATE: |
| case LIST: |
| case MAP: |
| case DICT: |
| case UNION: |
| case NULL: |
| case TIMETZ: // SQL TIME WITH TIME ZONE |
| case TIMESTAMPTZ: // SQL TIMESTAMP WITH TIME ZONE |
| isSigned = false; |
| break; |
| default: |
| throw new UnsupportedOperationException( |
| "Unexpected/unhandled MinorType value " + type.getMinorType() ); |
| } |
| break; |
| default: |
| throw new UnsupportedOperationException( |
| "Unexpected/unhandled DataMode value " + type.getMode() ); |
| } |
| return isSigned; |
| } |
| |
| public static int getJdbcDisplaySize(MajorType type) { |
| if (type.getMode() == DataMode.REPEATED || type.getMinorType() == MinorType.LIST) { |
| return UNDEFINED; |
| } |
| |
| final int precision = getPrecision(type); |
| switch(type.getMinorType()) { |
| case BIT: return 1; // 1 digit |
| |
| case TINYINT: return 4; // sign + 3 digit |
| case SMALLINT: return 6; // sign + 5 digits |
| case INT: return 11; // sign + 10 digits |
| case BIGINT: return 20; // sign + 19 digits |
| |
| case UINT1: return 3; // 3 digits |
| case UINT2: return 5; // 5 digits |
| case UINT4: return 10; // 10 digits |
| case UINT8: return 19; // 19 digits |
| |
| case FLOAT4: return 14; // sign + 7 digits + decimal point + E + 2 digits |
| case FLOAT8: return 24; // sign + 15 digits + decimal point + E + 3 digits |
| |
| case DECIMAL9: |
| case DECIMAL18: |
| case DECIMAL28DENSE: |
| case DECIMAL28SPARSE: |
| case DECIMAL38DENSE: |
| case DECIMAL38SPARSE: |
| case VARDECIMAL: |
| case MONEY: return 2 + precision; // precision of the column plus a sign and a decimal point |
| |
| case VARCHAR: |
| case FIXEDCHAR: |
| case VAR16CHAR: |
| case FIXED16CHAR: return precision; // number of characters |
| |
| case VARBINARY: |
| case FIXEDBINARY: return 2 * precision; // each binary byte is represented as a 2digit hex number |
| |
| case DATE: return 10; // yyyy-mm-dd |
| case TIME: |
| return precision > 0 |
| ? 9 + precision // hh-mm-ss.SSS |
| : 8; // hh-mm-ss |
| case TIMETZ: |
| return precision > 0 |
| ? 15 + precision // hh-mm-ss.SSS-zz:zz |
| : 14; // hh-mm-ss-zz:zz |
| case TIMESTAMP: |
| return precision > 0 |
| ? 20 + precision // yyyy-mm-ddThh:mm:ss.SSS |
| : 19; // yyyy-mm-ddThh:mm:ss |
| case TIMESTAMPTZ: |
| return precision > 0 |
| ? 26 + precision // yyyy-mm-ddThh:mm:ss.SSS:ZZ-ZZ |
| : 25; // yyyy-mm-ddThh:mm:ss-ZZ:ZZ |
| |
| case INTERVALYEAR: |
| return precision > 0 |
| ? 5 + precision // P..Y12M |
| : 9; // we assume max is P9999Y12M |
| |
| case INTERVALDAY: |
| return precision > 0 |
| ? 12 + precision // P..DT12H60M60S assuming fractional seconds precision is not supported |
| : 22; // the first 4 bytes give the number of days, so we assume max is P2147483648DT12H60M60S |
| |
| case INTERVAL: |
| case MAP: |
| case DICT: |
| case LATE: |
| case NULL: |
| case UNION: |
| return UNDEFINED; |
| |
| default: |
| throw new UnsupportedOperationException("Unexpected/unhandled MinorType value " + type.getMinorType()); |
| } |
| } |
| public static boolean usesHolderForGet(final MajorType type) { |
| if (type.getMode() == REPEATED) { |
| return true; |
| } |
| switch(type.getMinorType()) { |
| case BIGINT: |
| case FLOAT4: |
| case FLOAT8: |
| case INT: |
| case MONEY: |
| case SMALLINT: |
| case TINYINT: |
| case UINT1: |
| case UINT2: |
| case UINT4: |
| case UINT8: |
| case INTERVALYEAR: |
| case DATE: |
| case TIME: |
| case TIMESTAMP: |
| return false; |
| |
| default: |
| return true; |
| } |
| } |
| |
| public static boolean isFixedWidthType(final MajorType type) { |
| return isFixedWidthType(type.getMinorType()); |
| } |
| |
| public static boolean isFixedWidthType(final MinorType type) { |
| return ! isVarWidthType(type); |
| } |
| |
| public static boolean isVarWidthType(final MinorType type) { |
| switch (type) { |
| case VARBINARY: |
| case VAR16CHAR: |
| case VARCHAR: |
| case UNION: |
| case VARDECIMAL: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| /** |
| * Checks if given major type is string scalar type. |
| * |
| * @param type major type |
| * @return true if given major type is scalar string, false otherwise |
| */ |
| public static boolean isScalarStringType(final MajorType type) { |
| if (type.getMode() == REPEATED) { |
| return false; |
| } |
| switch (type.getMinorType()) { |
| case FIXEDCHAR: |
| case FIXED16CHAR: |
| case VARCHAR: |
| case VAR16CHAR: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| public static boolean softEquals(final MajorType a, final MajorType b, final boolean allowNullSwap) { |
| if (a.getMinorType() != b.getMinorType()) { |
| return false; |
| } |
| if (allowNullSwap) { |
| switch (a.getMode()) { |
| case OPTIONAL: |
| case REQUIRED: |
| switch (b.getMode()) { |
| case OPTIONAL: |
| case REQUIRED: |
| return true; |
| default: |
| } |
| default: |
| } |
| } |
| return a.getMode() == b.getMode(); |
| } |
| |
| public static boolean isUntypedNull(final MajorType type) { |
| return type.getMinorType() == MinorType.NULL; |
| } |
| |
| public static MajorType withMode(final MinorType type, final DataMode mode) { |
| return MajorType.newBuilder().setMode(mode).setMinorType(type).build(); |
| } |
| |
| /** |
| * Builds major type using given minor type, data mode and precision. |
| * |
| * @param type minor type |
| * @param mode data mode |
| * @param precision precision value |
| * @return major type |
| */ |
| public static MajorType withPrecision(final MinorType type, final DataMode mode, final int precision) { |
| return MajorType.newBuilder().setMinorType(type).setMode(mode).setPrecision(precision).build(); |
| } |
| |
| public static MajorType withPrecisionAndScale(MinorType type, DataMode mode, int precision, int scale) { |
| return MajorType.newBuilder().setMinorType(type).setMode(mode).setScale(scale).setPrecision(precision).build(); |
| } |
| |
| public static MajorType required(final MinorType type) { |
| return MajorType.newBuilder().setMode(DataMode.REQUIRED).setMinorType(type).build(); |
| } |
| |
| public static MajorType repeated(final MinorType type) { |
| return MajorType.newBuilder().setMode(REPEATED).setMinorType(type).build(); |
| } |
| |
| public static MajorType optional(final MinorType type) { |
| return MajorType.newBuilder().setMode(DataMode.OPTIONAL).setMinorType(type).build(); |
| } |
| |
| public static MajorType overrideMode(final MajorType originalMajorType, final DataMode overrideMode) { |
| return withPrecisionAndScale(originalMajorType.getMinorType(), overrideMode, originalMajorType.getPrecision(), originalMajorType.getScale()); |
| } |
| |
| public static MajorType getMajorTypeFromName(final String typeName) { |
| return getMajorTypeFromName(typeName, DataMode.REQUIRED); |
| } |
| |
| public static MinorType getMinorTypeFromName(String typeName) { |
| typeName = typeName.toLowerCase(); |
| switch (typeName) { |
| case "bool": |
| case "boolean": |
| return MinorType.BIT; |
| case "tinyint": |
| return MinorType.TINYINT; |
| case "uint1": |
| return MinorType.UINT1; |
| case "smallint": |
| return MinorType.SMALLINT; |
| case "uint2": |
| return MinorType.UINT2; |
| case "integer": |
| case "int": |
| return MinorType.INT; |
| case "uint4": |
| return MinorType.UINT4; |
| case "bigint": |
| return MinorType.BIGINT; |
| case "uint8": |
| return MinorType.UINT8; |
| case "float": |
| return MinorType.FLOAT4; |
| case "double": |
| return MinorType.FLOAT8; |
| case "decimal": |
| return MinorType.VARDECIMAL; |
| case "symbol": |
| case "char": |
| case "utf8": |
| case "varchar": |
| return MinorType.VARCHAR; |
| case "utf16": |
| case "string": |
| case "var16char": |
| return MinorType.VAR16CHAR; |
| case "timestamp": |
| return MinorType.TIMESTAMP; |
| case "interval_year_month": |
| return MinorType.INTERVALYEAR; |
| case "interval_day_time": |
| return MinorType.INTERVALDAY; |
| case "date": |
| return MinorType.DATE; |
| case "time": |
| return MinorType.TIME; |
| case "binary": |
| return MinorType.VARBINARY; |
| case "json": |
| case "simplejson": |
| case "extendedjson": |
| return MinorType.LATE; |
| case "null": |
| case "any": |
| return MinorType.NULL; |
| default: |
| throw new UnsupportedOperationException("Could not determine type: " + typeName); |
| } |
| } |
| |
| public static MajorType getMajorTypeFromName(final String typeName, final DataMode mode) { |
| return withMode(getMinorTypeFromName(typeName), mode); |
| } |
| |
| public static String getNameOfMinorType(final MinorType type) { |
| switch (type) { |
| case BIT: |
| return "bool"; |
| case TINYINT: |
| return "tinyint"; |
| case UINT1: |
| return "uint1"; |
| case SMALLINT: |
| return "smallint"; |
| case UINT2: |
| return "uint2"; |
| case INT: |
| return "int"; |
| case UINT4: |
| return "uint4"; |
| case BIGINT: |
| return "bigint"; |
| case UINT8: |
| return "uint8"; |
| case FLOAT4: |
| return "float"; |
| case FLOAT8: |
| return "double"; |
| case VARDECIMAL: |
| case DECIMAL9: |
| case DECIMAL18: |
| case DECIMAL28SPARSE: |
| case DECIMAL38SPARSE: |
| return "decimal"; |
| case VARCHAR: |
| return "varchar"; |
| case VAR16CHAR: |
| return "utf16"; |
| case DATE: |
| return "date"; |
| case TIME: |
| return "time"; |
| case TIMESTAMP: |
| return "timestamp"; |
| case VARBINARY: |
| return "binary"; |
| case LATE: |
| throw new DrillRuntimeException("The late type should never appear in execution or an SQL query, so it does not have a name to refer to it."); |
| default: |
| throw new DrillRuntimeException("Unrecognized type " + type); |
| } |
| } |
| |
| public static String toString(final MajorType type) { |
| return type != null ? "MajorType[" + TextFormat.shortDebugString(type) + "]" : "null"; |
| } |
| |
| /** |
| * Get the <code>precision</code> of given type. |
| * |
| * @param majorType major type |
| * @return precision value |
| */ |
| public static int getPrecision(MajorType majorType) { |
| if (majorType.hasPrecision()) { |
| return majorType.getPrecision(); |
| } |
| |
| return isScalarStringType(majorType) ? MAX_VARCHAR_LENGTH : UNDEFINED; |
| } |
| |
| /** |
| * Get the <code>scale</code> of given type. |
| * |
| * @param majorType major type |
| * @return scale value |
| */ |
| public static int getScale(MajorType majorType) { |
| if (majorType.hasScale()) { |
| return majorType.getScale(); |
| } |
| |
| return UNDEFINED; |
| } |
| |
| /** |
| * Checks if the given type column can be used in ORDER BY clause. |
| * |
| * @param type minor type |
| * @return true if type can be used in ORDER BY clause |
| */ |
| public static boolean isSortable(MinorType type) { |
| switch (type) { |
| case DICT: |
| case LIST: |
| case MAP: |
| return false; |
| default: |
| return true; |
| } |
| } |
| |
| /** |
| * Sets max precision from both types if these types are string scalar types. |
| * Sets max precision and scale from both types if these types are decimal types. |
| * Both types should be of the same minor type. |
| * |
| * @param leftType type from left side |
| * @param rightType type from right side |
| * @param typeBuilder type builder |
| * @return type builder |
| */ |
| public static MajorType.Builder calculateTypePrecisionAndScale(MajorType leftType, MajorType rightType, MajorType.Builder typeBuilder) { |
| if (leftType.getMinorType().equals(rightType.getMinorType())) { |
| final boolean isScalarString = Types.isScalarStringType(leftType) && Types.isScalarStringType(rightType); |
| final boolean isDecimal = isDecimalType(leftType); |
| |
| if ((isScalarString || isDecimal) && leftType.hasPrecision() && rightType.hasPrecision()) { |
| typeBuilder.setPrecision(Math.max(leftType.getPrecision(), rightType.getPrecision())); |
| } |
| |
| if (isDecimal && leftType.hasScale() && rightType.hasScale()) { |
| typeBuilder.setScale(Math.max(leftType.getScale(), rightType.getScale())); |
| } |
| } |
| return typeBuilder; |
| } |
| |
| public static boolean isEquivalent(MajorType type1, MajorType type2) { |
| |
| // Requires full type equality, including fields such as precision and scale. |
| // But, unset fields are equivalent to 0. Can't use the protobuf-provided |
| // isEquals() which treats set and unset fields as different. |
| |
| if (type1.getMinorType() != type2.getMinorType() || |
| type1.getMode() != type2.getMode() || |
| type1.getScale() != type2.getScale() || |
| type1.getPrecision() != type2.getPrecision()) { |
| return false; |
| } |
| |
| // Subtypes are only for unions and are seldom used. |
| |
| if (type1.getMinorType() != MinorType.UNION) { |
| return true; |
| } |
| |
| final List<MinorType> subtypes1 = type1.getSubTypeList(); |
| final List<MinorType> subtypes2 = type2.getSubTypeList(); |
| if (subtypes1 == subtypes2) { // Only occurs if both are null |
| return true; |
| } |
| if (subtypes1 == null || subtypes2 == null) { |
| return false; |
| } |
| if (subtypes1.size() != subtypes2.size()) { |
| return false; |
| } |
| |
| // Now it gets slow because subtype lists are not ordered. |
| |
| final List<MinorType> copy1 = new ArrayList<>(subtypes1); |
| final List<MinorType> copy2 = new ArrayList<>(subtypes2); |
| Collections.sort(copy1); |
| Collections.sort(copy2); |
| return copy1.equals(copy2); |
| } |
| |
| /** |
| * The union vector is a map of types. The following method provides |
| * the standard name to use in the type map. It replaces the many |
| * ad-hoc appearances of this code in each reference to the map. |
| * |
| * @param type Drill data type |
| * @return string key to use for this type in a union vector type |
| * map |
| */ |
| |
| public static String typeKey(MinorType type) { |
| return type.name().toLowerCase(); |
| } |
| |
| public static int maxPrecision(MinorType type) { |
| switch (type) { |
| case DECIMAL18: |
| return 18; |
| case DECIMAL28DENSE: |
| case DECIMAL28SPARSE: |
| return 28; |
| case DECIMAL38DENSE: |
| case DECIMAL38SPARSE: |
| return 38; |
| case DECIMAL9: |
| return 9; |
| case VARDECIMAL: |
| return 38; |
| default: |
| return 0; |
| } |
| } |
| |
| public static boolean isNullable(final MajorType type) { |
| switch (type.getMode()) { |
| case REQUIRED: |
| case REPEATED: |
| return false; |
| case OPTIONAL: |
| return !isComplex(type); |
| default: |
| throw new UnsupportedOperationException("Unexpected/unhandled DataMode value " + type.getMode()); |
| } |
| } |
| } |