Amazingly, we had apparently never tried to insert a preconfigured row into a

table that had field generators on its primary key. The code just blindly
overwrite the supplied primary key and ran the generators anyway.

We now only run the generators if the record has no primary key. This means we
can't use field generators on non-primary-key fields, but I'm not sure we ever
meant to support that in the first place.
This commit is contained in:
Michael Bayne
2008-09-16 21:33:22 +00:00
parent e25aa25bd6
commit 84dd3c6b5f
2 changed files with 23 additions and 27 deletions
@@ -358,7 +358,9 @@ public class DepotMarshaller<T extends PersistentRecord>
int nulls = 0; int nulls = 0;
for (int ii = 0; ii < _pkColumns.size(); ii++) { for (int ii = 0; ii < _pkColumns.size(); ii++) {
FieldMarshaller<?> field = _pkColumns.get(ii); FieldMarshaller<?> field = _pkColumns.get(ii);
if ((values[ii] = (Comparable<?>)field.getField().get(object)) == null) { values[ii] = (Comparable<?>)field.getField().get(object);
if (values[ii] == null ||
(values[ii] instanceof Number && ((Number)values[ii]).intValue() == 0)) {
nulls++; nulls++;
} }
} }
@@ -474,14 +476,14 @@ public class DepotMarshaller<T extends PersistentRecord>
} }
/** /**
* Go through the registered {@link ValueGenerator}s for our persistent object and run the * Go through the registered {@link ValueGenerator}s for our persistent object and run the ones
* ones that match the current postFactum phase, filling in the fields on the supplied object * that match the current postFactum phase, filling in the fields on the supplied object while
* while we go. This method used to generate a key; that is now a separate step. * we go.
* *
* The return value is only non-empty for the !postFactum phase, in which case it is a set * The return value is only non-empty for the !postFactum phase, in which case it is a set of
* of field names that are associated with {@link IdentityValueGenerator}, because these need * field names that are associated with {@link IdentityValueGenerator}, because these need
* special handling in the INSERT (specifically, 'DEFAULT' must be supplied as a value in * special handling in the INSERT (specifically, 'DEFAULT' must be supplied as a value in the
* the eventual SQL). * eventual SQL).
*/ */
public Set<String> generateFieldValues ( public Set<String> generateFieldValues (
Connection conn, DatabaseLiaison liaison, Object po, boolean postFactum) Connection conn, DatabaseLiaison liaison, Object po, boolean postFactum)
@@ -315,12 +315,11 @@ public abstract class DepotRepository
return _ctx.invoke(new CachingModifier<T>(record, key, key) { return _ctx.invoke(new CachingModifier<T>(record, key, key) {
@Override @Override
public int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { public int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
// set any auto-generated column values
Set<String> identityFields =
marsh.generateFieldValues(conn, liaison, _result, false);
// if needed, update our modifier's key so that it can cache our results // if needed, update our modifier's key so that it can cache our results
Set<String> identityFields = Collections.emptySet();
if (_key == null) { if (_key == null) {
// set any auto-generated column values
identityFields = marsh.generateFieldValues(conn, liaison, _result, false);
updateKey(marsh.getPrimaryKey(_result, false)); updateKey(marsh.getPrimaryKey(_result, false));
} }
@@ -329,15 +328,13 @@ public abstract class DepotRepository
PreparedStatement stmt = builder.prepare(conn); PreparedStatement stmt = builder.prepare(conn);
try { try {
int mods = stmt.executeUpdate(); int mods = stmt.executeUpdate();
// run any post-factum value generators and potentially generate our key
// run any post-factum value generators
marsh.generateFieldValues(conn, liaison, _result, true);
// and check once more if a key now exists
if (_key == null) { if (_key == null) {
marsh.generateFieldValues(conn, liaison, _result, true);
updateKey(marsh.getPrimaryKey(_result, false)); updateKey(marsh.getPrimaryKey(_result, false));
} }
return mods; return mods;
} finally { } finally {
JDBCUtil.close(stmt); JDBCUtil.close(stmt);
} }
@@ -739,13 +736,12 @@ public abstract class DepotRepository
JDBCUtil.close(stmt); JDBCUtil.close(stmt);
} }
// if the update modified zero rows or the primary key was obviously unset, do // if the update modified zero rows or the primary key was unset, insert
// an insertion: first, set any auto-generated column values Set<String> identityFields = Collections.emptySet();
Set<String> identityFields =
marsh.generateFieldValues(conn, liaison, _result, false);
// update our modifier's key so that it can cache our results
if (_key == null) { if (_key == null) {
// first, set any auto-generated column values
identityFields = marsh.generateFieldValues(conn, liaison, _result, false);
// update our modifier's key so that it can cache our results
updateKey(marsh.getPrimaryKey(_result, false)); updateKey(marsh.getPrimaryKey(_result, false));
} }
@@ -754,11 +750,9 @@ public abstract class DepotRepository
stmt = builder.prepare(conn); stmt = builder.prepare(conn);
int mods = stmt.executeUpdate(); int mods = stmt.executeUpdate();
// run any post-factum value generators // run any post-factum value generators and potentially generate our key
marsh.generateFieldValues(conn, liaison, _result, true);
// and check once more if a key now exists
if (_key == null) { if (_key == null) {
marsh.generateFieldValues(conn, liaison, _result, true);
updateKey(marsh.getPrimaryKey(_result, false)); updateKey(marsh.getPrimaryKey(_result, false));
} }
created[0] = true; created[0] = true;