Merge fixes from Kodo 4.0 line.

git-svn-id: https://svn.apache.org/repos/asf/incubator/openjpa/trunk@453796 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
A. Abram White 2006-10-06 22:31:28 +00:00
parent ac1679d41c
commit 433475f6ad
9 changed files with 108 additions and 52 deletions

View File

@ -1634,7 +1634,7 @@ public abstract class MappingInfo {
if (col.getDefaultString() != null) if (col.getDefaultString() != null)
copy.setDefaultString(col.getDefaultString()); copy.setDefaultString(col.getDefaultString());
if (col.isNotNull() && !col.isPrimaryKey() if (col.isNotNull() && !col.isPrimaryKey()
&& !isPrimitive(col.getJavaType())) && (!isPrimitive(col.getJavaType()) || isForeignKey(col)))
copy.setNotNull(true); copy.setNotNull(true);
// set type name if not default // set type name if not default
@ -1674,6 +1674,21 @@ public abstract class MappingInfo {
return copy; return copy;
} }
/**
* Return whether the given column belongs to a foreign key.
*/
private static boolean isForeignKey(Column col)
{
if (col.getTable() == null)
return false;
ForeignKey[] fks = col.getTable().getForeignKeys();
for (int i = 0; i < fks.length; i++)
if (fks[i].containsColumn(col)
|| fks[i].containsConstantColumn(col))
return true;
return false;
}
/** /**
* Return true if the given type code represents a primitive. * Return true if the given type code represents a primitive.
*/ */

View File

@ -180,7 +180,7 @@ public class RelationFieldStrategy
OpenJPAStateManager rel = RelationStrategies.getStateManager OpenJPAStateManager rel = RelationStrategies.getStateManager
(sm.fetchObjectField(field.getIndex()), store.getContext()); (sm.fetchObjectField(field.getIndex()), store.getContext());
if (field.getJoinDirection() == field.JOIN_INVERSE) if (field.getJoinDirection() == field.JOIN_INVERSE)
updateInverse(sm, rel, store, rm, sm); updateInverse(sm, rel, store, rm);
else { else {
Row row = field.getRow(sm, store, rm, Row.ACTION_INSERT); Row row = field.getRow(sm, store, rm, Row.ACTION_INSERT);
if (row != null) if (row != null)
@ -198,7 +198,7 @@ public class RelationFieldStrategy
if (field.getJoinDirection() == field.JOIN_INVERSE) { if (field.getJoinDirection() == field.JOIN_INVERSE) {
nullInverse(sm, rm); nullInverse(sm, rm);
updateInverse(sm, rel, store, rm, sm); updateInverse(sm, rel, store, rm);
} else { } else {
Row row = field.getRow(sm, store, rm, Row.ACTION_UPDATE); Row row = field.getRow(sm, store, rm, Row.ACTION_UPDATE);
if (row != null) if (row != null)
@ -215,7 +215,7 @@ public class RelationFieldStrategy
if (sm.getLoaded().get(field.getIndex())) { if (sm.getLoaded().get(field.getIndex())) {
OpenJPAStateManager rel = RelationStrategies.getStateManager(sm. OpenJPAStateManager rel = RelationStrategies.getStateManager(sm.
fetchObjectField(field.getIndex()), store.getContext()); fetchObjectField(field.getIndex()), store.getContext());
updateInverse(sm, rel, store, rm, null); updateInverse(sm, rel, store, rm);
} else } else
nullInverse(sm, rm); nullInverse(sm, rm);
} else { } else {
@ -241,6 +241,9 @@ public class RelationFieldStrategy
*/ */
private void nullInverse(OpenJPAStateManager sm, RowManager rm) private void nullInverse(OpenJPAStateManager sm, RowManager rm)
throws SQLException { throws SQLException {
if (field.getUseClassCriteria())
return;
ForeignKey fk = field.getForeignKey(); ForeignKey fk = field.getForeignKey();
ColumnIO io = field.getColumnIO(); ColumnIO io = field.getColumnIO();
if (!io.isAnyUpdatable(fk, true)) if (!io.isAnyUpdatable(fk, true))
@ -260,11 +263,9 @@ public class RelationFieldStrategy
* with the given object. * with the given object.
*/ */
private void updateInverse(OpenJPAStateManager sm, OpenJPAStateManager rel, private void updateInverse(OpenJPAStateManager sm, OpenJPAStateManager rel,
JDBCStore store, RowManager rm, OpenJPAStateManager sm2) JDBCStore store, RowManager rm)
throws SQLException { throws SQLException {
// nothing to do if inverse is null or about to be deleted if (rel == null)
//### should we throw an exception if the inverse is null?
if (rel == null || rel.isDeleted())
return; return;
ForeignKey fk = field.getForeignKey(); ForeignKey fk = field.getForeignKey();
@ -272,11 +273,17 @@ public class RelationFieldStrategy
int action; int action;
if (rel.isNew() && !rel.isFlushed()) { if (rel.isNew() && !rel.isFlushed()) {
if (sm2 == null || !io.isAnyInsertable(fk, false)) if (sm.isDeleted() || !io.isAnyInsertable(fk, false))
return; return;
action = Row.ACTION_INSERT; action = Row.ACTION_INSERT;
} else if (rel.isDeleted()) {
if (rel.isFlushed() || !sm.isDeleted())
return;
action = Row.ACTION_DELETE;
} else { } else {
if (!io.isAnyUpdatable(fk, sm2 == null)) if (sm.isDeleted())
sm = null;
if (!io.isAnyUpdatable(fk, sm == null))
return; return;
action = Row.ACTION_UPDATE; action = Row.ACTION_UPDATE;
} }
@ -306,7 +313,7 @@ public class RelationFieldStrategy
row.wherePrimaryKey(rel); row.wherePrimaryKey(rel);
// update the inverse pointer with our oid value // update the inverse pointer with our oid value
row.setForeignKey(fk, io, sm2); row.setForeignKey(fk, io, sm);
} }
public int supportsSelect(Select sel, int type, OpenJPAStateManager sm, public int supportsSelect(Select sel, int type, OpenJPAStateManager sm,

View File

@ -216,23 +216,32 @@ public abstract class RelationToManyInverseKeyFieldStrategy
public void delete(OpenJPAStateManager sm, JDBCStore store, RowManager rm) public void delete(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
throws SQLException { throws SQLException {
if (field.getMappedBy() != null if (field.getMappedBy() != null)
|| field.getElementMapping().getUseClassCriteria())
return; return;
// if nullable, null any existing inverse columns that refer to this obj
ValueMapping elem = field.getElementMapping(); ValueMapping elem = field.getElementMapping();
ColumnIO io = elem.getColumnIO(); ColumnIO io = elem.getColumnIO();
ForeignKey fk = elem.getForeignKey(); ForeignKey fk = elem.getForeignKey();
if (!io.isAnyUpdatable(fk, true)) if (!elem.getUseClassCriteria() && io.isAnyUpdatable(fk, true)) {
assertInversable();
Row row = rm.getAllRows(fk.getTable(), Row.ACTION_UPDATE);
row.setForeignKey(fk, io, null);
row.whereForeignKey(fk, sm);
rm.flushAllRows(row);
return;
}
if (!sm.getLoaded().get(field.getIndex()))
return; return;
// if the fk doesn't enforce it, null any existing inverse columns // update fk on each field value row
// that refer to this obj ClassMapping rel = field.getElementMapping().getTypeMapping();
assertInversable(); StoreContext ctx = store.getContext();
Row row = rm.getAllRows(fk.getTable(), Row.ACTION_UPDATE); Collection objs = toCollection(sm.fetchObject(field.getIndex()));
row.setForeignKey(fk, io, null); if (objs != null && !objs.isEmpty())
row.whereForeignKey(fk, sm); for (Iterator itr = objs.iterator(); itr.hasNext();)
rm.flushAllRows(row); updateInverse (ctx, itr.next(), rel, rm, sm, 0);
} }
/** /**
@ -244,7 +253,7 @@ public abstract class RelationToManyInverseKeyFieldStrategy
throws SQLException { throws SQLException {
OpenJPAStateManager invsm = RelationStrategies.getStateManager(inverse, OpenJPAStateManager invsm = RelationStrategies.getStateManager(inverse,
ctx); ctx);
if (invsm == null || invsm.isDeleted()) if (invsm == null)
return; return;
ValueMapping elem = field.getElementMapping(); ValueMapping elem = field.getElementMapping();
@ -257,12 +266,21 @@ public abstract class RelationToManyInverseKeyFieldStrategy
boolean orderWriteable; boolean orderWriteable;
if (invsm.isNew() && !invsm.isFlushed()) { if (invsm.isNew() && !invsm.isFlushed()) {
// no need to null inverse columns of new instance // no need to null inverse columns of new instance
if (sm == null) if (sm == null || sm.isDeleted())
return; return;
writeable = io.isAnyInsertable(fk, false); writeable = io.isAnyInsertable(fk, false);
orderWriteable = _orderInsert; orderWriteable = _orderInsert;
action = Row.ACTION_INSERT; action = Row.ACTION_INSERT;
} else if (invsm.isDeleted()) {
// no need to null inverse columns of deleted instance
if (invsm.isFlushed() || sm == null || !sm.isDeleted())
return;
writeable = true;
orderWriteable = false;
action = Row.ACTION_DELETE;
} else { } else {
if (sm != null && sm.isDeleted())
sm = null;
writeable = io.isAnyUpdatable(fk, sm == null); writeable = io.isAnyUpdatable(fk, sm == null);
orderWriteable = field.getOrderColumnIO().isUpdatable orderWriteable = field.getOrderColumnIO().isUpdatable
(order, sm == null); (order, sm == null);

View File

@ -80,7 +80,8 @@ public class ColumnIO {
* Return true if any columns for the given key are insertable. * Return true if any columns for the given key are insertable.
*/ */
public boolean isAnyInsertable(ForeignKey fk, boolean nullValue) { public boolean isAnyInsertable(ForeignKey fk, boolean nullValue) {
return isAny(fk, _unInsertable, _unNullInsertable, nullValue); return isAny(fk, _unInsertable, _unNullInsertable, nullValue)
&& (!nullValue || fk.isLogical() || isNullable(fk));
} }
/** /**
@ -101,7 +102,8 @@ public class ColumnIO {
* Return true if all columns for the given key are insertable. * Return true if all columns for the given key are insertable.
*/ */
public boolean isAllInsertable(ForeignKey fk, boolean nullValue) { public boolean isAllInsertable(ForeignKey fk, boolean nullValue) {
return isAll(fk, _unInsertable, _unNullInsertable, nullValue); return isAll(fk, _unInsertable, _unNullInsertable, nullValue)
&& (!nullValue || fk.isLogical() || isNullable(fk));
} }
/** /**
@ -152,7 +154,8 @@ public class ColumnIO {
* Return true if any columns for the given key are updatable. * Return true if any columns for the given key are updatable.
*/ */
public boolean isAnyUpdatable(ForeignKey fk, boolean nullValue) { public boolean isAnyUpdatable(ForeignKey fk, boolean nullValue) {
return isAny(fk, _unUpdatable, _unNullUpdatable, nullValue); return isAny(fk, _unUpdatable, _unNullUpdatable, nullValue)
&& (!nullValue || fk.isLogical() || isNullable(fk));
} }
/** /**
@ -173,7 +176,8 @@ public class ColumnIO {
* Return true if all columns for the given key are updatable. * Return true if all columns for the given key are updatable.
*/ */
public boolean isAllUpdatable(ForeignKey fk, boolean nullValue) { public boolean isAllUpdatable(ForeignKey fk, boolean nullValue) {
return isAll(fk, _unUpdatable, _unNullUpdatable, nullValue); return isAll(fk, _unUpdatable, _unNullUpdatable, nullValue)
&& (!nullValue || fk.isLogical() || isNullable(fk));
} }
/** /**
@ -284,4 +288,15 @@ public class ColumnIO {
return property & ~(2 << col); return property & ~(2 << col);
return property | (2 << col); return property | (2 << col);
} }
/**
* Whether the given foreign key is nullable.
*/
private boolean isNullable(ForeignKey fk) {
Column[] cols = fk.getColumns();
for (int i = 0; i < cols.length; i++)
if (cols[i].isNotNull() || cols[i].isPrimaryKey())
return false;
return true;
}
} }

View File

@ -203,7 +203,7 @@ public class ForeignKey
seen.add(this); seen.add(this);
for (int i = 0; i < cols.length; i++) { for (int i = 0; i < cols.length; i++) {
for (int j = 0; j < fks.length; j++) { for (int j = 0; j < fks.length; j++) {
if (fks[j].getPrimaryKeyColumn(cols[i]) == null) if (!fks[j].containsColumn(cols[i]))
continue; continue;
if (!seen.contains(fks[j]) if (!seen.contains(fks[j])
&& fks[j].isPrimaryKeyAutoAssigned(seen)) { && fks[j].isPrimaryKeyAutoAssigned(seen)) {

View File

@ -390,10 +390,11 @@ public class PCEnhancer {
setter = _pc.getDeclaredMethod(getSetterName(fmds[i]), setter = _pc.getDeclaredMethod(getSetterName(fmds[i]),
new Class[]{ fmds[i].getDeclaredType() }); new Class[]{ fmds[i].getDeclaredType() });
if (setter == null) { if (setter == null) {
if (returned == null) if (returned == null) {
addViolation("property-no-setter", addViolation("property-no-setter",
new Object[]{ fmds[i] }, true); new Object[]{ fmds[i] }, true);
else { continue;
} else {
// create synthetic setter // create synthetic setter
setter = _pc.declareMethod(getSetterName(fmds[i]), setter = _pc.declareMethod(getSetterName(fmds[i]),
void.class, new Class[]{ fmds[i].getDeclaredType() }); void.class, new Class[]{ fmds[i].getDeclaredType() });
@ -419,10 +420,9 @@ public class PCEnhancer {
_backingFields.put(setter.getName(), assigned.getName()); _backingFields.put(setter.getName(), assigned.getName());
if (assigned != returned) if (assigned != returned)
addViolation("property-setter-getter-mismatch", addViolation("property-setter-getter-mismatch", new Object[]
new Object[]{ fmds[i], assigned.getName(), { fmds[i], assigned.getName(), (returned == null)
(returned == null) ? null : returned.getName() }, ? null : returned.getName() }, false);
false);
} }
} }
} }

View File

@ -1928,8 +1928,7 @@ public class BrokerImpl
exceps = add(exceps, exceps = add(exceps,
newFlushException(_store.flush(transactional))); newFlushException(_store.flush(transactional)));
} }
} } finally {
finally {
_flags &= ~FLAG_STORE_FLUSHING; _flags &= ~FLAG_STORE_FLUSHING;
if (reason == FLUSH_ROLLBACK) if (reason == FLUSH_ROLLBACK)
@ -1942,21 +1941,24 @@ public class BrokerImpl
StateManagerImpl sm; StateManagerImpl sm;
for (Iterator itr = transactional.iterator(); itr.hasNext();) { for (Iterator itr = transactional.iterator(); itr.hasNext();) {
sm = (StateManagerImpl) itr.next(); sm = (StateManagerImpl) itr.next();
try {
// the state may have become transient, such as if
// it is embedded and the owner has been deleted during
// this flush process; bug #1100
if (sm.getPCState() == PCState.TRANSIENT)
continue;
// the state may have become transient, such as if sm.afterFlush(reason);
// it is embedded and the owner has been deleted during if (reason == FLUSH_INC) {
// this flush process; bug #1100 // if not about to clear trans cache for commit
if (sm.getPCState() == PCState.TRANSIENT) // anyway, re-cache dirty objects with default soft
continue; // refs; we don't need hard refs now that the
// changes have been flushed
sm.afterFlush(reason); sm.proxyFields(true, false);
if (reason == FLUSH_INC) { _transCache.flushed(sm);
// if not about to clear trans cache for commit anyway, }
// re-cache dirty objects with default soft refs; we } catch (Exception e) {
// don't need hard refs now that the changes have been exceps = add(exceps, e);
// flushed
sm.proxyFields(true, false);
_transCache.flushed(sm);
} }
} }
} }

View File

@ -194,7 +194,7 @@ public class DetachManager
* needed. Return true if flushed/stored, false otherwise. * needed. Return true if flushed/stored, false otherwise.
*/ */
private static boolean flushDirty(StateManagerImpl sm) { private static boolean flushDirty(StateManagerImpl sm) {
if (!sm.isDirty()) if (!sm.isDirty() || !sm.getBroker().isActive())
return false; return false;
// only flush if there are actually any dirty non-flushed fields // only flush if there are actually any dirty non-flushed fields

View File

@ -332,7 +332,6 @@ public abstract class XMLMetaDataParser extends DefaultHandler
// even if we want to validate, specify that it won't happen // even if we want to validate, specify that it won't happen
// if we have neither a DocType not a Schema // if we have neither a DocType not a Schema
Object schemaSource = getSchemaSource(); Object schemaSource = getSchemaSource();
if (schemaSource != null && _schemaBug) { if (schemaSource != null && _schemaBug) {
if (_log != null && _log.isInfoEnabled()) if (_log != null && _log.isInfoEnabled())
_log.info(_loc.get("parser-schema-bug")); _log.info(_loc.get("parser-schema-bug"));