[#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:
Lukas Eder 2012-02-16 23:03:24 +00:00
parent 83ee1dc699
commit 0071b65f4b
4 changed files with 74 additions and 14 deletions

View File

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

View File

@ -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

View File

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

View File

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