[jOOQ/jOOQ#9958] Add DataType.precisionDefined(), scaleDefined(),

lengthDefined()

Also, apply the optimistic locking truncation only if a precision is
defined on the TIMESTAMP data type [jOOQ/jOOQ#9933]
This commit is contained in:
Lukas Eder 2020-03-13 11:59:30 +01:00
parent b3ae36ef63
commit aebe5cf584
10 changed files with 228 additions and 131 deletions

View File

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

View File

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

View File

@ -442,6 +442,16 @@ public interface DataType<T> extends Serializable {
*/
boolean hasPrecision();
/**
* Whether the precision returned by {@link #precision()} is defined.
* <p>
* The default precision is <code>0</code> 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.
* <p>
@ -467,6 +477,16 @@ public interface DataType<T> extends Serializable {
*/
boolean hasScale();
/**
* Whether the precision returned by {@link #scale()} is defined.
* <p>
* The default scale is <code>0</code> 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.
* <p>
@ -492,6 +512,16 @@ public interface DataType<T> extends Serializable {
*/
boolean hasLength();
/**
* Whether the precision returned by {@link #length()} is defined.
* <p>
* The default length is <code>0</code> 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.
* <p>

View File

@ -70,9 +70,9 @@ final class ArrayDataType<T> extends DefaultDataType<T[]> {
ArrayDataType(
DefaultDataType<T[]> t,
DataType<T> 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<T> extends DefaultDataType<T[]> {
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
DefaultDataType<T[]> construct(
int newPrecision,
int newScale,
int newLength,
Integer newPrecision,
Integer newScale,
Integer newLength,
Nullability
newNullability,
Collation newCollation,

View File

@ -71,16 +71,16 @@ final class ConvertedDataType<T, U> extends DefaultDataType<U> {
private final DataType<T> delegate;
@SuppressWarnings("unchecked")
ConvertedDataType(DataType<T> delegate, Binding<? super T, U> binding) {
ConvertedDataType(DefaultDataType<T> delegate, Binding<? super T, U> 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<U>) delegate.defaultValue()
);

View File

@ -656,7 +656,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
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<T, U> implements Binding<T, U> {
// 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<T, U> implements Binding<T, U> {
// 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<T, U> implements Binding<T, U> {
// [#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<T, U> implements Binding<T, U> {
// [#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<EnumType>) dataType), dataType.length(), dataType.precision(), dataType.scale());
sqlCast(
ctx,
converted,
Tools.emulateEnumType((DataType<EnumType>) 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<T, U> implements Binding<T, U> {
}
}
private final void sqlCast(BindingSQLContext<U> ctx, T converted, DataType<?> dataType, int length, int precision, int scale) throws SQLException {
private final void sqlCast(BindingSQLContext<U> 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(')');
}

View File

@ -106,18 +106,18 @@ public class DefaultDataType<T> implements DataType<T> {
/**
* 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<T> implements DataType<T> {
/**
* A cache for dialect-specific data types by normalised.
*/
private static final Map<String, DataType<?>>[] TYPES_BY_NAME;
private static final Map<String, DefaultDataType<?>>[] TYPES_BY_NAME;
/**
* A cache for dialect-specific data types by Java type.
*/
private static final Map<Class<?>, DataType<?>>[] TYPES_BY_TYPE;
private static final Map<Class<?>, DefaultDataType<?>>[] TYPES_BY_TYPE;
/**
* A cache for dialect-specific data types by SQL DataTypes.
*/
private static final Map<DataType<?>, DataType<?>>[] TYPES_BY_SQL_DATATYPE;
private static final Map<DataType<?>, DefaultDataType<?>>[] TYPES_BY_SQL_DATATYPE;
/**
* A cache for SQL DataTypes by Java type.
*/
private static final Map<Class<?>, DataType<?>> SQL_DATATYPES_BY_TYPE;
private static final Map<Class<?>, DefaultDataType<?>> SQL_DATATYPES_BY_TYPE;
// -------------------------------------------------------------------------
// Precisions
@ -151,25 +151,25 @@ public class DefaultDataType<T> implements DataType<T> {
* 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<T> implements DataType<T> {
/**
* 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<T> sqlDataType;
private final DataType<T> sqlDataType;
/**
* The Java class corresponding to this data type's <code>&lt;U&gt;</code>
* type, i.e. the user type in case a {@link Binding} applies.
*/
private final Class<T> uType;
private final Class<T> uType;
/**
* The Java class corresponding to this data type's <code>&lt;T&gt;</code>
* 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<?, T> binding;
private final Binding<?, T> binding;
/**
* The Java class corresponding to arrays of this data type.
*/
private final Class<T[]> arrayType;
private final Class<T[]> 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<T> 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<T> 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<T> implements DataType<T> {
}
public DefaultDataType(SQLDialect dialect, DataType<T> 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<T> 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<T> 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<T> 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<T> type, String typeName, String castTypeName, int precision, int scale, int length, Nullability nullability, Field<T> defaultValue) {
DefaultDataType(SQLDialect dialect, Class<T> type, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field<T> defaultValue) {
this(dialect, null, type, typeName, castTypeName, precision, scale, length, nullability, defaultValue);
}
DefaultDataType(SQLDialect dialect, Class<T> type, Binding<?, T> binding, String typeName, String castTypeName, int precision, int scale, int length, Nullability nullability, Field<T> defaultValue) {
DefaultDataType(SQLDialect dialect, Class<T> type, Binding<?, T> binding, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field<T> defaultValue) {
this(dialect, null, type, binding, typeName, castTypeName, precision, scale, length, nullability, defaultValue);
}
DefaultDataType(SQLDialect dialect, DataType<T> sqlDataType, Class<T> type, String typeName, String castTypeName, int precision, int scale, int length, Nullability nullability, Field<T> defaultValue) {
DefaultDataType(SQLDialect dialect, DataType<T> sqlDataType, Class<T> type, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field<T> defaultValue) {
this(dialect, sqlDataType, type, null, typeName, castTypeName, precision, scale, length, nullability, defaultValue);
}
DefaultDataType(SQLDialect dialect, DataType<T> sqlDataType, Class<T> type, Binding<?, T> binding, String typeName, String castTypeName, int precision, int scale, int length, Nullability nullability, Field<T> defaultValue) {
DefaultDataType(SQLDialect dialect, DataType<T> sqlDataType, Class<T> type, Binding<?, T> binding, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field<T> defaultValue) {
this(dialect, sqlDataType, type, binding, typeName, castTypeName, precision, scale, length, nullability, null, null, false, defaultValue);
}
DefaultDataType(SQLDialect dialect, DataType<T> sqlDataType, Class<T> type, Binding<?, T> binding, String typeName, String castTypeName, int precision, int scale, int length, Nullability nullability, Collation collation, CharacterSet characterSet, boolean identity, Field<T> defaultValue) {
DefaultDataType(SQLDialect dialect, DataType<T> sqlDataType, Class<T> type, Binding<?, T> binding, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Collation collation, CharacterSet characterSet, boolean identity, Field<T> defaultValue) {
// Initialise final instance members
// ---------------------------------
@ -302,7 +313,7 @@ public class DefaultDataType<T> implements DataType<T> {
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<T> implements DataType<T> {
* [#7811] Allow for subtypes to override the constructor
*/
DefaultDataType<T> 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<T> implements DataType<T> {
*/
DefaultDataType(
DefaultDataType<T> 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<T> implements DataType<T> {
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<T> implements DataType<T> {
@Override
public final DataType<T> precision(int p) {
return precision(p, scale);
return precision0(p, scale);
}
@Override
public final DataType<T> precision(int p, int s) {
if (precision == p && scale == s)
return precision0(p, s);
}
private final DefaultDataType<T> 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<T> implements DataType<T> {
@Override
public final int precision() {
return precision;
return precision == null ? 0 : precision;
}
@Override
@ -527,9 +542,18 @@ public class DefaultDataType<T> implements DataType<T> {
;
}
@Override
public final boolean precisionDefined() {
return precision != null && hasPrecision();
}
@Override
public final DataType<T> scale(int s) {
if (scale == s)
return scale0(s);
}
private final DefaultDataType<T> 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<T> implements DataType<T> {
@Override
public final int scale() {
return scale;
return scale == null ? 0 : scale;
}
@Override
@ -549,9 +573,18 @@ public class DefaultDataType<T> implements DataType<T> {
return tType == BigDecimal.class;
}
@Override
public final boolean scaleDefined() {
return scale != null && hasScale();
}
@Override
public final DataType<T> length(int l) {
if (length == l)
return length0(l);
}
private final DefaultDataType<T> 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<T> implements DataType<T> {
@Override
public final int length() {
return length;
return length == null ? 0 : length;
}
@Override
@ -571,6 +604,11 @@ public class DefaultDataType<T> implements DataType<T> {
return (tType == byte[].class || tType == String.class) && !isLob();
}
@Override
public boolean lengthDefined() {
return length != null && hasLength();
}
@Override
public final DataType<T> getSQLDataType() {
return sqlDataType;
@ -582,18 +620,17 @@ public class DefaultDataType<T> implements DataType<T> {
// 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<T>) dataType.length(length).precision(precision, scale);
}
return (DataType<T>) 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<T> implements DataType<T> {
@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<T> implements DataType<T> {
// jOOQ data types are handled here
try {
if (UDTRecord.class.isAssignableFrom(type)) {
if (UDTRecord.class.isAssignableFrom(type))
return (DataType<T>) ((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<T>) ((TableRecord<?>) type.newInstance()).getTable().getDataType();
}
else if (EnumType.class.isAssignableFrom(type)) {
else if (EnumType.class.isAssignableFrom(type))
return (DataType<T>) SQLDataType.VARCHAR.asEnumDataType((Class<EnumType>) type);
}
}
catch (Exception e) {
throw new MappingException("Cannot create instance of " + type, e);
@ -940,23 +973,20 @@ public class DefaultDataType<T> implements DataType<T> {
}
if (result == null) {
if (SQL_DATATYPES_BY_TYPE.get(type) != null) {
if (SQL_DATATYPES_BY_TYPE.get(type) != null)
return (DataType<T>) 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<T>) SQLDataType.TIMESTAMP;
}
// All other data types are illegal
else {
else
throw new SQLDialectNotSupportedException("Type " + type + " is not supported in dialect " + dialect);
}
}
return (DataType<T>) result;
@ -1074,9 +1104,9 @@ public class DefaultDataType<T> implements DataType<T> {
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<T> implements DataType<T> {
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<T> implements DataType<T> {
static final Collection<DataType<?>> 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());
}
}

View File

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

View File

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

View File

@ -345,7 +345,7 @@ public class TableRecordImpl<R extends TableRecord<R>> 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()]);