[#456] Add runtime support for PRECISION, SCALE, and LENGTH attributes -

Removed unneeded DataType.getType(int, int)
This commit is contained in:
Lukas Eder 2012-12-21 19:51:31 +01:00
parent 2f8dbd5c53
commit a007ba599d
10 changed files with 115 additions and 187 deletions

View File

@ -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());

View File

@ -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<T extends Definition>
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<T extends Definition>
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);
}
}

View File

@ -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;

View File

@ -74,11 +74,6 @@ public interface DataType<T> extends Serializable {
*/
Class<T> 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
*/

View File

@ -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<T> implements DataType<T> {
*/
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<T> implements DataType<T> {
*/
private static final Map<Class<?>, 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<T> implements DataType<T> {
*/
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<T> implements DataType<T> {
SQL_DATATYPES_BY_TYPE = new LinkedHashMap<Class<?>, DataType<?>>();
}
protected AbstractDataType(SQLDialect dialect, SQLDataType<T> sqldatatype, Class<T> type, String typeName) {
this(dialect, sqldatatype, type, typeName, typeName, false);
protected AbstractDataType(SQLDialect dialect, SQLDataType<T> sqlDataType, Class<T> type, String typeName) {
this(dialect, sqlDataType, type, typeName, typeName);
}
protected AbstractDataType(SQLDialect dialect, SQLDataType<T> sqldatatype, Class<T> type, String typeName, String castTypeName) {
this(dialect, sqldatatype, type, typeName, castTypeName, false);
}
protected AbstractDataType(SQLDialect dialect, SQLDataType<T> sqldatatype, Class<T> type, String typeName, boolean hasPrecisionAndScale) {
this(dialect, sqldatatype, type, typeName, typeName, hasPrecisionAndScale);
}
protected AbstractDataType(SQLDialect dialect, SQLDataType<T> sqlDataType, Class<T> type, String typeName, String castTypeName, boolean hasPrecisionAndScale) {
protected AbstractDataType(SQLDialect dialect, SQLDataType<T> sqlDataType, Class<T> type, String typeName, String castTypeName) {
this.dialect = dialect;
// [#858] SQLDataTypes should reference themselves for more convenience
@ -179,7 +196,6 @@ public abstract class AbstractDataType<T> implements DataType<T> {
this.type = type;
this.typeName = typeName;
this.castTypeName = castTypeName;
this.hasPrecisionAndScale = hasPrecisionAndScale;
this.arrayType = (Class<T[]>) Array.newInstance(type, 0).getClass();
init();
@ -189,7 +205,7 @@ public abstract class AbstractDataType<T> implements DataType<T> {
// 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<T> implements DataType<T> {
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<T[]> getArrayType() {
return arrayType;
@ -463,7 +469,7 @@ public abstract class AbstractDataType<T> implements DataType<T> {
}
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<T> implements DataType<T> {
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;
}
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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;

View File

@ -223,12 +223,12 @@ public final class SQLDataType<T> extends AbstractDataType<T> {
/**
* The {@link Types#NUMERIC} type
*/
public static final SQLDataType<BigDecimal> NUMERIC = new SQLDataType<BigDecimal>(BigDecimal.class, "numeric", true);
public static final SQLDataType<BigDecimal> NUMERIC = new SQLDataType<BigDecimal>(BigDecimal.class, "numeric");
/**
* The {@link Types#DECIMAL} type
*/
public static final SQLDataType<BigDecimal> DECIMAL = new SQLDataType<BigDecimal>(BigDecimal.class, "decimal", true);
public static final SQLDataType<BigDecimal> DECIMAL = new SQLDataType<BigDecimal>(BigDecimal.class, "decimal");
// -------------------------------------------------------------------------
// Datetime types
@ -328,10 +328,6 @@ public final class SQLDataType<T> extends AbstractDataType<T> {
}
private SQLDataType(Class<T> type, String typeName) {
this(type, typeName, false);
}
private SQLDataType(Class<T> type, String typeName, boolean hasPrecisionAndScale) {
super(null, null, type, typeName, hasPrecisionAndScale);
super(null, null, type, typeName);
}
}

View File

@ -67,10 +67,10 @@ public class OracleDataType<T> extends AbstractDataType<T> {
// Default SQL data types and synonyms thereof
// -------------------------------------------------------------------------
public static final OracleDataType<BigDecimal> NUMBER = new OracleDataType<BigDecimal>(SQLDataType.NUMERIC, "number", true);
public static final OracleDataType<BigDecimal> NUMERIC = new OracleDataType<BigDecimal>(SQLDataType.NUMERIC, "numeric", true);
public static final OracleDataType<BigDecimal> DECIMAL = new OracleDataType<BigDecimal>(SQLDataType.DECIMAL, "decimal", true);
public static final OracleDataType<BigDecimal> DEC = new OracleDataType<BigDecimal>(SQLDataType.DECIMAL, "dec", true);
public static final OracleDataType<BigDecimal> NUMBER = new OracleDataType<BigDecimal>(SQLDataType.NUMERIC, "number");
public static final OracleDataType<BigDecimal> NUMERIC = new OracleDataType<BigDecimal>(SQLDataType.NUMERIC, "numeric");
public static final OracleDataType<BigDecimal> DECIMAL = new OracleDataType<BigDecimal>(SQLDataType.DECIMAL, "decimal");
public static final OracleDataType<BigDecimal> DEC = new OracleDataType<BigDecimal>(SQLDataType.DECIMAL, "dec");
public static final OracleDataType<String> VARCHAR2 = new OracleDataType<String>(SQLDataType.VARCHAR, "varchar2", "varchar2(4000)");
public static final OracleDataType<String> VARCHAR = new OracleDataType<String>(SQLDataType.VARCHAR, "varchar", "varchar2(4000)");
public static final OracleDataType<String> CHAR = new OracleDataType<String>(SQLDataType.CHAR, "char", "varchar2(4000)");
@ -141,18 +141,10 @@ public class OracleDataType<T> extends AbstractDataType<T> {
public static final OracleDataType<Boolean> BOOLEAN = new OracleDataType<Boolean>(SQLDataType.BOOLEAN, "boolean");
private OracleDataType(SQLDataType<T> sqlDataType, String typeName) {
this(sqlDataType, typeName, false);
super(SQLDialect.ORACLE, sqlDataType, sqlDataType.getType(), typeName);
}
private OracleDataType(SQLDataType<T> sqlDataType, String typeName, String castTypeName) {
this(sqlDataType, typeName, castTypeName, false);
}
private OracleDataType(SQLDataType<T> sqlDataType, String typeName, boolean hasPrecisionAndScale) {
super(SQLDialect.ORACLE, sqlDataType, sqlDataType.getType(), typeName, hasPrecisionAndScale);
}
private OracleDataType(SQLDataType<T> sqlDataType, String typeName, String castTypeName, boolean hasPrecisionAndScale) {
super(SQLDialect.ORACLE, sqlDataType, sqlDataType.getType(), typeName, castTypeName, hasPrecisionAndScale);
super(SQLDialect.ORACLE, sqlDataType, sqlDataType.getType(), typeName, castTypeName);
}
}