diff --git a/jOOQ-codegen/src/main/java/org/jooq/util/JavaGenerator.java b/jOOQ-codegen/src/main/java/org/jooq/util/JavaGenerator.java index 89daccc967..57e2ab1833 100644 --- a/jOOQ-codegen/src/main/java/org/jooq/util/JavaGenerator.java +++ b/jOOQ-codegen/src/main/java/org/jooq/util/JavaGenerator.java @@ -74,7 +74,6 @@ import org.jooq.impl.ArrayRecordImpl; import org.jooq.impl.DAOImpl; import org.jooq.impl.Executor; import org.jooq.impl.Factory; -import org.jooq.impl.FieldTypeHelper; import org.jooq.impl.PackageImpl; import org.jooq.impl.SQLDataType; import org.jooq.impl.SchemaImpl; @@ -2423,7 +2422,7 @@ public class JavaGenerator extends AbstractGenerator { // Try finding a basic standard SQL type according to the current dialect else { try { - Class clazz = FieldTypeHelper.getDialectJavaType(db.getDialect(), t, p, s); + Class clazz = AbstractDataType.getType(db.getDialect(), t, p, s); type = clazz.getCanonicalName(); if (clazz.getTypeParameters().length > 0) { @@ -2472,7 +2471,7 @@ public class JavaGenerator extends AbstractGenerator { sb.append("."); sb.append(db.getDialect().getName()); sb.append("DataType."); - sb.append(FieldTypeHelper.normalise(AbstractDataType.getDataType(db.getDialect(), String.class).getTypeName())); + sb.append(AbstractDataType.normalise(AbstractDataType.getDataType(db.getDialect(), String.class).getTypeName())); sb.append(".asEnumDataType("); sb.append(getStrategy().getFullJavaClassName(db.getEnum(schema, u))); sb.append(".class)"); @@ -2481,7 +2480,7 @@ public class JavaGenerator extends AbstractGenerator { DataType dataType = null; try { - dataType = FieldTypeHelper.getDialectDataType(db.getDialect(), t, p, s); + dataType = AbstractDataType.getDataType(db.getDialect(), t, p, s); } // Mostly because of unsupported data types. Will be handled later. @@ -2495,7 +2494,7 @@ public class JavaGenerator extends AbstractGenerator { sb.append(SQLDataType.class.getCanonicalName()); sb.append("."); - sb.append(FieldTypeHelper.normalise(sqlDataType.getTypeName())); + sb.append(AbstractDataType.normalise(sqlDataType.getTypeName())); if (db.getConfiguredCustomType(u) != null) { sb.append(".asConvertedDataType(new "); @@ -2519,14 +2518,14 @@ public class JavaGenerator extends AbstractGenerator { try { String type1 = getType(db, schema, t, p, s, u, null); String type2 = getType(db, schema, t, 0, 0, u, null); - String typeName = FieldTypeHelper.normalise(t); + String typeName = AbstractDataType.normalise(t); // [#1298] Prevent compilation errors for missing types Reflect.on(typeClass).field(typeName); sb.append(typeName); if (!type1.equals(type2)) { - Class clazz = FieldTypeHelper.getDialectJavaType(db.getDialect(), t, p, s); + Class clazz = AbstractDataType.getType(db.getDialect(), t, p, s); sb.append(".asNumberDataType("); sb.append(clazz.getCanonicalName()); diff --git a/jOOQ-meta/src/main/java/org/jooq/util/AbstractTypedElementDefinition.java b/jOOQ-meta/src/main/java/org/jooq/util/AbstractTypedElementDefinition.java index 05e538e99d..d0c7cb4127 100644 --- a/jOOQ-meta/src/main/java/org/jooq/util/AbstractTypedElementDefinition.java +++ b/jOOQ-meta/src/main/java/org/jooq/util/AbstractTypedElementDefinition.java @@ -35,7 +35,6 @@ */ package org.jooq.util; -import static org.jooq.impl.FieldTypeHelper.getDialectDataType; import java.sql.Types; import java.util.ArrayList; @@ -43,6 +42,7 @@ import java.util.List; import org.jooq.DataType; import org.jooq.exception.SQLDialectNotSupportedException; +import org.jooq.impl.AbstractDataType; import org.jooq.impl.SQLDataType; import org.jooq.tools.JooqLogger; import org.jooq.util.jaxb.ForcedType; @@ -108,7 +108,7 @@ abstract class AbstractTypedElementDefinition int s = definedType.getScale(); try { - forcedDataType = getDialectDataType(db.getDialect(), forcedType.getName(), p, s); + forcedDataType = AbstractDataType.getDataType(db.getDialect(), forcedType.getName(), p, s); } catch (SQLDialectNotSupportedException ignore) {} // [#677] SQLDataType matches are actual type-rewrites @@ -127,12 +127,12 @@ abstract class AbstractTypedElementDefinition DataType dataType = null; try { - dataType = getDialectDataType(db.getDialect(), definedType.getType(), 0, 0); + dataType = AbstractDataType.getDataType(db.getDialect(), definedType.getType(), 0, 0); } catch (SQLDialectNotSupportedException ignore) {} if (dataType != null) { if (dataType.getSQLType() == Types.DATE) { - DataType forcedDataType = getDialectDataType(db.getDialect(), SQLDataType.TIMESTAMP.getTypeName(), 0, 0); + DataType forcedDataType = AbstractDataType.getDataType(db.getDialect(), SQLDataType.TIMESTAMP.getTypeName(), 0, 0); type = new DefaultDataTypeDefinition(db, getSchema(), forcedDataType.getTypeName(), 0, 0, 0); } } diff --git a/jOOQ-meta/src/main/java/org/jooq/util/DefaultDataTypeDefinition.java b/jOOQ-meta/src/main/java/org/jooq/util/DefaultDataTypeDefinition.java index 1224710395..62cd92419f 100644 --- a/jOOQ-meta/src/main/java/org/jooq/util/DefaultDataTypeDefinition.java +++ b/jOOQ-meta/src/main/java/org/jooq/util/DefaultDataTypeDefinition.java @@ -36,7 +36,7 @@ package org.jooq.util; -import static org.jooq.impl.FieldTypeHelper.normalise; +import static org.jooq.impl.AbstractDataType.normalise; import org.jooq.SQLDialect; import org.jooq.util.oracle.OracleDataType; diff --git a/jOOQ/src/main/java/org/jooq/DataType.java b/jOOQ/src/main/java/org/jooq/DataType.java index a5826d7d1f..bc0f5262ef 100644 --- a/jOOQ/src/main/java/org/jooq/DataType.java +++ b/jOOQ/src/main/java/org/jooq/DataType.java @@ -74,11 +74,6 @@ public interface DataType extends Serializable { */ Class getType(); - /** - * Retrieve a Java type associated with this data type and precision/scale - */ - Class getType(int precision, int scale); - /** * Retrieve the Java type associated with ARRAYs of this data type */ diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java b/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java index 1fc9f641cd..08873560d1 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java @@ -52,6 +52,7 @@ import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.regex.Pattern; import org.jooq.ArrayRecord; import org.jooq.Configuration; @@ -82,6 +83,11 @@ public abstract class AbstractDataType implements DataType { */ private static final long serialVersionUID = 4155588654449505119L; + /** + * A pattern for data type name normalisation + */ + private static final Pattern NORMALISE_PATTERN = Pattern.compile("\"|\\.|\\s|\\(\\w+(,\\w+)*\\)|(NOT\\s*NULL)?"); + // ------------------------------------------------------------------------- // Data type caches // ------------------------------------------------------------------------- @@ -106,6 +112,30 @@ public abstract class AbstractDataType implements DataType { */ private static final Map, DataType> SQL_DATATYPES_BY_TYPE; + // ------------------------------------------------------------------------- + // Precisions + // ------------------------------------------------------------------------- + + /** + * The minimum decimal precision needed to represent a Java {@link Long} type + */ + private static final int LONG_PRECISION = String.valueOf(Long.MAX_VALUE).length(); + + /** + * The minimum decimal precision needed to represent a Java {@link Integer} type + */ + private static final int INTEGER_PRECISION = String.valueOf(Integer.MAX_VALUE).length(); + + /** + * The minimum decimal precision needed to represent a Java {@link Short} type + */ + private static final int SHORT_PRECISION = String.valueOf(Short.MAX_VALUE).length(); + + /** + * The minimum decimal precision needed to represent a Java {@link Byte} type + */ + private static final int BYTE_PRECISION = String.valueOf(Byte.MAX_VALUE).length(); + // ------------------------------------------------------------------------- // Data type attributes // ------------------------------------------------------------------------- @@ -140,11 +170,6 @@ public abstract class AbstractDataType implements DataType { */ private final String typeName; - /** - * Whether this type has allows for precision and scale - */ - private final boolean hasPrecisionAndScale; - static { TYPES_BY_SQL_DATATYPE = new Map[SQLDialect.values().length]; TYPES_BY_NAME = new Map[SQLDialect.values().length]; @@ -159,19 +184,11 @@ public abstract class AbstractDataType implements DataType { SQL_DATATYPES_BY_TYPE = new LinkedHashMap, DataType>(); } - protected AbstractDataType(SQLDialect dialect, SQLDataType sqldatatype, Class type, String typeName) { - this(dialect, sqldatatype, type, typeName, typeName, false); + protected AbstractDataType(SQLDialect dialect, SQLDataType sqlDataType, Class type, String typeName) { + this(dialect, sqlDataType, type, typeName, typeName); } - protected AbstractDataType(SQLDialect dialect, SQLDataType sqldatatype, Class type, String typeName, String castTypeName) { - this(dialect, sqldatatype, type, typeName, castTypeName, false); - } - - protected AbstractDataType(SQLDialect dialect, SQLDataType sqldatatype, Class type, String typeName, boolean hasPrecisionAndScale) { - this(dialect, sqldatatype, type, typeName, typeName, hasPrecisionAndScale); - } - - protected AbstractDataType(SQLDialect dialect, SQLDataType sqlDataType, Class type, String typeName, String castTypeName, boolean hasPrecisionAndScale) { + protected AbstractDataType(SQLDialect dialect, SQLDataType sqlDataType, Class type, String typeName, String castTypeName) { this.dialect = dialect; // [#858] SQLDataTypes should reference themselves for more convenience @@ -179,7 +196,6 @@ public abstract class AbstractDataType implements DataType { this.type = type; this.typeName = typeName; this.castTypeName = castTypeName; - this.hasPrecisionAndScale = hasPrecisionAndScale; this.arrayType = (Class) Array.newInstance(type, 0).getClass(); init(); @@ -189,7 +205,7 @@ public abstract class AbstractDataType implements DataType { // Dialect-specific data types int ordinal = dialect == null ? SQLDialect.SQL99.ordinal() : dialect.ordinal(); - String normalised = FieldTypeHelper.normalise(typeName); + String normalised = AbstractDataType.normalise(typeName); if (TYPES_BY_NAME[ordinal].get(normalised) == null) { TYPES_BY_NAME[ordinal].put(normalised, this); @@ -335,16 +351,6 @@ public abstract class AbstractDataType implements DataType { return type; } - @Override - public final Class getType(int precision, int scale) { - if (hasPrecisionAndScale) { - return FieldTypeHelper.getClass(Types.NUMERIC, precision, scale); - } - - // If no precise type could be guessed, take the default - return getType(); - } - @Override public final Class getArrayType() { return arrayType; @@ -463,7 +469,7 @@ public abstract class AbstractDataType implements DataType { } public static DataType getDataType(SQLDialect dialect, String typeName) { - String normalised = FieldTypeHelper.normalise(typeName); + String normalised = AbstractDataType.normalise(typeName); DataType result = TYPES_BY_NAME[dialect.ordinal()].get(normalised); // UDT data types and others are registered using SQL99 @@ -613,4 +619,61 @@ public abstract class AbstractDataType implements DataType { return false; return true; } + + /** + * @return The type name without all special characters and white spaces + */ + public static String normalise(String typeName) { + return NORMALISE_PATTERN.matcher(typeName.toUpperCase()).replaceAll(""); + } + + /** + * Convert a type name (using precision and scale) into a Java class + */ + public static DataType getDataType(SQLDialect dialect, String t, int p, int s) throws SQLDialectNotSupportedException { + DataType result = AbstractDataType.getDataType(dialect, AbstractDataType.normalise(t)); + + if (result.getType() == BigDecimal.class) { + result = AbstractDataType.getDataType(dialect, getNumericClass(p, s)); + } + + return result; + } + + /** + * Convert a type name (using precision and scale) into a Java class + */ + public static Class getType(SQLDialect dialect, String t, int p, int s) throws SQLDialectNotSupportedException { + return getDataType(dialect, t, p, s).getType(); + } + + /** + * Get the most suitable Java class for a given precision and scale + */ + private static Class getNumericClass(int precision, int scale) { + + // Integer numbers + if (scale == 0 && precision != 0) { + if (precision < BYTE_PRECISION) { + return Byte.class; + } + if (precision < SHORT_PRECISION) { + return Short.class; + } + if (precision < INTEGER_PRECISION) { + return Integer.class; + } + if (precision < LONG_PRECISION) { + return Long.class; + } + + // Default integer number + return BigInteger.class; + } + + // Real numbers should not be represented as float or double + else { + return BigDecimal.class; + } + } } diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldTypeHelper.java b/jOOQ/src/main/java/org/jooq/impl/FieldTypeHelper.java index 41e339a16c..6280d8e81f 100644 --- a/jOOQ/src/main/java/org/jooq/impl/FieldTypeHelper.java +++ b/jOOQ/src/main/java/org/jooq/impl/FieldTypeHelper.java @@ -56,13 +56,11 @@ import java.sql.SQLInput; import java.sql.SQLOutput; import java.sql.Time; import java.sql.Timestamp; -import java.sql.Types; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.List; -import java.util.regex.Pattern; import org.jooq.ArrayRecord; import org.jooq.Configuration; @@ -74,7 +72,6 @@ import org.jooq.Field; import org.jooq.Result; import org.jooq.SQLDialect; import org.jooq.UDTRecord; -import org.jooq.exception.SQLDialectNotSupportedException; import org.jooq.tools.Convert; import org.jooq.tools.JooqLogger; import org.jooq.types.DayToSecond; @@ -95,12 +92,6 @@ import org.jooq.util.postgres.PostgresUtils; */ public final class FieldTypeHelper { - private static final int LONG_PRECISION = String.valueOf(Long.MAX_VALUE).length(); - private static final int INTEGER_PRECISION = String.valueOf(Integer.MAX_VALUE).length(); - private static final int SHORT_PRECISION = String.valueOf(Short.MAX_VALUE).length(); - private static final int BYTE_PRECISION = String.valueOf(Byte.MAX_VALUE).length(); - private static final Pattern NORMALISE_PATTERN = Pattern.compile("\"|\\.|\\s|\\(\\w+(,\\w+)*\\)|(NOT\\s*NULL)?"); - private static final JooqLogger log = JooqLogger.getLogger(FieldTypeHelper.class); @SuppressWarnings("unchecked") @@ -772,95 +763,7 @@ public final class FieldTypeHelper { } } - public static Class getClass(int sqlType, int precision, int scale) { - switch (sqlType) { - case Types.BLOB: - case Types.BINARY: - case Types.LONGVARBINARY: - case Types.VARBINARY: - return byte[].class; - - case Types.BOOLEAN: - case Types.BIT: - return Boolean.class; - - case Types.TINYINT: - return Byte.class; - - case Types.SMALLINT: - return Short.class; - - case Types.INTEGER: - return Integer.class; - - case Types.BIGINT: - return Long.class; - - case Types.REAL: - return Float.class; - - case Types.DOUBLE: - case Types.FLOAT: - return Double.class; - - case Types.DECIMAL: - case Types.NUMERIC: { - - // Integer numbers - if (scale == 0 && precision != 0) { - if (precision < BYTE_PRECISION) { - return Byte.class; - } - if (precision < SHORT_PRECISION) { - return Short.class; - } - if (precision < INTEGER_PRECISION) { - return Integer.class; - } - if (precision < LONG_PRECISION) { - return Long.class; - } - - // Default integer number - return BigInteger.class; - } - - // Real numbers should not be represented as float or double - else { - return BigDecimal.class; - } - } - - case Types.CLOB: - case Types.CHAR: - case Types.LONGNVARCHAR: - case Types.LONGVARCHAR: - case Types.NCHAR: - case Types.NCLOB: - case Types.NVARCHAR: - case Types.VARCHAR: - return String.class; - - case Types.DATE: - return Date.class; - - case Types.TIME: - return Time.class; - - case Types.TIMESTAMP: - return Timestamp.class; - - default: - return Object.class; - } - } - - /** - * @return The type name without all special characters and white spaces - */ - public static String normalise(String typeName) { - return NORMALISE_PATTERN.matcher(typeName.toUpperCase()).replaceAll(""); - } + // ------------------------------------------------------------------------- // The following section has been added for Postgres UDT support. The @@ -1079,24 +982,4 @@ public final class FieldTypeHelper { } private FieldTypeHelper() {} - - /** - * Convert a type name (using precision and scale) into a Java class - */ - public static DataType getDialectDataType(SQLDialect dialect, String t, int p, int s) throws SQLDialectNotSupportedException { - DataType result = AbstractDataType.getDataType(dialect, normalise(t)); - - if (result.getType() == BigDecimal.class) { - result = AbstractDataType.getDataType(dialect, getClass(Types.NUMERIC, p, s)); - } - - return result; - } - - /** - * Convert a type name (using precision and scale) into a Java class - */ - public static Class getDialectJavaType(SQLDialect dialect, String t, int p, int s) throws SQLDialectNotSupportedException { - return getDialectDataType(dialect, t, p, s).getType(p, s); - } } diff --git a/jOOQ/src/main/java/org/jooq/impl/MetaDataFieldProvider.java b/jOOQ/src/main/java/org/jooq/impl/MetaDataFieldProvider.java index 67a2b7b1f4..7db5a861a6 100644 --- a/jOOQ/src/main/java/org/jooq/impl/MetaDataFieldProvider.java +++ b/jOOQ/src/main/java/org/jooq/impl/MetaDataFieldProvider.java @@ -104,7 +104,7 @@ class MetaDataFieldProvider implements FieldProvider, Serializable { String type = meta.getColumnTypeName(i); try { - dataType = FieldTypeHelper.getDialectDataType(configuration.getDialect(), type, precision, scale); + dataType = AbstractDataType.getDataType(configuration.getDialect(), type, precision, scale); } // [#650, #667] TODO This should not happen. All types diff --git a/jOOQ/src/main/java/org/jooq/impl/MetaImpl.java b/jOOQ/src/main/java/org/jooq/impl/MetaImpl.java index 9d6027dd86..d46a370f40 100644 --- a/jOOQ/src/main/java/org/jooq/impl/MetaImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/MetaImpl.java @@ -223,7 +223,7 @@ class MetaImpl implements Meta { // TODO: Exception handling should be moved inside SQLDataType DataType type = null; try { - type = FieldTypeHelper.getDialectDataType(SQLDialect.SQL99, typeName, precision, scale); + type = AbstractDataType.getDataType(SQLDialect.SQL99, typeName, precision, scale); } catch (SQLDialectNotSupportedException e) { type = SQLDataType.OTHER; diff --git a/jOOQ/src/main/java/org/jooq/impl/SQLDataType.java b/jOOQ/src/main/java/org/jooq/impl/SQLDataType.java index eda62e4d5c..b7d06980b3 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SQLDataType.java +++ b/jOOQ/src/main/java/org/jooq/impl/SQLDataType.java @@ -223,12 +223,12 @@ public final class SQLDataType extends AbstractDataType { /** * The {@link Types#NUMERIC} type */ - public static final SQLDataType NUMERIC = new SQLDataType(BigDecimal.class, "numeric", true); + public static final SQLDataType NUMERIC = new SQLDataType(BigDecimal.class, "numeric"); /** * The {@link Types#DECIMAL} type */ - public static final SQLDataType DECIMAL = new SQLDataType(BigDecimal.class, "decimal", true); + public static final SQLDataType DECIMAL = new SQLDataType(BigDecimal.class, "decimal"); // ------------------------------------------------------------------------- // Datetime types @@ -328,10 +328,6 @@ public final class SQLDataType extends AbstractDataType { } private SQLDataType(Class type, String typeName) { - this(type, typeName, false); - } - - private SQLDataType(Class type, String typeName, boolean hasPrecisionAndScale) { - super(null, null, type, typeName, hasPrecisionAndScale); + super(null, null, type, typeName); } } diff --git a/jOOQ/src/main/java/org/jooq/util/oracle/OracleDataType.java b/jOOQ/src/main/java/org/jooq/util/oracle/OracleDataType.java index b3b8651d72..e7206c9546 100644 --- a/jOOQ/src/main/java/org/jooq/util/oracle/OracleDataType.java +++ b/jOOQ/src/main/java/org/jooq/util/oracle/OracleDataType.java @@ -67,10 +67,10 @@ public class OracleDataType extends AbstractDataType { // Default SQL data types and synonyms thereof // ------------------------------------------------------------------------- - public static final OracleDataType NUMBER = new OracleDataType(SQLDataType.NUMERIC, "number", true); - public static final OracleDataType NUMERIC = new OracleDataType(SQLDataType.NUMERIC, "numeric", true); - public static final OracleDataType DECIMAL = new OracleDataType(SQLDataType.DECIMAL, "decimal", true); - public static final OracleDataType DEC = new OracleDataType(SQLDataType.DECIMAL, "dec", true); + public static final OracleDataType NUMBER = new OracleDataType(SQLDataType.NUMERIC, "number"); + public static final OracleDataType NUMERIC = new OracleDataType(SQLDataType.NUMERIC, "numeric"); + public static final OracleDataType DECIMAL = new OracleDataType(SQLDataType.DECIMAL, "decimal"); + public static final OracleDataType DEC = new OracleDataType(SQLDataType.DECIMAL, "dec"); public static final OracleDataType VARCHAR2 = new OracleDataType(SQLDataType.VARCHAR, "varchar2", "varchar2(4000)"); public static final OracleDataType VARCHAR = new OracleDataType(SQLDataType.VARCHAR, "varchar", "varchar2(4000)"); public static final OracleDataType CHAR = new OracleDataType(SQLDataType.CHAR, "char", "varchar2(4000)"); @@ -141,18 +141,10 @@ public class OracleDataType extends AbstractDataType { public static final OracleDataType BOOLEAN = new OracleDataType(SQLDataType.BOOLEAN, "boolean"); private OracleDataType(SQLDataType sqlDataType, String typeName) { - this(sqlDataType, typeName, false); + super(SQLDialect.ORACLE, sqlDataType, sqlDataType.getType(), typeName); } private OracleDataType(SQLDataType sqlDataType, String typeName, String castTypeName) { - this(sqlDataType, typeName, castTypeName, false); - } - - private OracleDataType(SQLDataType sqlDataType, String typeName, boolean hasPrecisionAndScale) { - super(SQLDialect.ORACLE, sqlDataType, sqlDataType.getType(), typeName, hasPrecisionAndScale); - } - - private OracleDataType(SQLDataType sqlDataType, String typeName, String castTypeName, boolean hasPrecisionAndScale) { - super(SQLDialect.ORACLE, sqlDataType, sqlDataType.getType(), typeName, castTypeName, hasPrecisionAndScale); + super(SQLDialect.ORACLE, sqlDataType, sqlDataType.getType(), typeName, castTypeName); } }