diff --git a/jOOQ-meta/src/main/java/org/jooq/meta/firebird/FirebirdDatabase.java b/jOOQ-meta/src/main/java/org/jooq/meta/firebird/FirebirdDatabase.java index a88723d63e..2c9193d8d3 100644 --- a/jOOQ-meta/src/main/java/org/jooq/meta/firebird/FirebirdDatabase.java +++ b/jOOQ-meta/src/main/java/org/jooq/meta/firebird/FirebirdDatabase.java @@ -715,7 +715,7 @@ public class FirebirdDatabase extends AbstractDatabase implements ResultQueryDat @Override protected DSLContext create0() { - return DSL.using(getConnection(), SQLDialect.FIREBIRD, new Settings().withFetchTrimmedStrings(true)); + return DSL.using(getConnection(), SQLDialect.FIREBIRD, new Settings().withFetchTrimmedCharValues(true)); } static Field FIELD_TYPE(Rdb$fields f) { diff --git a/jOOQ/src/main/java/org/jooq/DataType.java b/jOOQ/src/main/java/org/jooq/DataType.java index 08d6f657c2..8ec05db5b3 100644 --- a/jOOQ/src/main/java/org/jooq/DataType.java +++ b/jOOQ/src/main/java/org/jooq/DataType.java @@ -1218,6 +1218,13 @@ public interface DataType extends Named { */ boolean hasLength(); + /** + * Whether this data type has a fixed length. + * + * @return Whether this data type has a fixed length + */ + boolean hasFixedLength(); + /** * Whether the precision returned by {@link #length()} is defined. *

diff --git a/jOOQ/src/main/java/org/jooq/conf/Settings.java b/jOOQ/src/main/java/org/jooq/conf/Settings.java index 42da679ad0..fffaae99c5 100644 --- a/jOOQ/src/main/java/org/jooq/conf/Settings.java +++ b/jOOQ/src/main/java/org/jooq/conf/Settings.java @@ -131,7 +131,7 @@ public class Settings @XmlElement(defaultValue = "false") protected Boolean bindOffsetTimeType = false; @XmlElement(defaultValue = "false") - protected Boolean fetchTrimmedStrings = false; + protected Boolean fetchTrimmedCharValues = false; @XmlElement(defaultValue = "true") protected Boolean fetchTriggerValuesAfterSQLServerOutput = true; @XmlElement(defaultValue = "WHEN_NEEDED") @@ -1584,37 +1584,37 @@ public class Settings } /** - * Whether right trim fetched strings from JDBC {@link java.sql.ResultSet}. + * Whether right trim fetched CHAR typed strings from JDBC {@link java.sql.ResultSet}. *

* By default, jOOQ's internal {@link String} data type {@link org.jooq.Binding} fetched strings - * as returned by JDBC. With this flag enabled, jOOQ will always right-trim such strings, which - * can be useful in database products that will often right-pad strings with a fixed amount of - * useless whitespaces. + * as returned by JDBC. With this flag enabled, jOOQ will always right-trim CHAR + * typed strings, which can be useful in database products that will often use this historic + * fixed length string type, especially in dictionary views. * * @return * possible object is * {@link Boolean } * */ - public Boolean isFetchTrimmedStrings() { - return fetchTrimmedStrings; + public Boolean isFetchTrimmedCharValues() { + return fetchTrimmedCharValues; } /** - * Whether right trim fetched strings from JDBC {@link java.sql.ResultSet}. + * Whether right trim fetched CHAR typed strings from JDBC {@link java.sql.ResultSet}. *

* By default, jOOQ's internal {@link String} data type {@link org.jooq.Binding} fetched strings - * as returned by JDBC. With this flag enabled, jOOQ will always right-trim such strings, which - * can be useful in database products that will often right-pad strings with a fixed amount of - * useless whitespaces. + * as returned by JDBC. With this flag enabled, jOOQ will always right-trim CHAR + * typed strings, which can be useful in database products that will often use this historic + * fixed length string type, especially in dictionary views. * * @param value * allowed object is * {@link Boolean } * */ - public void setFetchTrimmedStrings(Boolean value) { - this.fetchTrimmedStrings = value; + public void setFetchTrimmedCharValues(Boolean value) { + this.fetchTrimmedCharValues = value; } /** @@ -7221,16 +7221,16 @@ public class Settings } /** - * Whether right trim fetched strings from JDBC {@link java.sql.ResultSet}. + * Whether right trim fetched CHAR typed strings from JDBC {@link java.sql.ResultSet}. *

* By default, jOOQ's internal {@link String} data type {@link org.jooq.Binding} fetched strings - * as returned by JDBC. With this flag enabled, jOOQ will always right-trim such strings, which - * can be useful in database products that will often right-pad strings with a fixed amount of - * useless whitespaces. + * as returned by JDBC. With this flag enabled, jOOQ will always right-trim CHAR + * typed strings, which can be useful in database products that will often use this historic + * fixed length string type, especially in dictionary views. * */ - public Settings withFetchTrimmedStrings(Boolean value) { - setFetchTrimmedStrings(value); + public Settings withFetchTrimmedCharValues(Boolean value) { + setFetchTrimmedCharValues(value); return this; } @@ -9571,7 +9571,7 @@ public class Settings builder.append("namePathSeparator", namePathSeparator); builder.append("bindOffsetDateTimeType", bindOffsetDateTimeType); builder.append("bindOffsetTimeType", bindOffsetTimeType); - builder.append("fetchTrimmedStrings", fetchTrimmedStrings); + builder.append("fetchTrimmedCharValues", fetchTrimmedCharValues); builder.append("fetchTriggerValuesAfterSQLServerOutput", fetchTriggerValuesAfterSQLServerOutput); builder.append("fetchTriggerValuesAfterReturning", fetchTriggerValuesAfterReturning); builder.append("fetchIntermediateResult", fetchIntermediateResult); @@ -10131,12 +10131,12 @@ public class Settings return false; } } - if (fetchTrimmedStrings == null) { - if (other.fetchTrimmedStrings!= null) { + if (fetchTrimmedCharValues == null) { + if (other.fetchTrimmedCharValues!= null) { return false; } } else { - if (!fetchTrimmedStrings.equals(other.fetchTrimmedStrings)) { + if (!fetchTrimmedCharValues.equals(other.fetchTrimmedCharValues)) { return false; } } @@ -11869,7 +11869,7 @@ public class Settings result = ((prime*result)+((namePathSeparator == null)? 0 :namePathSeparator.hashCode())); result = ((prime*result)+((bindOffsetDateTimeType == null)? 0 :bindOffsetDateTimeType.hashCode())); result = ((prime*result)+((bindOffsetTimeType == null)? 0 :bindOffsetTimeType.hashCode())); - result = ((prime*result)+((fetchTrimmedStrings == null)? 0 :fetchTrimmedStrings.hashCode())); + result = ((prime*result)+((fetchTrimmedCharValues == null)? 0 :fetchTrimmedCharValues.hashCode())); result = ((prime*result)+((fetchTriggerValuesAfterSQLServerOutput == null)? 0 :fetchTriggerValuesAfterSQLServerOutput.hashCode())); result = ((prime*result)+((fetchTriggerValuesAfterReturning == null)? 0 :fetchTriggerValuesAfterReturning.hashCode())); result = ((prime*result)+((fetchIntermediateResult == null)? 0 :fetchIntermediateResult.hashCode())); diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java b/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java index 5283fc0050..15d57be4c0 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java @@ -69,6 +69,7 @@ import static org.jooq.impl.Internal.arrayType; import static org.jooq.impl.QOM.GenerationOption.STORED; import static org.jooq.impl.QOM.GenerationOption.VIRTUAL; import static org.jooq.impl.SQLDataType.BLOB; +import static org.jooq.impl.SQLDataType.CHAR; import static org.jooq.impl.SQLDataType.CLOB; import static org.jooq.impl.SQLDataType.NCHAR; import static org.jooq.impl.SQLDataType.NCLOB; @@ -478,6 +479,17 @@ implements return (tType == byte[].class || tType == String.class) && !isLob(); } + @Override + public final boolean hasFixedLength() { + AbstractDataType t = (AbstractDataType) getSQLDataType(); + return t == CHAR + || t == NCHAR + + // [#9540] [#10368] In case the constant literals haven't been initialised yet + || CHAR == null && "char".equals(t.typeName0()) + || NCHAR == null && "nchar".equals(t.typeName0()); + } + @Override public final boolean lengthDefined() { return length0() != null && hasLength(); diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java index 1a1716a9bc..3e4887c35c 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java @@ -3927,7 +3927,7 @@ public class DefaultBinding implements Binding { } else if (object instanceof Clob clob) { try { - return autoRtrim(ctx, clob.getSubString(1, asInt(clob.length()))); + return clob.getSubString(1, asInt(clob.length())); } finally { JDBCUtils.safeFree(clob); @@ -4660,24 +4660,17 @@ public class DefaultBinding implements Binding { - return autoRtrim(ctx, ctx.resultSet().getString(ctx.index())); - } - - static final String autoRtrim(Scope ctx, String string) { - if (!isEmpty(string) && TRUE.equals(ctx.settings().isFetchTrimmedStrings())) - return rtrim(string); - else - return string; + return autoRtrim(ctx, dataType, ctx.resultSet().getString(ctx.index())); } @Override final String get0(BindingGetStatementContext ctx) throws SQLException { - return autoRtrim(ctx, ctx.statement().getString(ctx.index())); + return autoRtrim(ctx, dataType, ctx.statement().getString(ctx.index())); } @Override final String get0(BindingGetSQLInputContext ctx) throws SQLException { - return autoRtrim(ctx, ctx.input().readString()); + return autoRtrim(ctx, dataType, ctx.input().readString()); } @Override @@ -4691,6 +4684,13 @@ public class DefaultBinding implements Binding { return Types.VARCHAR; } + + static final String autoRtrim(Scope ctx, DataType type, String string) { + if (type.hasFixedLength() && !isEmpty(string) && TRUE.equals(ctx.settings().isFetchTrimmedCharValues())) + return rtrim(string); + else + return string; + } } static final class DefaultNStringBinding extends InternalBinding { @@ -4753,7 +4753,7 @@ public class DefaultBinding implements Binding { if (NO_SUPPORT_NVARCHAR.contains(ctx.dialect())) return fallback.get0(ctx); else - return autoRtrim(ctx, ctx.resultSet().getNString(ctx.index())); + return autoRtrim(ctx, dataType, ctx.resultSet().getNString(ctx.index())); } @Override @@ -4761,7 +4761,7 @@ public class DefaultBinding implements Binding { if (NO_SUPPORT_NVARCHAR.contains(ctx.dialect())) return fallback.get0(ctx); else - return autoRtrim(ctx, ctx.statement().getNString(ctx.index())); + return autoRtrim(ctx, dataType, ctx.statement().getNString(ctx.index())); } @Override @@ -4769,7 +4769,7 @@ public class DefaultBinding implements Binding { if (NO_SUPPORT_NVARCHAR.contains(ctx.dialect())) return fallback.get0(ctx); else - return autoRtrim(ctx, ctx.input().readNString()); + return autoRtrim(ctx, dataType, ctx.input().readNString()); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/MetaImpl.java b/jOOQ/src/main/java/org/jooq/impl/MetaImpl.java index 5a0d7d9fff..0149747a23 100644 --- a/jOOQ/src/main/java/org/jooq/impl/MetaImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/MetaImpl.java @@ -599,7 +599,7 @@ final class MetaImpl extends AbstractMeta { private final DSLContext ctx(DatabaseMetaData meta) throws SQLException { if (RTRIM_META_SQL_STRINGS.contains(dialect())) - return DSL.using(meta.getConnection(), dialect(), new Settings().withFetchTrimmedStrings(true)); + return DSL.using(meta.getConnection(), dialect(), new Settings().withFetchTrimmedCharValues(true)); else return DSL.using(meta.getConnection(), dialect()); } diff --git a/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.20.0.xsd b/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.20.0.xsd index c8a634f2c5..d46c6145f4 100644 --- a/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.20.0.xsd +++ b/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.20.0.xsd @@ -319,13 +319,13 @@ This flag allows for reverting to pre-jOOQ 3.14 behaviour, where the default is For details, see https://github.com/jOOQ/jOOQ/issues/9902.]]> - - + CHAR typed strings from JDBC {@link java.sql.ResultSet}.

By default, jOOQ's internal {@link String} data type {@link org.jooq.Binding} fetched strings -as returned by JDBC. With this flag enabled, jOOQ will always right-trim such strings, which -can be useful in database products that will often right-pad strings with a fixed amount of -useless whitespaces.]]> +as returned by JDBC. With this flag enabled, jOOQ will always right-trim CHAR +typed strings, which can be useful in database products that will often use this historic +fixed length string type, especially in dictionary views.]]>