diff --git a/jOOQ-test/src/org/jooq/test/BaseTest.java b/jOOQ-test/src/org/jooq/test/BaseTest.java index e46f4b56a3..3e9de8bdb1 100644 --- a/jOOQ-test/src/org/jooq/test/BaseTest.java +++ b/jOOQ-test/src/org/jooq/test/BaseTest.java @@ -139,9 +139,11 @@ public abstract class BaseTest< protected static final List BOOK_TITLES = Arrays.asList("1984", "Animal Farm", "O Alquimista", "Brida"); protected static final List BOOK_FIRST_NAMES = Arrays.asList("George", "George", "Paulo", "Paulo"); protected static final List BOOK_LAST_NAMES = Arrays.asList("Orwell", "Orwell", "Coelho", "Coelho"); + protected static final List BOOK_NULLS = Arrays.asList(null, null, null, null); protected static final List AUTHOR_IDS = Arrays.asList(1, 2); protected static final List AUTHOR_FIRST_NAMES = Arrays.asList("George", "Paulo"); protected static final List AUTHOR_LAST_NAMES = Arrays.asList("Orwell", "Coelho"); + protected static final List AUTHOR_NULLS = Arrays.asList(null, null); protected static final JooqLogger log = JooqLogger.getLogger(jOOQAbstractTest.class); diff --git a/jOOQ-test/src/org/jooq/test/_/testcases/FetchTests.java b/jOOQ-test/src/org/jooq/test/_/testcases/FetchTests.java index 08564221ba..bad59feb7a 100644 --- a/jOOQ-test/src/org/jooq/test/_/testcases/FetchTests.java +++ b/jOOQ-test/src/org/jooq/test/_/testcases/FetchTests.java @@ -819,6 +819,69 @@ extends BaseTest result1 = + create().select( + TBook_ID(), + TBook_TITLE(), + TBook_AUTHOR_ID(), + TAuthor_FIRST_NAME(), + TAuthor_LAST_NAME()) + .from(TBook()) + .join(TAuthor()) + .on(TBook_AUTHOR_ID().equal(TAuthor_ID())) + .orderBy(TBook_ID()) + .fetch() + .into(TBook()); + + // Assure that only book-related fields are actually contained in Result + assertEquals(4, result1.size()); + assertEquals(BOOK_IDS, result1.getValues(TBook_ID())); + assertEquals(BOOK_TITLES, result1.getValues(TBook_TITLE())); + assertEquals(BOOK_AUTHOR_IDS, result1.getValues(TBook_AUTHOR_ID())); + assertEquals(BOOK_NULLS, result1.getValues(TBook_PUBLISHED_IN())); + assertNull(result1.getField(TAuthor_FIRST_NAME())); + assertNull(result1.getField(TAuthor_LAST_NAME())); + + // Ensure that books can be updated using store() + result1.get(0).setValue(TBook_TITLE(), "Changed"); + assertEquals(1, result1.get(0).store()); + + Result books1 = create().selectFrom(TBook()).orderBy(TBook_ID()).fetch(); + assertEquals(4, books1.size()); + assertEquals(BOOK_IDS, books1.getValues(TBook_ID())); + assertEquals(1, (int) books1.getValue(0, TBook_ID())); + assertEquals(1, (int) books1.getValue(0, TBook_AUTHOR_ID())); + assertEquals("Changed", books1.getValue(0, TBook_TITLE())); + + // Without any fetched primary keys, the resulting records should be + // inserted using store() + B book = + create().select( + TBook_TITLE(), + TBook_AUTHOR_ID(), + TBook_PUBLISHED_IN(), + TBook_LANGUAGE_ID()) + .from(TBook()) + .where(TBook_ID().equal(2)) + .fetchOne() + .into(TBook()); + + assertNotNull(book); + assertEquals("Animal Farm", book.getValue(TBook_TITLE())); + assertNull(book.getValue(TBook_ID())); + + book.setValue(TBook_ID(), 5); + assertEquals(1, book.store()); + Result books2 = create().selectFrom(TBook()).orderBy(TBook_ID()).fetch(); + assertEquals(5, books2.size()); + assertEquals("Animal Farm", books2.getValue(4, TBook_TITLE())); + } + @Test public void testFetchIntoCustomTable() throws Exception { diff --git a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java index 3107828d9a..9a0888d471 100644 --- a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java +++ b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java @@ -1015,6 +1015,11 @@ public abstract class jOOQAbstractTest< new FetchTests(this).testReflectionWithImmutables(); } + @Test + public void testFetchIntoTable() throws Exception { + new FetchTests(this).testFetchIntoTable(); + } + @Test public void testFetchIntoCustomTable() throws Exception { new FetchTests(this).testFetchIntoCustomTable(); diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java b/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java index a13b619bbc..1fc836cbd9 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java @@ -212,6 +212,15 @@ abstract class AbstractRecord extends AbstractStore implements Record { return null; } + /** + * Reset all value flags' changed status + */ + final void setAllChanged(boolean changed) { + for (Value value : getValues()) { + value.setChanged(changed); + } + } + @Override public String toString() { return getClass().getSimpleName() + " [values=" + Arrays.asList(getValues()) + "]"; @@ -713,6 +722,25 @@ abstract class AbstractRecord extends AbstractStore implements Record { } } + // [#1522] If the primary key has been fully fetched, then changed + // flags should all be reset in order for the returned record to be + // updatable using store() + if (result instanceof AbstractRecord) { + UniqueKey key = ((AbstractRecord) result).getMainKey(); + + if (key != null) { + boolean isKeySet = true; + + for (Field field : key.getFields()) { + isKeySet &= (getField(field) != null); + } + + if (isKeySet) { + ((AbstractRecord) result).setAllChanged(false); + } + } + } + return result; } diff --git a/jOOQ/src/main/java/org/jooq/impl/BatchStore.java b/jOOQ/src/main/java/org/jooq/impl/BatchStore.java index fddd85429b..8ef78bb15d 100644 --- a/jOOQ/src/main/java/org/jooq/impl/BatchStore.java +++ b/jOOQ/src/main/java/org/jooq/impl/BatchStore.java @@ -203,8 +203,8 @@ class BatchStore implements Batch { private void setAllUnchanged() { for (UpdatableRecord record : records) { - if (record instanceof TableRecordImpl) { - ((TableRecordImpl) record).setAllChanged(false); + if (record instanceof AbstractRecord) { + ((AbstractRecord) record).setAllChanged(false); } } } diff --git a/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java b/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java index 13a99c6952..59c0a56489 100644 --- a/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java @@ -110,12 +110,6 @@ public class TableRecordImpl> extends TypeRecord value : getValues()) { - value.setChanged(changed); - } - } - @SuppressWarnings("unchecked") private final int storeInsert() { InsertQuery insert = create().insertQuery(getTable());