[jOOQ/jOOQ#10373] Derby CHAR casts erroneously casts to VARCHAR
This contains WIP for: - [jOOQ/jOOQ#10372] Refactor internal org.jooq.impl.Cast.Native for better reuse
This commit is contained in:
parent
09b08ae355
commit
2d0515d513
@ -40,17 +40,16 @@ package org.jooq.impl;
|
||||
import static org.jooq.impl.DSL.inline;
|
||||
import static org.jooq.impl.Keywords.K_AS;
|
||||
import static org.jooq.impl.Keywords.K_CAST;
|
||||
import static org.jooq.impl.Keywords.K_DECIMAL;
|
||||
import static org.jooq.impl.Keywords.K_TRIM;
|
||||
import static org.jooq.impl.Names.N_CAST;
|
||||
import static org.jooq.impl.Names.N_TO_CLOB;
|
||||
import static org.jooq.impl.Names.N_TO_DATE;
|
||||
import static org.jooq.impl.Names.N_TO_TIMESTAMP;
|
||||
import static org.jooq.impl.SQLDataType.BOOLEAN;
|
||||
import static org.jooq.impl.SQLDataType.CHAR;
|
||||
import static org.jooq.impl.SQLDataType.DECIMAL;
|
||||
import static org.jooq.impl.SQLDataType.DOUBLE;
|
||||
import static org.jooq.impl.SQLDataType.FLOAT;
|
||||
import static org.jooq.impl.SQLDataType.REAL;
|
||||
import static org.jooq.impl.SQLDataType.VARCHAR;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.sql.Time;
|
||||
@ -106,7 +105,7 @@ final class Cast<T> extends AbstractField<T> {
|
||||
break;
|
||||
|
||||
default:
|
||||
ctx.visit(new Native());
|
||||
ctx.visit(new CastNative<>(field, getDataType()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -157,13 +156,17 @@ final class Cast<T> extends AbstractField<T> {
|
||||
|
||||
|
||||
|
||||
private class CastDerby extends Native {
|
||||
private class CastDerby extends CastNative<T> {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
*/
|
||||
private static final long serialVersionUID = -8737153188122391258L;
|
||||
|
||||
CastDerby() {
|
||||
super(field, Cast.this.getDataType());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private final Field<Boolean> asDecodeNumberToBoolean() {
|
||||
|
||||
@ -186,62 +189,29 @@ final class Cast<T> extends AbstractField<T> {
|
||||
.otherwise(inline(true));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
|
||||
// Avoid casting bind values inside an explicit cast...
|
||||
CastMode castMode = ctx.castMode();
|
||||
DataType<T> type = getSQLDataType();
|
||||
|
||||
// [#857] Interestingly, Derby does not allow for casting numeric
|
||||
// types directly to VARCHAR. An intermediary cast to CHAR is needed
|
||||
if (field.getDataType().isNumeric() && VARCHAR.equals(type)) {
|
||||
ctx.visit(K_TRIM).sql('(')
|
||||
.visit(K_CAST).sql('(')
|
||||
.visit(K_CAST).sql('(')
|
||||
.castMode(CastMode.NEVER)
|
||||
.visit(field)
|
||||
.castMode(castMode)
|
||||
.sql(' ').visit(K_AS).sql(" char(38))")
|
||||
.sql(' ').visit(K_AS).sql(' ')
|
||||
.sql(getDataType(ctx.configuration()).getCastTypeName(ctx.configuration()))
|
||||
.sql("))");
|
||||
|
||||
return;
|
||||
}
|
||||
if (field.getDataType().isNumeric() && type.isString() && !CHAR.equals(type))
|
||||
ctx.visit(DSL.trim(new CastNative<>(new CastNative<>(field, CHAR(38)), (DataType<String>) getDataType())));
|
||||
|
||||
// [#888] ... neither does casting character types to FLOAT (and similar)
|
||||
else if (field.getDataType().isString() &&
|
||||
(FLOAT.equals(type) || DOUBLE.equals(type) || REAL.equals(type))) {
|
||||
|
||||
ctx.visit(K_CAST).sql('(')
|
||||
.visit(K_CAST).sql('(')
|
||||
.castMode(CastMode.NEVER)
|
||||
.visit(field)
|
||||
.castMode(castMode)
|
||||
.sql(' ').visit(K_AS).sql(' ').visit(K_DECIMAL)
|
||||
.sql(") ")
|
||||
.visit(K_AS)
|
||||
.sql(' ')
|
||||
.sql(getDataType(ctx.configuration()).getCastTypeName(ctx.configuration()))
|
||||
.sql(')');
|
||||
|
||||
return;
|
||||
}
|
||||
else if (field.getDataType().isString() && (FLOAT.equals(type) || DOUBLE.equals(type) || REAL.equals(type)))
|
||||
ctx.visit(new CastNative<>(new CastNative<>(field, DECIMAL), getDataType()));
|
||||
|
||||
// [#859] ... neither does casting numeric types to BOOLEAN
|
||||
else if (field.getDataType().isNumeric() && BOOLEAN.equals(type)) {
|
||||
else if (field.getDataType().isNumeric() && BOOLEAN.equals(type))
|
||||
ctx.visit(asDecodeNumberToBoolean());
|
||||
return;
|
||||
}
|
||||
|
||||
// [#859] ... neither does casting character types to BOOLEAN
|
||||
else if (field.getDataType().isString() && BOOLEAN.equals(type)) {
|
||||
else if (field.getDataType().isString() && BOOLEAN.equals(type))
|
||||
ctx.visit(asDecodeVarcharToBoolean());
|
||||
return;
|
||||
}
|
||||
|
||||
super.accept(ctx);
|
||||
else
|
||||
super.accept(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,15 +287,22 @@ final class Cast<T> extends AbstractField<T> {
|
||||
|
||||
|
||||
|
||||
private class Native extends AbstractField<T> {
|
||||
|
||||
|
||||
|
||||
|
||||
private static class CastNative<T> extends AbstractField<T> {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
*/
|
||||
private static final long serialVersionUID = -8497561014419483312L;
|
||||
private final Field<?> field;
|
||||
|
||||
Native() {
|
||||
super(N_CAST, Cast.this.getDataType());
|
||||
CastNative(Field<?> field, DataType<T> type) {
|
||||
super(N_CAST, type);
|
||||
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -92,8 +92,8 @@ public class DerbyDataType {
|
||||
public static final DataType<BigDecimal> NUMERIC = new DefaultDataType<>(FAMILY, SQLDataType.NUMERIC, "numeric");
|
||||
public static final DataType<String> VARCHAR = new DefaultDataType<>(FAMILY, SQLDataType.VARCHAR, "varchar", "varchar(32672)");
|
||||
public static final DataType<String> LONGVARCHAR = new DefaultDataType<>(FAMILY, SQLDataType.LONGVARCHAR, "long varchar");
|
||||
public static final DataType<String> CHAR = new DefaultDataType<>(FAMILY, SQLDataType.CHAR, "char", "varchar(32672)");
|
||||
public static final DataType<String> CHARACTER = new DefaultDataType<>(FAMILY, SQLDataType.CHAR, "character", "varchar(32672)");
|
||||
public static final DataType<String> CHAR = new DefaultDataType<>(FAMILY, SQLDataType.CHAR, "char", "char(1)");
|
||||
public static final DataType<String> CHARACTER = new DefaultDataType<>(FAMILY, SQLDataType.CHAR, "character", "character(1)");
|
||||
public static final DataType<String> CLOB = new DefaultDataType<>(FAMILY, SQLDataType.CLOB, "clob");
|
||||
public static final DataType<String> CHARACTERLARGEOBJECT = new DefaultDataType<>(FAMILY, SQLDataType.CLOB, "character large object");
|
||||
public static final DataType<String> CHARVARYING = new DefaultDataType<>(FAMILY, SQLDataType.VARCHAR, "char varying", "char varying(32672)");
|
||||
@ -112,7 +112,7 @@ public class DerbyDataType {
|
||||
protected static final DataType<byte[]> __BINARY = new DefaultDataType<>(FAMILY, SQLDataType.BINARY, "blob");
|
||||
protected static final DataType<Boolean> __BIT = new DefaultDataType<>(FAMILY, SQLDataType.BIT, "boolean");
|
||||
protected static final DataType<byte[]> __LONGVARBINARY = new DefaultDataType<>(FAMILY, SQLDataType.LONGVARBINARY, "blob");
|
||||
protected static final DataType<String> __NCHAR = new DefaultDataType<>(FAMILY, SQLDataType.NCHAR, "char", "varchar(32672)");
|
||||
protected static final DataType<String> __NCHAR = new DefaultDataType<>(FAMILY, SQLDataType.NCHAR, "char", "char(1)");
|
||||
protected static final DataType<String> __NCLOB = new DefaultDataType<>(FAMILY, SQLDataType.NCLOB, "clob");
|
||||
protected static final DataType<String> __LONGNVARCHAR = new DefaultDataType<>(FAMILY, SQLDataType.LONGNVARCHAR, "long varchar");
|
||||
protected static final DataType<String> __NVARCHAR = new DefaultDataType<>(FAMILY, SQLDataType.NVARCHAR, "varchar", "varchar(32672)");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user