[jOOQ/jOOQ#15346] Make this about fixed-length CHAR types only

This includes:

- [jOOQ/jOOQ#16607] Add DataType.hasFixedLength()
This commit is contained in:
Lukas Eder 2024-04-29 10:08:23 +02:00
parent 0f3733b1c2
commit 80b39b8aed
7 changed files with 64 additions and 45 deletions

View File

@ -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<String> FIELD_TYPE(Rdb$fields f) {

View File

@ -1218,6 +1218,13 @@ public interface DataType<T> 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.
* <p>

View File

@ -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 <code>CHAR</code> typed strings from JDBC {@link java.sql.ResultSet}.
* <p>
* 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 <code>CHAR</code>
* 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 <code>CHAR</code> typed strings from JDBC {@link java.sql.ResultSet}.
* <p>
* 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 <code>CHAR</code>
* 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 <code>CHAR</code> typed strings from JDBC {@link java.sql.ResultSet}.
* <p>
* 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 <code>CHAR</code>
* 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()));

View File

@ -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> t = (AbstractDataType<T>) 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();

View File

@ -3927,7 +3927,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
}
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<T, U> implements Binding<T, U> {
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<U> 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<U> ctx) throws SQLException {
return autoRtrim(ctx, ctx.input().readString());
return autoRtrim(ctx, dataType, ctx.input().readString());
}
@Override
@ -4691,6 +4684,13 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
return Types.VARCHAR;
}
static final String autoRtrim(Scope ctx, DataType<String> type, String string) {
if (type.hasFixedLength() && !isEmpty(string) && TRUE.equals(ctx.settings().isFetchTrimmedCharValues()))
return rtrim(string);
else
return string;
}
}
static final class DefaultNStringBinding<U> extends InternalBinding<String, U> {
@ -4753,7 +4753,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
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<T, U> implements Binding<T, U> {
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<T, U> implements Binding<T, U> {
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

View File

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

View File

@ -319,13 +319,13 @@ This flag allows for reverting to pre-jOOQ 3.14 behaviour, where the default is
For details, see <a href="https://github.com/jOOQ/jOOQ/issues/9902">https://github.com/jOOQ/jOOQ/issues/9902</a>.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="fetchTrimmedStrings" type="boolean" minOccurs="0" maxOccurs="1" default="false">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether right trim fetched strings from JDBC {@link java.sql.ResultSet}.
<element name="fetchTrimmedCharValues" type="boolean" minOccurs="0" maxOccurs="1" default="false">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether right trim fetched <code>CHAR</code> typed strings from JDBC {@link java.sql.ResultSet}.
<p>
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.]]></jxb:javadoc></jxb:property></appinfo></annotation>
as returned by JDBC. With this flag enabled, jOOQ will always right-trim <code>CHAR</code>
typed strings, which can be useful in database products that will often use this historic
fixed length string type, especially in dictionary views.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="fetchTriggerValuesAfterSQLServerOutput" type="boolean" minOccurs="0" maxOccurs="1" default="true">