[#3253] Pull up TableRecord.insert()
This commit is contained in:
parent
358fa06035
commit
3cf66dd99d
@ -61,6 +61,21 @@ public interface TableRecord<R extends TableRecord<R>> extends Record {
|
||||
@Override
|
||||
R original();
|
||||
|
||||
/**
|
||||
* Store this record to the database using an <code>INSERT</code>
|
||||
* statement.
|
||||
* <p>
|
||||
* 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 <code>1</code> if the record was stored to the database. <code>0
|
||||
* </code> 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
|
||||
* <p>
|
||||
|
||||
@ -241,6 +241,7 @@ public interface UpdatableRecord<R extends UpdatableRecord<R>> extends TableReco
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @see #store()
|
||||
*/
|
||||
@Override
|
||||
int insert() throws DataAccessException;
|
||||
|
||||
/**
|
||||
|
||||
@ -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<R extends TableRecord<R>> extends AbstractRecord im
|
||||
public final <O extends UpdatableRecord<O>> O fetchParent(ForeignKey<R, O> 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<Record, RuntimeException>() {
|
||||
|
||||
@Override
|
||||
public Record operate(Record record) throws RuntimeException {
|
||||
result[0] = storeInsert0();
|
||||
return record;
|
||||
}
|
||||
});
|
||||
|
||||
return result[0];
|
||||
}
|
||||
|
||||
final int storeInsert0() {
|
||||
DSLContext create = create();
|
||||
InsertQuery<R> 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<Field<?>> 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<Object>(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<R, ?> field = getTable().getRecordVersion();
|
||||
setValue(field, new Value<Object>(field.getDataType().convert(version)));
|
||||
}
|
||||
if (timestamp != null) {
|
||||
TableField<R, ?> field = getTable().getRecordTimestamp();
|
||||
setValue(field, new Value<Object>(field.getDataType().convert(timestamp)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all changed values of this record to a store query
|
||||
*/
|
||||
final void addChangedValues(StoreQuery<R> query) {
|
||||
for (Field<?> field : fields.fields.fields) {
|
||||
if (getValue0(field).isChanged()) {
|
||||
addValue(query, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracted method to ensure generic type safety.
|
||||
*/
|
||||
final <T> void addValue(StoreQuery<?> store, Field<T> field, Object value) {
|
||||
store.addValue(field, Utils.field(value, field));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracted method to ensure generic type safety.
|
||||
*/
|
||||
final <T> void addValue(StoreQuery<?> store, Field<T> 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<R, ? extends java.util.Date> 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<R, ? extends Number> 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<Field<?>> getReturning() {
|
||||
Collection<Field<?>> result = new LinkedHashSet<Field<?>>();
|
||||
|
||||
Identity<R, ?> identity = getTable().getIdentity();
|
||||
if (identity != null) {
|
||||
result.add(identity.getField());
|
||||
}
|
||||
|
||||
result.addAll(getPrimaryKey().getFields());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<R extends UpdatableRecord<R>> 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<R extends UpdatableRecord<R>> extends TableReco
|
||||
return result;
|
||||
}
|
||||
|
||||
private final int storeInsert() {
|
||||
final int[] result = new int[1];
|
||||
|
||||
delegate(configuration(), (Record) this, INSERT)
|
||||
.operate(new RecordOperation<Record, RuntimeException>() {
|
||||
|
||||
@Override
|
||||
public Record operate(Record record) throws RuntimeException {
|
||||
result[0] = storeInsert0();
|
||||
return record;
|
||||
}
|
||||
});
|
||||
|
||||
return result[0];
|
||||
}
|
||||
|
||||
private final int storeInsert0() {
|
||||
DSLContext create = create();
|
||||
InsertQuery<R> 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<Field<?>> 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<Object>(insert.getReturnedRecord().getValue(field)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changed(false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private final int storeUpdate(final TableField<R, ?>[] keys) {
|
||||
final int[] result = new int[1];
|
||||
|
||||
@ -303,78 +232,6 @@ public class UpdatableRecordImpl<R extends UpdatableRecord<R>> extends TableReco
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all changed values of this record to a store query
|
||||
*/
|
||||
private final void addChangedValues(StoreQuery<R> query) {
|
||||
for (Field<?> field : fields.fields.fields) {
|
||||
if (getValue0(field).isChanged()) {
|
||||
addValue(query, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracted method to ensure generic type safety.
|
||||
*/
|
||||
private final <T> void addValue(StoreQuery<?> store, Field<T> field, Object value) {
|
||||
store.addValue(field, Utils.field(value, field));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracted method to ensure generic type safety.
|
||||
*/
|
||||
private final <T> void addValue(StoreQuery<?> store, Field<T> 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<R, ? extends java.util.Date> 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<R, ? extends Number> 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<R extends UpdatableRecord<R>> extends TableReco
|
||||
}
|
||||
}
|
||||
|
||||
private final Collection<Field<?>> getReturning() {
|
||||
Collection<Field<?>> result = new LinkedHashSet<Field<?>>();
|
||||
|
||||
Identity<R, ?> 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<R extends UpdatableRecord<R>> 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<R extends UpdatableRecord<R>> 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<R, ?> field = getTable().getRecordVersion();
|
||||
setValue(field, new Value<Object>(field.getDataType().convert(version)));
|
||||
}
|
||||
if (timestamp != null) {
|
||||
TableField<R, ?> field = getTable().getRecordTimestamp();
|
||||
setValue(field, new Value<Object>(field.getDataType().convert(timestamp)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user