[#1154] Bad inlining of byte[] in most dialects - Fixed for H2
[#1155] byte[] are erroneously converted to String when using Record.intoArray()
This commit is contained in:
parent
83ee1dc699
commit
0071b65f4b
@ -301,7 +301,7 @@ extends BaseTest<A, B, S, B2S, BS, L, X, D, T, U, I, IPK, T658, T725, T639, T785
|
||||
Timestamp ts1 = Timestamp.valueOf("1981-07-10 12:01:15");
|
||||
Timestamp ts2 = null;
|
||||
|
||||
byte[] by1 = null; // "some bytes".getBytes();
|
||||
byte[] by1 = "some bytes".getBytes();
|
||||
byte[] by2 = null;
|
||||
Boolean bool1 = true;
|
||||
Boolean bool2 = false;
|
||||
@ -324,6 +324,8 @@ extends BaseTest<A, B, S, B2S, BS, L, X, D, T, U, I, IPK, T658, T725, T639, T785
|
||||
assertEquals(asList(s1, s2, s3, s4), asList(array1));
|
||||
assertEquals(asList((Number) b1, b2, sh1, sh2, i1, i2, l1, l2, bi1, bi2, bd1, bd2, db1, db2, f1, f2), asList(array2));
|
||||
assertEquals(asList(d1, d2, t1, t2, ts1, ts2), asList(array3));
|
||||
assertEquals(asList(by1, by2, bool1, bool2, bool3), asList(array4));
|
||||
|
||||
array4[0] = new String((byte[]) array4[0]);
|
||||
assertEquals(asList(new String(by1), by2, bool1, bool2, bool3), asList(array4));
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,6 +47,7 @@ import static org.jooq.SQLDialect.POSTGRES;
|
||||
import static org.jooq.SQLDialect.SQLITE;
|
||||
import static org.jooq.SQLDialect.SQLSERVER;
|
||||
import static org.jooq.SQLDialect.SYBASE;
|
||||
import static org.jooq.conf.StatementType.STATEMENT;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
@ -63,6 +64,8 @@ import org.jooq.Param;
|
||||
import org.jooq.RenderContext;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.UDTRecord;
|
||||
import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.tools.JooqLogger;
|
||||
import org.jooq.tools.StringUtils;
|
||||
|
||||
/**
|
||||
@ -250,6 +253,8 @@ class Val<T> extends AbstractField<T> implements Param<T>, BindingProvider {
|
||||
* Inlining abstraction
|
||||
*/
|
||||
private void toSQL(RenderContext context, Object val, Class<?> type) {
|
||||
SQLDialect dialect = context.getDialect();
|
||||
|
||||
if (context.inline()) {
|
||||
if (val == null) {
|
||||
context.sql("null");
|
||||
@ -258,7 +263,7 @@ class Val<T> extends AbstractField<T> implements Param<T>, BindingProvider {
|
||||
|
||||
// [#1153] Some dialects don't support boolean literals
|
||||
// TRUE and FALSE
|
||||
if (asList(ASE, DB2, ORACLE, SQLSERVER, SQLITE, SYBASE).contains(context.getDialect())) {
|
||||
if (asList(ASE, DB2, ORACLE, SQLSERVER, SQLITE, SYBASE).contains(dialect)) {
|
||||
context.sql(((Boolean) val) ? "1" : "0");
|
||||
}
|
||||
else {
|
||||
@ -266,9 +271,25 @@ class Val<T> extends AbstractField<T> implements Param<T>, BindingProvider {
|
||||
}
|
||||
}
|
||||
else if (type == byte[].class) {
|
||||
context.sql("'")
|
||||
.sql(Arrays.toString((byte[]) val).replace("'", "''"))
|
||||
.sql("'");
|
||||
byte[] binary = (byte[]) val;
|
||||
|
||||
// [#1154] Binary data cannot always be inlined
|
||||
if (dialect == H2) {
|
||||
context.sql("X'")
|
||||
.sql(StringUtils.convertBytesToHex(binary))
|
||||
.sql("'");
|
||||
}
|
||||
else if (Util.getStatementType(context.getSettings()) == STATEMENT) {
|
||||
throw new DataAccessException("Cannot inline binary data in dialect " + dialect + ". Use StatementType.PREPARED_STATEMENT instead");
|
||||
}
|
||||
|
||||
// This default behaviour is used in debug logging for dialects
|
||||
// that do not support inlining binary data
|
||||
else {
|
||||
context.sql("'")
|
||||
.sql(Arrays.toString(binary).replace("'", "''"))
|
||||
.sql("'");
|
||||
}
|
||||
}
|
||||
else if (Number.class.isAssignableFrom(type)) {
|
||||
context.sql(val.toString());
|
||||
@ -276,7 +297,7 @@ class Val<T> extends AbstractField<T> implements Param<T>, BindingProvider {
|
||||
else if (type.isArray()) {
|
||||
|
||||
// H2 renders arrays as tuples
|
||||
if (context.getDialect() == H2) {
|
||||
if (dialect == H2) {
|
||||
context.sql(Arrays.toString((Object[]) val).replaceAll("\\[([^]]*)\\]", "($1)"));
|
||||
}
|
||||
|
||||
@ -312,13 +333,13 @@ class Val<T> extends AbstractField<T> implements Param<T>, BindingProvider {
|
||||
|
||||
// In Postgres, some additional casting must be done in some cases...
|
||||
// TODO: Improve this implementation with [#215] (cast support)
|
||||
else if (context.getDialect() == SQLDialect.POSTGRES) {
|
||||
else if (dialect == SQLDialect.POSTGRES) {
|
||||
|
||||
// Postgres needs explicit casting for array types
|
||||
if (type.isArray() && byte[].class != type) {
|
||||
context.sql(getBindVariable(context));
|
||||
context.sql("::");
|
||||
context.sql(FieldTypeHelper.getDataType(context.getDialect(), type).getCastTypeName(context));
|
||||
context.sql(FieldTypeHelper.getDataType(dialect, type).getCastTypeName(context));
|
||||
}
|
||||
|
||||
// ... and also for enum types
|
||||
|
||||
@ -223,10 +223,18 @@ public final class Convert {
|
||||
else {
|
||||
final Class<?> fromClass = from.getClass();
|
||||
|
||||
// No conversion
|
||||
if (toClass == fromClass) {
|
||||
return (T) from;
|
||||
}
|
||||
|
||||
// [#1155] Do this early: identity-conversion into Object
|
||||
else if (toClass == Object.class) {
|
||||
return (T) from;
|
||||
}
|
||||
else if (fromClass == byte[].class) {
|
||||
|
||||
// This may not make much sense. Any other options?
|
||||
return convert(Arrays.toString((byte[]) from), toClass);
|
||||
}
|
||||
else if (fromClass.isArray()) {
|
||||
@ -242,11 +250,6 @@ public final class Convert {
|
||||
return (T) from.toString();
|
||||
}
|
||||
|
||||
// All types can be converted into Object
|
||||
else if (toClass == Object.class) {
|
||||
return (T) from;
|
||||
}
|
||||
|
||||
// Various number types are converted between each other via String
|
||||
else if (toClass == Byte.class || toClass == byte.class) {
|
||||
return (T) Byte.valueOf(new BigDecimal(from.toString().trim()).byteValue());
|
||||
|
||||
@ -936,4 +936,38 @@ public final class StringUtils {
|
||||
String cc = toCamelCase(string);
|
||||
return cc.substring(0, 1).toLowerCase() + cc.substring(1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// XXX This section is taken from the H2 Database
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
private static final char[] HEX = "0123456789abcdef".toCharArray();
|
||||
|
||||
/**
|
||||
* Convert a byte array to a hex encoded string.
|
||||
*
|
||||
* @param value the byte array
|
||||
* @return the hex encoded string
|
||||
*/
|
||||
public static String convertBytesToHex(byte[] value) {
|
||||
return convertBytesToHex(value, value.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a byte array to a hex encoded string.
|
||||
*
|
||||
* @param value the byte array
|
||||
* @param len the number of bytes to encode
|
||||
* @return the hex encoded string
|
||||
*/
|
||||
public static String convertBytesToHex(byte[] value, int len) {
|
||||
char[] buff = new char[len + len];
|
||||
char[] hex = HEX;
|
||||
for (int i = 0; i < len; i++) {
|
||||
int c = value[i] & 0xff;
|
||||
buff[i + i] = hex[c >> 4];
|
||||
buff[i + i + 1] = hex[c & 0xf];
|
||||
}
|
||||
return new String(buff);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user