[#2007] Bad type coercion on the right hand side of a comparison
predicate, when the left hand side is Field<Object>
This commit is contained in:
parent
8b6e4f2a27
commit
f958e32075
@ -6801,10 +6801,38 @@ public class Factory {
|
||||
|
||||
// The default behaviour
|
||||
else {
|
||||
return new Val<T>(type.convert(value), type);
|
||||
T converted = type.convert(value);
|
||||
return new Val<T>(converted, mostSpecific(converted, type));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "most specific" data type between a concrete value and an actual
|
||||
* coercion data type
|
||||
* <p>
|
||||
* [#2007] When coercing a (previously converted) value to a type, it may be that
|
||||
* the type is still more general than the actual type. This is typically
|
||||
* the case when <code>dataType == SQLDataType.OTHER</code>, i.e. when
|
||||
* <code>dataType.getType() == Object.class</code>. In that case, it is wise
|
||||
* to keep the additional type information of the <code>value</code>
|
||||
*
|
||||
* @param value The value
|
||||
* @param dataType The coercion data type
|
||||
* @return The most specific data type
|
||||
*/
|
||||
private static <T> DataType<T> mostSpecific(T value, DataType<T> dataType) {
|
||||
if (value != null) {
|
||||
Class<?> valueType = value.getClass();
|
||||
Class<T> coercionType = dataType.getType();
|
||||
|
||||
if (valueType != coercionType && coercionType.isAssignableFrom(valueType)) {
|
||||
return (DataType<T>) DefaultDataType.getDataType(null, valueType);
|
||||
}
|
||||
}
|
||||
|
||||
return dataType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of bind values and fields
|
||||
*/
|
||||
|
||||
@ -38,11 +38,18 @@ package org.jooq.test;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static org.jooq.impl.Factory.fieldByName;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
import org.jooq.Condition;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.test.data.Table1;
|
||||
import org.jooq.types.DayToSecond;
|
||||
import org.jooq.types.Interval;
|
||||
import org.jooq.types.YearToMonth;
|
||||
|
||||
import org.jmock.Expectations;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
@ -53,6 +60,97 @@ import org.junit.Test;
|
||||
*/
|
||||
public class DataTypeTest extends AbstractTest {
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Test
|
||||
public void testComparisonPredicateTypeCoercion() throws Exception {
|
||||
// This test checks whether automatic type coercion works well for
|
||||
// comparison predicates
|
||||
|
||||
Field integer = Table1.FIELD_ID1;
|
||||
Field string = Table1.FIELD_NAME1;
|
||||
Field object = fieldByName("ANY");
|
||||
|
||||
// Check if a correct type was coerced correctly
|
||||
// ---------------------------------------------
|
||||
{
|
||||
Condition int_int = integer.eq(1);
|
||||
assertEquals("\"TABLE1\".\"ID1\" = 1", r_refI().render(int_int));
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(statement).setInt(1, 1);
|
||||
}});
|
||||
|
||||
assertEquals(2, b_ref().bind(int_int).peekIndex());
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
{
|
||||
Condition string_string = string.eq("1");
|
||||
assertEquals("\"TABLE1\".\"NAME1\" = '1'", r_refI().render(string_string));
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(statement).setString(1, "1");
|
||||
}});
|
||||
|
||||
assertEquals(2, b_ref().bind(string_string).peekIndex());
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
// Check if a convertible type was coerced correctly
|
||||
// -------------------------------------------------
|
||||
{
|
||||
Condition int_string = integer.eq("1");
|
||||
assertEquals("\"TABLE1\".\"ID1\" = 1", r_refI().render(int_string));
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(statement).setInt(1, 1);
|
||||
}});
|
||||
|
||||
assertEquals(2, b_ref().bind(int_string).peekIndex());
|
||||
context.assertIsSatisfied();
|
||||
|
||||
Condition string_int = string.eq(1);
|
||||
assertEquals("\"TABLE1\".\"NAME1\" = '1'", r_refI().render(string_int));
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(statement).setString(1, "1");
|
||||
}});
|
||||
|
||||
assertEquals(2, b_ref().bind(string_int).peekIndex());
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
// Check if ...
|
||||
// ------------
|
||||
{
|
||||
Condition object_int = object.eq(1);
|
||||
assertEquals("\"ANY\" = 1", r_refI().render(object_int));
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(statement).setInt(1, 1);
|
||||
}});
|
||||
|
||||
assertEquals(2, b_ref().bind(object_int).peekIndex());
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
{
|
||||
Condition object_string = object.eq("1");
|
||||
assertEquals("\"ANY\" = '1'", r_refI().render(object_string));
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(statement).setString(1, "1");
|
||||
}});
|
||||
|
||||
assertEquals(2, b_ref().bind(object_string).peekIndex());
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
{
|
||||
Condition object_date = object.eq(Timestamp.valueOf("2012-12-21 15:30:00.0"));
|
||||
assertEquals("\"ANY\" = timestamp '2012-12-21 15:30:00.0'", r_refI().render(object_date));
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(statement).setTimestamp(1, Timestamp.valueOf("2012-12-21 15:30:00.0"));
|
||||
}});
|
||||
|
||||
assertEquals(2, b_ref().bind(object_date).peekIndex());
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testYearToMonth() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user