mirror of https://github.com/apache/openjpa.git
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:
parent
ac1679d41c
commit
433475f6ad
|
@ -1634,7 +1634,7 @@ public abstract class MappingInfo {
|
|||
if (col.getDefaultString() != null)
|
||||
copy.setDefaultString(col.getDefaultString());
|
||||
if (col.isNotNull() && !col.isPrimaryKey()
|
||||
&& !isPrimitive(col.getJavaType()))
|
||||
&& (!isPrimitive(col.getJavaType()) || isForeignKey(col)))
|
||||
copy.setNotNull(true);
|
||||
|
||||
// set type name if not default
|
||||
|
@ -1674,6 +1674,21 @@ public abstract class MappingInfo {
|
|||
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.
|
||||
*/
|
||||
|
|
|
@ -180,7 +180,7 @@ public class RelationFieldStrategy
|
|||
OpenJPAStateManager rel = RelationStrategies.getStateManager
|
||||
(sm.fetchObjectField(field.getIndex()), store.getContext());
|
||||
if (field.getJoinDirection() == field.JOIN_INVERSE)
|
||||
updateInverse(sm, rel, store, rm, sm);
|
||||
updateInverse(sm, rel, store, rm);
|
||||
else {
|
||||
Row row = field.getRow(sm, store, rm, Row.ACTION_INSERT);
|
||||
if (row != null)
|
||||
|
@ -198,7 +198,7 @@ public class RelationFieldStrategy
|
|||
|
||||
if (field.getJoinDirection() == field.JOIN_INVERSE) {
|
||||
nullInverse(sm, rm);
|
||||
updateInverse(sm, rel, store, rm, sm);
|
||||
updateInverse(sm, rel, store, rm);
|
||||
} else {
|
||||
Row row = field.getRow(sm, store, rm, Row.ACTION_UPDATE);
|
||||
if (row != null)
|
||||
|
@ -215,7 +215,7 @@ public class RelationFieldStrategy
|
|||
if (sm.getLoaded().get(field.getIndex())) {
|
||||
OpenJPAStateManager rel = RelationStrategies.getStateManager(sm.
|
||||
fetchObjectField(field.getIndex()), store.getContext());
|
||||
updateInverse(sm, rel, store, rm, null);
|
||||
updateInverse(sm, rel, store, rm);
|
||||
} else
|
||||
nullInverse(sm, rm);
|
||||
} else {
|
||||
|
@ -241,6 +241,9 @@ public class RelationFieldStrategy
|
|||
*/
|
||||
private void nullInverse(OpenJPAStateManager sm, RowManager rm)
|
||||
throws SQLException {
|
||||
if (field.getUseClassCriteria())
|
||||
return;
|
||||
|
||||
ForeignKey fk = field.getForeignKey();
|
||||
ColumnIO io = field.getColumnIO();
|
||||
if (!io.isAnyUpdatable(fk, true))
|
||||
|
@ -260,11 +263,9 @@ public class RelationFieldStrategy
|
|||
* with the given object.
|
||||
*/
|
||||
private void updateInverse(OpenJPAStateManager sm, OpenJPAStateManager rel,
|
||||
JDBCStore store, RowManager rm, OpenJPAStateManager sm2)
|
||||
JDBCStore store, RowManager rm)
|
||||
throws SQLException {
|
||||
// nothing to do if inverse is null or about to be deleted
|
||||
//### should we throw an exception if the inverse is null?
|
||||
if (rel == null || rel.isDeleted())
|
||||
if (rel == null)
|
||||
return;
|
||||
|
||||
ForeignKey fk = field.getForeignKey();
|
||||
|
@ -272,11 +273,17 @@ public class RelationFieldStrategy
|
|||
|
||||
int action;
|
||||
if (rel.isNew() && !rel.isFlushed()) {
|
||||
if (sm2 == null || !io.isAnyInsertable(fk, false))
|
||||
if (sm.isDeleted() || !io.isAnyInsertable(fk, false))
|
||||
return;
|
||||
action = Row.ACTION_INSERT;
|
||||
} else if (rel.isDeleted()) {
|
||||
if (rel.isFlushed() || !sm.isDeleted())
|
||||
return;
|
||||
action = Row.ACTION_DELETE;
|
||||
} else {
|
||||
if (!io.isAnyUpdatable(fk, sm2 == null))
|
||||
if (sm.isDeleted())
|
||||
sm = null;
|
||||
if (!io.isAnyUpdatable(fk, sm == null))
|
||||
return;
|
||||
action = Row.ACTION_UPDATE;
|
||||
}
|
||||
|
@ -306,7 +313,7 @@ public class RelationFieldStrategy
|
|||
row.wherePrimaryKey(rel);
|
||||
|
||||
// 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,
|
||||
|
|
|
@ -216,23 +216,32 @@ public abstract class RelationToManyInverseKeyFieldStrategy
|
|||
|
||||
public void delete(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
|
||||
throws SQLException {
|
||||
if (field.getMappedBy() != null
|
||||
|| field.getElementMapping().getUseClassCriteria())
|
||||
if (field.getMappedBy() != null)
|
||||
return;
|
||||
|
||||
// if nullable, null any existing inverse columns that refer to this obj
|
||||
ValueMapping elem = field.getElementMapping();
|
||||
ColumnIO io = elem.getColumnIO();
|
||||
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;
|
||||
|
||||
// if the fk doesn't enforce it, null any existing inverse columns
|
||||
// that refer to this obj
|
||||
assertInversable();
|
||||
Row row = rm.getAllRows(fk.getTable(), Row.ACTION_UPDATE);
|
||||
row.setForeignKey(fk, io, null);
|
||||
row.whereForeignKey(fk, sm);
|
||||
rm.flushAllRows(row);
|
||||
// update fk on each field value row
|
||||
ClassMapping rel = field.getElementMapping().getTypeMapping();
|
||||
StoreContext ctx = store.getContext();
|
||||
Collection objs = toCollection(sm.fetchObject(field.getIndex()));
|
||||
if (objs != null && !objs.isEmpty())
|
||||
for (Iterator itr = objs.iterator(); itr.hasNext();)
|
||||
updateInverse (ctx, itr.next(), rel, rm, sm, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -244,7 +253,7 @@ public abstract class RelationToManyInverseKeyFieldStrategy
|
|||
throws SQLException {
|
||||
OpenJPAStateManager invsm = RelationStrategies.getStateManager(inverse,
|
||||
ctx);
|
||||
if (invsm == null || invsm.isDeleted())
|
||||
if (invsm == null)
|
||||
return;
|
||||
|
||||
ValueMapping elem = field.getElementMapping();
|
||||
|
@ -257,12 +266,21 @@ public abstract class RelationToManyInverseKeyFieldStrategy
|
|||
boolean orderWriteable;
|
||||
if (invsm.isNew() && !invsm.isFlushed()) {
|
||||
// no need to null inverse columns of new instance
|
||||
if (sm == null)
|
||||
if (sm == null || sm.isDeleted())
|
||||
return;
|
||||
writeable = io.isAnyInsertable(fk, false);
|
||||
orderWriteable = _orderInsert;
|
||||
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 {
|
||||
if (sm != null && sm.isDeleted())
|
||||
sm = null;
|
||||
writeable = io.isAnyUpdatable(fk, sm == null);
|
||||
orderWriteable = field.getOrderColumnIO().isUpdatable
|
||||
(order, sm == null);
|
||||
|
|
|
@ -80,7 +80,8 @@ public class ColumnIO {
|
|||
* Return true if any columns for the given key are insertable.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -203,7 +203,7 @@ public class ForeignKey
|
|||
seen.add(this);
|
||||
for (int i = 0; i < cols.length; i++) {
|
||||
for (int j = 0; j < fks.length; j++) {
|
||||
if (fks[j].getPrimaryKeyColumn(cols[i]) == null)
|
||||
if (!fks[j].containsColumn(cols[i]))
|
||||
continue;
|
||||
if (!seen.contains(fks[j])
|
||||
&& fks[j].isPrimaryKeyAutoAssigned(seen)) {
|
||||
|
|
|
@ -390,10 +390,11 @@ public class PCEnhancer {
|
|||
setter = _pc.getDeclaredMethod(getSetterName(fmds[i]),
|
||||
new Class[]{ fmds[i].getDeclaredType() });
|
||||
if (setter == null) {
|
||||
if (returned == null)
|
||||
if (returned == null) {
|
||||
addViolation("property-no-setter",
|
||||
new Object[]{ fmds[i] }, true);
|
||||
else {
|
||||
continue;
|
||||
} else {
|
||||
// create synthetic setter
|
||||
setter = _pc.declareMethod(getSetterName(fmds[i]),
|
||||
void.class, new Class[]{ fmds[i].getDeclaredType() });
|
||||
|
@ -419,10 +420,9 @@ public class PCEnhancer {
|
|||
_backingFields.put(setter.getName(), assigned.getName());
|
||||
|
||||
if (assigned != returned)
|
||||
addViolation("property-setter-getter-mismatch",
|
||||
new Object[]{ fmds[i], assigned.getName(),
|
||||
(returned == null) ? null : returned.getName() },
|
||||
false);
|
||||
addViolation("property-setter-getter-mismatch", new Object[]
|
||||
{ fmds[i], assigned.getName(), (returned == null)
|
||||
? null : returned.getName() }, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1928,8 +1928,7 @@ public class BrokerImpl
|
|||
exceps = add(exceps,
|
||||
newFlushException(_store.flush(transactional)));
|
||||
}
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
_flags &= ~FLAG_STORE_FLUSHING;
|
||||
|
||||
if (reason == FLUSH_ROLLBACK)
|
||||
|
@ -1942,21 +1941,24 @@ public class BrokerImpl
|
|||
StateManagerImpl sm;
|
||||
for (Iterator itr = transactional.iterator(); itr.hasNext();) {
|
||||
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
|
||||
// it is embedded and the owner has been deleted during
|
||||
// this flush process; bug #1100
|
||||
if (sm.getPCState() == PCState.TRANSIENT)
|
||||
continue;
|
||||
|
||||
sm.afterFlush(reason);
|
||||
if (reason == FLUSH_INC) {
|
||||
// if not about to clear trans cache for commit anyway,
|
||||
// re-cache dirty objects with default soft refs; we
|
||||
// don't need hard refs now that the changes have been
|
||||
// flushed
|
||||
sm.proxyFields(true, false);
|
||||
_transCache.flushed(sm);
|
||||
sm.afterFlush(reason);
|
||||
if (reason == FLUSH_INC) {
|
||||
// if not about to clear trans cache for commit
|
||||
// anyway, re-cache dirty objects with default soft
|
||||
// refs; we don't need hard refs now that the
|
||||
// changes have been flushed
|
||||
sm.proxyFields(true, false);
|
||||
_transCache.flushed(sm);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
exceps = add(exceps, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -194,7 +194,7 @@ public class DetachManager
|
|||
* needed. Return true if flushed/stored, false otherwise.
|
||||
*/
|
||||
private static boolean flushDirty(StateManagerImpl sm) {
|
||||
if (!sm.isDirty())
|
||||
if (!sm.isDirty() || !sm.getBroker().isActive())
|
||||
return false;
|
||||
|
||||
// only flush if there are actually any dirty non-flushed fields
|
||||
|
|
|
@ -332,7 +332,6 @@ public abstract class XMLMetaDataParser extends DefaultHandler
|
|||
// even if we want to validate, specify that it won't happen
|
||||
// if we have neither a DocType not a Schema
|
||||
Object schemaSource = getSchemaSource();
|
||||
|
||||
if (schemaSource != null && _schemaBug) {
|
||||
if (_log != null && _log.isInfoEnabled())
|
||||
_log.info(_loc.get("parser-schema-bug"));
|
||||
|
|
Loading…
Reference in New Issue