/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.transformation.reverseeng.api; import static java.sql.Types.ARRAY; import static java.sql.Types.BIGINT; import static java.sql.Types.BINARY; import static java.sql.Types.BIT; import static java.sql.Types.BLOB; import static java.sql.Types.BOOLEAN; import static java.sql.Types.CHAR; import static java.sql.Types.CLOB; import static java.sql.Types.DATE; import static java.sql.Types.DECIMAL; import static java.sql.Types.DOUBLE; import static java.sql.Types.FLOAT; import static java.sql.Types.INTEGER; import static java.sql.Types.LONGNVARCHAR; import static java.sql.Types.LONGVARBINARY; import static java.sql.Types.LONGVARCHAR; import static java.sql.Types.NCHAR; import static java.sql.Types.NCLOB; import static java.sql.Types.NULL; import static java.sql.Types.NUMERIC; import static java.sql.Types.NVARCHAR; import static java.sql.Types.OTHER; import static java.sql.Types.REAL; import static java.sql.Types.SMALLINT; import static java.sql.Types.SQLXML; import static java.sql.Types.TIME; import static java.sql.Types.TIMESTAMP; import static java.sql.Types.TINYINT; import static java.sql.Types.VARBINARY; import static java.sql.Types.VARCHAR; //import java.sql.DatabaseMetaData; //import java.sql.ResultSet; //import java.sql.SQLException; import java.sql.Types; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; /** * A utility class that handles mappings of JDBC data types to the database types and Java * types. Also contains methods that provide information about JDBC types. */ public class TypesMapping { // Never use "-1" or any other normal integer, since there // is a big chance it is being reserved in java.sql.Types public static final int NOT_DEFINED = Integer.MAX_VALUE; // char constants for the sql data types public static final String SQL_ARRAY = "ARRAY"; public static final String SQL_BIGINT = "BIGINT"; public static final String SQL_BINARY = "BINARY"; public static final String SQL_BIT = "BIT"; public static final String SQL_BLOB = "BLOB"; /** * @since 1.2 */ public static final String SQL_BOOLEAN = "BOOLEAN"; public static final String SQL_CLOB = "CLOB"; public static final String SQL_NCLOB = "NCLOB"; public static final String SQL_CHAR = "CHAR"; public static final String SQL_NCHAR = "NCHAR"; public static final String SQL_DATE = "DATE"; public static final String SQL_DECIMAL = "DECIMAL"; public static final String SQL_DOUBLE = "DOUBLE"; public static final String SQL_FLOAT = "FLOAT"; public static final String SQL_INTEGER = "INTEGER"; public static final String SQL_LONGVARCHAR = "LONGVARCHAR"; public static final String SQL_LONGNVARCHAR = "LONGNVARCHAR"; public static final String SQL_LONGVARBINARY = "LONGVARBINARY"; public static final String SQL_NUMERIC = "NUMERIC"; public static final String SQL_REAL = "REAL"; public static final String SQL_SMALLINT = "SMALLINT"; public static final String SQL_TINYINT = "TINYINT"; public static final String SQL_TIME = "TIME"; public static final String SQL_TIMESTAMP = "TIMESTAMP"; public static final String SQL_VARBINARY = "VARBINARY"; public static final String SQL_VARCHAR = "VARCHAR"; public static final String SQL_NVARCHAR = "NVARCHAR"; public static final String SQL_SQLXML = "SQLXML"; public static final String SQL_OTHER = "OTHER"; public static final String SQL_NULL = "NULL"; // char constants for Java data types public static final String JAVA_LONG = "java.lang.Long"; public static final String JAVA_BYTES = "byte[]"; public static final String JAVA_BOOLEAN = "java.lang.Boolean"; public static final String JAVA_STRING = "java.lang.String"; public static final String JAVA_SQLDATE = "java.sql.Date"; public static final String JAVA_UTILDATE = "java.util.Date"; public static final String JAVA_BIGDECIMAL = "java.math.BigDecimal"; public static final String JAVA_DOUBLE = "java.lang.Double"; public static final String JAVA_FLOAT = "java.lang.Float"; public static final String JAVA_INTEGER = "java.lang.Integer"; public static final String JAVA_SHORT = "java.lang.Short"; public static final String JAVA_BYTE = "java.lang.Byte"; public static final String JAVA_TIME = "java.sql.Time"; public static final String JAVA_TIMESTAMP = "java.sql.Timestamp"; public static final String JAVA_BLOB = "java.sql.Blob"; public static final String JAVA_OBJECT = "java.lang.Object"; /** * Keys: SQL string type names, Values: SQL int type definitions from java.sql.Types */ private static final Map<String, Integer> SQL_STRING_TYPE = new HashMap<String, Integer>(); /** * Keys: SQL int type definitions from java.sql.Types, Values: SQL string type names */ private static final Map<Integer, String> SQL_ENUM_TYPE = new HashMap<Integer, String>(); /** * Keys: SQL int type definitions from java.sql.Types, Values: java class names */ private static final Map<Integer, String> SQL_ENUM_JAVA = new HashMap<Integer, String>(); /** * Keys: java class names, Values: SQL int type definitions from java.sql.Types */ private static final Map<String, Integer> JAVA_SQL_ENUM = new HashMap<String, Integer>(); static { SQL_STRING_TYPE.put(SQL_ARRAY, ARRAY); SQL_STRING_TYPE.put(SQL_BIGINT, BIGINT); SQL_STRING_TYPE.put(SQL_BINARY, BINARY); SQL_STRING_TYPE.put(SQL_BIT, BIT); SQL_STRING_TYPE.put(SQL_BLOB, BLOB); SQL_STRING_TYPE.put(SQL_BOOLEAN, BOOLEAN); SQL_STRING_TYPE.put(SQL_CLOB, CLOB); SQL_STRING_TYPE.put(SQL_NCLOB, NCLOB); SQL_STRING_TYPE.put(SQL_CHAR, CHAR); SQL_STRING_TYPE.put(SQL_NCHAR, NCHAR); SQL_STRING_TYPE.put(SQL_DATE, DATE); SQL_STRING_TYPE.put(SQL_DECIMAL, DECIMAL); SQL_STRING_TYPE.put(SQL_DOUBLE, DOUBLE); SQL_STRING_TYPE.put(SQL_FLOAT, FLOAT); SQL_STRING_TYPE.put(SQL_INTEGER, INTEGER); SQL_STRING_TYPE.put(SQL_LONGVARCHAR, LONGVARCHAR); SQL_STRING_TYPE.put(SQL_LONGNVARCHAR, LONGNVARCHAR); SQL_STRING_TYPE.put(SQL_LONGVARBINARY, LONGVARBINARY); SQL_STRING_TYPE.put(SQL_NUMERIC, NUMERIC); SQL_STRING_TYPE.put(SQL_REAL, REAL); SQL_STRING_TYPE.put(SQL_SMALLINT, SMALLINT); SQL_STRING_TYPE.put(SQL_TINYINT, TINYINT); SQL_STRING_TYPE.put(SQL_TIME, TIME); SQL_STRING_TYPE.put(SQL_TIMESTAMP, TIMESTAMP); SQL_STRING_TYPE.put(SQL_VARBINARY, VARBINARY); SQL_STRING_TYPE.put(SQL_VARCHAR, VARCHAR); SQL_STRING_TYPE.put(SQL_NVARCHAR, NVARCHAR); SQL_STRING_TYPE.put(SQL_OTHER, OTHER); SQL_STRING_TYPE.put(SQL_NULL, NULL); SQL_STRING_TYPE.put(SQL_BINARY, java.sql.Types.JAVA_OBJECT); SQL_ENUM_TYPE.put(ARRAY, SQL_ARRAY); SQL_ENUM_TYPE.put(BIGINT, SQL_BIGINT); SQL_ENUM_TYPE.put(BINARY, SQL_BINARY); SQL_ENUM_TYPE.put(BIT, SQL_BIT); SQL_ENUM_TYPE.put(BOOLEAN, SQL_BOOLEAN); SQL_ENUM_TYPE.put(BLOB, SQL_BLOB); SQL_ENUM_TYPE.put(CLOB, SQL_CLOB); SQL_ENUM_TYPE.put(NCLOB, SQL_NCLOB); SQL_ENUM_TYPE.put(CHAR, SQL_CHAR); SQL_ENUM_TYPE.put(NCHAR, SQL_NCHAR); SQL_ENUM_TYPE.put(DATE, SQL_DATE); SQL_ENUM_TYPE.put(DECIMAL, SQL_DECIMAL); SQL_ENUM_TYPE.put(DOUBLE, SQL_DOUBLE); SQL_ENUM_TYPE.put(FLOAT, SQL_FLOAT); SQL_ENUM_TYPE.put(INTEGER, SQL_INTEGER); SQL_ENUM_TYPE.put(LONGVARCHAR, SQL_LONGVARCHAR); SQL_ENUM_TYPE.put(LONGNVARCHAR, SQL_LONGNVARCHAR); SQL_ENUM_TYPE.put(LONGVARBINARY, SQL_LONGVARBINARY); SQL_ENUM_TYPE.put(NUMERIC, SQL_NUMERIC); SQL_ENUM_TYPE.put(REAL, SQL_REAL); SQL_ENUM_TYPE.put(SMALLINT, SQL_SMALLINT); SQL_ENUM_TYPE.put(TINYINT, SQL_TINYINT); SQL_ENUM_TYPE.put(TIME, SQL_TIME); SQL_ENUM_TYPE.put(TIMESTAMP, SQL_TIMESTAMP); SQL_ENUM_TYPE.put(VARBINARY, SQL_VARBINARY); SQL_ENUM_TYPE.put(VARCHAR, SQL_VARCHAR); SQL_ENUM_TYPE.put(NVARCHAR, SQL_NVARCHAR); SQL_ENUM_TYPE.put(SQLXML, SQL_SQLXML); SQL_ENUM_TYPE.put(OTHER, SQL_OTHER); SQL_ENUM_TYPE.put(NULL, SQL_NULL); SQL_ENUM_TYPE.put(java.sql.Types.JAVA_OBJECT, SQL_BINARY); SQL_ENUM_JAVA.put(BIGINT, JAVA_LONG); SQL_ENUM_JAVA.put(BINARY, JAVA_BYTES); SQL_ENUM_JAVA.put(BIT, JAVA_BOOLEAN); SQL_ENUM_JAVA.put(BOOLEAN, JAVA_BOOLEAN); SQL_ENUM_JAVA.put(BLOB, JAVA_BYTES); SQL_ENUM_JAVA.put(CLOB, JAVA_STRING); SQL_ENUM_JAVA.put(NCLOB, JAVA_STRING); SQL_ENUM_JAVA.put(CHAR, JAVA_STRING); SQL_ENUM_JAVA.put(NCHAR, JAVA_STRING); SQL_ENUM_JAVA.put(DATE, JAVA_UTILDATE); SQL_ENUM_JAVA.put(DECIMAL, JAVA_BIGDECIMAL); SQL_ENUM_JAVA.put(DOUBLE, JAVA_DOUBLE); SQL_ENUM_JAVA.put(FLOAT, JAVA_FLOAT); SQL_ENUM_JAVA.put(INTEGER, JAVA_INTEGER); SQL_ENUM_JAVA.put(LONGVARCHAR, JAVA_STRING); SQL_ENUM_JAVA.put(LONGNVARCHAR, JAVA_STRING); SQL_ENUM_JAVA.put(LONGVARBINARY, JAVA_BYTES); SQL_ENUM_JAVA.put(NUMERIC, JAVA_BIGDECIMAL); SQL_ENUM_JAVA.put(REAL, JAVA_FLOAT); SQL_ENUM_JAVA.put(SMALLINT, JAVA_SHORT); SQL_ENUM_JAVA.put(TINYINT, JAVA_SHORT); SQL_ENUM_JAVA.put(TIME, JAVA_UTILDATE); SQL_ENUM_JAVA.put(TIMESTAMP, JAVA_UTILDATE); SQL_ENUM_JAVA.put(VARBINARY, JAVA_BYTES); SQL_ENUM_JAVA.put(VARCHAR, JAVA_STRING); SQL_ENUM_JAVA.put(NVARCHAR, JAVA_STRING); SQL_ENUM_JAVA.put(SQLXML, JAVA_STRING); SQL_ENUM_JAVA.put(java.sql.Types.JAVA_OBJECT, JAVA_OBJECT); JAVA_SQL_ENUM.put(JAVA_LONG, BIGINT); JAVA_SQL_ENUM.put(JAVA_BYTES, BINARY); JAVA_SQL_ENUM.put(JAVA_BOOLEAN, BIT); JAVA_SQL_ENUM.put(JAVA_STRING, VARCHAR); JAVA_SQL_ENUM.put(JAVA_SQLDATE, DATE); JAVA_SQL_ENUM.put(JAVA_UTILDATE, DATE); JAVA_SQL_ENUM.put(JAVA_TIMESTAMP, TIMESTAMP); JAVA_SQL_ENUM.put(JAVA_BIGDECIMAL, DECIMAL); JAVA_SQL_ENUM.put(JAVA_DOUBLE, DOUBLE); JAVA_SQL_ENUM.put(JAVA_FLOAT, FLOAT); JAVA_SQL_ENUM.put(JAVA_INTEGER, INTEGER); JAVA_SQL_ENUM.put(JAVA_SHORT, SMALLINT); JAVA_SQL_ENUM.put(JAVA_BYTE, SMALLINT); JAVA_SQL_ENUM.put(JAVA_TIME, TIME); JAVA_SQL_ENUM.put(JAVA_TIMESTAMP, TIMESTAMP); // add primitives JAVA_SQL_ENUM.put("byte", TINYINT); JAVA_SQL_ENUM.put("int", INTEGER); JAVA_SQL_ENUM.put("short", SMALLINT); JAVA_SQL_ENUM.put("char", CHAR); JAVA_SQL_ENUM.put("double", DOUBLE); JAVA_SQL_ENUM.put("long", BIGINT); JAVA_SQL_ENUM.put("float", FLOAT); JAVA_SQL_ENUM.put("boolean", BIT); } /* * Returns true if supplied type can have a length attribute as a part of column * definition. */ public static boolean supportsLength(int type) { return type == Types.BINARY || type == Types.CHAR || type == Types.NCHAR || type == Types.NVARCHAR || type == Types.LONGNVARCHAR || type == Types.DECIMAL || type == Types.DOUBLE || type == Types.FLOAT || type == Types.NUMERIC || type == Types.REAL || type == Types.VARBINARY || type == Types.VARCHAR; } /** * Returns true if supplied type is a numeric type. * @param type * @return boolean */ public static boolean isNumeric(int type) { return type == BIGINT || type == BIT || type == DECIMAL || type == DOUBLE || type == FLOAT || type == INTEGER || type == NUMERIC || type == REAL || type == SMALLINT || type == TINYINT; } /** * Returns true if supplied type is a decimal type. * @param type * @return boolean */ public static boolean isDecimal(int type) { return type == DECIMAL || type == DOUBLE || type == FLOAT || type == REAL || type == NUMERIC; } /** * Returns an array of string names of the default JDBC data types. * @return String[] */ public static String[] getDatabaseTypes() { Collection<String> types = SQL_STRING_TYPE.keySet(); return types.toArray(new String[types.size()]); } /** * Method implements an algorithm to pick a data type from a list of alternatives that * most closely matches JDBC data type. * @param jdbcType * @param alts * @return String */ protected static String pickDataType(int jdbcType, TypeInfo[] alts) { int len = alts.length; if (len == 0) { return null; } if (len == 1) { return alts[0].name; } // now the fun starts.. try to guess the right type String jdbcName = getSqlNameByType(jdbcType).toUpperCase(); // 1. exact match for (TypeInfo alt : alts) { if (jdbcName.equalsIgnoreCase(alt.name)) { return alt.name; } } // 2. filter those with biggest precision long maxPrec = 0; for (TypeInfo alt : alts) { if (maxPrec < alt.precision) { maxPrec = alt.precision; } } List<TypeInfo> list = new ArrayList<TypeInfo>(); for (TypeInfo alt : alts) { if (maxPrec == alt.precision) { list.add(alt); } } // work with smaller list now..... int slen = list.size(); if (slen == 1) { return list.get(0).name; } // start/end match for (TypeInfo aList : list) { String uppercase = aList.name.toUpperCase(); if (uppercase.startsWith(jdbcName) || uppercase.endsWith(jdbcName)) { return aList.name; } } // in the middle match for (TypeInfo aList : list) { String uppercase = aList.name.toUpperCase(); if (uppercase.contains(jdbcName)) { return aList.name; } } // out of ideas... return the first one return list.get(0).name; } /** * Returns a String representation of the SQL type from its JDBC code. * @param type * @return String */ public static String getSqlNameByType(int type) { return SQL_ENUM_TYPE.get(type); } /** * Get the corresponding Java type by its java.sql.Types counterpart. Note that this * method should be used as a last resort, with explicit mapping provided by user used * as a first choice, as it can only guess how to map certain types, such as NUMERIC, * etc. * @param type * * @return Fully qualified Java type name or null if not found. */ public static String getJavaBySqlType(int type) { return SQL_ENUM_JAVA.get(type); } // protected Map<Integer, List<TypeInfo>> databaseTypes = new HashMap<Integer, List<TypeInfo>>(); // // public TypesMapping(DatabaseMetaData metaData) throws SQLException { // // map database types to standard JDBC types // ResultSet rs = metaData.getTypeInfo(); // // try { // while (rs.next()) { // TypeInfo info = new TypeInfo(); // info.name = rs.getString("TYPE_NAME"); // info.jdbcType = rs.getInt("DATA_TYPE"); // info.precision = rs.getLong("PRECISION"); // // Integer key = info.jdbcType; // List<TypeInfo> infos = databaseTypes.get(key); // // if (infos == null) { // infos = new ArrayList<TypeInfo>(); // databaseTypes.put(key, infos); // } // // infos.add(info); // } // } // finally { // rs.close(); // } // // // do some tricks to substitute for missing datatypes // //// // 1. swap TIMESTAMP - DATE //// swapTypes(TIMESTAMP, DATE); //// //// // 2. Swap CLOB - LONGVARCHAR //// swapTypes(CLOB, LONGVARCHAR); //// //// // 3. Swap BLOB - LONGVARBINARY //// swapTypes(BLOB, LONGVARBINARY); //// //// // 4. Swap NCLOB - LONGNVARCHAR //// swapTypes(NCLOB, LONGNVARCHAR); // } // private void swapTypes(int type1, int type2) { // List<TypeInfo> type1Info = databaseTypes.get(type1); // List<TypeInfo> type2Info = databaseTypes.get(type2); // // if (type1Info != null && type2Info == null) { // databaseTypes.put(type2, type1Info); // } // if (type2Info != null && type1Info == null) { // databaseTypes.put(type1, type2Info); // } // } /** Stores (incomplete) information about database data type */ static class TypeInfo { String name; int jdbcType; long precision; @Override public String toString() { return "[ TypeInfo: " + name + "\n JDBC Type: " + TypesMapping.getSqlNameByType(jdbcType) + "\n Precision: " + precision + "\n]"; } } }