[#1005] The INSERT INTO .. VALUES .. syntax may cause type-safety issues in some databases. VALUES should be converted before binding

This commit is contained in:
Lukas Eder 2011-12-23 10:48:15 +00:00
parent 08c6cf0d43
commit 12565c2508
3 changed files with 64 additions and 24 deletions

View File

@ -4038,11 +4038,13 @@ public abstract class jOOQAbstractTest<
public void testInsertUpdateDelete() throws Exception {
reset = false;
long time = System.currentTimeMillis();
InsertQuery<A> i = create().insertQuery(TAuthor());
i.addValue(TAuthor_ID(), 100);
i.addValue(TAuthor_FIRST_NAME(), "Hermann");
i.addValue(TAuthor_LAST_NAME(), "Hesse");
i.addValue(TAuthor_DATE_OF_BIRTH(), new Date(System.currentTimeMillis()));
i.addValue(TAuthor_DATE_OF_BIRTH(), new Date(time));
i.addValue(TAuthor_YEAR_OF_BIRTH(), 2010);
// Check insertion of UDTs and Enums if applicable
@ -4056,6 +4058,9 @@ public abstract class jOOQAbstractTest<
assertEquals("Hermann", author.getValue(TAuthor_FIRST_NAME()));
assertEquals("Hesse", author.getValue(TAuthor_LAST_NAME()));
// TODO [#1009] This doesn't work yet. Add more substantial tz tests
// assertEquals(time, author.getValue(TAuthor_DATE_OF_BIRTH()).getTime());
Map<Field<?>, String> map = new HashMap<Field<?>, String>();
map.put(TAuthor_FIRST_NAME(), "Hermie");
@ -4210,9 +4215,11 @@ public abstract class jOOQAbstractTest<
A author1 = create().selectFrom(TAuthor()).where(TAuthor_ID().equal(5)).fetchOne();
assertNotNull(author1);
assertEquals(37, (int) author1.getValue(TAuthor_ID()));
assertEquals(5, (int) author1.getValue(TAuthor_ID()));
assertEquals("Smith", author1.getValue(TAuthor_LAST_NAME()));
assertEquals(new Date(0), author1.getValue(TAuthor_DATE_OF_BIRTH()));
// TODO [#1009] This doesn't work yet. Add more substantial tz tests
// assertEquals(0L, author1.getValue(TAuthor_DATE_OF_BIRTH()).getTime());
assertEquals(1980, (int) author1.getValue(TAuthor_YEAR_OF_BIRTH()));
// Implicit field list

View File

@ -54,6 +54,7 @@ import org.jooq.Query;
import org.jooq.Record;
import org.jooq.Result;
import org.jooq.Table;
import org.jooq.tools.Convert;
/**
* @author Lukas Eder
@ -109,7 +110,7 @@ class InsertImpl<R extends Record>
@Override
public final InsertImpl<R> values(Object... values) {
return values0(vals(values));
return values0(vals(convert(values)));
}
@Override
@ -119,11 +120,52 @@ class InsertImpl<R extends Record>
@Override
public final InsertImpl<R> values(Collection<?> values) {
return values0(vals(values.toArray()));
return values0(vals(convert(values.toArray())));
}
/**
* [#1005] Convert values from the <code>VALUES</code> clause to appropriate
* values as specified by the <code>INTO</code> clause's column list.
*/
final Object[] convert(Object[] values) {
if (values != null) {
Object[] result = new Object[values.length];
for (int i = 0; i < values.length; i++) {
// TODO [#1008] Should fields be cast? Check this with
// appropriate integration tests
if (values[i] instanceof Field<?>) {
result[i] = values[i];
}
else {
result[i] = Convert.convert(values[i], getFields().get(i).getType());
}
}
return result;
}
else {
return null;
}
}
@SuppressWarnings("unchecked")
private final InsertImpl<R> values0(List<Field<?>> values) {
if (getFields().size() != values.size()) {
throw new IllegalArgumentException("The number of values must match the number of fields");
}
getDelegate().newRecord();
for (int i = 0; i < getFields().size(); i++) {
// javac has trouble when inferring Object for T. Use Void instead
getDelegate().addValue((Field<Void>) getFields().get(i), (Field<Void>) values.get(i));
}
return this;
}
private final List<Field<?>> getFields() {
// [#885] If this insert is called with an implicit field name set, take
// the fields from the underlying table.
@ -131,17 +173,7 @@ class InsertImpl<R extends Record>
fields.addAll(into.getFields());
}
if (fields.size() != values.size()) {
throw new IllegalArgumentException("The number of values must match the number of fields");
}
getDelegate().newRecord();
for (int i = 0; i < fields.size(); i++) {
// javac has trouble when inferring Object for T. Use Void instead
getDelegate().addValue((Field<Void>) fields.get(i), (Field<Void>) values.get(i));
}
return this;
return fields;
}
@Override

View File

@ -321,12 +321,12 @@ public final class Convert {
// Date types can be converted among each other
else if (java.util.Date.class.isAssignableFrom(fromClass)) {
return (T) toDate(((java.util.Date) from).getTime(), toClass);
return toDate(((java.util.Date) from).getTime(), toClass);
}
// Long may also be converted into a date type
else if ((fromClass == Long.class || fromClass == long.class) && java.util.Date.class.isAssignableFrom(toClass)) {
return (T) toDate((Long) from, toClass);
return toDate((Long) from, toClass);
}
}
@ -336,23 +336,24 @@ public final class Convert {
/**
* Convert a long timestamp to any date type
*/
private static Object toDate(long time, Class<?> toClass) {
@SuppressWarnings("unchecked")
private static <T> T toDate(long time, Class<T> toClass) {
if (toClass == Date.class) {
return new Date(time);
return (T) new Date(time);
}
else if (toClass == Time.class) {
return new Time(time);
return (T) new Time(time);
}
else if (toClass == Timestamp.class) {
return new Timestamp(time);
return (T) new Timestamp(time);
}
else if (toClass == java.util.Date.class) {
return new java.util.Date(time);
return (T) new java.util.Date(time);
}
else if (toClass == Calendar.class) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(time);
return calendar;
return (T) calendar;
}
throw fail(time, toClass);