diff --git a/jOOQ-meta/src/main/java/org/jooq/meta/DefaultMetaTableDefinition.java b/jOOQ-meta/src/main/java/org/jooq/meta/DefaultMetaTableDefinition.java index 449ca7ebdf..de68d76424 100644 --- a/jOOQ-meta/src/main/java/org/jooq/meta/DefaultMetaTableDefinition.java +++ b/jOOQ-meta/src/main/java/org/jooq/meta/DefaultMetaTableDefinition.java @@ -42,6 +42,7 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import org.jooq.DataType; import org.jooq.Field; import org.jooq.Name; import org.jooq.Table; @@ -65,15 +66,17 @@ public class DefaultMetaTableDefinition extends AbstractTableDefinition { int ordinal = 0; for (Field field : table.fields()) { + DataType dataType = field.getDataType(); + DataTypeDefinition type = new DefaultDataTypeDefinition( getDatabase(), getSchema(), - field.getDataType().getTypeName(), - field.getDataType().length(), - field.getDataType().precision(), - field.getDataType().scale(), - field.getDataType().nullable(), - create().renderInlined(field.getDataType().defaultValue()), + dataType.getTypeName(), + dataType.lengthDefined() ? dataType.length() : null, + dataType.precisionDefined() ? dataType.precision() : null, + dataType.scaleDefined() ? dataType.scale() : null, + dataType.nullable(), + create().renderInlined(dataType.defaultValue()), (Name) null ); diff --git a/jOOQ-meta/src/main/java/org/jooq/meta/derby/DerbyTableDefinition.java b/jOOQ-meta/src/main/java/org/jooq/meta/derby/DerbyTableDefinition.java index f017f160db..97ccfd1e23 100644 --- a/jOOQ-meta/src/main/java/org/jooq/meta/derby/DerbyTableDefinition.java +++ b/jOOQ-meta/src/main/java/org/jooq/meta/derby/DerbyTableDefinition.java @@ -86,18 +86,21 @@ public class DerbyTableDefinition extends AbstractTableDefinition { .orderBy(Syscolumns.COLUMNNUMBER) .fetch()) { - String typeName = record.get(Syscolumns.COLUMNDATATYPE, String.class); - Number precision = parsePrecision(typeName); - Number scale = parseScale(typeName); + String columnDataType = record.get(Syscolumns.COLUMNDATATYPE, String.class); + String typeName = parseTypeName(columnDataType); + + // [#9945] Derby timestamps always have a precision of 9 + Number precision = "TIMESTAMP".equalsIgnoreCase(typeName) ? 9 : parsePrecision(columnDataType); + Number scale = parseScale(columnDataType); DataTypeDefinition type = new DefaultDataTypeDefinition( getDatabase(), getSchema(), - parseTypeName(typeName), + typeName, precision, precision, scale, - !parseNotNull(typeName), + !parseNotNull(columnDataType), record.get(Syscolumns.COLUMNDEFAULT) ); diff --git a/jOOQ/src/main/java/org/jooq/DataType.java b/jOOQ/src/main/java/org/jooq/DataType.java index 6639fb48e6..f8c54afa86 100644 --- a/jOOQ/src/main/java/org/jooq/DataType.java +++ b/jOOQ/src/main/java/org/jooq/DataType.java @@ -442,6 +442,16 @@ public interface DataType extends Serializable { */ boolean hasPrecision(); + /** + * Whether the precision returned by {@link #precision()} is defined. + *

+ * The default precision is 0 for all data types. If a data + * type does not have a precision (see {@link #hasPrecision()}), or if it + * was initialised without precision (e.g. {@link SQLDataType#TIMESTAMP}), + * then the precision is not defined. + */ + boolean precisionDefined(); + /** * Return a new data type like this, with a new scale value. *

@@ -467,6 +477,16 @@ public interface DataType extends Serializable { */ boolean hasScale(); + /** + * Whether the precision returned by {@link #scale()} is defined. + *

+ * The default scale is 0 for all data types. If a data type + * does not have a scale (see {@link #hasScale()}), or if it was initialised + * without scale (e.g. {@link SQLDataType#TIMESTAMP}), then the scale is not + * defined. + */ + boolean scaleDefined(); + /** * Return a new data type like this, with a new length value. *

@@ -492,6 +512,16 @@ public interface DataType extends Serializable { */ boolean hasLength(); + /** + * Whether the precision returned by {@link #length()} is defined. + *

+ * The default length is 0 for all data types. If a data type + * does not have a length (see {@link #hasLength()}), or if it was initialised + * without length (e.g. {@link SQLDataType#TIMESTAMP}), then the length is not + * defined. + */ + boolean lengthDefined(); + /** * Whether this data type is any numeric data type. *

diff --git a/jOOQ/src/main/java/org/jooq/impl/ArrayDataType.java b/jOOQ/src/main/java/org/jooq/impl/ArrayDataType.java index fffa28aabc..610159808a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ArrayDataType.java +++ b/jOOQ/src/main/java/org/jooq/impl/ArrayDataType.java @@ -70,9 +70,9 @@ final class ArrayDataType extends DefaultDataType { ArrayDataType( DefaultDataType t, DataType elementType, - int precision, - int scale, - int length, + Integer precision, + Integer scale, + Integer length, Nullability nullability, Collation collation, CharacterSet characterSet, @@ -87,9 +87,9 @@ final class ArrayDataType extends DefaultDataType { @SuppressWarnings({ "unchecked", "rawtypes" }) @Override DefaultDataType construct( - int newPrecision, - int newScale, - int newLength, + Integer newPrecision, + Integer newScale, + Integer newLength, Nullability newNullability, Collation newCollation, diff --git a/jOOQ/src/main/java/org/jooq/impl/ConvertedDataType.java b/jOOQ/src/main/java/org/jooq/impl/ConvertedDataType.java index 304eaeec92..df89f76e88 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ConvertedDataType.java +++ b/jOOQ/src/main/java/org/jooq/impl/ConvertedDataType.java @@ -71,16 +71,16 @@ final class ConvertedDataType extends DefaultDataType { private final DataType delegate; @SuppressWarnings("unchecked") - ConvertedDataType(DataType delegate, Binding binding) { + ConvertedDataType(DefaultDataType delegate, Binding binding) { super( null, binding.converter().toType(), binding, delegate.getTypeName(), delegate.getCastTypeName(), - delegate.precision(), - delegate.scale(), - delegate.length(), + delegate.precisionDefined() ? delegate.precision() : null, + delegate.scaleDefined() ? delegate.scale() : null, + delegate.lengthDefined() ? delegate.length() : null, delegate.nullability(), (Field) delegate.defaultValue() ); diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java index 16aca5febc..e5efba6432 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java @@ -656,7 +656,7 @@ public class DefaultBinding implements Binding { if (scale >= precision) precision = scale + 1; - sqlCast(ctx, converted, dataType, 0, precision, scale); + sqlCast(ctx, converted, dataType, null, precision, scale); } // [#7905] The ROWID type cannot be cast to @@ -668,7 +668,7 @@ public class DefaultBinding implements Binding { // If the bind value is set, it can be used to derive the cast type if (converted != null) - sqlCast(ctx, converted, DefaultDataType.getDataType(family, converted.getClass()), 0, 0, 0); + sqlCast(ctx, converted, DefaultDataType.getDataType(family, converted.getClass()), null, null, null); @@ -680,7 +680,7 @@ public class DefaultBinding implements Binding { // Derby and DB2 must have a type associated with NULL. Use VARCHAR // as a workaround. That's probably not correct in all cases, though else - sqlCast(ctx, converted, DefaultDataType.getDataType(family, String.class), 0, 0, 0); + sqlCast(ctx, converted, DefaultDataType.getDataType(family, String.class), null, null, null); // [#1029] Postgres generally doesn't need the casting. Only in the // above case where the type is OTHER @@ -700,7 +700,7 @@ public class DefaultBinding implements Binding { // [#1727] VARCHAR types should be cast to their actual lengths in some // dialects else if (FIREBIRD == family && (sqlDataType == SQLDataType.VARCHAR || sqlDataType == SQLDataType.CHAR)) - sqlCast(ctx, converted, dataType, getValueLength((String) converted), 0, 0); + sqlCast(ctx, converted, dataType, getValueLength((String) converted), null, null); @@ -710,11 +710,25 @@ public class DefaultBinding implements Binding { // [#7379] Most databases cannot cast a bind variable to an enum type else if (!NO_SUPPORT_ENUM_CAST.contains(family) && EnumType.class.isAssignableFrom(type)) - sqlCast(ctx, converted, Tools.emulateEnumType((DataType) dataType), dataType.length(), dataType.precision(), dataType.scale()); + sqlCast( + ctx, + converted, + Tools.emulateEnumType((DataType) dataType), + dataType.lengthDefined() ? dataType.length() : null, + dataType.precisionDefined() ? dataType.precision() : null, + dataType.scaleDefined() ? dataType.scale() : null + ); // In all other cases, the bind variable can be cast normally else - sqlCast(ctx, converted, dataType, dataType.length(), dataType.precision(), dataType.scale()); + sqlCast( + ctx, + converted, + dataType, + dataType.lengthDefined() ? dataType.length() : null, + dataType.precisionDefined() ? dataType.precision() : null, + dataType.scaleDefined() ? dataType.scale() : null + ); } private static final int getValueLength(String string) { @@ -735,11 +749,11 @@ public class DefaultBinding implements Binding { } } - private final void sqlCast(BindingSQLContext ctx, T converted, DataType dataType, int length, int precision, int scale) throws SQLException { + private final void sqlCast(BindingSQLContext ctx, T converted, DataType dataType, Integer length, Integer precision, Integer scale) throws SQLException { ctx.render().visit(K_CAST).sql('('); sql(ctx, converted); ctx.render().sql(' ').visit(K_AS).sql(' ') - .sql(dataType.length(length).precision(precision, scale).getCastTypeName(ctx.configuration())) + .sql(DefaultDataType.set(dataType, length, precision, scale).getCastTypeName(ctx.configuration())) .sql(')'); } diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultDataType.java b/jOOQ/src/main/java/org/jooq/impl/DefaultDataType.java index c1c731f04b..31b7254b3d 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultDataType.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultDataType.java @@ -106,18 +106,18 @@ public class DefaultDataType implements DataType { /** * Generated UID */ - private static final long serialVersionUID = 4155588654449505119L; + private static final long serialVersionUID = 4155588654449505119L; /** * A pattern for data type name normalisation. */ - private static final Pattern NORMALISE_PATTERN = Pattern.compile("\"|\\.|\\s|\\(\\w+(\\s*,\\s*\\w+)*\\)|(NOT\\s*NULL)?"); + private static final Pattern NORMALISE_PATTERN = Pattern.compile("\"|\\.|\\s|\\(\\w+(\\s*,\\s*\\w+)*\\)|(NOT\\s*NULL)?"); /** * A pattern to be used to replace all precision, scale, and length * information. */ - private static final Pattern TYPE_NAME_PATTERN = Pattern.compile("\\([^\\)]*\\)"); + private static final Pattern TYPE_NAME_PATTERN = Pattern.compile("\\([^\\)]*\\)"); // ------------------------------------------------------------------------- // Data type caches @@ -126,22 +126,22 @@ public class DefaultDataType implements DataType { /** * A cache for dialect-specific data types by normalised. */ - private static final Map>[] TYPES_BY_NAME; + private static final Map>[] TYPES_BY_NAME; /** * A cache for dialect-specific data types by Java type. */ - private static final Map, DataType>[] TYPES_BY_TYPE; + private static final Map, DefaultDataType>[] TYPES_BY_TYPE; /** * A cache for dialect-specific data types by SQL DataTypes. */ - private static final Map, DataType>[] TYPES_BY_SQL_DATATYPE; + private static final Map, DefaultDataType>[] TYPES_BY_SQL_DATATYPE; /** * A cache for SQL DataTypes by Java type. */ - private static final Map, DataType> SQL_DATATYPES_BY_TYPE; + private static final Map, DefaultDataType> SQL_DATATYPES_BY_TYPE; // ------------------------------------------------------------------------- // Precisions @@ -151,25 +151,25 @@ public class DefaultDataType implements DataType { * The minimum decimal precision needed to represent a Java {@link Long} * type. */ - private static final int LONG_PRECISION = String.valueOf(Long.MAX_VALUE).length(); + 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(); + 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(); + 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(); + private static final int BYTE_PRECISION = String.valueOf(Byte.MAX_VALUE).length(); // ------------------------------------------------------------------------- // Data type attributes @@ -178,57 +178,57 @@ public class DefaultDataType implements DataType { /** * The SQL dialect associated with this data type. */ - private final SQLDialect dialect; + private final SQLDialect dialect; /** * The SQL DataType corresponding to this data type. */ - private final DataType sqlDataType; + private final DataType sqlDataType; /** * The Java class corresponding to this data type's <U> * type, i.e. the user type in case a {@link Binding} applies. */ - private final Class uType; + private final Class uType; /** * The Java class corresponding to this data type's <T> * type, i.e. the database type in case a {@link Binding} applies. */ - private final Class tType; + private final Class tType; /** * The data type binding corresponding to this data type. */ - private final Binding binding; + private final Binding binding; /** * The Java class corresponding to arrays of this data type. */ - private final Class arrayType; + private final Class arrayType; /** * The type name used for casting to this type. */ - private final String castTypeName; + private final String castTypeName; /** * The type name used for casting to this type. */ - private final String castTypeBase; + private final String castTypeBase; /** * The type name. */ - private final String typeName; + private final String typeName; - private final Nullability nullability; - private final Collation collation; - private final CharacterSet characterSet; - private final boolean identity; - private final Field defaultValue; - private final int precision; - private final int scale; - private final int length; + private final Nullability nullability; + private final Collation collation; + private final CharacterSet characterSet; + private final boolean identity; + private final Field defaultValue; + private final Integer precision; + private final Integer scale; + private final Integer length; static { TYPES_BY_SQL_DATATYPE = new Map[SQLDialect.values().length]; @@ -251,38 +251,49 @@ public class DefaultDataType implements DataType { } public DefaultDataType(SQLDialect dialect, DataType sqlDataType, String typeName) { - this(dialect, sqlDataType, sqlDataType.getType(), typeName, typeName, sqlDataType.precision(), sqlDataType.scale(), sqlDataType.length(), sqlDataType.nullability(), sqlDataType.defaultValue()); + this(dialect, sqlDataType, typeName, typeName); } public DefaultDataType(SQLDialect dialect, DataType sqlDataType, String typeName, String castTypeName) { - this(dialect, sqlDataType, sqlDataType.getType(), typeName, castTypeName, sqlDataType.precision(), sqlDataType.scale(), sqlDataType.length(), sqlDataType.nullability(), sqlDataType.defaultValue()); + this( + dialect, + sqlDataType, + sqlDataType.getType(), + typeName, + castTypeName, + sqlDataType.precisionDefined() ? sqlDataType.precision() : null, + sqlDataType.scaleDefined() ? sqlDataType.scale() : null, + sqlDataType.lengthDefined() ? sqlDataType.length() : null, + sqlDataType.nullability(), + sqlDataType.defaultValue() + ); } public DefaultDataType(SQLDialect dialect, Class type, String typeName) { - this(dialect, null, type, typeName, typeName, 0, 0, 0, Nullability.DEFAULT, null); + this(dialect, null, type, typeName, typeName, null, null, null, Nullability.DEFAULT, null); } public DefaultDataType(SQLDialect dialect, Class type, String typeName, String castTypeName) { - this(dialect, null, type, typeName, castTypeName, 0, 0, 0, Nullability.DEFAULT, null); + this(dialect, null, type, typeName, castTypeName, null, null, null, Nullability.DEFAULT, null); } - DefaultDataType(SQLDialect dialect, Class type, String typeName, String castTypeName, int precision, int scale, int length, Nullability nullability, Field defaultValue) { + DefaultDataType(SQLDialect dialect, Class type, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field defaultValue) { this(dialect, null, type, typeName, castTypeName, precision, scale, length, nullability, defaultValue); } - DefaultDataType(SQLDialect dialect, Class type, Binding binding, String typeName, String castTypeName, int precision, int scale, int length, Nullability nullability, Field defaultValue) { + DefaultDataType(SQLDialect dialect, Class type, Binding binding, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field defaultValue) { this(dialect, null, type, binding, typeName, castTypeName, precision, scale, length, nullability, defaultValue); } - DefaultDataType(SQLDialect dialect, DataType sqlDataType, Class type, String typeName, String castTypeName, int precision, int scale, int length, Nullability nullability, Field defaultValue) { + DefaultDataType(SQLDialect dialect, DataType sqlDataType, Class type, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field defaultValue) { this(dialect, sqlDataType, type, null, typeName, castTypeName, precision, scale, length, nullability, defaultValue); } - DefaultDataType(SQLDialect dialect, DataType sqlDataType, Class type, Binding binding, String typeName, String castTypeName, int precision, int scale, int length, Nullability nullability, Field defaultValue) { + DefaultDataType(SQLDialect dialect, DataType sqlDataType, Class type, Binding binding, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field defaultValue) { this(dialect, sqlDataType, type, binding, typeName, castTypeName, precision, scale, length, nullability, null, null, false, defaultValue); } - DefaultDataType(SQLDialect dialect, DataType sqlDataType, Class type, Binding binding, String typeName, String castTypeName, int precision, int scale, int length, Nullability nullability, Collation collation, CharacterSet characterSet, boolean identity, Field defaultValue) { + DefaultDataType(SQLDialect dialect, DataType sqlDataType, Class type, Binding binding, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Collation collation, CharacterSet characterSet, boolean identity, Field defaultValue) { // Initialise final instance members // --------------------------------- @@ -302,7 +313,7 @@ public class DefaultDataType implements DataType { this.characterSet = characterSet; this.identity = identity; this.defaultValue = defaultValue; - this.precision = precision0(type, precision); + this.precision = integerPrecision(type, precision); this.scale = scale; this.length = length; @@ -339,9 +350,9 @@ public class DefaultDataType implements DataType { * [#7811] Allow for subtypes to override the constructor */ DefaultDataType construct( - int newPrecision, - int newScale, - int newLength, + Integer newPrecision, + Integer newScale, + Integer newLength, Nullability newNullability, Collation newCollation, CharacterSet newCharacterSet, @@ -356,9 +367,9 @@ public class DefaultDataType implements DataType { */ DefaultDataType( DefaultDataType t, - int precision, - int scale, - int length, + Integer precision, + Integer scale, + Integer length, Nullability nullability, Collation collation, CharacterSet characterSet, @@ -379,15 +390,15 @@ public class DefaultDataType implements DataType { this.characterSet = characterSet; this.identity = identity; this.defaultValue = defaultValue; - this.precision = precision0(uType, precision); + this.precision = integerPrecision(uType, precision); this.scale = scale; this.length = length; this.binding = t.binding; } - private static final int precision0(Class type, int precision) { - if (precision == 0) + private static final Integer integerPrecision(Class type, Integer precision) { + if (precision == null) if (type == Long.class || type == ULong.class) precision = LONG_PRECISION; else if (type == Integer.class || type == UInteger.class) @@ -493,12 +504,16 @@ public class DefaultDataType implements DataType { @Override public final DataType precision(int p) { - return precision(p, scale); + return precision0(p, scale); } @Override public final DataType precision(int p, int s) { - if (precision == p && scale == s) + return precision0(p, s); + } + + private final DefaultDataType precision0(Integer p, Integer s) { + if (eq(precision, p) && eq(scale, s)) return this; // [#4120] LOB types are not allowed to have precision @@ -510,7 +525,7 @@ public class DefaultDataType implements DataType { @Override public final int precision() { - return precision; + return precision == null ? 0 : precision; } @Override @@ -527,9 +542,18 @@ public class DefaultDataType implements DataType { ; } + @Override + public final boolean precisionDefined() { + return precision != null && hasPrecision(); + } + @Override public final DataType scale(int s) { - if (scale == s) + return scale0(s); + } + + private final DefaultDataType scale0(Integer s) { + if (eq(scale, s)) return this; // [#4120] LOB types are not allowed to have scale @@ -541,7 +565,7 @@ public class DefaultDataType implements DataType { @Override public final int scale() { - return scale; + return scale == null ? 0 : scale; } @Override @@ -549,9 +573,18 @@ public class DefaultDataType implements DataType { return tType == BigDecimal.class; } + @Override + public final boolean scaleDefined() { + return scale != null && hasScale(); + } + @Override public final DataType length(int l) { - if (length == l) + return length0(l); + } + + private final DefaultDataType length0(Integer l) { + if (eq(length, l)) return this; // [#4120] LOB types are not allowed to have length @@ -563,7 +596,7 @@ public class DefaultDataType implements DataType { @Override public final int length() { - return length; + return length == null ? 0 : length; } @Override @@ -571,6 +604,11 @@ public class DefaultDataType implements DataType { return (tType == byte[].class || tType == String.class) && !isLob(); } + @Override + public boolean lengthDefined() { + return length != null && hasLength(); + } + @Override public final DataType getSQLDataType() { return sqlDataType; @@ -582,18 +620,17 @@ public class DefaultDataType implements DataType { // If this is a SQLDataType find the most suited dialect-specific // data type if (getDialect() == null) { - DataType dataType = TYPES_BY_SQL_DATATYPE[configuration.family().ordinal()] + DefaultDataType dataType = TYPES_BY_SQL_DATATYPE[configuration.family().ordinal()] - // Be sure to reset length, precision, and scale, as those values - // were not registered in the below cache - .get(length(0).precision(0, 0)); + // Be sure to reset length, precision, and scale, as those + // values were not registered in the below cache + .get(length0(null).precision0((Integer) null, null)); - if (dataType != null) { + if (dataType != null) // ... and then, set them back to the original value // [#2710] TODO: Remove this logic along with cached data types - return (DataType) dataType.length(length).precision(precision, scale); - } + return (DataType) dataType.length0(length).precision0(precision, scale); } // If this is already the dialect's specific data type, return this @@ -752,20 +789,20 @@ public class DefaultDataType implements DataType { @Override public final String getCastTypeName() { - if (length != 0 && hasLength()) { + + // [#9958] We should be able to avoid checking for x > 0, but there may + // be a lot of data types constructed with a 0 value instead of + // a null value, historically, so removing this check would + // introduce a lot of regressions! + if (lengthDefined() && length() > 0) return castTypeBase + "(" + length + ")"; - } - else if (precision != 0 && hasPrecision()) { - if (scale != 0 && hasScale()) { + else if (precisionDefined() && precision() > 0) + if (scaleDefined() && scale() > 0) return castTypeBase + "(" + precision + ", " + scale + ")"; - } - else { + else return castTypeBase + "(" + precision + ")"; - } - } - else { + else return castTypeName; - } } @Override @@ -915,24 +952,20 @@ public class DefaultDataType implements DataType { // jOOQ data types are handled here try { - if (UDTRecord.class.isAssignableFrom(type)) { + if (UDTRecord.class.isAssignableFrom(type)) return (DataType) ((UDTRecord) type.newInstance()).getUDT().getDataType(); - } // [#7174] PostgreSQL table records can be function argument types - else if (TableRecord.class.isAssignableFrom(type)) { + else if (TableRecord.class.isAssignableFrom(type)) return (DataType) ((TableRecord) type.newInstance()).getTable().getDataType(); - } - - else if (EnumType.class.isAssignableFrom(type)) { + else if (EnumType.class.isAssignableFrom(type)) return (DataType) SQLDataType.VARCHAR.asEnumDataType((Class) type); - } } catch (Exception e) { throw new MappingException("Cannot create instance of " + type, e); @@ -940,23 +973,20 @@ public class DefaultDataType implements DataType { } if (result == null) { - if (SQL_DATATYPES_BY_TYPE.get(type) != null) { + if (SQL_DATATYPES_BY_TYPE.get(type) != null) return (DataType) SQL_DATATYPES_BY_TYPE.get(type); - } // If we have a "fallback" data type from an outer context - else if (fallbackDataType != null) { + else if (fallbackDataType != null) return fallbackDataType; - } + // [#8022] Special handling - else if (java.util.Date.class == type) { + else if (java.util.Date.class == type) return (DataType) SQLDataType.TIMESTAMP; - } // All other data types are illegal - else { + else throw new SQLDialectNotSupportedException("Type " + type + " is not supported in dialect " + dialect); - } } return (DataType) result; @@ -1074,9 +1104,9 @@ public class DefaultDataType implements DataType { final int prime = 31; int result = 1; result = prime * result + ((dialect == null) ? 0 : dialect.hashCode()); - result = prime * result + length; - result = prime * result + precision; - result = prime * result + scale; + result = prime * result + length(); + result = prime * result + precision(); + result = prime * result + scale(); result = prime * result + ((uType == null) ? 0 : uType.hashCode()); result = prime * result + ((tType == null) ? 0 : tType.hashCode()); result = prime * result + ((typeName == null) ? 0 : typeName.hashCode()); @@ -1094,11 +1124,11 @@ public class DefaultDataType implements DataType { DefaultDataType other = (DefaultDataType) obj; if (dialect != other.dialect) return false; - if (length != other.length) + if (!eq(length, other.length)) return false; - if (precision != other.precision) + if (!eq(precision, other.precision)) return false; - if (scale != other.scale) + if (!eq(scale, other.scale)) return false; if (uType == null) { if (other.uType != null) @@ -1179,4 +1209,21 @@ public class DefaultDataType implements DataType { static final Collection> dataTypes() { return unmodifiableCollection(SQL_DATATYPES_BY_TYPE.values()); } + + static final DataType set(DataType d, Integer l, Integer p, Integer s) { + if (l != null) + d = d.length(l); + + if (p != null) + if (s != null) + d = d.precision(p, s); + else + d = d.precision(p); + + return d; + } + + private static final boolean eq(Integer i1, Integer i2) { + return (i1 == i2) || (i1 != null && i2 != null && i1.intValue() == i2.intValue()); + } } diff --git a/jOOQ/src/main/java/org/jooq/impl/Diff.java b/jOOQ/src/main/java/org/jooq/impl/Diff.java index bbbb87103d..bb61444b8b 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Diff.java +++ b/jOOQ/src/main/java/org/jooq/impl/Diff.java @@ -376,9 +376,9 @@ final class Diff { else if (type2.defaulted() && (!type1.defaulted() || !d2.equals(d1))) r.queries.add(ctx.alterTable(t1).alter(f1).setDefault((Field) d2)); - if ((type1.hasLength() && type2.hasLength() && type1.length() != type2.length()) - || (type1.hasPrecision() && type2.hasPrecision() && type1.precision() != type2.precision()) - || (type1.hasScale() && type2.hasScale() && type1.scale() != type2.scale())) + if ((type1.hasLength() && type2.hasLength() && (type1.lengthDefined() != type2.lengthDefined() || type1.length() != type2.length())) + || (type1.hasPrecision() && type2.hasPrecision() && (type1.precisionDefined() != type2.precisionDefined() || type1.precision() != type2.precision())) + || (type1.hasScale() && type2.hasScale() && (type1.scaleDefined() != type2.scaleDefined() || type1.scale() != type2.scale()))) r.queries.add(ctx.alterTable(t1).alter(f1).set(type2)); // [#9656] TODO: Change collation diff --git a/jOOQ/src/main/java/org/jooq/impl/InformationSchemaExport.java b/jOOQ/src/main/java/org/jooq/impl/InformationSchemaExport.java index b484546d8d..0c2e633b18 100644 --- a/jOOQ/src/main/java/org/jooq/impl/InformationSchemaExport.java +++ b/jOOQ/src/main/java/org/jooq/impl/InformationSchemaExport.java @@ -172,13 +172,13 @@ final class InformationSchemaExport { iq.setSequenceName(q.getName()); iq.setDataType(q.getDataType().getTypeName(configuration)); - if (q.getDataType().hasLength()) + if (q.getDataType().lengthDefined()) iq.setCharacterMaximumLength(q.getDataType().length()); - if (q.getDataType().hasPrecision()) + if (q.getDataType().precisionDefined()) iq.setNumericPrecision(q.getDataType().precision()); - if (q.getDataType().hasScale()) + if (q.getDataType().scaleDefined()) iq.setNumericScale(q.getDataType().scale()); if (q.getStartWith() != null) @@ -273,13 +273,13 @@ final class InformationSchemaExport { ic.setComment(f.getComment()); ic.setDataType(f.getDataType().getTypeName(configuration)); - if (f.getDataType().hasLength()) + if (f.getDataType().lengthDefined()) ic.setCharacterMaximumLength(f.getDataType().length()); - if (f.getDataType().hasPrecision()) + if (f.getDataType().precisionDefined()) ic.setNumericPrecision(f.getDataType().precision()); - if (f.getDataType().hasScale()) + if (f.getDataType().scaleDefined()) ic.setNumericScale(f.getDataType().scale()); ic.setColumnDefault(DSL.using(configuration).render(f.getDataType().defaultValue())); diff --git a/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java b/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java index 7547112fa8..5a25ec5a45 100644 --- a/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java @@ -345,7 +345,7 @@ public class TableRecordImpl> extends AbstractRecord im private static final Timestamp truncate(Timestamp ts, DataType type) { if (type.isDate()) return new Timestamp(ts.getYear(), ts.getMonth(), ts.getDate(), 0, 0, 0, 0); - else if (type.precision() >= 3) + else if (!type.precisionDefined() || type.precision() >= 3) return ts; else return new Timestamp((ts.getTime() / TRUNCATE[type.precision()]) * TRUNCATE[type.precision()]);