From 712a0f2f624ed8f3c79e809b61a7603d3d96db33 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Sat, 11 May 2013 10:11:47 +0200 Subject: [PATCH] [#2265] Add Result.store(), delete(), refresh(), to allow for batch-synchronisation of Records contained in a Result - Prototype implementation --- .../test/_/testcases/KeepResultSetTests.java | 23 ++++++--- jOOQ/src/main/java/org/jooq/Record.java | 51 +++++++++++++++++++ .../main/java/org/jooq/UpdatableRecord.java | 1 + .../java/org/jooq/impl/AbstractRecord.java | 24 +++++++++ .../org/jooq/impl/AbstractResultQuery.java | 10 +++- 5 files changed, 102 insertions(+), 7 deletions(-) diff --git a/jOOQ-test/src/org/jooq/test/_/testcases/KeepResultSetTests.java b/jOOQ-test/src/org/jooq/test/_/testcases/KeepResultSetTests.java index d99a132ddd..a21450d71b 100644 --- a/jOOQ-test/src/org/jooq/test/_/testcases/KeepResultSetTests.java +++ b/jOOQ-test/src/org/jooq/test/_/testcases/KeepResultSetTests.java @@ -52,6 +52,7 @@ import java.sql.SQLException; import java.util.Collections; import org.jooq.Cursor; +import org.jooq.Record; import org.jooq.Record1; import org.jooq.Record2; import org.jooq.Record3; @@ -134,23 +135,32 @@ extends BaseTest b2 = create().selectFrom(TBook()).keepResultSet(KEEP_AFTER_FETCH).fetch(); + Result b2 = create().select().from(TBook().getName()).keepResultSet(KEEP_AFTER_FETCH).fetch(); + Record r = b2.get(0); assertNotNull(b2.resultSet()); + assertNotNull(r.resultSet()); testFailUpdateRow(b2.resultSet()); // Changing a TITLE has no effect - b2.get(0).setValue(TBook_TITLE(), "XX"); - assertTrue(b2.get(0).changed()); - assertFalse(b2.get(0).original().equals(b2.get(0))); + r.setValue(TBook_TITLE(), "XX"); + assertEquals("XX", r.getValue(TBook_TITLE())); + assertTrue(r.changed()); + assertFalse(r.original().equals(r)); assertEquals(BOOK_TITLES.get(0), getBook(1).getValue(TBook_TITLE())); + // Refresh the record + r.refresh(); + assertEquals("1984", r.getValue(TBook_TITLE())); + assertFalse(r.changed()); + assertEquals(r.original(), r); + b2.close(); assertNull(b2.resultSet()); - Cursor c1 = create().selectFrom(TBook()).keepResultSet(KEEP_AFTER_FETCH).fetchLazy(); + Cursor c1 = create().select().from(TBook().getName()).keepResultSet(KEEP_AFTER_FETCH).fetchLazy(); assertFalse(c1.closesAfterFetch()); while (c1.hasNext()) { - Result result = c1.fetch(1); + Result result = c1.fetch(1); assertNotNull(result.get(0).resultSet()); assertNotNull(result.resultSet()); assertNotNull(c1.resultSet()); @@ -304,5 +314,6 @@ extends BaseTest { // Methods related to the underlying ResultSet (if applicable) // ------------------------------------------------------------------------- + /** + * Refresh this record from the database. + *

+ * A successful refresh results in the following: + *

    + *
  • {@link #valuesRow()} will have been restored to the respective values + * from the database
  • + *
  • {@link #original()} will match this record
  • + *
  • {@link #changed()} will be false
  • + *
+ *

+ * Refreshing can trigger any of the following actions: + *

    + *
  • Re-reading the underlying {@link #resultSet()}, if that + * ResultSet is available.
  • + *
  • Executing a new SELECT statement, if this is an + * {@link UpdatableRecord}.
  • + *
  • Failing, otherwise
  • + *
+ *

+ * This is the same as calling record.refresh(record.fields()) + * + * @throws DataAccessException This exception is thrown if + *

    + *
  • something went wrong executing the query
  • the + * {@link #resultSet()} is not available, or is in + * {@link ResultSet#TYPE_FORWARD_ONLY} mode, such that + * refreshing is not possible.
  • the record does not exist + * anymore in the database
  • + *
+ * @see UpdatableRecord#refresh() + * @see ResultQuery#keepResultSet(KeepResultSetMode) + */ + void refresh() throws DataAccessException; + +// /** +// * Refresh this record from the database, based on the value of the primary +// * key or main unique key. +// *

+// * The executed statement is

+//     * SELECT [fields] FROM [table]
+//     * WHERE [primary key fields = primary key values]
+// * +// * @throws DataAccessException This exception is thrown if +// *
    +// *
  • something went wrong executing the query
  • the +// * record does not exist anymore in the database
  • +// *
+// */ +// void refresh(Field... fields) throws DataAccessException; + /** * Close the underlying JDBC {@link ResultSet}, if applicable. *

diff --git a/jOOQ/src/main/java/org/jooq/UpdatableRecord.java b/jOOQ/src/main/java/org/jooq/UpdatableRecord.java index 0b9209937f..32a802d0b3 100644 --- a/jOOQ/src/main/java/org/jooq/UpdatableRecord.java +++ b/jOOQ/src/main/java/org/jooq/UpdatableRecord.java @@ -317,6 +317,7 @@ public interface UpdatableRecord> extends TableReco * record does not exist anymore in the database * */ + @Override void refresh() throws DataAccessException; /** diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java b/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java index f1a6951cd6..90217ba11b 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java @@ -63,6 +63,7 @@ import org.jooq.RecordMapper; import org.jooq.Result; import org.jooq.Table; import org.jooq.UniqueKey; +import org.jooq.exception.DataAccessException; import org.jooq.exception.InvalidResultException; import org.jooq.exception.MappingException; import org.jooq.tools.Convert; @@ -692,6 +693,29 @@ abstract class AbstractRecord extends AbstractStore implements Record { // XXX: Methods related to the underlying ResultSet (if applicable) // ------------------------------------------------------------------------- + @Override + public void refresh() { + if (rs != null) { + try { + + // [#2265] TODO: This code is prototypical. fetchLazy() is not + // the best way to fetch a record + rs.absolute(rsIndex - 1); + Record record = create().fetchLazy(rs).fetchOne(); + + for (int i = 0; i < record.size(); i++) { + setValue(i, new Value(record.getValue(i))); + } + } + catch (SQLException e) { + throw translate("Cannot refresh record", e); + } + } + else { + throw new DataAccessException("Cannot refresh record. No ResultSet available"); + } + } + @Override public final void close() { try { diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java b/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java index 741294e4b2..d5e602796e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java @@ -35,11 +35,13 @@ */ package org.jooq.impl; +import static java.sql.ResultSet.CONCUR_READ_ONLY; import static java.sql.ResultSet.CONCUR_UPDATABLE; import static java.sql.ResultSet.TYPE_SCROLL_SENSITIVE; import static java.util.Arrays.asList; import static java.util.concurrent.Executors.newSingleThreadExecutor; import static org.jooq.KeepResultSetMode.CLOSE_AFTER_FETCH; +import static org.jooq.KeepResultSetMode.KEEP_AFTER_FETCH; import static org.jooq.KeepResultSetMode.UPDATE_ON_CHANGE; import static org.jooq.KeepResultSetMode.UPDATE_ON_STORE; import static org.jooq.SQLDialect.ASE; @@ -224,7 +226,12 @@ abstract class AbstractResultQuery extends AbstractQuery imple } } - // [#1846] When updatable Results are fetched + // [#1846] When scrollable Results are fetched + else if (keepResultSetMode == KEEP_AFTER_FETCH) { + ctx.statement(ctx.connection().prepareStatement(ctx.sql(), TYPE_SCROLL_SENSITIVE, CONCUR_READ_ONLY)); + } + + // [#1846] When scrollable and updatable Results are fetched else if (keepResultSetMode == UPDATE_ON_CHANGE || keepResultSetMode == UPDATE_ON_STORE) { ctx.statement(ctx.connection().prepareStatement(ctx.sql(), TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE)); @@ -350,6 +357,7 @@ abstract class AbstractResultQuery extends AbstractQuery imple @Override protected final boolean keepResultSet() { return lazy + || keepResultSetMode == KEEP_AFTER_FETCH || keepResultSetMode == UPDATE_ON_CHANGE || keepResultSetMode == UPDATE_ON_STORE; }