/* * Copyright © 2014 Cask Data, Inc. * * Licensed 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 co.cask.cdap.explore.jdbc; import java.math.BigInteger; import java.sql.Date; import java.sql.SQLException; import java.sql.Timestamp; import java.sql.Types; /** * Column metadata. */ public class JdbcColumn { /** * Default precision when user doesn't specify in the column metadata, such as * decimal and decimal(8). * TODO: right now we don't return precision and scale given by a user - this should be returned with * columns metadata, see CDAP-14. */ public static final int USER_DEFAULT_PRECISION = 10; /** * Sql types and corresponding hive type names and Java classes names. */ public enum SqlTypes { STRING("string", Types.VARCHAR, String.class.getName(), Integer.MAX_VALUE, 0, Integer.MAX_VALUE), VARCHAR("varchar", Types.VARCHAR, String.class.getName(), Integer.MAX_VALUE, 0, Integer.MAX_VALUE), CHAR("char", Types.CHAR, String.class.getName(), Integer.MAX_VALUE, 0, Integer.MAX_VALUE), FLOAT("float", Types.FLOAT, Float.class.getName(), 7, 7, 24), DOUBLE("double", Types.DOUBLE, Double.class.getName(), 15, 15, 25), BOOLEAN("boolean", Types.BOOLEAN, Boolean.class.getName(), 1, 0, 1), TINYINT("tinyint", Types.TINYINT, Byte.class.getName(), 3, 0, 4), SMALLINT("smallint", Types.SMALLINT, Short.class.getName(), 5, 0, 6), INT("int", Types.INTEGER, Integer.class.getName(), 10, 0, 11), BIGINT("bigint", Types.BIGINT, Long.class.getName(), 19, 0, 20), TIMESTAMP("timestamp", Types.TIMESTAMP, Timestamp.class.getName(), 29, 9, 29), DATE("date", Types.DATE, Date.class.getName(), 10, 0, 10), DECIMAL("decimal", Types.DECIMAL, BigInteger.class.getName(), USER_DEFAULT_PRECISION, Integer.MAX_VALUE, USER_DEFAULT_PRECISION + 2), BINARY("binary", Types.BINARY, byte[].class.getName(), Integer.MAX_VALUE, 0, Integer.MAX_VALUE), MAP("map", Types.JAVA_OBJECT, String.class.getName(), Integer.MAX_VALUE, 0, Integer.MAX_VALUE), ARRAY("array", Types.ARRAY, String.class.getName(), Integer.MAX_VALUE, 0, Integer.MAX_VALUE), STRUCT("struct", Types.STRUCT, String.class.getName(), Integer.MAX_VALUE, 0, Integer.MAX_VALUE); private final String typeName; private final int sqlType; private final String className; private final int precision; private final int scale; private final int displaySize; SqlTypes(String typeName, int sqlType, String className, int precision, int scale, int displaySize) { this.typeName = typeName; this.sqlType = sqlType; this.className = className; this.precision = precision; this.scale = scale; this.displaySize = displaySize; } public boolean isNumber() { switch (this) { case FLOAT: case DOUBLE: case SMALLINT: case INT: case BIGINT: case DECIMAL: case TINYINT: return true; case STRING: case VARCHAR: case CHAR: case BOOLEAN: case TIMESTAMP: case DATE: case BINARY: case MAP: case ARRAY: case STRUCT: return false; default: return false; } } public String getTypeName() { return typeName; } public String getClassName() { return className; } public int getSqlType() { return sqlType; } public int getPrecision() { return precision; } public int getScale() { return scale; } public int getDisplaySize() { return displaySize; } } static int columnDisplaySize(int columnType) throws SQLException { for (SqlTypes t : SqlTypes.values()) { if (t.getSqlType() == columnType) { return t.getDisplaySize(); } } throw new SQLException("Invalid column type: " + columnType); } static int columnScale(int columnType) throws SQLException { for (SqlTypes t : SqlTypes.values()) { if (t.getSqlType() == columnType) { return t.getScale(); } } throw new SQLException("Invalid column type: " + columnType); } static int columnPrecision(int columnType) throws SQLException { for (SqlTypes t : SqlTypes.values()) { if (t.getSqlType() == columnType) { return t.getPrecision(); } } throw new SQLException("Invalid column type: " + columnType); } static String columnClassName(int columnType) throws SQLException { for (SqlTypes t : SqlTypes.values()) { if (t.getSqlType() == columnType) { return t.getClassName(); } } throw new SQLException("Invalid column type: " + columnType); } public static int hiveTypeToSqlType(String type) throws SQLException { for (SqlTypes t : SqlTypes.values()) { // We use startsWith instead of equals because of some types like: // array<int>, array<...>, map<...> if (type.toLowerCase().startsWith(t.getTypeName())) { return t.getSqlType(); } } throw new SQLException("Unrecognized column type: " + type); } static String getColumnTypeName(String type) throws SQLException { // we need to convert the Hive type to the SQL type name for (SqlTypes t : SqlTypes.values()) { // We use startsWith instead of equals because of some types like: // array<int>, array<...>, map<...> if (type.toLowerCase().startsWith(t.getTypeName())) { return t.getTypeName(); } } throw new SQLException("Unrecognized column type: " + type); } static boolean isNumber(int columnType) throws SQLException { for (SqlTypes t : SqlTypes.values()) { if (t.getSqlType() == columnType) { return t.isNumber(); } } throw new SQLException("Invalid column type: " + columnType); } }