diff --git a/jOOQ-test/src/org/jooq/test/_/testcases/MetaDataTests.java b/jOOQ-test/src/org/jooq/test/_/testcases/MetaDataTests.java index 00e88b44f0..4d7c81c825 100644 --- a/jOOQ-test/src/org/jooq/test/_/testcases/MetaDataTests.java +++ b/jOOQ-test/src/org/jooq/test/_/testcases/MetaDataTests.java @@ -367,7 +367,7 @@ extends BaseTest 0); assertEquals(0, field.getDataType().scale()); assertEquals(0, field.getDataType().length()); @@ -381,14 +381,14 @@ extends BaseTest 0); assertEquals(5, field.getDataType().scale()); assertEquals(0, field.getDataType().length()); } else if ("BIG_DECIMAL".equalsIgnoreCase(field.getName())) { assertEquals(BigDecimal.class, field.getType()); - assertEquals(SQLDataType.NUMERIC, field.getDataType()); + assertEquals(SQLDataType.NUMERIC.getType(), field.getDataType().getType()); assertTrue(field.getDataType().precision() > 0); assertEquals(5, field.getDataType().scale()); assertEquals(0, field.getDataType().length()); diff --git a/jOOQ/src/main/java/org/jooq/DataType.java b/jOOQ/src/main/java/org/jooq/DataType.java index 4376cceaa9..6d59f9c46c 100644 --- a/jOOQ/src/main/java/org/jooq/DataType.java +++ b/jOOQ/src/main/java/org/jooq/DataType.java @@ -129,26 +129,6 @@ public interface DataType extends Serializable { */ String getCastTypeName(Configuration configuration); - /** - * Retrieve the dialect-specific type name associated with this data type - * used for casting - *

- * This is useful for some dialects that have specialised type names for - * cast expressions. Other dialects require type-length binding when - * casting, (e.g. VARCHAR(20)) - */ - String getCastTypeName(Configuration configuration, int length); - - /** - * Retrieve the dialect-specific type name associated with this data type - * used for casting - *

- * This is useful for some dialects that have specialised type names for - * cast expressions. Other dialects require type-length binding when - * casting, (e.g. DECIMAL(20,5)) - */ - String getCastTypeName(Configuration configuration, int precision, int scale); - /** * Retrieve the underlying {@link SQLDialect} */ diff --git a/jOOQ/src/main/java/org/jooq/impl/ConvertedDataType.java b/jOOQ/src/main/java/org/jooq/impl/ConvertedDataType.java index 9105b097f6..a75767bc3e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ConvertedDataType.java +++ b/jOOQ/src/main/java/org/jooq/impl/ConvertedDataType.java @@ -78,11 +78,6 @@ class ConvertedDataType extends DefaultDataType { return delegate.getCastTypeName(configuration); } - @Override - public String getCastTypeName(Configuration configuration, int precision, int scale) { - return delegate.getCastTypeName(configuration, precision, scale); - } - @SuppressWarnings("unchecked") @Override public U convert(Object object) { diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultDataType.java b/jOOQ/src/main/java/org/jooq/impl/DefaultDataType.java index b13d3e626a..e2775e5d3d 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultDataType.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultDataType.java @@ -92,6 +92,12 @@ public class DefaultDataType implements DataType { */ private static final Pattern NORMALISE_PATTERN = Pattern.compile("\"|\\.|\\s|\\(\\w+(,\\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("\\([^\\)]*\\)"); + // ------------------------------------------------------------------------- // Data type caches // ------------------------------------------------------------------------- @@ -168,6 +174,10 @@ public class DefaultDataType implements DataType { * The type name used for casting to this type */ private final String castTypeName; + /** + * The type name used for casting to this type + */ + private final String castTypeBase; /** * The type name @@ -220,6 +230,7 @@ public class DefaultDataType implements DataType { this.type = type; this.typeName = typeName; this.castTypeName = castTypeName; + this.castTypeBase = TYPE_NAME_PATTERN.matcher(castTypeName).replaceAll("").trim(); this.arrayType = (Class) Array.newInstance(type, 0).getClass(); if (type == Long.class || type == ULong.class) { @@ -270,11 +281,15 @@ public class DefaultDataType implements DataType { @Override public final DataType precision(int p) { - if (hasPrecision()) { + if (precision == p) { + return this; + } + else if (hasPrecision()) { return new DefaultDataType(dialect, sqlDataType, type, typeName, castTypeName, p, scale, length); } - - return this; + else { + return this; + } } @Override @@ -289,11 +304,15 @@ public class DefaultDataType implements DataType { @Override public final DataType scale(int s) { - if (hasScale()) { + if (scale == s) { + return this; + } + else if (hasScale()) { return new DefaultDataType(dialect, sqlDataType, type, typeName, castTypeName, precision, s, length); } - - return this; + else { + return this; + } } @Override @@ -308,11 +327,15 @@ public class DefaultDataType implements DataType { @Override public final DataType length(int l) { - if (hasLength()) { + if (length == l) { + return this; + } + else if (hasLength()) { return new DefaultDataType(dialect, sqlDataType, type, typeName, castTypeName, precision, scale, l); } - - return this; + else { + return this; + } } @Override @@ -322,16 +345,7 @@ public class DefaultDataType implements DataType { @Override public final boolean hasLength() { - return sqlDataType == SQLDataType.BINARY - || sqlDataType == SQLDataType.BIT - || sqlDataType == SQLDataType.CHAR - || sqlDataType == SQLDataType.LONGNVARCHAR - || sqlDataType == SQLDataType.LONGVARBINARY - || sqlDataType == SQLDataType.LONGVARCHAR - || sqlDataType == SQLDataType.NCHAR - || sqlDataType == SQLDataType.NVARCHAR - || sqlDataType == SQLDataType.VARBINARY - || sqlDataType == SQLDataType.VARCHAR; + return type == byte[].class || type == String.class; } @Override @@ -345,7 +359,10 @@ 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.getDialect().ordinal()].get(this); + + // Be sure to reset length, precision, and scale, as those values + // were not registered in the below cache + DataType dataType = TYPES_BY_SQL_DATATYPE[configuration.getDialect().ordinal()].get(length(0).precision(0).scale(0)); if (dataType != null) { return (DataType) dataType; @@ -475,41 +492,20 @@ public class DefaultDataType implements DataType { @Override public final String getCastTypeName() { - return castTypeName; - } - - @Override - public /* final */ String getCastTypeName(Configuration configuration, int length) { - String result = getCastTypeName(configuration); - - if (length != 0) { - - // Remove existing length information, first - result = result.replaceAll("\\([^\\)]*\\)", ""); - result += "(" + length + ")"; + if (length != 0 && hasLength()) { + return castTypeBase + "(" + length + ")"; } - - return result; - } - - @Override - public /* final */ String getCastTypeName(Configuration configuration, int precision, int scale) { - String result = getCastTypeName(configuration); - - if (precision != 0) { - - // Remove existing precision / scale information, first - result = result.replaceAll("\\([^\\)]*\\)", ""); - - if (scale != 0) { - result += "(" + precision + ", " + scale + ")"; + else if (precision != 0 && hasPrecision()) { + if (scale != 0 && hasScale()) { + return castTypeBase + "(" + precision + ", " + scale + ")"; } else { - result += "(" + precision + ")"; + return castTypeBase + "(" + precision + ")"; } } - - return result; + else { + return castTypeName; + } } @Override @@ -696,6 +692,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 + ((type == null) ? 0 : type.hashCode()); result = prime * result + ((typeName == null) ? 0 : typeName.hashCode()); return result; @@ -712,6 +711,12 @@ public class DefaultDataType implements DataType { DefaultDataType other = (DefaultDataType) obj; if (dialect != other.dialect) return false; + if (length != other.length) + return false; + if (precision != other.precision) + return false; + if (scale != other.scale) + return false; if (type == null) { if (other.type != null) return false; diff --git a/jOOQ/src/main/java/org/jooq/impl/Val.java b/jOOQ/src/main/java/org/jooq/impl/Val.java index 96cba33d51..8634cce077 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Val.java +++ b/jOOQ/src/main/java/org/jooq/impl/Val.java @@ -194,7 +194,8 @@ class Val extends AbstractField implements Param { * Render the bind variable including a cast, if necessary */ private void toSQLCast(RenderContext context) { - DataType type = getDataType(context).getSQLDataType(); + DataType dataType = getDataType(context); + DataType type = dataType.getSQLDataType(); SQLDialect dialect = context.getDialect(); // [#822] Some RDBMS need precision / scale information on BigDecimals @@ -209,7 +210,7 @@ class Val extends AbstractField implements Param { precision = Math.min(precision, 18); } - toSQLCast(context, getDataType(context), precision, scale); + toSQLCast(context, dataType, 0, precision, scale); } // [#1028] Most databases don't know an OTHER type (except H2, HSQLDB). @@ -217,7 +218,7 @@ class Val extends AbstractField implements Param { // If the bind value is set, it can be used to derive the cast type if (value != null) { - toSQLCast(context, DefaultDataType.getDataType(dialect, value.getClass()), 0, 0); + toSQLCast(context, DefaultDataType.getDataType(dialect, value.getClass()), 0, 0, 0); } // [#632] [#722] Current integration tests show that Ingres and @@ -229,7 +230,7 @@ class Val extends AbstractField implements Param { // 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 { - toSQLCast(context, DefaultDataType.getDataType(dialect, String.class), 0, 0); + toSQLCast(context, DefaultDataType.getDataType(dialect, String.class), 0, 0, 0); } } @@ -244,12 +245,12 @@ class Val extends AbstractField implements Param { // [#1727] VARCHAR types should be cast to their actual lengths in some // dialects else if ((type == SQLDataType.VARCHAR || type == SQLDataType.CHAR) && asList(FIREBIRD).contains(dialect)) { - toSQLCast(context, getDataType(context), getValueLength()); + toSQLCast(context, dataType, getValueLength(), 0, 0); } // In all other cases, the bind variable can be cast normally else { - toSQLCast(context, getDataType(context), 0, 0); + toSQLCast(context, dataType, dataType.length(), dataType.precision(), dataType.scale()); } } @@ -275,19 +276,11 @@ class Val extends AbstractField implements Param { } } - private void toSQLCast(RenderContext context, DataType type, int length) { + private void toSQLCast(RenderContext context, DataType type, int length, int precision, int scale) { context.keyword("cast("); toSQL(context, getValue(), getType()); context.keyword(" as ") - .sql(type.getCastTypeName(context, length)) - .sql(")"); - } - - private void toSQLCast(RenderContext context, DataType type, int precision, int scale) { - context.keyword("cast("); - toSQL(context, getValue(), getType()); - context.keyword(" as ") - .sql(type.getCastTypeName(context, precision, scale)) + .sql(type.length(length).precision(precision).scale(scale).getCastTypeName(context)) .sql(")"); }