From 3cf66dd99d703431ebc319b3fa6c4149bcd0c9d1 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Wed, 7 May 2014 18:24:17 +0200 Subject: [PATCH] [#3253] Pull up TableRecord.insert() --- jOOQ/src/main/java/org/jooq/TableRecord.java | 15 ++ .../main/java/org/jooq/UpdatableRecord.java | 1 + .../java/org/jooq/impl/TableRecordImpl.java | 183 ++++++++++++++++++ .../org/jooq/impl/UpdatableRecordImpl.java | 174 ----------------- 4 files changed, 199 insertions(+), 174 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/TableRecord.java b/jOOQ/src/main/java/org/jooq/TableRecord.java index b8f0ab2708..f748888484 100644 --- a/jOOQ/src/main/java/org/jooq/TableRecord.java +++ b/jOOQ/src/main/java/org/jooq/TableRecord.java @@ -61,6 +61,21 @@ public interface TableRecord> extends Record { @Override R original(); + /** + * Store this record to the database using an INSERT + * statement. + *

+ * If you want to enforce statement execution, regardless if the values in + * this record were changed, you can explicitly set the changed flags for + * all values with {@link #changed(boolean)} or for single values with + * {@link #changed(Field, boolean)}, prior to insertion. + * + * @return 1 if the record was stored to the database. 0 + * if storing was not necessary. + * @throws DataAccessException if something went wrong executing the query + */ + int insert() throws DataAccessException; + /** * Fetch a parent record of this record, given a foreign key *

diff --git a/jOOQ/src/main/java/org/jooq/UpdatableRecord.java b/jOOQ/src/main/java/org/jooq/UpdatableRecord.java index a80fcb0cfc..61322b2e64 100644 --- a/jOOQ/src/main/java/org/jooq/UpdatableRecord.java +++ b/jOOQ/src/main/java/org/jooq/UpdatableRecord.java @@ -241,6 +241,7 @@ public interface UpdatableRecord> extends TableReco * @throws DataAccessException if something went wrong executing the query * @see #store() */ + @Override int insert() throws DataAccessException; /** diff --git a/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java b/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java index 53110d4d79..63a831d82d 100644 --- a/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java @@ -40,9 +40,25 @@ */ package org.jooq.impl; +import static java.lang.Boolean.TRUE; +import static org.jooq.impl.RecordDelegate.delegate; +import static org.jooq.impl.RecordDelegate.RecordLifecycleType.INSERT; + +import java.math.BigInteger; +import java.sql.Timestamp; +import java.util.Collection; +import java.util.LinkedHashSet; + +import org.jooq.DSLContext; +import org.jooq.Field; import org.jooq.ForeignKey; +import org.jooq.Identity; +import org.jooq.InsertQuery; +import org.jooq.Record; import org.jooq.Row; +import org.jooq.StoreQuery; import org.jooq.Table; +import org.jooq.TableField; import org.jooq.TableRecord; import org.jooq.UpdatableRecord; @@ -100,4 +116,171 @@ public class TableRecordImpl> extends AbstractRecord im public final > O fetchParent(ForeignKey key) { return key.fetchParent((R) this); } + + @Override + public final int insert() { + return storeInsert(); + } + + final int storeInsert() { + final int[] result = new int[1]; + + delegate(configuration(), (Record) this, INSERT) + .operate(new RecordOperation() { + + @Override + public Record operate(Record record) throws RuntimeException { + result[0] = storeInsert0(); + return record; + } + }); + + return result[0]; + } + + final int storeInsert0() { + DSLContext create = create(); + InsertQuery insert = create.insertQuery(getTable()); + addChangedValues(insert); + + // Don't store records if no value was set by client code + if (!insert.isExecutable()) return 0; + + // [#1596] Set timestamp and/or version columns to appropriate values + BigInteger version = addRecordVersion(insert); + Timestamp timestamp = addRecordTimestamp(insert); + + // [#814] Refresh identity and/or main unique key values + // [#1002] Consider also identity columns of non-updatable records + // [#1537] Avoid refreshing identity columns on batch inserts + Collection> key = null; + if (!TRUE.equals(create.configuration().data(Utils.DATA_OMIT_RETURNING_CLAUSE))) { + key = getReturning(); + insert.setReturning(key); + } + + int result = insert.execute(); + + if (result > 0) { + + // [#1596] If insert was successful, update timestamp and/or version columns + setRecordVersionAndTimestamp(version, timestamp); + + // If an insert was successful try fetching the generated IDENTITY value + if (key != null && !key.isEmpty()) { + if (insert.getReturnedRecord() != null) { + for (Field field : key) { + setValue(field, new Value(insert.getReturnedRecord().getValue(field))); + } + } + } + + changed(false); + } + + return result; + } + + /** + * Set a generated version and timestamp value onto this record after + * successfully storing the record. + */ + final void setRecordVersionAndTimestamp(BigInteger version, Timestamp timestamp) { + if (version != null) { + TableField field = getTable().getRecordVersion(); + setValue(field, new Value(field.getDataType().convert(version))); + } + if (timestamp != null) { + TableField field = getTable().getRecordTimestamp(); + setValue(field, new Value(field.getDataType().convert(timestamp))); + } + } + + /** + * Set all changed values of this record to a store query + */ + final void addChangedValues(StoreQuery query) { + for (Field field : fields.fields.fields) { + if (getValue0(field).isChanged()) { + addValue(query, field); + } + } + } + + /** + * Extracted method to ensure generic type safety. + */ + final void addValue(StoreQuery store, Field field, Object value) { + store.addValue(field, Utils.field(value, field)); + } + + /** + * Extracted method to ensure generic type safety. + */ + final void addValue(StoreQuery store, Field field) { + addValue(store, field, getValue(field)); + } + + /** + * Set an updated timestamp value to a store query + */ + final Timestamp addRecordTimestamp(StoreQuery store) { + Timestamp result = null; + + if (isTimestampOrVersionAvailable()) { + TableField timestamp = getTable().getRecordTimestamp(); + + if (timestamp != null) { + + // Use Timestamp locally, to provide maximum precision + result = new Timestamp(System.currentTimeMillis()); + addValue(store, timestamp, result); + } + } + + return result; + } + + /** + * Set an updated version value to a store query + */ + final BigInteger addRecordVersion(StoreQuery store) { + BigInteger result = null; + + if (isTimestampOrVersionAvailable()) { + TableField version = getTable().getRecordVersion(); + + if (version != null) { + Number value = getValue(version); + + // Use BigInteger locally to avoid arithmetic overflows + if (value == null) { + result = BigInteger.ONE; + } + else { + result = new BigInteger(value.toString()).add(BigInteger.ONE); + } + + addValue(store, version, result); + } + } + + return result; + } + + final boolean isTimestampOrVersionAvailable() { + return getTable().getRecordTimestamp() != null || getTable().getRecordVersion() != null; + } + + final Collection> getReturning() { + Collection> result = new LinkedHashSet>(); + + Identity identity = getTable().getIdentity(); + if (identity != null) { + result.add(identity.getField()); + } + + result.addAll(getPrimaryKey().getFields()); + return result; + } } diff --git a/jOOQ/src/main/java/org/jooq/impl/UpdatableRecordImpl.java b/jOOQ/src/main/java/org/jooq/impl/UpdatableRecordImpl.java index 93468451b3..362dbe6011 100644 --- a/jOOQ/src/main/java/org/jooq/impl/UpdatableRecordImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/UpdatableRecordImpl.java @@ -47,7 +47,6 @@ import static org.jooq.SQLDialect.SQLITE; import static org.jooq.conf.SettingsTools.updatablePrimaryKeys; import static org.jooq.impl.RecordDelegate.delegate; import static org.jooq.impl.RecordDelegate.RecordLifecycleType.DELETE; -import static org.jooq.impl.RecordDelegate.RecordLifecycleType.INSERT; import static org.jooq.impl.RecordDelegate.RecordLifecycleType.REFRESH; import static org.jooq.impl.RecordDelegate.RecordLifecycleType.STORE; import static org.jooq.impl.RecordDelegate.RecordLifecycleType.UPDATE; @@ -55,21 +54,15 @@ import static org.jooq.impl.Utils.settings; import java.math.BigInteger; import java.sql.Timestamp; -import java.util.Collection; -import java.util.LinkedHashSet; import java.util.List; import org.jooq.Configuration; -import org.jooq.DSLContext; import org.jooq.DeleteQuery; import org.jooq.Field; import org.jooq.ForeignKey; -import org.jooq.Identity; -import org.jooq.InsertQuery; import org.jooq.Record; import org.jooq.Result; import org.jooq.SelectQuery; -import org.jooq.StoreQuery; import org.jooq.Table; import org.jooq.TableField; import org.jooq.TableRecord; @@ -139,11 +132,6 @@ public class UpdatableRecordImpl> extends TableReco return result[0]; } - @Override - public final int insert() { - return storeInsert(); - } - @Override public final int update() { return storeUpdate(getPrimaryKey().getFieldsArray()); @@ -190,65 +178,6 @@ public class UpdatableRecordImpl> extends TableReco return result; } - private final int storeInsert() { - final int[] result = new int[1]; - - delegate(configuration(), (Record) this, INSERT) - .operate(new RecordOperation() { - - @Override - public Record operate(Record record) throws RuntimeException { - result[0] = storeInsert0(); - return record; - } - }); - - return result[0]; - } - - private final int storeInsert0() { - DSLContext create = create(); - InsertQuery insert = create.insertQuery(getTable()); - addChangedValues(insert); - - // Don't store records if no value was set by client code - if (!insert.isExecutable()) return 0; - - // [#1596] Set timestamp and/or version columns to appropriate values - BigInteger version = addRecordVersion(insert); - Timestamp timestamp = addRecordTimestamp(insert); - - // [#814] Refresh identity and/or main unique key values - // [#1002] Consider also identity columns of non-updatable records - // [#1537] Avoid refreshing identity columns on batch inserts - Collection> key = null; - if (!TRUE.equals(create.configuration().data(Utils.DATA_OMIT_RETURNING_CLAUSE))) { - key = getReturning(); - insert.setReturning(key); - } - - int result = insert.execute(); - - if (result > 0) { - - // [#1596] If insert was successful, update timestamp and/or version columns - setRecordVersionAndTimestamp(version, timestamp); - - // If an insert was successful try fetching the generated IDENTITY value - if (key != null && !key.isEmpty()) { - if (insert.getReturnedRecord() != null) { - for (Field field : key) { - setValue(field, new Value(insert.getReturnedRecord().getValue(field))); - } - } - } - - changed(false); - } - - return result; - } - private final int storeUpdate(final TableField[] keys) { final int[] result = new int[1]; @@ -303,78 +232,6 @@ public class UpdatableRecordImpl> extends TableReco return result; } - /** - * Set all changed values of this record to a store query - */ - private final void addChangedValues(StoreQuery query) { - for (Field field : fields.fields.fields) { - if (getValue0(field).isChanged()) { - addValue(query, field); - } - } - } - - /** - * Extracted method to ensure generic type safety. - */ - private final void addValue(StoreQuery store, Field field, Object value) { - store.addValue(field, Utils.field(value, field)); - } - - /** - * Extracted method to ensure generic type safety. - */ - private final void addValue(StoreQuery store, Field field) { - addValue(store, field, getValue(field)); - } - - /** - * Set an updated timestamp value to a store query - */ - private final Timestamp addRecordTimestamp(StoreQuery store) { - Timestamp result = null; - - if (isTimestampOrVersionAvailable()) { - TableField timestamp = getTable().getRecordTimestamp(); - - if (timestamp != null) { - - // Use Timestamp locally, to provide maximum precision - result = new Timestamp(System.currentTimeMillis()); - addValue(store, timestamp, result); - } - } - - return result; - } - - /** - * Set an updated version value to a store query - */ - private final BigInteger addRecordVersion(StoreQuery store) { - BigInteger result = null; - - if (isTimestampOrVersionAvailable()) { - TableField version = getTable().getRecordVersion(); - - if (version != null) { - Number value = getValue(version); - - // Use BigInteger locally to avoid arithmetic overflows - if (value == null) { - result = BigInteger.ONE; - } - else { - result = new BigInteger(value.toString()).add(BigInteger.ONE); - } - - addValue(store, version, result); - } - } - - return result; - } - @Override public final int delete() { final int[] result = new int[1]; @@ -454,18 +311,6 @@ public class UpdatableRecordImpl> extends TableReco } } - private final Collection> getReturning() { - Collection> result = new LinkedHashSet>(); - - Identity identity = getTable().getIdentity(); - if (identity != null) { - result.add(identity.getField()); - } - - result.addAll(getPrimaryKey().getFields()); - return result; - } - @Override public final R copy() { return Utils.newRecord(getTable(), configuration()) @@ -515,10 +360,6 @@ public class UpdatableRecordImpl> extends TableReco if (t != null) Utils.addCondition(query, this, t); } - private final boolean isTimestampOrVersionAvailable() { - return getTable().getRecordTimestamp() != null || getTable().getRecordVersion() != null; - } - /** * Perform an additional SELECT .. FOR UPDATE to check if the underlying * database record has been changed compared to this record. @@ -569,19 +410,4 @@ public class UpdatableRecordImpl> extends TableReco throw new DataChangedException("Database record has been changed or doesn't exist any longer"); } } - - /** - * Set a generated version and timestamp value onto this record after - * successfully storing the record. - */ - private final void setRecordVersionAndTimestamp(BigInteger version, Timestamp timestamp) { - if (version != null) { - TableField field = getTable().getRecordVersion(); - setValue(field, new Value(field.getDataType().convert(version))); - } - if (timestamp != null) { - TableField field = getTable().getRecordTimestamp(); - setValue(field, new Value(field.getDataType().convert(timestamp))); - } - } }