OPENJPA:2099: Cacheing select construct with class/field strategy. Adding configuration

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@1232415 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Pinaki Poddar 2012-01-17 14:04:07 +00:00
parent 5bb79b9309
commit 1a50b5fe76
20 changed files with 598 additions and 423 deletions

View File

@ -629,4 +629,24 @@ public interface JDBCConfiguration
*/ */
public void setIdentifierUtil(DBIdentifierUtil util); public void setIdentifierUtil(DBIdentifierUtil util);
/**
* Affirms if select statements are aggressively cached.
* An aggressive select cache assumes that {@link FetchConfiguration fetch plan}
* does not change between execution.
*
* @return false by default.
*
* @since 2.2.0
*/
public boolean getSelectCacheEnabled();
/**
* Sets if select statements are aggressively cached.
* An aggressive select cache assumes that {@link FetchConfiguration fetch plan}
* does not change between execution.
*
* @since 2.2.0
*/
public void setSelectCacheEnabled(boolean enable);
} }

View File

@ -43,6 +43,8 @@ import org.apache.openjpa.jdbc.sql.MaxDBDictionary;
import org.apache.openjpa.jdbc.sql.SQLFactory; import org.apache.openjpa.jdbc.sql.SQLFactory;
import org.apache.openjpa.kernel.BrokerImpl; import org.apache.openjpa.kernel.BrokerImpl;
import org.apache.openjpa.kernel.StoreContext; import org.apache.openjpa.kernel.StoreContext;
import org.apache.openjpa.lib.conf.BooleanValue;
import org.apache.openjpa.lib.conf.ImmutableBooleanValue;
import org.apache.openjpa.lib.conf.IntValue; import org.apache.openjpa.lib.conf.IntValue;
import org.apache.openjpa.lib.conf.ObjectValue; import org.apache.openjpa.lib.conf.ObjectValue;
import org.apache.openjpa.lib.conf.PluginValue; import org.apache.openjpa.lib.conf.PluginValue;
@ -87,6 +89,7 @@ public class JDBCConfigurationImpl
public PluginValue driverDataSourcePlugin; public PluginValue driverDataSourcePlugin;
public MappingFactoryValue mappingFactoryPlugin; public MappingFactoryValue mappingFactoryPlugin;
public ObjectValue identifierUtilPlugin; public ObjectValue identifierUtilPlugin;
public ImmutableBooleanValue cacheSelect;
// used internally // used internally
private String firstUser = null; private String firstUser = null;
@ -350,6 +353,9 @@ public class JDBCConfigurationImpl
identifierUtilPlugin.setString(aliases[0]); identifierUtilPlugin.setString(aliases[0]);
identifierUtilPlugin.setInstantiatingGetter("getIdentifierUtilInstance"); identifierUtilPlugin.setInstantiatingGetter("getIdentifierUtilInstance");
cacheSelect = new ImmutableBooleanValue("jdbc.CachesSelect");
addValue(cacheSelect);
cacheSelect.setDefault("false");
// this static initializer is to get past a weird // this static initializer is to get past a weird
// ClassCircularityError that happens only under IBM's // ClassCircularityError that happens only under IBM's
@ -997,4 +1003,12 @@ public class JDBCConfigurationImpl
identifierUtilPlugin.set(util); identifierUtilPlugin.set(util);
} }
public boolean getSelectCacheEnabled() {
return cacheSelect.get();
}
public void setSelectCacheEnabled(boolean enable) {
cacheSelect.set(enable);
}
} }

View File

@ -260,9 +260,9 @@ public class JDBCStoreManager implements StoreManager, JDBCStore {
private boolean exists(ClassMapping mapping, Object oid, Object context) { private boolean exists(ClassMapping mapping, Object oid, Object context) {
// add where conditions on base class to avoid joins if subclass // add where conditions on base class to avoid joins if subclass
// doesn't use oid as identifier // doesn't use oid as identifier
Select sel = _sql.newSelect();
while (mapping.getJoinablePCSuperclassMapping() != null) while (mapping.getJoinablePCSuperclassMapping() != null)
mapping = mapping.getJoinablePCSuperclassMapping(); mapping = mapping.getJoinablePCSuperclassMapping();
Select sel = mapping.getSelect();
sel.wherePrimaryKey(oid, mapping, this); sel.wherePrimaryKey(oid, mapping, this);
if (_log.isTraceEnabled()) { if (_log.isTraceEnabled()) {
@ -301,8 +301,7 @@ public class JDBCStoreManager implements StoreManager, JDBCStore {
FetchConfiguration fetch, Object context) { FetchConfiguration fetch, Object context) {
ConnectionInfo info = (ConnectionInfo) context; ConnectionInfo info = (ConnectionInfo) context;
try { try {
return initializeState(sm, state, (JDBCFetchConfiguration) fetch, return initializeState(sm, state, (JDBCFetchConfiguration) fetch, info);
info);
} catch (ClassNotFoundException cnfe) { } catch (ClassNotFoundException cnfe) {
throw new UserException(cnfe); throw new UserException(cnfe);
} catch (SQLException se) { } catch (SQLException se) {
@ -332,27 +331,24 @@ public class JDBCStoreManager implements StoreManager, JDBCStore {
Boolean custom = customLoad(sm, mapping, state, fetch); Boolean custom = customLoad(sm, mapping, state, fetch);
if (custom != null) if (custom != null)
return custom.booleanValue(); return custom.booleanValue();
res = getInitializeStateResult(sm, mapping, fetch, res = getInitializeStateResult(sm, mapping, fetch, Select.SUBS_EXACT);
Select.SUBS_EXACT);
if (res == null && !selectPrimaryKey(sm, mapping, fetch)) if (res == null && !selectPrimaryKey(sm, mapping, fetch))
return false; return false;
if (isEmptyResult(res)) if (isEmptyResult(res))
return false; return false;
} else { } else {
ClassMapping[] mappings = mapping. ClassMapping[] mappings = mapping.getIndependentAssignableMappings();
getIndependentAssignableMappings();
if (mappings.length == 1) { if (mappings.length == 1) {
mapping = mappings[0]; mapping = mappings[0];
Boolean custom = customLoad(sm, mapping, state, fetch); Boolean custom = customLoad(sm, mapping, state, fetch);
if (custom != null) if (custom != null)
return custom.booleanValue(); return custom.booleanValue();
res = getInitializeStateResult(sm, mapping, fetch, res = getInitializeStateResult(sm, mapping, fetch, Select.SUBS_ANY_JOINABLE);
Select.SUBS_ANY_JOINABLE);
if (res == null && !selectPrimaryKey(sm, mapping, fetch)) if (res == null && !selectPrimaryKey(sm, mapping, fetch))
return false; return false;
} else } else {
res = getInitializeStateUnionResult(sm, mapping, mappings, res = getInitializeStateUnionResult(sm, mapping, mappings, fetch);
fetch); }
if (isEmptyResult(res)) if (isEmptyResult(res))
return false; return false;
} }
@ -365,8 +361,7 @@ public class JDBCStoreManager implements StoreManager, JDBCStore {
mapping = res.getBaseMapping(); mapping = res.getBaseMapping();
res.startDataRequest(mapping.getDiscriminator()); res.startDataRequest(mapping.getDiscriminator());
try { try {
type = mapping.getDiscriminator().getClass(this, mapping, type = mapping.getDiscriminator().getClass(this, mapping, res);
res);
} finally { } finally {
res.endDataRequest(); res.endDataRequest();
} }
@ -378,19 +373,15 @@ public class JDBCStoreManager implements StoreManager, JDBCStore {
sm.initialize(type, state); sm.initialize(type, state);
if (info != null && info.result != null) { if (info != null && info.result != null) {
FieldMapping mappedByFieldMapping = info.result. FieldMapping mappedByFieldMapping = info.result.getMappedByFieldMapping();
getMappedByFieldMapping();
Object mappedByObject = info.result.getMappedByValue(); Object mappedByObject = info.result.getMappedByValue();
if (mappedByFieldMapping != null && mappedByObject != null) if (mappedByFieldMapping != null && mappedByObject != null)
if (mappedByObject instanceof OpenJPAId && if (mappedByObject instanceof OpenJPAId &&
mapping.getExtraFieldDataIndex(mappedByFieldMapping.getIndex()) != -1) { mapping.getExtraFieldDataIndex(mappedByFieldMapping.getIndex()) != -1) {
// The inverse relation can not be set since // The inverse relation can not be set since we are eagerly loading this sm for
// we are eagerly loading this sm for // an owner that is still in the process of initializing itself.
// a sm owner that is still in the process of
// initializing itself.
// Remember owner oid by setIntermediate(). // Remember owner oid by setIntermediate().
// The inverse relation is set later by // The inverse relation is set later by setInverseRelation() when the owner is fully
// setInverseRelation() when the sm owner is fully
// initialized. // initialized.
int index = mappedByFieldMapping.getIndex(); int index = mappedByFieldMapping.getIndex();
if (sm.getLoaded().get(index)) { if (sm.getLoaded().get(index)) {
@ -535,7 +526,7 @@ public class JDBCStoreManager implements StoreManager, JDBCStore {
FinderQueryImpl fq = getFinder(mapping, fetch); FinderQueryImpl fq = getFinder(mapping, fetch);
if (fq != null) if (fq != null)
return fq.execute(sm, this, fetch); return fq.execute(sm, this, fetch);
Select sel = _sql.newSelect(); Select sel = mapping.getSelect();
if (!select(sel, mapping, subs, sm, null, fetch, if (!select(sel, mapping, subs, sm, null, fetch,
JDBCFetchConfiguration.EAGER_JOIN, true, false)) JDBCFetchConfiguration.EAGER_JOIN, true, false))
return null; return null;
@ -563,7 +554,7 @@ public class JDBCStoreManager implements StoreManager, JDBCStore {
final int eager = Math.min(fetch.getEagerFetchMode(), final int eager = Math.min(fetch.getEagerFetchMode(),
JDBCFetchConfiguration.EAGER_JOIN); JDBCFetchConfiguration.EAGER_JOIN);
Union union = _sql.newUnion(mappings.length); Union union = mapping.getUnion(mappings.length);
union.setExpectedResultCount(1, false); union.setExpectedResultCount(1, false);
if (fetch.getSubclassFetchMode(mapping) != EagerFetchModes.EAGER_JOIN) if (fetch.getSubclassFetchMode(mapping) != EagerFetchModes.EAGER_JOIN)
union.abortUnion(); union.abortUnion();
@ -592,7 +583,7 @@ public class JDBCStoreManager implements StoreManager, JDBCStore {
while (base.getJoinablePCSuperclassMapping() != null) while (base.getJoinablePCSuperclassMapping() != null)
base = base.getJoinablePCSuperclassMapping(); base = base.getJoinablePCSuperclassMapping();
Select sel = _sql.newSelect(); Select sel = mapping.getSelect();
sel.select(base.getPrimaryKeyColumns()); sel.select(base.getPrimaryKeyColumns());
sel.wherePrimaryKey(sm.getObjectId(), base, this); sel.wherePrimaryKey(sm.getObjectId(), base, this);
if (_log.isTraceEnabled()) { if (_log.isTraceEnabled()) {
@ -645,7 +636,7 @@ public class JDBCStoreManager implements StoreManager, JDBCStore {
//### use it... would it be worth it to have a small shell select //### use it... would it be worth it to have a small shell select
//### object that only creates a real select when actually used? //### object that only creates a real select when actually used?
Select sel = _sql.newSelect(); Select sel = mapping.getSelect();
if (select(sel, mapping, Select.SUBS_EXACT, sm, fields, jfetch, if (select(sel, mapping, Select.SUBS_EXACT, sm, fields, jfetch,
EagerFetchModes.EAGER_JOIN, true, false)) { EagerFetchModes.EAGER_JOIN, true, false)) {
sel.wherePrimaryKey(sm.getObjectId(), mapping, this); sel.wherePrimaryKey(sm.getObjectId(), mapping, this);
@ -818,7 +809,7 @@ public class JDBCStoreManager implements StoreManager, JDBCStore {
if (rops[i] != null) if (rops[i] != null)
continue; continue;
Select sel = _sql.newSelect(); Select sel = mapping.getSelect();
sel.setLRS(true); sel.setLRS(true);
if (_log.isTraceEnabled()) { if (_log.isTraceEnabled()) {
_log.trace("executeExtent: "+mappings[i].getDescribedType()); _log.trace("executeExtent: "+mappings[i].getDescribedType());
@ -839,13 +830,12 @@ public class JDBCStoreManager implements StoreManager, JDBCStore {
} }
// perform a union on all independent classes // perform a union on all independent classes
Union union = _sql.newUnion(mappings.length); Union union = mapping.getUnion(mappings.length);
union.setLRS(true); union.setLRS(true);
final BitSet[] paged = new BitSet[mappings.length]; final BitSet[] paged = new BitSet[mappings.length];
union.select(new Union.Selector() { union.select(new Union.Selector() {
public void select(Select sel, int idx) { public void select(Select sel, int idx) {
paged[idx] = selectExtent(sel, mappings[idx], jfetch, paged[idx] = selectExtent(sel, mappings[idx], jfetch, subclasses);
subclasses);
} }
}); });
@ -1124,6 +1114,8 @@ public class JDBCStoreManager implements StoreManager, JDBCStore {
public boolean select(Select sel, ClassMapping mapping, int subs, public boolean select(Select sel, ClassMapping mapping, int subs,
OpenJPAStateManager sm, BitSet fields, JDBCFetchConfiguration fetch, OpenJPAStateManager sm, BitSet fields, JDBCFetchConfiguration fetch,
int eager, boolean ident, boolean outer) { int eager, boolean ident, boolean outer) {
if (sel.isReadOnly())
return true;
// add class conditions so that they're cloned for any batched selects // add class conditions so that they're cloned for any batched selects
boolean joinedSupers = false; boolean joinedSupers = false;
if(needClassCondition(mapping, subs, sm)) { if(needClassCondition(mapping, subs, sm)) {
@ -1134,8 +1126,7 @@ public class JDBCStoreManager implements StoreManager, JDBCStore {
// and cannot be reused during the actual eager select process, // and cannot be reused during the actual eager select process,
// preventing infinite recursion // preventing infinite recursion
eager = Math.min(eager, fetch.getEagerFetchMode()); eager = Math.min(eager, fetch.getEagerFetchMode());
FieldMapping eagerToMany = createEagerSelects(sel, mapping, sm, fields, FieldMapping eagerToMany = createEagerSelects(sel, mapping, sm, fields, fetch, eager);
fetch, eager);
// select all base class mappings; do this after batching so that // select all base class mappings; do this after batching so that
// the joins needed by these selects don't get in the WHERE clause // the joins needed by these selects don't get in the WHERE clause
@ -1145,10 +1136,9 @@ public class JDBCStoreManager implements StoreManager, JDBCStore {
// select eager to-many relations last because during load they // select eager to-many relations last because during load they
// advance the result set and could exhaust it, so no other mappings // advance the result set and could exhaust it, so no other mappings
// can load afterwords // can load afterwards
if (eagerToMany != null) if (eagerToMany != null)
eagerToMany.selectEagerJoin(sel, sm, this, eagerToMany.selectEagerJoin(sel, sm, this, fetch.traverseJDBC(eagerToMany), eager);
fetch.traverseJDBC(eagerToMany), eager);
// optionally select subclass mappings // optionally select subclass mappings
if (subs == Select.SUBS_JOINABLE || subs == Select.SUBS_ANY_JOINABLE) if (subs == Select.SUBS_JOINABLE || subs == Select.SUBS_ANY_JOINABLE)
@ -1164,8 +1154,7 @@ public class JDBCStoreManager implements StoreManager, JDBCStore {
return mapping.getDiscriminator().addClassConditions(sel, subs == Select.SUBS_JOINABLE, joins); return mapping.getDiscriminator().addClassConditions(sel, subs == Select.SUBS_JOINABLE, joins);
} }
private boolean needClassCondition(ClassMapping mapping, int subs, private boolean needClassCondition(ClassMapping mapping, int subs, OpenJPAStateManager sm) {
OpenJPAStateManager sm) {
boolean retVal = false; boolean retVal = false;
if(sm == null || sm.getPCState() == PCState.TRANSIENT) { if(sm == null || sm.getPCState() == PCState.TRANSIENT) {
if(subs == Select.SUBS_JOINABLE || subs == Select.SUBS_NONE) { if(subs == Select.SUBS_JOINABLE || subs == Select.SUBS_NONE) {

View File

@ -31,6 +31,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.apache.openjpa.enhance.PersistenceCapable; import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.enhance.Reflection; import org.apache.openjpa.enhance.Reflection;
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration; import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
import org.apache.openjpa.jdbc.kernel.JDBCStore; import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.meta.strats.NoneClassStrategy; import org.apache.openjpa.jdbc.meta.strats.NoneClassStrategy;
@ -44,6 +45,8 @@ import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.Result; import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.RowManager; import org.apache.openjpa.jdbc.sql.RowManager;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.jdbc.sql.SelectExecutor;
import org.apache.openjpa.jdbc.sql.Union;
import org.apache.openjpa.kernel.FetchConfiguration; import org.apache.openjpa.kernel.FetchConfiguration;
import org.apache.openjpa.kernel.OpenJPAStateManager; import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.kernel.PCState; import org.apache.openjpa.kernel.PCState;
@ -60,17 +63,22 @@ import org.apache.openjpa.util.OpenJPAId;
/** /**
* Specialization of metadata for relational databases. * Specialization of metadata for relational databases.
* <br>
* The mapping may reuse the same {@link SelectExecutor select} if the
* {@link JDBCConfiguration#getSelectCacheEnabled() configuration option}
* instructs to do so.
* *
* @author Abe White * @author Abe White
* @author Pinaki Poddar (select caching)
*/ */
@SuppressWarnings("serial")
public class ClassMapping public class ClassMapping
extends ClassMetaData extends ClassMetaData
implements ClassStrategy { implements ClassStrategy {
public static final ClassMapping[] EMPTY_MAPPINGS = new ClassMapping[0]; public static final ClassMapping[] EMPTY_MAPPINGS = new ClassMapping[0];
private static final Localizer _loc = Localizer.forPackage private static final Localizer _loc = Localizer.forPackage(ClassMapping.class);
(ClassMapping.class);
private final ClassMappingInfo _info; private final ClassMappingInfo _info;
private final Discriminator _discrim; private final Discriminator _discrim;
@ -89,6 +97,9 @@ public class ClassMapping
// maps columns to joinables // maps columns to joinables
private final Map _joinables = new ConcurrentHashMap(); private final Map _joinables = new ConcurrentHashMap();
private Select _select;
private Union _union;
/** /**
* Constructor. Supply described type and owning repository. * Constructor. Supply described type and owning repository.
*/ */
@ -1109,4 +1120,48 @@ public class ClassMapping
return true; return true;
return false; return false;
} }
/**
* Gets the {@link Select select} used for selecting instances of this mapping.
* If {@link JDBCConfiguration#getSelectCacheEnabled() aggressive caching} of
* select statements is enabled, then a select is generated for the first call,
* cached in this mapping and subsequently returned. A cached select becomes
* {@link Select#isReadOnly() immutable} i.e. no structural modification is
* allowed <em>after</em> its corresponding SQL has been executed on the database.
*
* @return a new or cached select to select instances of this mapping.
*/
public Select getSelect() {
Select result = _select;
if (result == null) {
JDBCConfiguration conf = (JDBCConfiguration)getMappingRepository().getConfiguration();
result = conf.getSQLFactoryInstance().newSelect();
if (conf.getSelectCacheEnabled()) {
_select = result;
}
}
return result;
}
/**
* Gets the {@link Union union} used for selecting instances of this mapping.
* If {@link JDBCConfiguration#getSelectCacheEnabled() aggressive caching} of
* union statements is enabled, then a union is generated for the first call,
* cached in this mapping and subsequently returned. A cached union becomes
* {@link Select#isReadOnly() immutable} i.e. no structural modification is
* allowed <em>after</em> its corresponding SQL has been executed on the database.
*
* @return a new or cached union to select instances of this mapping.
*/
public Union getUnion(int selects) {
Union result = _union;
if (result == null) {
JDBCConfiguration conf = (JDBCConfiguration)getMappingRepository().getConfiguration();
result = conf.getSQLFactoryInstance().newUnion(selects);
if (conf.getSelectCacheEnabled()) {
_union = result;
}
}
return result;
}
} }

View File

@ -81,19 +81,19 @@ public class FieldMapping
private boolean _outer = false; private boolean _outer = false;
private int _fetchMode = Integer.MAX_VALUE; private int _fetchMode = Integer.MAX_VALUE;
private Unique[] _joinTableUniques; // Unique constraints on JoinTable private Unique[] _joinTableUniques; // Unique constraints on JoinTable
private Boolean _bidirectionalJoinTableOwner = null; private Boolean _bidirectionalJoinTableOwner;
private Boolean _bidirectionalJoinTableNonOwner = null; private Boolean _bidirectionalJoinTableNonOwner;
private Boolean _bi_MTo1_JT = null; private Boolean _bidirectionalManyToOneJoinTable;
private Boolean _uni_1ToM_FK = null; private Boolean _unidirectionalOneToManyForeignKey;
private Boolean _uni_MTo1_JT = null; private Boolean _unidirectionalManyToOneJoinTable;
private Boolean _uni_1To1_JT = null; private Boolean _unidirectionalOneToOneJoinTable;
private Boolean _bi_1To1_JT = null; private Boolean _bidirectionalOneToOneJoinTable;
private FieldMapping _bi_1ToM_JT_Field = null; private FieldMapping _bidirectionalOneToManyJoinTableField;
private FieldMapping _bi_MTo1_JT_Field = null; private FieldMapping _bidirectionalManyToOneJoinTableField;
private ForeignKey _bi_1ToM_Join_FK = null; private ForeignKey _bidirectionalOneToManyJoinForeignKey;
private ForeignKey _bi_1ToM_Elem_FK = null; private ForeignKey _bidirectionalOneToManyElementForeignKey;
private boolean _hasMapsIdCols = false; private boolean _hasMapsIdCols = false;
@ -1271,85 +1271,90 @@ public class FieldMapping
return _bidirectionalJoinTableNonOwner.booleanValue(); return _bidirectionalJoinTableNonOwner.booleanValue();
} }
public boolean isBiMTo1JT() { public boolean isBidirectionalManyToOneJoinTable() {
if (_bi_MTo1_JT == null) { if (_bidirectionalManyToOneJoinTable == null) {
_bi_MTo1_JT = getMappingRepository().isBiMTo1JT(this); _bidirectionalManyToOneJoinTable = getMappingRepository().isBidirectionalManyToOneJoinTable(this);
} }
return _bi_MTo1_JT; return _bidirectionalManyToOneJoinTable;
} }
public boolean isUni1ToMFK() { public boolean isUnidirectionalOneToManyForeignKey() {
if (_uni_1ToM_FK == null) if (_unidirectionalOneToManyForeignKey == null)
_uni_1ToM_FK = getMappingRepository().isUni1ToMFK(this); _unidirectionalOneToManyForeignKey = getMappingRepository().isUnidirectionalOneToManyForeignKey(this);
return _uni_1ToM_FK; return _unidirectionalOneToManyForeignKey;
} }
public boolean isUniMTo1JT() { public boolean isUnidirectionalManyToOneJoinTable() {
if (_uni_MTo1_JT == null) if (_unidirectionalManyToOneJoinTable == null)
_uni_MTo1_JT = getMappingRepository().isUniMTo1JT(this); _unidirectionalManyToOneJoinTable = getMappingRepository().isUnidirectionalManyToOneJoinTable(this);
return _uni_MTo1_JT; return _unidirectionalManyToOneJoinTable;
} }
public boolean isUni1To1JT() { public boolean isUnidirectionalOneToOneJoinTable() {
if (_uni_1To1_JT == null) if (_unidirectionalOneToOneJoinTable == null)
_uni_1To1_JT = getMappingRepository().isUni1To1JT(this); _unidirectionalOneToOneJoinTable = getMappingRepository().isUnidirectionalOneToOneJoinTable(this);
return _uni_1To1_JT; return _unidirectionalOneToOneJoinTable;
} }
public boolean isBi1To1JT() { public boolean isBidirectionalOneToOneJoinTable() {
if (_bi_1To1_JT == null) if (_bidirectionalOneToOneJoinTable == null)
_bi_1To1_JT = getMappingRepository().isBi1To1JT(this); _bidirectionalOneToOneJoinTable = getMappingRepository().isBidirectionalOneToOneJoinTable(this);
return _bi_1To1_JT; return _bidirectionalOneToOneJoinTable;
} }
public FieldMapping getBi_1ToM_JTField() { public FieldMapping getBidirectionalOneToManyJoinTableField() {
if (_bi_1ToM_JT_Field == null) { if (_bidirectionalOneToManyJoinTableField == null) {
_bi_1ToM_JT_Field = getMappingRepository().getBi_1ToM_JoinTableField(this); _bidirectionalOneToManyJoinTableField =
getMappingRepository().getBidirectionalOneToManyJoinTableField(this);
} }
return _bi_1ToM_JT_Field; return _bidirectionalOneToManyJoinTableField;
} }
public FieldMapping getBi_MTo1_JTField() { public FieldMapping getBidirectionalManyToOneJoinTableField() {
if (_bi_MTo1_JT_Field == null) { if (_bidirectionalManyToOneJoinTableField == null) {
_bi_MTo1_JT_Field = getMappingRepository().getBi_MTo1_JoinTableField(this); _bidirectionalManyToOneJoinTableField =
getMappingRepository().getBidirectionalManyToOneJoinTableField(this);
} }
return _bi_MTo1_JT_Field; return _bidirectionalManyToOneJoinTableField;
} }
public ForeignKey getBi1ToMJoinFK() { public ForeignKey getBidirectionalOneToManyJoinForeignKey() {
if (_bi_1ToM_Join_FK == null) { if (_bidirectionalOneToManyJoinForeignKey == null) {
getBi_1ToM_JTField(); getBidirectionalOneToManyJoinTableField();
if (_bi_1ToM_JT_Field != null) if (_bidirectionalOneToManyJoinTableField != null)
_bi_1ToM_Join_FK = _bi_1ToM_JT_Field.getJoinForeignKey(); _bidirectionalOneToManyJoinForeignKey = _bidirectionalOneToManyJoinTableField.getJoinForeignKey();
} }
return _bi_1ToM_Join_FK; return _bidirectionalOneToManyJoinForeignKey;
} }
public ForeignKey getBi1ToMElemFK() { public ForeignKey getBidirectionalOneToManyElementForeignKey() {
if (_bi_1ToM_Elem_FK == null) { if (_bidirectionalOneToManyElementForeignKey == null) {
getBi_1ToM_JTField(); getBidirectionalOneToManyJoinTableField();
if (_bi_1ToM_JT_Field != null) if (_bidirectionalOneToManyJoinTableField != null)
_bi_1ToM_Elem_FK = _bi_1ToM_JT_Field.getElementMapping().getForeignKey(); _bidirectionalOneToManyElementForeignKey =
_bidirectionalOneToManyJoinTableField.getElementMapping().getForeignKey();
} }
return _bi_1ToM_Elem_FK; return _bidirectionalOneToManyElementForeignKey;
} }
public void setBi1MJoinTableInfo() { public void setBidirectionalOneToManyJoinTableInfo() {
if (getAssociationType() == FieldMetaData.ONE_TO_MANY) { if (getAssociationType() == FieldMetaData.ONE_TO_MANY) {
FieldMapping mapped = getBi_MTo1_JTField(); FieldMapping mapped = getBidirectionalManyToOneJoinTableField();
if (mapped != null) { if (mapped != null) {
FieldMappingInfo info = getMappingInfo(); FieldMappingInfo info = getMappingInfo();
FieldMappingInfo mappedInfo = mapped.getMappingInfo(); FieldMappingInfo mappedInfo = mapped.getMappingInfo();
info.setTableIdentifier(mappedInfo.getTableIdentifier()); info.setTableIdentifier(mappedInfo.getTableIdentifier());
info.setColumns(mapped.getElementMapping().getValueInfo().getColumns()); info.setColumns(mapped.getElementMapping().getValueInfo().getColumns());
getElementMapping().getValueInfo().setColumns( getElementMapping().getValueInfo().setColumns(mappedInfo.getColumns());
mappedInfo.getColumns());
} }
} }
} }
public boolean isNonDefaultMappingUsingJoinTableStrategy() { public boolean isNonDefaultMappingUsingJoinTableStrategy() {
return isBi1To1JT() || isUni1To1JT() || isUniMTo1JT() || isBiMTo1JT(); return isBidirectionalOneToOneJoinTable()
|| isUnidirectionalOneToOneJoinTable()
|| isUnidirectionalManyToOneJoinTable()
|| isBidirectionalManyToOneJoinTable();
} }
public void setMapsIdCols(boolean hasMapsIdCols) { public void setMapsIdCols(boolean hasMapsIdCols) {

View File

@ -165,7 +165,7 @@ public class FieldMappingInfo
public ForeignKey getJoinForeignKey (final FieldMapping field, Table table, public ForeignKey getJoinForeignKey (final FieldMapping field, Table table,
boolean adapt) { boolean adapt) {
if (field.isUni1ToMFK()) { if (field.isUnidirectionalOneToManyForeignKey()) {
List<Column> cols = field.getElementMapping().getValueInfo().getColumns(); List<Column> cols = field.getElementMapping().getValueInfo().getColumns();
return getJoin(field, table, adapt, cols); return getJoin(field, table, adapt, cols);
} }

View File

@ -105,15 +105,14 @@ import org.apache.openjpa.util.UserException;
* *
* @author Abe White * @author Abe White
*/ */
@SuppressWarnings("serial")
public class MappingRepository extends MetaDataRepository { public class MappingRepository extends MetaDataRepository {
private static final Localizer _loc = Localizer.forPackage private static final Localizer _loc = Localizer.forPackage(MappingRepository.class);
(MappingRepository.class);
private transient DBDictionary _dict = null; private transient DBDictionary _dict = null;
private transient MappingDefaults _defaults = null; private transient MappingDefaults _defaults = null;
// object->queryresultmapping
private Map<Object, QueryResultMapping> _results = new HashMap<Object, QueryResultMapping>(); private Map<Object, QueryResultMapping> _results = new HashMap<Object, QueryResultMapping>();
private SchemaGroup _schema = null; private SchemaGroup _schema = null;
private StrategyInstaller _installer = null; private StrategyInstaller _installer = null;
@ -260,12 +259,10 @@ public class MappingRepository extends MetaDataRepository {
public QueryResultMapping[] getQueryResultMappings() { public QueryResultMapping[] getQueryResultMappings() {
if (_locking) { if (_locking) {
synchronized (this) { synchronized (this) {
Collection values = _results.values(); return _results.values().toArray(new QueryResultMapping[_results.size()]);
return (QueryResultMapping[]) values.toArray(new QueryResultMapping[values.size()]);
} }
} else { } else {
Collection values = _results.values(); return _results.values().toArray(new QueryResultMapping[_results.size()]);
return (QueryResultMapping[]) values.toArray(new QueryResultMapping[values.size()]);
} }
} }
@ -273,7 +270,7 @@ public class MappingRepository extends MetaDataRepository {
* Return the cached query result mapping with the given name, or null if * Return the cached query result mapping with the given name, or null if
* none. * none.
*/ */
public QueryResultMapping getCachedQueryResultMapping(Class cls, String name) { public QueryResultMapping getCachedQueryResultMapping(Class<?> cls, String name) {
if (_locking) { if (_locking) {
synchronized (this) { synchronized (this) {
return (QueryResultMapping) _results.get(getQueryResultKey(cls, name)); return (QueryResultMapping) _results.get(getQueryResultKey(cls, name));
@ -286,7 +283,7 @@ public class MappingRepository extends MetaDataRepository {
/** /**
* Add a query result mapping. * Add a query result mapping.
*/ */
public QueryResultMapping addQueryResultMapping(Class cls, String name) { public QueryResultMapping addQueryResultMapping(Class<?> cls, String name) {
if (_locking) { if (_locking) {
synchronized (this) { synchronized (this) {
return addQueryResultMappingInternal(cls, name); return addQueryResultMappingInternal(cls, name);
@ -296,7 +293,7 @@ public class MappingRepository extends MetaDataRepository {
} }
} }
private QueryResultMapping addQueryResultMappingInternal(Class cls, String name) { private QueryResultMapping addQueryResultMappingInternal(Class<?> cls, String name) {
QueryResultMapping res = new QueryResultMapping(name, this); QueryResultMapping res = new QueryResultMapping(name, this);
res.setDefiningType(cls); res.setDefiningType(cls);
_results.put(getQueryResultKey(res), res); _results.put(getQueryResultKey(res), res);
@ -319,7 +316,7 @@ public class MappingRepository extends MetaDataRepository {
/** /**
* Remove a query result mapping. * Remove a query result mapping.
*/ */
public boolean removeQueryResultMapping(Class cls, String name) { public boolean removeQueryResultMapping(Class<?> cls, String name) {
if (_locking) { if (_locking) {
synchronized (this) { synchronized (this) {
if (name == null) if (name == null)
@ -1008,8 +1005,7 @@ public class MappingRepository extends MetaDataRepository {
protected FieldStrategy handlerCollectionStrategy(FieldMapping field, protected FieldStrategy handlerCollectionStrategy(FieldMapping field,
ValueHandler ehandler, boolean installHandlers) { ValueHandler ehandler, boolean installHandlers) {
// TODO: JPA 2.0 should ignore this flag and not to serialize // TODO: JPA 2.0 should ignore this flag and not to serialize
if (getConfiguration().getCompatibilityInstance() if (getConfiguration().getCompatibilityInstance().getStoreMapCollectionInEntityAsBlob())
.getStoreMapCollectionInEntityAsBlob())
return null; return null;
if (installHandlers) if (installHandlers)
field.getElementMapping().setHandler(ehandler); field.getElementMapping().setHandler(ehandler);
@ -1024,8 +1020,7 @@ public class MappingRepository extends MetaDataRepository {
ValueHandler khandler, ValueHandler vhandler, boolean krel, ValueHandler khandler, ValueHandler vhandler, boolean krel,
boolean vrel, boolean installHandlers) { boolean vrel, boolean installHandlers) {
// TODO: JPA 2.0 should ignore this flag and not to serialize // TODO: JPA 2.0 should ignore this flag and not to serialize
if (getConfiguration().getCompatibilityInstance() if (getConfiguration().getCompatibilityInstance().getStoreMapCollectionInEntityAsBlob())
.getStoreMapCollectionInEntityAsBlob())
return null; return null;
if (installHandlers) { if (installHandlers) {
field.getKeyMapping().setHandler(khandler); field.getKeyMapping().setHandler(khandler);
@ -1048,14 +1043,13 @@ public class MappingRepository extends MetaDataRepository {
FieldMapping mapped = field.getMappedByMapping(); FieldMapping mapped = field.getMappedByMapping();
if (mapped != null) { if (mapped != null) {
//bi-/M-1/JoinTable ==> join table strategy //bi-/M-1/JoinTable ==> join table strategy
if (isBiMTo1JT(field)) if (isBidirectionalManyToOneJoinTable(field))
return false; return false;
if (mapped.getTypeCode() == JavaTypes.PC || mapped.getTypeCode() == JavaTypes.PC_UNTYPED) if (mapped.getTypeCode() == JavaTypes.PC || mapped.getTypeCode() == JavaTypes.PC_UNTYPED)
return true; return true;
if (mapped.getElement().getTypeCode() == JavaTypes.PC) if (mapped.getElement().getTypeCode() == JavaTypes.PC)
return false; return false;
throw new MetaDataException(_loc.get("bad-mapped-by", field, throw new MetaDataException(_loc.get("bad-mapped-by", field, mapped));
mapped));
} }
// without a mapped-by, we have to look for clues as to the mapping. // without a mapped-by, we have to look for clues as to the mapping.
@ -1064,82 +1058,84 @@ public class MappingRepository extends MetaDataRepository {
// an association table // an association table
FieldMappingInfo info = field.getMappingInfo(); FieldMappingInfo info = field.getMappingInfo();
ValueMapping elem = field.getElementMapping(); ValueMapping elem = field.getElementMapping();
boolean useInverseKeyMapping = DBIdentifier.isNull(info.getTableIdentifier()) && info.getColumns().isEmpty() boolean useInverseKeyMapping = DBIdentifier.isNull(info.getTableIdentifier())
&& !elem.getValueInfo().getColumns().isEmpty(); && info.getColumns().isEmpty()
&& !elem.getValueInfo().getColumns().isEmpty();
// JPA 2.0: non-default mapping: uni-/1-M/JoinColumn ==> foreign key strategy // JPA 2.0: non-default mapping: uni-/1-M/JoinColumn ==> foreign key strategy
if (isUni1ToMFK(field)) { if (isUnidirectionalOneToManyForeignKey(field)) {
return true; return true;
} }
return useInverseKeyMapping; return useInverseKeyMapping;
} }
public boolean isNonDefaultMappingAllowed() { public boolean isNonDefaultMappingAllowed() {
OpenJPAConfiguration conf = getConfiguration(); return getMetaDataFactory().getDefaults().isNonDefaultMappingAllowed(getConfiguration());
return getMetaDataFactory().getDefaults().isNonDefaultMappingAllowed(conf);
} }
public boolean isUniMTo1JT(FieldMapping field) { public boolean isUnidirectionalManyToOneJoinTable(FieldMapping field) {
if (isNonDefaultMappingAllowed() && if (isNonDefaultMappingAllowed()
field.getAssociationType() == FieldMetaData.MANY_TO_ONE && && field.getAssociationType() == FieldMetaData.MANY_TO_ONE
hasJoinTable(field) && && hasJoinTable(field)
!isBidirectional(field)) { && !isBidirectional(field)) {
field.getValueMapping().getValueInfo().setColumns(field.getElementMapping().getValueInfo().getColumns()); field.getValueMapping().getValueInfo().setColumns(field.getElementMapping().getValueInfo().getColumns());
return true; return true;
} }
return false; return false;
} }
public boolean isUni1To1JT(FieldMapping field) { public boolean isUnidirectionalOneToOneJoinTable(FieldMapping field) {
if (isNonDefaultMappingAllowed() && if (isNonDefaultMappingAllowed()
field.getAssociationType() == FieldMetaData.ONE_TO_ONE && && field.getAssociationType() == FieldMetaData.ONE_TO_ONE
hasJoinTable(field) && && hasJoinTable(field)
!isBidirectional(field)) { && !isBidirectional(field)) {
field.getValueMapping().getValueInfo().setColumns(field.getElementMapping().getValueInfo().getColumns()); field.getValueMapping().getValueInfo().setColumns(field.getElementMapping().getValueInfo().getColumns());
return true; return true;
} }
return false; return false;
} }
public boolean isBi1To1JT(FieldMapping field) { public boolean isBidirectionalOneToOneJoinTable(FieldMapping field) {
if (isNonDefaultMappingAllowed() && if (isNonDefaultMappingAllowed()
field.getAssociationType() == FieldMetaData.ONE_TO_ONE && && field.getAssociationType() == FieldMetaData.ONE_TO_ONE
hasJoinTable(field) && && hasJoinTable(field)
isBidirectional(field)) { && isBidirectional(field)) {
field.getValueMapping().getValueInfo().setColumns(field.getElementMapping().getValueInfo().getColumns()); field.getValueMapping().getValueInfo().setColumns(field.getElementMapping().getValueInfo().getColumns());
return true; return true;
} }
return false; return false;
} }
public boolean isUni1ToMFK(FieldMapping field) { public boolean isUnidirectionalOneToManyForeignKey(FieldMapping field) {
if (isNonDefaultMappingAllowed() && if (isNonDefaultMappingAllowed()
field.getAssociationType() == FieldMetaData.ONE_TO_MANY && && field.getAssociationType() == FieldMetaData.ONE_TO_MANY
hasJoinColumn(field) && && hasJoinColumn(field)
!isBidirectional(field)) { && !isBidirectional(field)) {
field.getElementMapping().getValueInfo().setColumns(field.getValueInfo().getColumns()); field.getElementMapping().getValueInfo().setColumns(field.getValueInfo().getColumns());
return true; return true;
} }
return false; return false;
} }
public boolean isBiMTo1JT(FieldMapping field) { public boolean isBidirectionalManyToOneJoinTable(FieldMapping field) {
FieldMapping mapped = field.getMappedByMapping(); FieldMapping mapped = field.getMappedByMapping();
if (isNonDefaultMappingAllowed()) { if (isNonDefaultMappingAllowed()) {
if (field.getAssociationType() == FieldMetaData.ONE_TO_MANY ) { if (field.getAssociationType() == FieldMetaData.ONE_TO_MANY ) {
if (mapped != null && hasJoinTable(mapped)) if (mapped != null && hasJoinTable(mapped))
return true; return true;
} else if (field.getAssociationType() == FieldMetaData.MANY_TO_ONE) { } else if (field.getAssociationType() == FieldMetaData.MANY_TO_ONE) {
if (getBi_1ToM_JoinTableField(field) != null) if (getBidirectionalOneToManyJoinTableField(field) != null)
return true; return true;
} }
} }
return false; return false;
} }
// return the inverse field of bidirectional many to one /**
// relation using join table strategy * Gets the inverse field of bidirectional many to one relation using join table strategy
public FieldMapping getBi_1ToM_JoinTableField(FieldMapping field) { * for the given field.
*/
public FieldMapping getBidirectionalOneToManyJoinTableField(FieldMapping field) {
if (isNonDefaultMappingAllowed()) { if (isNonDefaultMappingAllowed()) {
if (field.getAssociationType() == FieldMetaData.ONE_TO_MANY) { if (field.getAssociationType() == FieldMetaData.ONE_TO_MANY) {
FieldMapping mappedBy = field.getMappedByMapping(); FieldMapping mappedBy = field.getMappedByMapping();
@ -1159,9 +1155,10 @@ public class MappingRepository extends MetaDataRepository {
return null; return null;
} }
// return the owning field of bidirectional one to many /**
// relation using join table strategy * Gets the owning field of bidirectional one to many relation using join table strategy of the given field.
public FieldMapping getBi_MTo1_JoinTableField(FieldMapping field) { */
public FieldMapping getBidirectionalManyToOneJoinTableField(FieldMapping field) {
if (isNonDefaultMappingAllowed()) { if (isNonDefaultMappingAllowed()) {
if (field.getAssociationType() == FieldMetaData.MANY_TO_ONE) { if (field.getAssociationType() == FieldMetaData.MANY_TO_ONE) {
if (!hasJoinTable(field)) if (!hasJoinTable(field))

View File

@ -87,7 +87,7 @@ public class HandlerRelationMapTableFieldStrategy
union.select(new Union.Selector() { union.select(new Union.Selector() {
public void select(Select sel, int idx) { public void select(Select sel, int idx) {
sel.select(_kcols); sel.select(_kcols);
if (field.isUni1ToMFK()) { if (field.isUnidirectionalOneToManyForeignKey()) {
sel.whereForeignKey(field.getElementMapping().getForeignKey(), sel.whereForeignKey(field.getElementMapping().getForeignKey(),
sm.getObjectId(), field.getElementMapping().getDeclaredTypeMapping(), store); sm.getObjectId(), field.getElementMapping().getDeclaredTypeMapping(), store);
sel.select(vals[idx], field.getElementMapping(). sel.select(vals[idx], field.getElementMapping().
@ -146,10 +146,11 @@ public class HandlerRelationMapTableFieldStrategy
throw new MetaDataException(_loc.get("not-relation", val)); throw new MetaDataException(_loc.get("not-relation", val));
FieldMapping mapped = field.getMappedByMapping(); FieldMapping mapped = field.getMappedByMapping();
if (field.isUni1ToMFK() || (!field.isBiMTo1JT() && mapped != null)) { if (field.isUnidirectionalOneToManyForeignKey()
|| (!field.isBidirectionalManyToOneJoinTable() && mapped != null)) {
// map to the owner table // map to the owner table
handleMappedByForeignKey(adapt); handleMappedByForeignKey(adapt);
} else if (field.isBiMTo1JT() || mapped == null) { } else if (field.isBidirectionalManyToOneJoinTable() || mapped == null) {
// map to a separate table // map to a separate table
field.mapJoin(adapt, true); field.mapJoin(adapt, true);
if (val.getTypeMapping().isMapped()) { if (val.getTypeMapping().isMapped()) {
@ -186,11 +187,11 @@ public class HandlerRelationMapTableFieldStrategy
if (map == null || map.isEmpty()) if (map == null || map.isEmpty())
return; return;
if (!field.isBiMTo1JT() && field.getMappedBy() != null) if (!field.isBidirectionalManyToOneJoinTable() && field.getMappedBy() != null)
return; return;
Row row = null; Row row = null;
if (!field.isUni1ToMFK()) { if (!field.isUnidirectionalOneToManyForeignKey()) {
row = rm.getSecondaryRow(field.getTable(), Row.ACTION_INSERT); row = rm.getSecondaryRow(field.getTable(), Row.ACTION_INSERT);
row.setForeignKey(field.getJoinForeignKey(), field.getJoinColumnIO(), row.setForeignKey(field.getJoinForeignKey(), field.getJoinColumnIO(),
sm); sm);
@ -204,7 +205,7 @@ public class HandlerRelationMapTableFieldStrategy
entry = (Map.Entry) itr.next(); entry = (Map.Entry) itr.next();
valsm = RelationStrategies.getStateManager(entry.getValue(), valsm = RelationStrategies.getStateManager(entry.getValue(),
ctx); ctx);
if (field.isUni1ToMFK()){ if (field.isUnidirectionalOneToManyForeignKey()){
row = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(), row = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(),
Row.ACTION_UPDATE, valsm, true); Row.ACTION_UPDATE, valsm, true);
row.wherePrimaryKey(valsm); row.wherePrimaryKey(valsm);
@ -223,7 +224,7 @@ public class HandlerRelationMapTableFieldStrategy
// from the view point of the owned side // from the view point of the owned side
PersistenceCapable obj = sm.getPersistenceCapable(); PersistenceCapable obj = sm.getPersistenceCapable();
if (!populateKey(row, valsm, obj, ctx, rm, store)) { if (!populateKey(row, valsm, obj, ctx, rm, store)) {
if (!field.isUni1ToMFK()) if (!field.isUnidirectionalOneToManyForeignKey())
rm.flushSecondaryRow(row); rm.flushSecondaryRow(row);
} }
} }
@ -238,7 +239,7 @@ public class HandlerRelationMapTableFieldStrategy
public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm) public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
throws SQLException { throws SQLException {
if (field.getMappedBy() != null && !field.isBiMTo1JT()) if (field.getMappedBy() != null && !field.isBidirectionalManyToOneJoinTable())
return; return;
Map map = (Map) sm.fetchObject(field.getIndex()); Map map = (Map) sm.fetchObject(field.getIndex());
@ -269,7 +270,7 @@ public class HandlerRelationMapTableFieldStrategy
Object mkey; Object mkey;
if (canChange && !change.isEmpty()) { if (canChange && !change.isEmpty()) {
Row changeRow = null; Row changeRow = null;
if (!field.isUni1ToMFK()) { if (!field.isUnidirectionalOneToManyForeignKey()) {
changeRow = rm.getSecondaryRow(field.getTable(), changeRow = rm.getSecondaryRow(field.getTable(),
Row.ACTION_UPDATE); Row.ACTION_UPDATE);
changeRow.whereForeignKey(field.getJoinForeignKey(), sm); changeRow.whereForeignKey(field.getJoinForeignKey(), sm);
@ -278,7 +279,7 @@ public class HandlerRelationMapTableFieldStrategy
for (Iterator itr = change.iterator(); itr.hasNext();) { for (Iterator itr = change.iterator(); itr.hasNext();) {
mkey = itr.next(); mkey = itr.next();
valsm = RelationStrategies.getStateManager(map.get(mkey), ctx); valsm = RelationStrategies.getStateManager(map.get(mkey), ctx);
if (field.isUni1ToMFK()){ if (field.isUnidirectionalOneToManyForeignKey()){
changeRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(), changeRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(),
Row.ACTION_UPDATE, valsm, true); Row.ACTION_UPDATE, valsm, true);
changeRow.wherePrimaryKey(valsm); changeRow.wherePrimaryKey(valsm);
@ -288,7 +289,7 @@ public class HandlerRelationMapTableFieldStrategy
} }
HandlerStrategies.where(key, mkey, store, changeRow, _kcols); HandlerStrategies.where(key, mkey, store, changeRow, _kcols);
if (!field.isUni1ToMFK()) if (!field.isUnidirectionalOneToManyForeignKey())
rm.flushSecondaryRow(changeRow); rm.flushSecondaryRow(changeRow);
} }
} }
@ -297,14 +298,14 @@ public class HandlerRelationMapTableFieldStrategy
Collection rem = ct.getRemoved(); Collection rem = ct.getRemoved();
if (!rem.isEmpty() || (!canChange && !change.isEmpty())) { if (!rem.isEmpty() || (!canChange && !change.isEmpty())) {
Row delRow = null; Row delRow = null;
if (!field.isUni1ToMFK()) { if (!field.isUnidirectionalOneToManyForeignKey()) {
delRow = rm.getSecondaryRow(field.getTable(), delRow = rm.getSecondaryRow(field.getTable(),
Row.ACTION_DELETE); Row.ACTION_DELETE);
delRow.whereForeignKey(field.getJoinForeignKey(), sm); delRow.whereForeignKey(field.getJoinForeignKey(), sm);
} }
for (Iterator itr = rem.iterator(); itr.hasNext();) { for (Iterator itr = rem.iterator(); itr.hasNext();) {
mkey = itr.next(); mkey = itr.next();
if (field.isUni1ToMFK()){ if (field.isUnidirectionalOneToManyForeignKey()){
updateSetNull(sm, mkey, store, rm); updateSetNull(sm, mkey, store, rm);
} else { } else {
HandlerStrategies.where(key, mkey, store, delRow, _kcols); HandlerStrategies.where(key, mkey, store, delRow, _kcols);
@ -314,7 +315,7 @@ public class HandlerRelationMapTableFieldStrategy
if (!canChange && !change.isEmpty()) { if (!canChange && !change.isEmpty()) {
for (Iterator itr = change.iterator(); itr.hasNext();) { for (Iterator itr = change.iterator(); itr.hasNext();) {
mkey = itr.next(); mkey = itr.next();
if (field.isUni1ToMFK()){ if (field.isUnidirectionalOneToManyForeignKey()){
updateSetNull(sm, mkey, store, rm); updateSetNull(sm, mkey, store, rm);
} else { } else {
HandlerStrategies.where(key, itr.next(), store, delRow, _kcols); HandlerStrategies.where(key, itr.next(), store, delRow, _kcols);
@ -328,7 +329,7 @@ public class HandlerRelationMapTableFieldStrategy
Collection add = ct.getAdded(); Collection add = ct.getAdded();
if (!add.isEmpty() || (!canChange && !change.isEmpty())) { if (!add.isEmpty() || (!canChange && !change.isEmpty())) {
Row addRow = null; Row addRow = null;
if (!field.isUni1ToMFK()) { if (!field.isUnidirectionalOneToManyForeignKey()) {
addRow = rm.getSecondaryRow(field.getTable(), addRow = rm.getSecondaryRow(field.getTable(),
Row.ACTION_INSERT); Row.ACTION_INSERT);
addRow.setForeignKey(field.getJoinForeignKey(), addRow.setForeignKey(field.getJoinForeignKey(),
@ -337,7 +338,7 @@ public class HandlerRelationMapTableFieldStrategy
for (Iterator itr = add.iterator(); itr.hasNext();) { for (Iterator itr = add.iterator(); itr.hasNext();) {
mkey = itr.next(); mkey = itr.next();
valsm = RelationStrategies.getStateManager(map.get(mkey), ctx); valsm = RelationStrategies.getStateManager(map.get(mkey), ctx);
if (field.isUni1ToMFK()){ if (field.isUnidirectionalOneToManyForeignKey()){
addRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(), addRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(),
Row.ACTION_UPDATE, valsm, true); Row.ACTION_UPDATE, valsm, true);
addRow.wherePrimaryKey(valsm); addRow.wherePrimaryKey(valsm);
@ -348,14 +349,14 @@ public class HandlerRelationMapTableFieldStrategy
HandlerStrategies.set(key, mkey, store, addRow, _kcols, HandlerStrategies.set(key, mkey, store, addRow, _kcols,
_kio, true); _kio, true);
if (!field.isUni1ToMFK()) if (!field.isUnidirectionalOneToManyForeignKey())
rm.flushSecondaryRow(addRow); rm.flushSecondaryRow(addRow);
} }
if (!canChange && !change.isEmpty()) { if (!canChange && !change.isEmpty()) {
for (Iterator itr = change.iterator(); itr.hasNext();) { for (Iterator itr = change.iterator(); itr.hasNext();) {
mkey = itr.next(); mkey = itr.next();
valsm = RelationStrategies.getStateManager(map.get(mkey), ctx); valsm = RelationStrategies.getStateManager(map.get(mkey), ctx);
if (field.isUni1ToMFK()){ if (field.isUnidirectionalOneToManyForeignKey()){
addRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(), addRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(),
Row.ACTION_UPDATE, valsm, true); Row.ACTION_UPDATE, valsm, true);
addRow.wherePrimaryKey(valsm); addRow.wherePrimaryKey(valsm);
@ -366,7 +367,7 @@ public class HandlerRelationMapTableFieldStrategy
HandlerStrategies.set(key, mkey, store, addRow, _kcols, HandlerStrategies.set(key, mkey, store, addRow, _kcols,
_kio, true); _kio, true);
if (!field.isUni1ToMFK()) if (!field.isUnidirectionalOneToManyForeignKey())
rm.flushSecondaryRow(addRow); rm.flushSecondaryRow(addRow);
} }
} }
@ -413,9 +414,9 @@ public class HandlerRelationMapTableFieldStrategy
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 && !field.isBiMTo1JT())) if ((field.getMappedBy() != null && !field.isBidirectionalManyToOneJoinTable()))
return; return;
if (field.isUni1ToMFK()) { if (field.isUnidirectionalOneToManyForeignKey()) {
Map mapObj = (Map)sm.fetchObject(field.getIndex()); Map mapObj = (Map)sm.fetchObject(field.getIndex());
updateSetNull(sm, store, rm, mapObj.keySet()); updateSetNull(sm, store, rm, mapObj.keySet());
return; return;

View File

@ -112,10 +112,10 @@ public abstract class MapTableFieldStrategy
throw new MetaDataException(_loc.get("mapped-by-key", field)); throw new MetaDataException(_loc.get("mapped-by-key", field));
// Non-default mapping Uni-/OneToMany/ForeignKey allows schema components // Non-default mapping Uni-/OneToMany/ForeignKey allows schema components
if (field.isUni1ToMFK()) if (field.isUnidirectionalOneToManyForeignKey())
return; return;
if (field.isBiMTo1JT()) if (field.isBidirectionalManyToOneJoinTable())
field.setBi1MJoinTableInfo(); field.setBidirectionalOneToManyJoinTableInfo();
field.getValueInfo().assertNoSchemaComponents(field, !adapt); field.getValueInfo().assertNoSchemaComponents(field, !adapt);
} }

View File

@ -28,6 +28,7 @@ import java.util.Set;
import org.apache.openjpa.enhance.PersistenceCapable; import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.enhance.ReflectingPersistenceCapable; import org.apache.openjpa.enhance.ReflectingPersistenceCapable;
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.jdbc.identifier.DBIdentifier; import org.apache.openjpa.jdbc.identifier.DBIdentifier;
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration; import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
import org.apache.openjpa.jdbc.kernel.JDBCStore; import org.apache.openjpa.jdbc.kernel.JDBCStore;
@ -37,7 +38,6 @@ import org.apache.openjpa.jdbc.meta.FieldMapping;
import org.apache.openjpa.jdbc.meta.FieldStrategy; import org.apache.openjpa.jdbc.meta.FieldStrategy;
import org.apache.openjpa.jdbc.meta.Joinable; import org.apache.openjpa.jdbc.meta.Joinable;
import org.apache.openjpa.jdbc.meta.MappingInfo; import org.apache.openjpa.jdbc.meta.MappingInfo;
import org.apache.openjpa.jdbc.meta.ValueHandler;
import org.apache.openjpa.jdbc.meta.ValueMapping; import org.apache.openjpa.jdbc.meta.ValueMapping;
import org.apache.openjpa.jdbc.meta.ValueMappingImpl; import org.apache.openjpa.jdbc.meta.ValueMappingImpl;
import org.apache.openjpa.jdbc.meta.ValueMappingInfo; import org.apache.openjpa.jdbc.meta.ValueMappingInfo;
@ -55,13 +55,13 @@ import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.jdbc.sql.SelectExecutor; import org.apache.openjpa.jdbc.sql.SelectExecutor;
import org.apache.openjpa.jdbc.sql.Union; import org.apache.openjpa.jdbc.sql.Union;
import org.apache.openjpa.kernel.LockManager;
import org.apache.openjpa.kernel.OpenJPAStateManager; import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.lib.log.Log; import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData; import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.meta.JavaTypes; import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.meta.MetaDataModes;
import org.apache.openjpa.util.ApplicationIds; import org.apache.openjpa.util.ApplicationIds;
import org.apache.openjpa.util.ImplHelper; import org.apache.openjpa.util.ImplHelper;
import org.apache.openjpa.util.InternalException; import org.apache.openjpa.util.InternalException;
@ -74,27 +74,33 @@ import org.apache.openjpa.util.UnsupportedException;
/** /**
* Mapping for a single-valued relation to another entity. * Mapping for a single-valued relation to another entity.
* *
* <br>
* The strategy may reuse the same {@link SelectExecutor select} if the
* {@link JDBCConfiguration#getSelectCacheEnabled() configuration option}
* instructs to do so.
* @author Abe White * @author Abe White
* @author Pinaki Poddar (select caching)
* @since 0.4.0 * @since 0.4.0
*/ */
@SuppressWarnings("serial")
public class RelationFieldStrategy public class RelationFieldStrategy
extends AbstractFieldStrategy extends AbstractFieldStrategy
implements Joinable, Embeddable { implements Joinable, Embeddable {
private static final Localizer _loc = Localizer.forPackage private static final Localizer _loc = Localizer.forPackage(RelationFieldStrategy.class);
(RelationFieldStrategy.class);
private Boolean _fkOid = null; private Boolean _fkOid = null;
private SelectExecutor _executor;
public void map(boolean adapt) { public void map(boolean adapt) {
if (field.getTypeCode() != JavaTypes.PC || field.isEmbeddedPC()) if (field.getTypeCode() != JavaTypes.PC || field.isEmbeddedPC())
throw new MetaDataException(_loc.get("not-relation", field)); throw new MetaDataException(_loc.get("not-relation", field));
field.getKeyMapping().getValueInfo().assertNoSchemaComponents field.getKeyMapping().getValueInfo().assertNoSchemaComponents(field.getKey(), !adapt);
(field.getKey(), !adapt);
if (!field.isNonDefaultMappingUsingJoinTableStrategy()) if (!field.isNonDefaultMappingUsingJoinTableStrategy())
field.getElementMapping().getValueInfo().assertNoSchemaComponents field.getElementMapping().getValueInfo().assertNoSchemaComponents(field.getElement(), !adapt);
(field.getElement(), !adapt);
boolean criteria = field.getValueInfo().getUseClassCriteria(); boolean criteria = field.getValueInfo().getUseClassCriteria();
// check for named inverse // check for named inverse
@ -102,40 +108,33 @@ public class RelationFieldStrategy
if (mapped != null) { if (mapped != null) {
field.getMappingInfo().assertNoSchemaComponents(field, !adapt); field.getMappingInfo().assertNoSchemaComponents(field, !adapt);
field.getValueInfo().assertNoSchemaComponents(field, !adapt); field.getValueInfo().assertNoSchemaComponents(field, !adapt);
mapped.resolve(mapped.MODE_META | mapped.MODE_MAPPING); mapped.resolve(MetaDataModes.MODE_META | MetaDataModes.MODE_MAPPING);
if (!mapped.isMapped() || mapped.isSerialized()) if (!mapped.isMapped() || mapped.isSerialized())
throw new MetaDataException(_loc.get("mapped-by-unmapped", throw new MetaDataException(_loc.get("mapped-by-unmapped", field, mapped));
field, mapped));
if (mapped.getTypeCode() == JavaTypes.PC) { if (mapped.getTypeCode() == JavaTypes.PC) {
if (mapped.getJoinDirection() == mapped.JOIN_FORWARD) { if (mapped.getJoinDirection() == FieldMapping.JOIN_FORWARD) {
field.setJoinDirection(field.JOIN_INVERSE); field.setJoinDirection(FieldMapping.JOIN_INVERSE);
field.setColumns(mapped.getDefiningMapping(). field.setColumns(mapped.getDefiningMapping().getPrimaryKeyColumns());
getPrimaryKeyColumns());
} else if (isTypeUnjoinedSubclass(mapped)) } else if (isTypeUnjoinedSubclass(mapped))
throw new MetaDataException(_loc.get throw new MetaDataException(_loc.get
("mapped-inverse-unjoined", field.getName(), ("mapped-inverse-unjoined", field.getName(), field.getDefiningMapping(), mapped));
field.getDefiningMapping(), mapped));
field.setForeignKey(mapped.getForeignKey field.setForeignKey(mapped.getForeignKey(field.getDefiningMapping()));
(field.getDefiningMapping()));
} else if (mapped.getElement().getTypeCode() == JavaTypes.PC) { } else if (mapped.getElement().getTypeCode() == JavaTypes.PC) {
if (isTypeUnjoinedSubclass(mapped.getElementMapping())) if (isTypeUnjoinedSubclass(mapped.getElementMapping()))
throw new MetaDataException(_loc.get throw new MetaDataException(_loc.get
("mapped-inverse-unjoined", field.getName(), ("mapped-inverse-unjoined", field.getName(), field.getDefiningMapping(), mapped));
field.getDefiningMapping(), mapped));
// warn the user about making the collection side the owner // warn the user about making the collection side the owner
Log log = field.getRepository().getLog(); Log log = field.getRepository().getLog();
if (log.isInfoEnabled()) if (log.isInfoEnabled())
log.info(_loc.get("coll-owner", field, mapped)); log.info(_loc.get("coll-owner", field, mapped));
field.setForeignKey(mapped.getElementMapping(). field.setForeignKey(mapped.getElementMapping().getForeignKey());
getForeignKey()); } else {
} else throw new MetaDataException(_loc.get("not-inv-relation", field, mapped));
throw new MetaDataException(_loc.get("not-inv-relation", }
field, mapped));
field.setUseClassCriteria(criteria); field.setUseClassCriteria(criteria);
return; return;
} }
@ -157,24 +156,22 @@ public class RelationFieldStrategy
field.getMappingInfo().setColumns(null); field.getMappingInfo().setColumns(null);
} }
if (!field.isBiMTo1JT()) if (!field.isBidirectionalManyToOneJoinTable())
field.mapJoin(adapt, false); field.mapJoin(adapt, false);
if (field.getTypeMapping().isMapped()) { if (field.getTypeMapping().isMapped()) {
if (field.getMappedByIdValue() != null) if (field.getMappedByIdValue() != null)
setMappedByIdColumns(); setMappedByIdColumns();
if (!field.isBiMTo1JT()) { if (!field.isBidirectionalManyToOneJoinTable()) {
ForeignKey fk = vinfo.getTypeJoin(field, field.getName(), true, ForeignKey fk = vinfo.getTypeJoin(field, field.getName(), true, adapt);
adapt);
field.setForeignKey(fk); field.setForeignKey(fk);
} }
field.setColumnIO(vinfo.getColumnIO()); field.setColumnIO(vinfo.getColumnIO());
if (vinfo.getJoinDirection() == vinfo.JOIN_INVERSE) if (vinfo.getJoinDirection() == MappingInfo.JOIN_INVERSE)
field.setJoinDirection(field.JOIN_INVERSE); field.setJoinDirection(FieldMapping.JOIN_INVERSE);
} else } else {
RelationStrategies.mapRelationToUnmappedPC(field, field.getName(), RelationStrategies.mapRelationToUnmappedPC(field, field.getName(), adapt);
adapt); }
field.setUseClassCriteria(criteria); field.setUseClassCriteria(criteria);
field.mapPrimaryKey(adapt); field.mapPrimaryKey(adapt);
PrimaryKey pk = field.getTable().getPrimaryKey(); PrimaryKey pk = field.getTable().getPrimaryKey();
@ -209,11 +206,10 @@ public class RelationFieldStrategy
} }
} }
private List getMappedByIdColumns(FieldMapping pk) { private List<Column> getMappedByIdColumns(FieldMapping pk) {
ClassMetaData embeddedId = ((ValueMappingImpl)pk.getValue()). ClassMetaData embeddedId = ((ValueMappingImpl)pk.getValue()).getEmbeddedMetaData();
getEmbeddedMetaData();
Column[] pkCols = null; Column[] pkCols = null;
List cols = new ArrayList(); List<Column> cols = new ArrayList<Column>();
String mappedByIdValue = field.getMappedByIdValue(); String mappedByIdValue = field.getMappedByIdValue();
if (embeddedId != null) { if (embeddedId != null) {
FieldMetaData[] fmds = embeddedId.getFields(); FieldMetaData[] fmds = embeddedId.getFields();
@ -221,20 +217,19 @@ public class RelationFieldStrategy
if ((fmds[i].getName().equals(mappedByIdValue)) || if ((fmds[i].getName().equals(mappedByIdValue)) ||
mappedByIdValue.length() == 0) { mappedByIdValue.length() == 0) {
if (fmds[i].getValue().getEmbeddedMetaData() != null) { if (fmds[i].getValue().getEmbeddedMetaData() != null) {
EmbedValueHandler.getEmbeddedIdCols( EmbedValueHandler.getEmbeddedIdCols((FieldMapping)fmds[i], cols);
(FieldMapping)fmds[i], cols); } else {
} else EmbedValueHandler.getIdColumns((FieldMapping)fmds[i], cols);
EmbedValueHandler.getIdColumns( }
(FieldMapping)fmds[i], cols);
} }
} }
return cols; return cols;
} else { // primary key is single-value } else { // primary key is single-value
Class pkType = pk.getDeclaredType(); Class<?> pkType = pk.getDeclaredType();
FieldMetaData[] pks = field.getValue().getDeclaredTypeMetaData(). FieldMetaData[] pks = field.getValue().getDeclaredTypeMetaData().
getPrimaryKeyFields(); getPrimaryKeyFields();
if (pks.length != 1 || pks[0].getDeclaredType() != pkType) if (pks.length != 1 || pks[0].getDeclaredType() != pkType)
return Collections.EMPTY_LIST; return Collections.emptyList();
pkCols = pk.getColumns(); pkCols = pk.getColumns();
for (int i = 0; i < pkCols.length; i++) for (int i = 0; i < pkCols.length; i++)
cols.add(pkCols[i]); cols.add(pkCols[i]);
@ -271,11 +266,11 @@ 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() == FieldMapping.JOIN_INVERSE)
updateInverse(sm, rel, store, rm); 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 && !field.isBiMTo1JT()) { if (row != null && !field.isBidirectionalManyToOneJoinTable()) {
field.setForeignKey(row, rel); field.setForeignKey(row, rel);
// this is for bi-directional maps, the key and value of the // this is for bi-directional maps, the key and value of the
// map are stored in the table of the mapped-by entity // map are stored in the table of the mapped-by entity
@ -295,7 +290,7 @@ public class RelationFieldStrategy
if (mapField == null) if (mapField == null)
return; return;
Map mapObj = (Map)rel.fetchObjectField(mapField.getIndex()); Map<Object,Object> mapObj = (Map<Object,Object>)rel.fetchObjectField(mapField.getIndex());
Object keyObj = getMapKeyObj(mapObj, sm.getPersistenceCapable()); Object keyObj = getMapKeyObj(mapObj, sm.getPersistenceCapable());
ValueMapping key = mapField.getKeyMapping(); ValueMapping key = mapField.getKeyMapping();
if (!key.isEmbedded()) { if (!key.isEmbedded()) {
@ -311,14 +306,11 @@ public class RelationFieldStrategy
} else { } else {
// key is an embeddable or basic type // key is an embeddable or basic type
FieldStrategy strategy = mapField.getStrategy(); FieldStrategy strategy = mapField.getStrategy();
if (strategy instanceof if (strategy instanceof HandlerRelationMapTableFieldStrategy) {
HandlerRelationMapTableFieldStrategy) { HandlerRelationMapTableFieldStrategy strat = (HandlerRelationMapTableFieldStrategy) strategy;
HandlerRelationMapTableFieldStrategy strat =
(HandlerRelationMapTableFieldStrategy) strategy;
Column[] kcols = strat.getKeyColumns((ClassMapping)meta); Column[] kcols = strat.getKeyColumns((ClassMapping)meta);
ColumnIO kio = strat.getKeyColumnIO(); ColumnIO kio = strat.getKeyColumnIO();
HandlerStrategies.set(key, keyObj, store, row, kcols, HandlerStrategies.set(key, keyObj, store, row, kcols, kio, true);
kio, true);
} }
} }
} }
@ -327,19 +319,18 @@ public class RelationFieldStrategy
FieldMapping[] fields = ((ClassMapping)meta).getFieldMappings(); FieldMapping[] fields = ((ClassMapping)meta).getFieldMappings();
for (int i = 0; i < fields.length; i++) { for (int i = 0; i < fields.length; i++) {
FieldMetaData mappedBy = fields[i].getMappedByMetaData(); FieldMetaData mappedBy = fields[i].getMappedByMetaData();
if (fields[i].getDeclaredTypeCode() == JavaTypes.MAP && if (fields[i].getDeclaredTypeCode() == JavaTypes.MAP && mappedBy == field)
mappedBy == field)
return fields[i]; return fields[i];
} }
return null; return null;
} }
private Object getMapKeyObj(Map mapObj, Object value) { private Object getMapKeyObj(Map<Object,Object> mapObj, Object value) {
if (value instanceof ReflectingPersistenceCapable) if (value instanceof ReflectingPersistenceCapable)
value = ((ReflectingPersistenceCapable)value).getManagedInstance(); value = ((ReflectingPersistenceCapable)value).getManagedInstance();
Set<Map.Entry> entries = mapObj.entrySet(); Set<Map.Entry<Object,Object>> entries = mapObj.entrySet();
for (Map.Entry entry : entries) { for (Map.Entry<Object,Object> entry : entries) {
if (entry.getValue() == value) if (entry.getValue() == value)
return entry.getKey(); return entry.getKey();
} }
@ -355,7 +346,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() == FieldMapping.JOIN_INVERSE) {
nullInverse(sm, rm); nullInverse(sm, rm);
updateInverse(sm, rel, store, rm); updateInverse(sm, rel, store, rm);
} else { } else {
@ -363,22 +354,22 @@ public class RelationFieldStrategy
field.isBidirectionalJoinTableMappingNonOwner()) ? field.isBidirectionalJoinTableMappingNonOwner()) ?
Row.ACTION_DELETE : Row.ACTION_UPDATE; Row.ACTION_DELETE : Row.ACTION_UPDATE;
Row row = field.getRow(sm, store, rm, action); Row row = field.getRow(sm, store, rm, action);
if (row != null && !field.isBiMTo1JT()) { if (row != null && !field.isBidirectionalManyToOneJoinTable()) {
field.setForeignKey(row, rel); field.setForeignKey(row, rel);
// this is for bi-directional maps, the key and value of the // this is for bi-directional maps, the key and value of the
// map are stored in the table of the mapped-by entity // map are stored in the table of the mapped-by entity
setMapKey(sm, rel, store, row); setMapKey(sm, rel, store, row);
} }
if (field.isBiMTo1JT()) { // also need to update the join table if (field.isBidirectionalManyToOneJoinTable()) { // also need to update the join table
PersistenceCapable invPC = (PersistenceCapable)sm.fetchObject( PersistenceCapable invPC = (PersistenceCapable)sm.fetchObject(
field.getBi_1ToM_JTField().getIndex()); field.getBidirectionalOneToManyJoinTableField().getIndex());
Row secondaryRow = null; Row secondaryRow = null;
if (invPC != null) { if (invPC != null) {
secondaryRow = rm.getSecondaryRow(field.getBi1ToMJoinFK().getTable(), secondaryRow = rm.getSecondaryRow(field.getBidirectionalOneToManyJoinForeignKey().getTable(),
Row.ACTION_INSERT); Row.ACTION_INSERT);
secondaryRow.setForeignKey(field.getBi1ToMElemFK(), null, sm); secondaryRow.setForeignKey(field.getBidirectionalOneToManyElementForeignKey(), null, sm);
secondaryRow.setForeignKey(field.getBi1ToMJoinFK(), null, secondaryRow.setForeignKey(field.getBidirectionalOneToManyJoinForeignKey(), null,
RelationStrategies.getStateManager(invPC, RelationStrategies.getStateManager(invPC,
store.getContext())); store.getContext()));
rm.flushSecondaryRow(secondaryRow); rm.flushSecondaryRow(secondaryRow);
@ -392,7 +383,7 @@ public class RelationFieldStrategy
if (field.getMappedBy() != null) if (field.getMappedBy() != null)
return; return;
if (field.getJoinDirection() == field.JOIN_INVERSE) { if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE) {
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());
@ -504,7 +495,7 @@ public class RelationFieldStrategy
public int supportsSelect(Select sel, int type, OpenJPAStateManager sm, public int supportsSelect(Select sel, int type, OpenJPAStateManager sm,
JDBCStore store, JDBCFetchConfiguration fetch) { JDBCStore store, JDBCFetchConfiguration fetch) {
if (type == Select.TYPE_JOINLESS) if (type == Select.TYPE_JOINLESS)
return (field.getJoinDirection() != field.JOIN_INVERSE return (field.getJoinDirection() != FieldMapping.JOIN_INVERSE
&& sel.isSelected(field.getTable())) ? 1 : 0; && sel.isSelected(field.getTable())) ? 1 : 0;
if (type == Select.TYPE_TWO_PART) if (type == Select.TYPE_TWO_PART)
return 1; return 1;
@ -535,17 +526,15 @@ public class RelationFieldStrategy
final OpenJPAStateManager sm, final JDBCStore store, final OpenJPAStateManager sm, final JDBCStore store,
final JDBCFetchConfiguration fetch, final int eagerMode) { final JDBCFetchConfiguration fetch, final int eagerMode) {
final ClassMapping[] clss = field.getIndependentTypeMappings(); final ClassMapping[] clss = field.getIndependentTypeMappings();
if (!(sel instanceof Union)) if (!(sel instanceof Union)) {
selectEagerParallel((Select) sel, clss[0], store, fetch, eagerMode); selectEagerParallel((Select) sel, clss[0], store, fetch, eagerMode);
else { } else {
Union union = (Union) sel; Union union = (Union) sel;
if (fetch.getSubclassFetchMode (field.getTypeMapping()) if (fetch.getSubclassFetchMode (field.getTypeMapping()) != JDBCFetchConfiguration.EAGER_JOIN)
!= JDBCFetchConfiguration.EAGER_JOIN)
union.abortUnion(); union.abortUnion();
union.select(new Union.Selector() { union.select(new Union.Selector() {
public void select(Select sel, int idx) { public void select(Select sel, int idx) {
selectEagerParallel(sel, clss[idx], store, fetch, selectEagerParallel(sel, clss[idx], store, fetch, eagerMode);
eagerMode);
} }
}); });
} }
@ -556,7 +545,7 @@ public class RelationFieldStrategy
*/ */
private void selectEagerParallel(Select sel, ClassMapping cls, private void selectEagerParallel(Select sel, ClassMapping cls,
JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) { JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) {
if (field.isBiMTo1JT()) if (field.isBidirectionalManyToOneJoinTable())
return; return;
sel.selectPrimaryKey(field.getDefiningMapping()); sel.selectPrimaryKey(field.getDefiningMapping());
// set a variable name that does not conflict with any in the query; // set a variable name that does not conflict with any in the query;
@ -571,7 +560,7 @@ public class RelationFieldStrategy
public void selectEagerJoin(Select sel, OpenJPAStateManager sm, public void selectEagerJoin(Select sel, OpenJPAStateManager sm,
JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) { JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) {
if (field.isBiMTo1JT()) if (field.isBidirectionalManyToOneJoinTable())
return; return;
// limit the eager mode to single on recursive eager fetching b/c // limit the eager mode to single on recursive eager fetching b/c
@ -590,7 +579,7 @@ public class RelationFieldStrategy
* Add the joins needed to select/load eager data. * Add the joins needed to select/load eager data.
*/ */
private Joins eagerJoin(Joins joins, ClassMapping cls, boolean forceInner) { private Joins eagerJoin(Joins joins, ClassMapping cls, boolean forceInner) {
boolean inverse = field.getJoinDirection() == field.JOIN_INVERSE; boolean inverse = field.getJoinDirection() == FieldMapping.JOIN_INVERSE;
if (!inverse) { if (!inverse) {
joins = join(joins, false); joins = join(joins, false);
joins = setEmbeddedVariable(joins); joins = setEmbeddedVariable(joins);
@ -618,7 +607,7 @@ public class RelationFieldStrategy
public int select(Select sel, OpenJPAStateManager sm, JDBCStore store, public int select(Select sel, OpenJPAStateManager sm, JDBCStore store,
JDBCFetchConfiguration fetch, int eagerMode) { JDBCFetchConfiguration fetch, int eagerMode) {
if (field.getJoinDirection() == field.JOIN_INVERSE) if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE)
return -1; return -1;
// already cached oid? // already cached oid?
if (sm != null && sm.getIntermediate(field.getIndex()) != null) if (sm != null && sm.getIntermediate(field.getIndex()) != null)
@ -633,11 +622,11 @@ public class RelationFieldStrategy
JDBCFetchConfiguration fetch, Object res) JDBCFetchConfiguration fetch, Object res)
throws SQLException { throws SQLException {
// process batched results if we haven't already // process batched results if we haven't already
Map rels; Map<Object,Object> rels;
if (res instanceof Result) if (res instanceof Result)
rels = processEagerParallelResult(sm, store, fetch, (Result) res); rels = processEagerParallelResult(sm, store, fetch, (Result) res);
else else
rels = (Map) res; rels = (Map<Object,Object>) res;
// store object for this oid in instance // store object for this oid in instance
sm.storeObject(field.getIndex(), rels.remove(sm.getObjectId())); sm.storeObject(field.getIndex(), rels.remove(sm.getObjectId()));
@ -647,7 +636,7 @@ public class RelationFieldStrategy
/** /**
* Process the given batched result. * Process the given batched result.
*/ */
private Map processEagerParallelResult(OpenJPAStateManager sm, private Map<Object,Object> processEagerParallelResult(OpenJPAStateManager sm,
JDBCStore store, JDBCFetchConfiguration fetch, Result res) JDBCStore store, JDBCFetchConfiguration fetch, Result res)
throws SQLException { throws SQLException {
// do same joins as for load // do same joins as for load
@ -657,7 +646,7 @@ public class RelationFieldStrategy
Joins joins = res.newJoins().setVariable("*"); Joins joins = res.newJoins().setVariable("*");
eagerJoin(joins, clss[0], true); eagerJoin(joins, clss[0], true);
Map rels = new HashMap(); Map<Object,Object> rels = new HashMap<Object,Object>();
ClassMapping owner = field.getDefiningMapping(); ClassMapping owner = field.getDefiningMapping();
ClassMapping cls; ClassMapping cls;
Object oid; Object oid;
@ -676,7 +665,7 @@ public class RelationFieldStrategy
public void loadEagerJoin(OpenJPAStateManager sm, JDBCStore store, public void loadEagerJoin(OpenJPAStateManager sm, JDBCStore store,
JDBCFetchConfiguration fetch, Result res) JDBCFetchConfiguration fetch, Result res)
throws SQLException { throws SQLException {
if (field.isBiMTo1JT()) if (field.isBidirectionalManyToOneJoinTable())
return; return;
ClassMapping cls = field.getIndependentTypeMappings()[0]; ClassMapping cls = field.getIndependentTypeMappings()[0];
@ -719,7 +708,7 @@ public class RelationFieldStrategy
public void load(OpenJPAStateManager sm, JDBCStore store, public void load(OpenJPAStateManager sm, JDBCStore store,
JDBCFetchConfiguration fetch, Result res) JDBCFetchConfiguration fetch, Result res)
throws SQLException { throws SQLException {
if (field.getJoinDirection() == field.JOIN_INVERSE) if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE)
return; return;
// cached oid? // cached oid?
if (sm != null && sm.getIntermediate(field.getIndex()) != null) if (sm != null && sm.getIntermediate(field.getIndex()) != null)
@ -732,7 +721,7 @@ public class RelationFieldStrategy
// get the related object's oid // get the related object's oid
ClassMapping relMapping = field.getTypeMapping(); ClassMapping relMapping = field.getTypeMapping();
Object oid = null; Object oid = null;
if (relMapping.isMapped() && !field.isBiMTo1JT()) { if (relMapping.isMapped() && !field.isBidirectionalManyToOneJoinTable()) {
oid = relMapping.getObjectId(store, res, field.getForeignKey(), oid = relMapping.getObjectId(store, res, field.getForeignKey(),
field.getPolymorphic() != ValueMapping.POLY_FALSE, null); field.getPolymorphic() != ValueMapping.POLY_FALSE, null);
} else { } else {
@ -746,8 +735,7 @@ public class RelationFieldStrategy
if (cols.length == 1) { if (cols.length == 1) {
Object val = res.getObject(cols[0], null, null); Object val = res.getObject(cols[0], null, null);
if (val != null) if (val != null)
oid = ApplicationIds.fromPKValues(new Object[]{ val }, oid = ApplicationIds.fromPKValues(new Object[]{ val }, relMapping);
relMapping);
} else { } else {
Object[] vals = new Object[cols.length]; Object[] vals = new Object[cols.length];
for (int i = 0; i < cols.length; i++) { for (int i = 0; i < cols.length; i++) {
@ -767,8 +755,7 @@ public class RelationFieldStrategy
sm.setIntermediate(field.getIndex(), oid); sm.setIntermediate(field.getIndex(), oid);
} }
public void load(final OpenJPAStateManager sm, final JDBCStore store, public void load(final OpenJPAStateManager sm, final JDBCStore store, final JDBCFetchConfiguration fetch)
final JDBCFetchConfiguration fetch)
throws SQLException { throws SQLException {
// check for cached oid value, or load oid if no way to join // check for cached oid value, or load oid if no way to join
if (Boolean.TRUE.equals(_fkOid)) { if (Boolean.TRUE.equals(_fkOid)) {
@ -787,41 +774,54 @@ public class RelationFieldStrategy
// select related mapping columns; joining from the related type // select related mapping columns; joining from the related type
// back to our fk table if not an inverse mapping (in which case we // back to our fk table if not an inverse mapping (in which case we
// can just make sure the inverse cols == our pk values) // can just make sure the inverse cols == our pk values)
Union union = store.getSQLFactory().newUnion(rels.length); Union union;
union.setExpectedResultCount(1, false); if (_executor == null) {
if (fetch.getSubclassFetchMode(field.getTypeMapping()) union = store.getSQLFactory().newUnion(rels.length);
!= JDBCFetchConfiguration.EAGER_JOIN) union.setExpectedResultCount(1, false);
union.abortUnion(); if (fetch.getSubclassFetchMode(field.getTypeMapping()) != JDBCFetchConfiguration.EAGER_JOIN)
union.abortUnion();
if (((JDBCConfiguration)field.getMappingRepository().getConfiguration()).getSelectCacheEnabled()) {
_executor = union;
}
} else {
union = (Union)_executor;
}
union.select(new Union.Selector() { union.select(new Union.Selector() {
public void select(Select sel, int idx) { public void select(Select sel, int idx) {
if (field.getJoinDirection() == field.JOIN_INVERSE) ForeignKey fk = field.getForeignKey(rels[idx]);
sel.whereForeignKey(field.getForeignKey(rels[idx]), ClassMapping mapping = field.getDefiningMapping();
sm.getObjectId(), field.getDefiningMapping(), store); Object oid = sm.getObjectId();
else { if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE) {
if (!field.isBiMTo1JT()) { sel.whereForeignKey(fk, oid, mapping, store);
resJoins[idx] = sel.newJoins().joinRelation(field.getName(), } else {
field.getForeignKey(rels[idx]), rels[idx], if (!field.isBidirectionalManyToOneJoinTable()) {
field.getSelectSubclasses(), false, false); if (sel.isReadOnly()) {
resJoins[idx] = sel.getJoins();
} else {
resJoins[idx] = sel.newJoins().joinRelation(field.getName(), fk, rels[idx],
subs, false, false);
}
field.wherePrimaryKey(sel, sm, store); field.wherePrimaryKey(sel, sm, store);
} else { } else {
resJoins[idx] = sel.newJoins().joinRelation(null, if (sel.isReadOnly()) {
field.getBi1ToMJoinFK(), rels[idx], resJoins[idx] = sel.getJoins();
field.getSelectSubclasses(), false, false); } else {
sel.whereForeignKey(field.getBi1ToMElemFK(), sm.getObjectId(), resJoins[idx] = sel.newJoins().joinRelation(null,
field.getDefiningMapping(), store); field.getBidirectionalOneToManyJoinForeignKey(), rels[idx],
subs, false, false);
}
sel.whereForeignKey(field.getBidirectionalOneToManyElementForeignKey(), oid, mapping, store);
} }
} }
sel.select(rels[idx], subs, store, fetch, fetch.EAGER_JOIN, if (!sel.isReadOnly()) {
resJoins[idx]); sel.select(rels[idx], subs, store, fetch, JDBCFetchConfiguration.EAGER_JOIN, resJoins[idx]);
}
} }
}); });
Result res = union.execute(store, fetch); Result res = union.execute(store, fetch);
try { try {
Object val = null; Object val = (res.next()) ? res.load(rels[res.indexOf()], store, fetch, resJoins[res.indexOf()]) : null;
if (res.next())
val = res.load(rels[res.indexOf()], store, fetch,
resJoins[res.indexOf()]);
sm.storeObject(field.getIndex(), val); sm.storeObject(field.getIndex(), val);
} finally { } finally {
res.close(); res.close();
@ -837,7 +837,7 @@ public class RelationFieldStrategy
// because it'll be in the primary table) and see if fk cols are null; // because it'll be in the primary table) and see if fk cols are null;
// if inverse, then we have to do a sub-select to see if any inverse // if inverse, then we have to do a sub-select to see if any inverse
// objects point back to this field's owner // objects point back to this field's owner
if (field.getJoinDirection() != field.JOIN_INVERSE) { if (field.getJoinDirection() != FieldMapping.JOIN_INVERSE) {
//### probably need some sort of subselect here on fk constants //### probably need some sort of subselect here on fk constants
joins = join(joins, false); joins = join(joins, false);
Column[] cols = field.getColumns(); Column[] cols = field.getColumns();
@ -846,8 +846,9 @@ public class RelationFieldStrategy
else else
sql.append(sel.getColumnAlias(cols[0], joins)). sql.append(sel.getColumnAlias(cols[0], joins)).
append(" IS ").appendValue(null, cols[0]); append(" IS ").appendValue(null, cols[0]);
} else } else {
testInverseNull(sql, sel, joins, true); testInverseNull(sql, sel, joins, true);
}
} }
public void appendIsNotNull(SQLBuffer sql, Select sel, Joins joins) { public void appendIsNotNull(SQLBuffer sql, Select sel, Joins joins) {
@ -855,7 +856,7 @@ public class RelationFieldStrategy
// because it'll be in the primary table) and see if fk cols aren't // because it'll be in the primary table) and see if fk cols aren't
// null; if inverse, then we have to do a sub-select to see if any // null; if inverse, then we have to do a sub-select to see if any
// inverse objects point back to this field's owner // inverse objects point back to this field's owner
if (field.getJoinDirection() != field.JOIN_INVERSE) { if (field.getJoinDirection() != FieldMapping.JOIN_INVERSE) {
//### probably need some sort of subselect here on fk constants //### probably need some sort of subselect here on fk constants
joins = join(joins, false); joins = join(joins, false);
Column[] cols = field.getColumns(); Column[] cols = field.getColumns();
@ -886,30 +887,27 @@ public class RelationFieldStrategy
sql.append("0 < "); sql.append("0 < ");
ForeignKey fk = field.getForeignKey(); ForeignKey fk = field.getForeignKey();
ContainerFieldStrategy.appendJoinCount(sql, sel, joins, dict, field, ContainerFieldStrategy.appendJoinCount(sql, sel, joins, dict, field, fk);
fk);
} }
public Joins join(Joins joins, boolean forceOuter) { public Joins join(Joins joins, boolean forceOuter) {
// if we're not in an inverse object table join normally, otherwise // if we're not in an inverse object table join normally, otherwise
// already traversed the relation; just join back to owner table // already traversed the relation; just join back to owner table
if (field.getJoinDirection() != field.JOIN_INVERSE) if (field.getJoinDirection() != FieldMapping.JOIN_INVERSE)
return field.join(joins, forceOuter, false); return field.join(joins, forceOuter, false);
ClassMapping[] clss = field.getIndependentTypeMappings(); ClassMapping[] clss = field.getIndependentTypeMappings();
if (clss.length != 1) if (clss.length != 1)
throw RelationStrategies.uninversable(field); throw RelationStrategies.uninversable(field);
if (forceOuter) if (forceOuter)
return joins.outerJoinRelation(field.getName(), return joins.outerJoinRelation(field.getName(),
field.getForeignKey(), clss[0], field.getSelectSubclasses(), field.getForeignKey(), clss[0], field.getSelectSubclasses(), true, false);
true, false);
return joins.joinRelation(field.getName(), field.getForeignKey(), return joins.joinRelation(field.getName(), field.getForeignKey(),
clss[0], field.getSelectSubclasses(), true, false); clss[0], field.getSelectSubclasses(), true, false);
} }
public Joins joinRelation(Joins joins, boolean forceOuter, public Joins joinRelation(Joins joins, boolean forceOuter, boolean traverse) {
boolean traverse) {
// if this is an inverse mapping it's already joined to the relation // if this is an inverse mapping it's already joined to the relation
if (field.getJoinDirection() == field.JOIN_INVERSE) if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE)
return joins; return joins;
ClassMapping[] clss = field.getIndependentTypeMappings(); ClassMapping[] clss = field.getIndependentTypeMappings();
if (clss.length != 1) { if (clss.length != 1) {
@ -946,8 +944,7 @@ public class RelationFieldStrategy
long id = res.getLong(col, joins); long id = res.getLong(col, joins);
if (field.getObjectIdFieldTypeCode() == JavaTypes.LONG) if (field.getObjectIdFieldTypeCode() == JavaTypes.LONG)
return id; return id;
return store.newDataStoreId(id, relmapping, field.getPolymorphic() return store.newDataStoreId(id, relmapping, field.getPolymorphic() != ValueMapping.POLY_FALSE);
!= ValueMapping.POLY_FALSE);
} }
if (relmapping.isOpenJPAIdentity()) if (relmapping.isOpenJPAIdentity())
@ -1000,27 +997,21 @@ public class RelationFieldStrategy
fieldVal = store.getContext().getObjectId(fieldVal); fieldVal = store.getContext().getObjectId(fieldVal);
if (fieldVal instanceof OpenJPAId) if (fieldVal instanceof OpenJPAId)
fieldVal = ((OpenJPAId) fieldVal).getIdObject(); fieldVal = ((OpenJPAId) fieldVal).getIdObject();
if (relmapping.getObjectIdType() != null if (relmapping.getObjectIdType() != null && relmapping.getObjectIdType().isInstance(fieldVal)) {
&& relmapping.getObjectIdType().isInstance(fieldVal)) {
Object[] pks = ApplicationIds.toPKValues(fieldVal, relmapping); Object[] pks = ApplicationIds.toPKValues(fieldVal, relmapping);
fieldVal = pks[relmapping.getField(j.getFieldIndex()). fieldVal = pks[relmapping.getField(j.getFieldIndex()).getPrimaryKeyIndex()];
getPrimaryKeyIndex()];
} else if (relmapping.getObjectIdType() == ObjectId.class && } else if (relmapping.getObjectIdType() == ObjectId.class &&
relmapping.getPrimaryKeyFieldMappings()[0].getValueMapping().isEmbedded()) { relmapping.getPrimaryKeyFieldMappings()[0].getValueMapping().isEmbedded()) {
if (fieldVal == null) return j.getJoinValue((fieldVal == null) ? savedFieldVal : fieldVal, col, store);
return j.getJoinValue(savedFieldVal, col, store);
return j.getJoinValue(fieldVal, col, store);
} }
return j.getJoinValue(fieldVal, col, store); return j.getJoinValue(fieldVal, col, store);
} }
public Object getJoinValue(OpenJPAStateManager sm, Column col, public Object getJoinValue(OpenJPAStateManager sm, Column col, JDBCStore store) {
JDBCStore store) {
return getJoinValue(sm.fetch(field.getIndex()), col, store); return getJoinValue(sm.fetch(field.getIndex()), col, store);
} }
public void setAutoAssignedValue(OpenJPAStateManager sm, JDBCStore store, public void setAutoAssignedValue(OpenJPAStateManager sm, JDBCStore store, Column col, Object autoInc) {
Column col, Object autoInc) {
throw new UnsupportedException(); throw new UnsupportedException();
} }
@ -1048,8 +1039,7 @@ public class RelationFieldStrategy
return UNSUPPORTED; return UNSUPPORTED;
} }
public void loadEmbedded(OpenJPAStateManager sm, JDBCStore store, public void loadEmbedded(OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch, Object val)
JDBCFetchConfiguration fetch, Object val)
throws SQLException { throws SQLException {
ClassMapping relMapping = field.getTypeMapping(); ClassMapping relMapping = field.getTypeMapping();
Object oid; Object oid;
@ -1059,8 +1049,7 @@ public class RelationFieldStrategy
oid = store.newDataStoreId(((Number) val).longValue(), relMapping, oid = store.newDataStoreId(((Number) val).longValue(), relMapping,
field.getPolymorphic() != ValueMapping.POLY_FALSE); field.getPolymorphic() != ValueMapping.POLY_FALSE);
else { else {
Object[] pks = (getColumns().length == 1) ? new Object[]{ val } Object[] pks = (getColumns().length == 1) ? new Object[]{ val } : (Object[]) val;
: (Object[]) val;
boolean nulls = true; boolean nulls = true;
for (int i = 0; nulls && i < pks.length; i++) for (int i = 0; nulls && i < pks.length; i++)
nulls = pks[i] == null; nulls = pks[i] == null;
@ -1068,17 +1057,15 @@ public class RelationFieldStrategy
oid = null; oid = null;
else { else {
oid = ApplicationIds.fromPKValues(pks, relMapping); oid = ApplicationIds.fromPKValues(pks, relMapping);
if (field.getPolymorphic() == ValueMapping.POLY_FALSE if (field.getPolymorphic() == ValueMapping.POLY_FALSE && oid instanceof OpenJPAId) {
&& oid instanceof OpenJPAId) { ((OpenJPAId) oid).setManagedInstanceType(relMapping.getDescribedType());
((OpenJPAId) oid).setManagedInstanceType(relMapping.
getDescribedType());
} }
} }
} }
if (oid == null) if (oid == null) {
sm.storeObject(field.getIndex(), null); sm.storeObject(field.getIndex(), null);
else { } else {
if (JavaTypes.maybePC(field.getValue()) && if (JavaTypes.maybePC(field.getValue()) &&
field.getElement().getEmbeddedMetaData() == null) { field.getElement().getEmbeddedMetaData() == null) {
Object obj = store.find(oid, field, fetch); Object obj = store.find(oid, field, fetch);

View File

@ -82,7 +82,7 @@ public class RelationRelationMapTableFieldStrategy
kunion.select(new Union.Selector() { kunion.select(new Union.Selector() {
public void select(Select sel, int idx) { public void select(Select sel, int idx) {
ForeignKey joinFK = null; ForeignKey joinFK = null;
if (field.isUni1ToMFK()) { if (field.isUnidirectionalOneToManyForeignKey()) {
ValueMapping val = field.getElementMapping(); ValueMapping val = field.getElementMapping();
ValueMappingInfo vinfo = val.getValueInfo(); ValueMappingInfo vinfo = val.getValueInfo();
Table table = vinfo.getTable(val); Table table = vinfo.getTable(val);
@ -117,7 +117,7 @@ public class RelationRelationMapTableFieldStrategy
vunion.setLRS(lrs); vunion.setLRS(lrs);
vunion.select(new Union.Selector() { vunion.select(new Union.Selector() {
public void select(Select sel, int idx) { public void select(Select sel, int idx) {
if (field.isUni1ToMFK()) { if (field.isUnidirectionalOneToManyForeignKey()) {
sel.orderBy(field.getKeyMapping().getColumns(), true, true); sel.orderBy(field.getKeyMapping().getColumns(), true, true);
sel.select(vals[idx], field.getElementMapping(). sel.select(vals[idx], field.getElementMapping().
getSelectSubclasses(), store, fetch, eagerMode, null); getSelectSubclasses(), store, fetch, eagerMode, null);
@ -203,10 +203,11 @@ public class RelationRelationMapTableFieldStrategy
FieldMapping mapped = field.getMappedByMapping(); FieldMapping mapped = field.getMappedByMapping();
DBDictionary dict = field.getMappingRepository().getDBDictionary(); DBDictionary dict = field.getMappingRepository().getDBDictionary();
DBIdentifier keyName = null; DBIdentifier keyName = null;
if (field.isUni1ToMFK() || (!field.isBiMTo1JT() && mapped != null)) { if (field.isUnidirectionalOneToManyForeignKey()
|| (!field.isBidirectionalManyToOneJoinTable() && mapped != null)) {
handleMappedByForeignKey(adapt); handleMappedByForeignKey(adapt);
keyName = dict.getValidColumnName(DBIdentifier.newColumn("vkey"), field.getTable()); keyName = dict.getValidColumnName(DBIdentifier.newColumn("vkey"), field.getTable());
} else if (field.isBiMTo1JT() || mapped == null) { } else if (field.isBidirectionalManyToOneJoinTable() || mapped == null) {
field.mapJoin(adapt, true); field.mapJoin(adapt, true);
mapTypeJoin(val, DBIdentifier.newColumn("value"), adapt); mapTypeJoin(val, DBIdentifier.newColumn("value"), adapt);
keyName = dict.getValidColumnName(DBIdentifier.newColumn("key"), field.getTable()); keyName = dict.getValidColumnName(DBIdentifier.newColumn("key"), field.getTable());
@ -245,11 +246,11 @@ public class RelationRelationMapTableFieldStrategy
if (map == null || map.isEmpty()) if (map == null || map.isEmpty())
return; return;
if (!field.isBiMTo1JT() && field.getMappedBy() != null) if (!field.isBidirectionalManyToOneJoinTable() && field.getMappedBy() != null)
return; return;
Row row = null; Row row = null;
if (!field.isUni1ToMFK()) { if (!field.isUnidirectionalOneToManyForeignKey()) {
row = rm.getSecondaryRow(field.getTable(), Row.ACTION_INSERT); row = rm.getSecondaryRow(field.getTable(), Row.ACTION_INSERT);
row.setForeignKey(field.getJoinForeignKey(), field.getJoinColumnIO(), row.setForeignKey(field.getJoinForeignKey(), field.getJoinColumnIO(),
sm); sm);
@ -263,7 +264,7 @@ public class RelationRelationMapTableFieldStrategy
entry = (Map.Entry) itr.next(); entry = (Map.Entry) itr.next();
keysm = RelationStrategies.getStateManager(entry.getKey(), ctx); keysm = RelationStrategies.getStateManager(entry.getKey(), ctx);
valsm = RelationStrategies.getStateManager(entry.getValue(), ctx); valsm = RelationStrategies.getStateManager(entry.getValue(), ctx);
if (field.isUni1ToMFK()){ if (field.isUnidirectionalOneToManyForeignKey()){
row = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(), row = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(),
Row.ACTION_UPDATE, valsm, true); Row.ACTION_UPDATE, valsm, true);
row.wherePrimaryKey(valsm); row.wherePrimaryKey(valsm);
@ -281,14 +282,14 @@ public class RelationRelationMapTableFieldStrategy
// from the view point of the owned side // from the view point of the owned side
PersistenceCapable obj = sm.getPersistenceCapable(); PersistenceCapable obj = sm.getPersistenceCapable();
if (!populateKey(row, valsm, obj, ctx, rm, store)) if (!populateKey(row, valsm, obj, ctx, rm, store))
if (!field.isUni1ToMFK()) if (!field.isUnidirectionalOneToManyForeignKey())
rm.flushSecondaryRow(row); rm.flushSecondaryRow(row);
} }
} }
public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm) public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
throws SQLException { throws SQLException {
if (field.getMappedBy() != null && !field.isBiMTo1JT()) if (field.getMappedBy() != null && !field.isBidirectionalManyToOneJoinTable())
return; return;
Map map = (Map) sm.fetchObject(field.getIndex()); Map map = (Map) sm.fetchObject(field.getIndex());
@ -319,7 +320,7 @@ public class RelationRelationMapTableFieldStrategy
Object mkey; Object mkey;
if (canChange && !change.isEmpty()) { if (canChange && !change.isEmpty()) {
Row changeRow = null; Row changeRow = null;
if (!field.isUni1ToMFK()) { if (!field.isUnidirectionalOneToManyForeignKey()) {
changeRow = rm.getSecondaryRow(field.getTable(), changeRow = rm.getSecondaryRow(field.getTable(),
Row.ACTION_UPDATE); Row.ACTION_UPDATE);
changeRow.whereForeignKey(field.getJoinForeignKey(), sm); changeRow.whereForeignKey(field.getJoinForeignKey(), sm);
@ -339,7 +340,7 @@ public class RelationRelationMapTableFieldStrategy
keysm = RelationStrategies.getStateManager(mkey, ctx); keysm = RelationStrategies.getStateManager(mkey, ctx);
valsm = RelationStrategies.getStateManager(mval, ctx); valsm = RelationStrategies.getStateManager(mval, ctx);
key.whereForeignKey(changeRow, keysm); key.whereForeignKey(changeRow, keysm);
if (field.isUni1ToMFK()){ if (field.isUnidirectionalOneToManyForeignKey()){
changeRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(), changeRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(),
Row.ACTION_UPDATE, valsm, true); Row.ACTION_UPDATE, valsm, true);
changeRow.wherePrimaryKey(valsm); changeRow.wherePrimaryKey(valsm);
@ -355,7 +356,7 @@ public class RelationRelationMapTableFieldStrategy
Collection rem = ct.getRemoved(); Collection rem = ct.getRemoved();
if (!rem.isEmpty() || (!canChange && !change.isEmpty())) { if (!rem.isEmpty() || (!canChange && !change.isEmpty())) {
Row delRow = null; Row delRow = null;
if (!field.isUni1ToMFK()) { if (!field.isUnidirectionalOneToManyForeignKey()) {
delRow = rm.getSecondaryRow(field.getTable(), delRow = rm.getSecondaryRow(field.getTable(),
Row.ACTION_DELETE); Row.ACTION_DELETE);
delRow.whereForeignKey(field.getJoinForeignKey(), sm); delRow.whereForeignKey(field.getJoinForeignKey(), sm);
@ -363,7 +364,7 @@ public class RelationRelationMapTableFieldStrategy
for (Iterator itr = rem.iterator(); itr.hasNext();) { for (Iterator itr = rem.iterator(); itr.hasNext();) {
Object pc = itr.next(); Object pc = itr.next();
if (field.isUni1ToMFK()){ if (field.isUnidirectionalOneToManyForeignKey()){
updateSetNull(sm, rm, pc); updateSetNull(sm, rm, pc);
} else { } else {
keysm = RelationStrategies.getStateManager(pc, ctx); keysm = RelationStrategies.getStateManager(pc, ctx);
@ -374,7 +375,7 @@ public class RelationRelationMapTableFieldStrategy
if (!canChange && !change.isEmpty()) { if (!canChange && !change.isEmpty()) {
for (Iterator itr = change.iterator(); itr.hasNext();) { for (Iterator itr = change.iterator(); itr.hasNext();) {
Object pc = itr.next(); Object pc = itr.next();
if (field.isUni1ToMFK()){ if (field.isUnidirectionalOneToManyForeignKey()){
updateSetNull(sm, rm, pc); updateSetNull(sm, rm, pc);
} else { } else {
keysm = RelationStrategies.getStateManager(pc, ctx); keysm = RelationStrategies.getStateManager(pc, ctx);
@ -389,7 +390,7 @@ public class RelationRelationMapTableFieldStrategy
Collection add = ct.getAdded(); Collection add = ct.getAdded();
if (!add.isEmpty() || (!canChange && !change.isEmpty())) { if (!add.isEmpty() || (!canChange && !change.isEmpty())) {
Row addRow = null; Row addRow = null;
if (!field.isUni1ToMFK()) { if (!field.isUnidirectionalOneToManyForeignKey()) {
addRow = rm.getSecondaryRow(field.getTable(), addRow = rm.getSecondaryRow(field.getTable(),
Row.ACTION_INSERT); Row.ACTION_INSERT);
addRow.setForeignKey(field.getJoinForeignKey(), addRow.setForeignKey(field.getJoinForeignKey(),
@ -409,7 +410,7 @@ public class RelationRelationMapTableFieldStrategy
continue; continue;
keysm = RelationStrategies.getStateManager(mkey, ctx); keysm = RelationStrategies.getStateManager(mkey, ctx);
valsm = RelationStrategies.getStateManager(mval, ctx); valsm = RelationStrategies.getStateManager(mval, ctx);
if (field.isUni1ToMFK()){ if (field.isUnidirectionalOneToManyForeignKey()){
addRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(), addRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(),
Row.ACTION_UPDATE, valsm, true); Row.ACTION_UPDATE, valsm, true);
addRow.wherePrimaryKey(valsm); addRow.wherePrimaryKey(valsm);
@ -436,7 +437,7 @@ public class RelationRelationMapTableFieldStrategy
continue; continue;
keysm = RelationStrategies.getStateManager(mkey, ctx); keysm = RelationStrategies.getStateManager(mkey, ctx);
valsm = RelationStrategies.getStateManager(mval, ctx); valsm = RelationStrategies.getStateManager(mval, ctx);
if (field.isUni1ToMFK()){ if (field.isUnidirectionalOneToManyForeignKey()){
addRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(), addRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(),
Row.ACTION_UPDATE, valsm, true); Row.ACTION_UPDATE, valsm, true);
addRow.wherePrimaryKey(valsm); addRow.wherePrimaryKey(valsm);
@ -503,7 +504,7 @@ public class RelationRelationMapTableFieldStrategy
public void delete(OpenJPAStateManager sm, JDBCStore store, RowManager rm) public void delete(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
throws SQLException { throws SQLException {
if (field.isUni1ToMFK()) { if (field.isUnidirectionalOneToManyForeignKey()) {
Map mapObj = (Map)sm.fetchObject(field.getIndex()); Map mapObj = (Map)sm.fetchObject(field.getIndex());
updateSetNull(sm, store, rm, mapObj.keySet()); updateSetNull(sm, store, rm, mapObj.keySet());
return; return;

View File

@ -113,7 +113,7 @@ public abstract class RelationToManyTableFieldStrategy
// Bi-directional oneToMany relation with join table strategy // Bi-directional oneToMany relation with join table strategy
// ==> should not mapped in the owner's table // ==> should not mapped in the owner's table
if (mapped != null) { if (mapped != null) {
if (!field.isBiMTo1JT()) { if (!field.isBidirectionalManyToOneJoinTable()) {
if (mapped.getElement().getTypeCode() != JavaTypes.PC) { if (mapped.getElement().getTypeCode() != JavaTypes.PC) {
throw new MetaDataException(_loc.get("not-inv-relation-coll", throw new MetaDataException(_loc.get("not-inv-relation-coll",
field, mapped)); field, mapped));
@ -134,9 +134,9 @@ public abstract class RelationToManyTableFieldStrategy
} }
} }
if (mapped == null || field.isBiMTo1JT()) { if (mapped == null || field.isBidirectionalManyToOneJoinTable()) {
if (field.isBiMTo1JT()) if (field.isBidirectionalManyToOneJoinTable())
field.setBi1MJoinTableInfo(); field.setBidirectionalOneToManyJoinTableInfo();
field.mapJoin(adapt, true); field.mapJoin(adapt, true);
if (elem.getTypeMapping().isMapped()) { if (elem.getTypeMapping().isMapped()) {
ForeignKey fk = vinfo.getTypeJoin(elem, "element", false, adapt); ForeignKey fk = vinfo.getTypeJoin(elem, "element", false, adapt);
@ -157,7 +157,7 @@ public abstract class RelationToManyTableFieldStrategy
public void insert(OpenJPAStateManager sm, JDBCStore store, RowManager rm) public void insert(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
throws SQLException { throws SQLException {
if (field.getMappedBy() == null || field.isBiMTo1JT()) if (field.getMappedBy() == null || field.isBidirectionalManyToOneJoinTable())
insert(sm, rm, sm.fetchObject(field.getIndex())); insert(sm, rm, sm.fetchObject(field.getIndex()));
} }
@ -188,7 +188,7 @@ public abstract class RelationToManyTableFieldStrategy
public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm) public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
throws SQLException { throws SQLException {
if (field.getMappedBy() != null && !field.isBiMTo1JT()) if (field.getMappedBy() != null && !field.isBidirectionalManyToOneJoinTable())
return; return;
Object obj = sm.fetchObject(field.getIndex()); Object obj = sm.fetchObject(field.getIndex());

View File

@ -26,6 +26,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.openjpa.enhance.PersistenceCapable; import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration; import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
import org.apache.openjpa.jdbc.kernel.JDBCStore; import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.meta.ClassMapping; import org.apache.openjpa.jdbc.meta.ClassMapping;
@ -57,8 +58,13 @@ import org.apache.openjpa.util.Proxy;
* insert/update/delete behavior as well as overriding * insert/update/delete behavior as well as overriding
* {@link FieldStrategy#toDataStoreValue}, {@link FieldStrategy#join}, and * {@link FieldStrategy#toDataStoreValue}, {@link FieldStrategy#join}, and
* {@link FieldStrategy#joinRelation} if necessary. * {@link FieldStrategy#joinRelation} if necessary.
* <br>
* The strategy may reuse the same {@link SelectExecutor select} if the
* {@link JDBCConfiguration#getSelectCacheEnabled() configuration option}
* instructs to do so.
* *
* @author Abe White * @author Abe White
* @author Pinaki Poddar (select caching)
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
public abstract class StoreCollectionFieldStrategy public abstract class StoreCollectionFieldStrategy
@ -194,6 +200,7 @@ public abstract class StoreCollectionFieldStrategy
private void selectEager(Select sel, ClassMapping elem, private void selectEager(Select sel, ClassMapping elem,
OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch, OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch,
int eagerMode, boolean selectOid, boolean outer) { int eagerMode, boolean selectOid, boolean outer) {
if (sel.isReadOnly()) return;
// force distinct if there was a to-many join to avoid duplicates, but // force distinct if there was a to-many join to avoid duplicates, but
// if this is a parallel select don't make distinct based on the // if this is a parallel select don't make distinct based on the
// eager joins alone if the original wasn't distinct // eager joins alone if the original wasn't distinct
@ -523,7 +530,9 @@ public abstract class StoreCollectionFieldStrategy
Union union; Union union;
if (_executor == null) { if (_executor == null) {
union = store.getSQLFactory().newUnion(Math.max(1, elems.length)); union = store.getSQLFactory().newUnion(Math.max(1, elems.length));
_executor = union; if (store.getConfiguration().getSelectCacheEnabled()) {
_executor = union;
}
} else { } else {
union = (Union)_executor; union = (Union)_executor;
} }
@ -571,25 +580,24 @@ public abstract class StoreCollectionFieldStrategy
} }
/** /**
* Select data for loading, starting in field table. * Selects data for loading, starting in field table.
*
*/ */
protected Joins selectAll(Select sel, ClassMapping elem, protected Joins selectAll(Select sel, ClassMapping elem,
OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch, OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) {
int eagerMode) {
ForeignKey fk = getJoinForeignKey(elem); ForeignKey fk = getJoinForeignKey(elem);
Object oid = getObjectIdForJoin(fk, sm); Object oid = getObjectIdForJoin(fk, sm);
sel.whereForeignKey(fk, oid, field.getDefiningMapping(), store); sel.whereForeignKey(fk, oid, field.getDefiningMapping(), store);
Joins joins; if (sel.isReadOnly()) {
if (!sel.isReadOnly()) { return sel.getJoins();
// order first, then select so that if the projection introduces
// additional ordering, it will be after our required ordering
field.orderLocal(sel, elem, null);
joins = joinElementRelation(sel.newJoins(), elem);
field.orderRelation(sel, elem, joins);
selectElement(sel, elem, store, fetch, eagerMode, joins);
} else {
joins = joinElementRelation(sel.newJoins(), elem);
} }
// order first, then select so that if the projection introduces
// additional ordering, it will be after our required ordering
field.orderLocal(sel, elem, null);
Joins joins = joinElementRelation(sel.newJoins(), elem);
field.orderRelation(sel, elem, joins);
selectElement(sel, elem, store, fetch, eagerMode, joins);
return joins; return joins;
} }

View File

@ -1894,7 +1894,8 @@ public class DBDictionary
public SQLBuffer toSelectCount(Select sel) { public SQLBuffer toSelectCount(Select sel) {
SQLBuffer selectSQL = new SQLBuffer(this); SQLBuffer selectSQL = new SQLBuffer(this);
SQLBuffer from; SQLBuffer from;
sel.addJoinClassConditions(); if (!sel.isReadOnly())
sel.addJoinClassConditions();
if (sel.getFromSelect() != null) if (sel.getFromSelect() != null)
from = getFromSelect(sel, false); from = getFromSelect(sel, false);
else else

View File

@ -255,6 +255,8 @@ public class SelectImpl
} }
public SQLBuffer toSelect(boolean forUpdate, JDBCFetchConfiguration fetch) { public SQLBuffer toSelect(boolean forUpdate, JDBCFetchConfiguration fetch) {
if (_readOnly)
return _full;
_full = _dict.toSelect(this, forUpdate, fetch); _full = _dict.toSelect(this, forUpdate, fetch);
return _full; return _full;
} }
@ -378,12 +380,10 @@ public class SelectImpl
throws SQLException { throws SQLException {
if (fetch == null) if (fetch == null)
fetch = store.getFetchConfiguration(); fetch = store.getFetchConfiguration();
return execute(store.getContext(), store, fetch, return execute(store.getContext(), store, fetch, fetch.getReadLockLevel());
fetch.getReadLockLevel());
} }
public Result execute(JDBCStore store, JDBCFetchConfiguration fetch, public Result execute(JDBCStore store, JDBCFetchConfiguration fetch, int lockLevel)
int lockLevel)
throws SQLException { throws SQLException {
if (fetch == null) if (fetch == null)
fetch = store.getFetchConfiguration(); fetch = store.getFetchConfiguration();
@ -394,8 +394,7 @@ public class SelectImpl
* Execute this select in the context of the given store manager. The * Execute this select in the context of the given store manager. The
* context is passed in separately for profiling purposes. * context is passed in separately for profiling purposes.
*/ */
protected Result execute(StoreContext ctx, JDBCStore store, protected Result execute(StoreContext ctx, JDBCStore store, JDBCFetchConfiguration fetch, int lockLevel)
JDBCFetchConfiguration fetch, int lockLevel)
throws SQLException { throws SQLException {
boolean forUpdate = false; boolean forUpdate = false;
if (!isAggregate() && _grouping == null) { if (!isAggregate() && _grouping == null) {
@ -678,6 +677,7 @@ public class SelectImpl
} }
public void addJoinClassConditions() { public void addJoinClassConditions() {
assertMutable();
if (_joins == null || _joins.joins() == null) if (_joins == null || _joins.joins() == null)
return; return;
@ -806,6 +806,7 @@ public class SelectImpl
} }
public void clearSelects() { public void clearSelects() {
assertMutable();
_selects.clear(); _selects.clear();
} }
@ -873,6 +874,7 @@ public class SelectImpl
* to count from the back of the select list. * to count from the back of the select list.
*/ */
public void insertPlaceholder(String sql, int pos) { public void insertPlaceholder(String sql, int pos) {
assertMutable();
Object holder = (_placeholders >= PLACEHOLDERS.length) Object holder = (_placeholders >= PLACEHOLDERS.length)
? new Placeholder() : PLACEHOLDERS[_placeholders++]; ? new Placeholder() : PLACEHOLDERS[_placeholders++];
_selects.insertAlias(pos, holder, sql); _selects.insertAlias(pos, holder, sql);
@ -882,14 +884,17 @@ public class SelectImpl
* Clear selected placeholders, and return removed select indexes. * Clear selected placeholders, and return removed select indexes.
*/ */
public void clearPlaceholderSelects() { public void clearPlaceholderSelects() {
assertMutable();
_selects.clearPlaceholders(); _selects.clearPlaceholders();
} }
public boolean select(Column col) { public boolean select(Column col) {
assertMutable();
return select(col, (Joins) null); return select(col, (Joins) null);
} }
public boolean select(Column col, Joins joins) { public boolean select(Column col, Joins joins) {
assertMutable();
if (!isGrouping()) if (!isGrouping())
return select(col, getJoins(joins, true), false); return select(col, getJoins(joins, true), false);
groupBy(col, joins); groupBy(col, joins);
@ -897,10 +902,12 @@ public class SelectImpl
} }
public int select(Column[] cols) { public int select(Column[] cols) {
assertMutable();
return select(cols, null); return select(cols, null);
} }
public int select(Column[] cols, Joins joins) { public int select(Column[] cols, Joins joins) {
assertMutable();
if (cols == null || cols.length == 0) if (cols == null || cols.length == 0)
return 0; return 0;
if (isGrouping()) { if (isGrouping()) {
@ -919,6 +926,7 @@ public class SelectImpl
* Select the given column after making the given joins. * Select the given column after making the given joins.
*/ */
private boolean select(Column col, PathJoins pj, boolean ident) { private boolean select(Column col, PathJoins pj, boolean ident) {
assertMutable();
// we cache on column object if there are no joins so that when // we cache on column object if there are no joins so that when
// looking up columns in the result we don't have to create a string // looking up columns in the result we don't have to create a string
// buffer for the table + column alias; if there are joins, then // buffer for the table + column alias; if there are joins, then
@ -940,12 +948,14 @@ public class SelectImpl
public void select(ClassMapping mapping, int subclasses, public void select(ClassMapping mapping, int subclasses,
JDBCStore store, JDBCFetchConfiguration fetch, int eager) { JDBCStore store, JDBCFetchConfiguration fetch, int eager) {
assertMutable();
select(mapping, subclasses, store, fetch, eager, null); select(mapping, subclasses, store, fetch, eager, null);
} }
public void select(ClassMapping mapping, int subclasses, public void select(ClassMapping mapping, int subclasses,
JDBCStore store, JDBCFetchConfiguration fetch, int eager, JDBCStore store, JDBCFetchConfiguration fetch, int eager,
Joins joins) { Joins joins) {
assertMutable();
select(this, mapping, subclasses, store, fetch, eager, joins, false); select(this, mapping, subclasses, store, fetch, eager, joins, false);
} }
@ -994,10 +1004,12 @@ public class SelectImpl
} }
public boolean selectIdentifier(Column col) { public boolean selectIdentifier(Column col) {
assertMutable();
return selectIdentifier(col, (Joins) null); return selectIdentifier(col, (Joins) null);
} }
public boolean selectIdentifier(Column col, Joins joins) { public boolean selectIdentifier(Column col, Joins joins) {
assertMutable();
if (!isGrouping()) if (!isGrouping())
return select(col, getJoins(joins, true), true); return select(col, getJoins(joins, true), true);
groupBy(col, joins); groupBy(col, joins);
@ -1005,10 +1017,12 @@ public class SelectImpl
} }
public int selectIdentifier(Column[] cols) { public int selectIdentifier(Column[] cols) {
assertMutable();
return selectIdentifier(cols, null); return selectIdentifier(cols, null);
} }
public int selectIdentifier(Column[] cols, Joins joins) { public int selectIdentifier(Column[] cols, Joins joins) {
assertMutable();
if (cols == null || cols.length == 0) if (cols == null || cols.length == 0)
return 0; return 0;
if (isGrouping()) { if (isGrouping()) {
@ -1025,20 +1039,24 @@ public class SelectImpl
public void selectIdentifier(ClassMapping mapping, int subclasses, public void selectIdentifier(ClassMapping mapping, int subclasses,
JDBCStore store, JDBCFetchConfiguration fetch, int eager) { JDBCStore store, JDBCFetchConfiguration fetch, int eager) {
assertMutable();
selectIdentifier(mapping, subclasses, store, fetch, eager, null); selectIdentifier(mapping, subclasses, store, fetch, eager, null);
} }
public void selectIdentifier(ClassMapping mapping, int subclasses, public void selectIdentifier(ClassMapping mapping, int subclasses,
JDBCStore store, JDBCFetchConfiguration fetch, int eager, JDBCStore store, JDBCFetchConfiguration fetch, int eager,
Joins joins) { Joins joins) {
assertMutable();
select(this, mapping, subclasses, store, fetch, eager, joins, true); select(this, mapping, subclasses, store, fetch, eager, joins, true);
} }
public int selectPrimaryKey(ClassMapping mapping) { public int selectPrimaryKey(ClassMapping mapping) {
assertMutable();
return selectPrimaryKey(mapping, null); return selectPrimaryKey(mapping, null);
} }
public int selectPrimaryKey(ClassMapping mapping, Joins joins) { public int selectPrimaryKey(ClassMapping mapping, Joins joins) {
assertMutable();
return primaryKeyOperation(mapping, true, null, joins, false); return primaryKeyOperation(mapping, true, null, joins, false);
} }
@ -1047,6 +1065,7 @@ public class SelectImpl
*/ */
private int primaryKeyOperation(ClassMapping mapping, boolean sel, private int primaryKeyOperation(ClassMapping mapping, boolean sel,
Boolean asc, Joins joins, boolean aliasOrder) { Boolean asc, Joins joins, boolean aliasOrder) {
assertMutable();
if (!sel && asc == null) if (!sel && asc == null)
return 0; return 0;
@ -1134,6 +1153,7 @@ public class SelectImpl
* Append ordering information to our internal buffer. * Append ordering information to our internal buffer.
*/ */
private void appendOrdering(Object orderBy, boolean asc) { private void appendOrdering(Object orderBy, boolean asc) {
assertMutable();
if (_ordering == null) if (_ordering == null)
_ordering = new SQLBuffer(_dict); _ordering = new SQLBuffer(_dict);
else else
@ -1169,10 +1189,12 @@ public class SelectImpl
} }
public boolean orderBy(Column col, boolean asc, boolean sel) { public boolean orderBy(Column col, boolean asc, boolean sel) {
assertMutable();
return orderBy(col, asc, null, sel); return orderBy(col, asc, null, sel);
} }
public boolean orderBy(Column col, boolean asc, Joins joins, boolean sel) { public boolean orderBy(Column col, boolean asc, Joins joins, boolean sel) {
assertMutable();
return orderBy(col, asc, joins, sel, false); return orderBy(col, asc, joins, sel, false);
} }
@ -1181,15 +1203,18 @@ public class SelectImpl
*/ */
boolean orderBy(Column col, boolean asc, Joins joins, boolean sel, boolean orderBy(Column col, boolean asc, Joins joins, boolean sel,
boolean aliasOrder) { boolean aliasOrder) {
assertMutable();
return columnOperation(col, sel, (asc) ? Boolean.TRUE : Boolean.FALSE, return columnOperation(col, sel, (asc) ? Boolean.TRUE : Boolean.FALSE,
getJoins(joins, true), aliasOrder); getJoins(joins, true), aliasOrder);
} }
public int orderBy(Column[] cols, boolean asc, boolean sel) { public int orderBy(Column[] cols, boolean asc, boolean sel) {
assertMutable();
return orderBy(cols, asc, null, sel); return orderBy(cols, asc, null, sel);
} }
public int orderBy(Column[] cols, boolean asc, Joins joins, boolean sel) { public int orderBy(Column[] cols, boolean asc, Joins joins, boolean sel) {
assertMutable();
return orderBy(cols, asc, joins, sel, false); return orderBy(cols, asc, joins, sel, false);
} }
@ -1198,6 +1223,7 @@ public class SelectImpl
*/ */
int orderBy(Column[] cols, boolean asc, Joins joins, boolean sel, int orderBy(Column[] cols, boolean asc, Joins joins, boolean sel,
boolean aliasOrder) { boolean aliasOrder) {
assertMutable();
PathJoins pj = getJoins(joins, true); PathJoins pj = getJoins(joins, true);
int seld = 0; int seld = 0;
for (int i = 0; i < cols.length; i++) for (int i = 0; i < cols.length; i++)
@ -1207,29 +1233,28 @@ public class SelectImpl
return seld; return seld;
} }
public boolean orderBy(SQLBuffer sql, boolean asc, boolean sel, Value selAs) public boolean orderBy(SQLBuffer sql, boolean asc, boolean sel, Value selAs) {
{ assertMutable();
return orderBy(sql, asc, (Joins) null, sel, selAs); return orderBy(sql, asc, (Joins) null, sel, selAs);
} }
public boolean orderBy(SQLBuffer sql, boolean asc, Joins joins, public boolean orderBy(SQLBuffer sql, boolean asc, Joins joins, boolean sel, Value selAs) {
boolean sel, Value selAs) { assertMutable();
return orderBy(sql, asc, joins, sel, false, selAs); return orderBy(sql, asc, joins, sel, false, selAs);
} }
/** /**
* Allow unions to set aliases on order columns. * Allow unions to set aliases on order columns.
*/ */
boolean orderBy(SQLBuffer sql, boolean asc, Joins joins, boolean sel, boolean orderBy(SQLBuffer sql, boolean asc, Joins joins, boolean sel, boolean aliasOrder, Value selAs) {
boolean aliasOrder, Value selAs) { assertMutable();
return orderBy((Object) sql, asc, joins, sel, aliasOrder, selAs); return orderBy((Object) sql, asc, joins, sel, aliasOrder, selAs);
} }
/** /**
* Order on a SQL buffer or string. * Order on a SQL buffer or string.
*/ */
private boolean orderBy(Object sql, boolean asc, Joins joins, boolean sel, private boolean orderBy(Object sql, boolean asc, Joins joins, boolean sel, boolean aliasOrder, Value selAs) {
boolean aliasOrder, Value selAs) {
assertMutable(); assertMutable();
Object order = sql; Object order = sql;
if (aliasOrder) { if (aliasOrder) {
@ -1255,22 +1280,25 @@ public class SelectImpl
} }
public boolean orderBy(String sql, boolean asc, boolean sel) { public boolean orderBy(String sql, boolean asc, boolean sel) {
assertMutable();
return orderBy(sql, asc, null, sel); return orderBy(sql, asc, null, sel);
} }
public boolean orderBy(String sql, boolean asc, Joins joins, boolean sel) { public boolean orderBy(String sql, boolean asc, Joins joins, boolean sel) {
assertMutable();
return orderBy(sql, asc, joins, sel, false); return orderBy(sql, asc, joins, sel, false);
} }
/** /**
* Allow unions to set aliases on order columns. * Allow unions to set aliases on order columns.
*/ */
boolean orderBy(String sql, boolean asc, Joins joins, boolean sel, boolean orderBy(String sql, boolean asc, Joins joins, boolean sel, boolean aliasOrder) {
boolean aliasOrder) { assertMutable();
return orderBy((Object) sql, asc, joins, sel, aliasOrder, null); return orderBy((Object) sql, asc, joins, sel, aliasOrder, null);
} }
public void clearOrdering() { public void clearOrdering() {
assertMutable();
_ordering = null; _ordering = null;
_orders = 0; _orders = 0;
} }
@ -1279,9 +1307,9 @@ public class SelectImpl
* Allow unions to record the select list indexes of items we order by. * Allow unions to record the select list indexes of items we order by.
*/ */
void setRecordOrderedIndexes(boolean record) { void setRecordOrderedIndexes(boolean record) {
if (record) if (record) {
_flags |= RECORD_ORDERED; _flags |= RECORD_ORDERED;
else { } else {
_ordered = null; _ordered = null;
_flags &= ~RECORD_ORDERED; _flags &= ~RECORD_ORDERED;
} }
@ -1300,8 +1328,7 @@ public class SelectImpl
return idxs; return idxs;
} }
public void wherePrimaryKey(Object oid, ClassMapping mapping, public void wherePrimaryKey(Object oid, ClassMapping mapping, JDBCStore store) {
JDBCStore store) {
wherePrimaryKey(oid, mapping, null, store); wherePrimaryKey(oid, mapping, null, store);
} }
@ -1311,8 +1338,7 @@ public class SelectImpl
* primary key, we will recursively join to its superclass until we find * primary key, we will recursively join to its superclass until we find
* an ancestor that does. * an ancestor that does.
*/ */
private void wherePrimaryKey(Object oid, ClassMapping mapping, Joins joins, private void wherePrimaryKey(Object oid, ClassMapping mapping, Joins joins, JDBCStore store) {
JDBCStore store) {
// if this mapping's identifiers include something other than // if this mapping's identifiers include something other than
// the pk values, join to super and recurse // the pk values, join to super and recurse
if (!mapping.isPrimaryKeyObjectId(false)) { if (!mapping.isPrimaryKeyObjectId(false)) {
@ -1325,12 +1351,10 @@ public class SelectImpl
} }
Column[] cols = mapping.getPrimaryKeyColumns(); Column[] cols = mapping.getPrimaryKeyColumns();
where(oid, mapping, cols, cols, null, null, getJoins(joins, true), where(oid, mapping, cols, cols, null, null, getJoins(joins, true), store);
store);
} }
public void whereForeignKey(ForeignKey fk, Object oid, public void whereForeignKey(ForeignKey fk, Object oid, ClassMapping mapping, JDBCStore store) {
ClassMapping mapping, JDBCStore store) {
whereForeignKey(fk, oid, mapping, null, store); whereForeignKey(fk, oid, mapping, null, store);
} }
@ -1340,8 +1364,7 @@ public class SelectImpl
* *
* @see #wherePrimaryKey * @see #wherePrimaryKey
*/ */
private void whereForeignKey(ForeignKey fk, Object oid, private void whereForeignKey(ForeignKey fk, Object oid, ClassMapping mapping, Joins joins, JDBCStore store) {
ClassMapping mapping, Joins joins, JDBCStore store) {
// if this mapping's identifiers include something other than // if this mapping's identifiers include something other than
// the pk values, or if this foreign key doesn't link to only // the pk values, or if this foreign key doesn't link to only
// identifiers, join to table and do a getPrimaryKey // identifiers, join to table and do a getPrimaryKey
@ -1364,8 +1387,7 @@ public class SelectImpl
} }
where(oid, mapping, fk.getPrimaryKeyColumns(), fk.getColumns(), where(oid, mapping, fk.getPrimaryKeyColumns(), fk.getColumns(),
fk.getConstants(), fk.getConstantColumns(), fk.getConstants(), fk.getConstantColumns(), getJoins(joins, true), store);
getJoins(joins, true), store);
} }
/** /**
@ -1505,10 +1527,12 @@ public class SelectImpl
public void having(SQLBuffer sql) { public void having(SQLBuffer sql) {
assertMutable();
having(sql, (Joins) null); having(sql, (Joins) null);
} }
public void having(SQLBuffer sql, Joins joins) { public void having(SQLBuffer sql, Joins joins) {
assertMutable();
having(sql, getJoins(joins, true)); having(sql, getJoins(joins, true));
} }
@ -1516,6 +1540,7 @@ public class SelectImpl
* Add the given condition to the HAVING clause. * Add the given condition to the HAVING clause.
*/ */
private void having(SQLBuffer sql, PathJoins pj) { private void having(SQLBuffer sql, PathJoins pj) {
assertMutable();
// no need to use joins... // no need to use joins...
if (sql == null || sql.isEmpty()) if (sql == null || sql.isEmpty())
return; return;
@ -1528,37 +1553,45 @@ public class SelectImpl
} }
public void groupBy(SQLBuffer sql) { public void groupBy(SQLBuffer sql) {
assertMutable();
groupBy(sql, (Joins) null); groupBy(sql, (Joins) null);
} }
public void groupBy(SQLBuffer sql, Joins joins) { public void groupBy(SQLBuffer sql, Joins joins) {
assertMutable();
getJoins(joins, true); getJoins(joins, true);
groupByAppend(sql.getSQL()); groupByAppend(sql.getSQL());
} }
public void groupBy(String sql) { public void groupBy(String sql) {
assertMutable();
groupBy(sql, (Joins) null); groupBy(sql, (Joins) null);
} }
public void groupBy(String sql, Joins joins) { public void groupBy(String sql, Joins joins) {
assertMutable();
getJoins(joins, true); getJoins(joins, true);
groupByAppend(sql); groupByAppend(sql);
} }
public void groupBy(Column col) { public void groupBy(Column col) {
assertMutable();
groupBy(col, null); groupBy(col, null);
} }
public void groupBy(Column col, Joins joins) { public void groupBy(Column col, Joins joins) {
assertMutable();
PathJoins pj = getJoins(joins, true); PathJoins pj = getJoins(joins, true);
groupByAppend(getColumnAlias(col, pj)); groupByAppend(getColumnAlias(col, pj));
} }
public void groupBy(Column[] cols) { public void groupBy(Column[] cols) {
assertMutable();
groupBy(cols, null); groupBy(cols, null);
} }
public void groupBy(Column[] cols, Joins joins) { public void groupBy(Column[] cols, Joins joins) {
assertMutable();
PathJoins pj = getJoins(joins, true); PathJoins pj = getJoins(joins, true);
for (int i = 0; i < cols.length; i++) { for (int i = 0; i < cols.length; i++) {
groupByAppend(getColumnAlias(cols[i], pj)); groupByAppend(getColumnAlias(cols[i], pj));
@ -1566,6 +1599,7 @@ public class SelectImpl
} }
private void groupByAppend(String sql) { private void groupByAppend(String sql) {
assertMutable();
if (_grouped == null || !_grouped.contains(sql)) { if (_grouped == null || !_grouped.contains(sql)) {
if (_grouping == null) { if (_grouping == null) {
_grouping = new SQLBuffer(_dict); _grouping = new SQLBuffer(_dict);
@ -1580,11 +1614,13 @@ public class SelectImpl
public void groupBy(ClassMapping mapping, int subclasses, JDBCStore store, public void groupBy(ClassMapping mapping, int subclasses, JDBCStore store,
JDBCFetchConfiguration fetch) { JDBCFetchConfiguration fetch) {
assertMutable();
groupBy(mapping, subclasses, store, fetch, null); groupBy(mapping, subclasses, store, fetch, null);
} }
public void groupBy(ClassMapping mapping, int subclasses, JDBCStore store, public void groupBy(ClassMapping mapping, int subclasses, JDBCStore store,
JDBCFetchConfiguration fetch, Joins joins) { JDBCFetchConfiguration fetch, Joins joins) {
assertMutable();
// we implement this by putting ourselves into grouping mode, where // we implement this by putting ourselves into grouping mode, where
// all select invocations are re-routed to group-by invocations instead. // all select invocations are re-routed to group-by invocations instead.
// this allows us to utilize the same select APIs of the store manager // this allows us to utilize the same select APIs of the store manager
@ -1593,8 +1629,7 @@ public class SelectImpl
boolean wasGrouping = isGrouping(); boolean wasGrouping = isGrouping();
_flags |= GROUPING; _flags |= GROUPING;
try { try {
select(mapping, subclasses, store, fetch, select(mapping, subclasses, store, fetch, EagerFetchModes.EAGER_NONE, joins);
EagerFetchModes.EAGER_NONE, joins);
} finally { } finally {
if (!wasGrouping) if (!wasGrouping)
_flags &= ~GROUPING; _flags &= ~GROUPING;
@ -1627,7 +1662,7 @@ public class SelectImpl
else if (!pre) { else if (!pre) {
if ((_flags & OUTER) != 0) if ((_flags & OUTER) != 0)
pj = (PathJoins) outer(pj); pj = (PathJoins) outer(pj);
if (record) { if (record && !_readOnly) {
if (!pj.isEmpty()) { if (!pj.isEmpty()) {
if (_joins == null) if (_joins == null)
_joins = new SelectJoins(this); _joins = new SelectJoins(this);
@ -1818,6 +1853,7 @@ public class SelectImpl
} }
public void append(SQLBuffer buf, Joins joins) { public void append(SQLBuffer buf, Joins joins) {
assertMutable();
if (joins == null || joins.isEmpty()) if (joins == null || joins.isEmpty())
return; return;
if (_joinSyntax == JoinSyntaxes.SYNTAX_SQL92) if (_joinSyntax == JoinSyntaxes.SYNTAX_SQL92)
@ -1846,6 +1882,7 @@ public class SelectImpl
} }
public Joins and(Joins joins1, Joins joins2) { public Joins and(Joins joins1, Joins joins2) {
assertMutable();
return and((PathJoins) joins1, (PathJoins) joins2, true); return and((PathJoins) joins1, (PathJoins) joins2, true);
} }
@ -1857,6 +1894,7 @@ public class SelectImpl
* Combine the given joins. * Combine the given joins.
*/ */
private SelectJoins and(PathJoins j1, PathJoins j2, boolean nullJoins) { private SelectJoins and(PathJoins j1, PathJoins j2, boolean nullJoins) {
assertMutable();
if ((j1 == null || j1.isEmpty()) if ((j1 == null || j1.isEmpty())
&& (j2 == null || j2.isEmpty())) && (j2 == null || j2.isEmpty()))
return null; return null;
@ -1894,6 +1932,7 @@ public class SelectImpl
} }
public Joins or(Joins joins1, Joins joins2) { public Joins or(Joins joins1, Joins joins2) {
assertMutable();
PathJoins j1 = (PathJoins) joins1; PathJoins j1 = (PathJoins) joins1;
PathJoins j2 = (PathJoins) joins2; PathJoins j2 = (PathJoins) joins2;
@ -2190,32 +2229,38 @@ public class SelectImpl
} }
public Joins join(ForeignKey fk, boolean inverse, boolean toMany) { public Joins join(ForeignKey fk, boolean inverse, boolean toMany) {
assertMutable();
return new SelectJoins(this).join(fk, inverse, toMany); return new SelectJoins(this).join(fk, inverse, toMany);
} }
public Joins outerJoin(ForeignKey fk, boolean inverse, boolean toMany) { public Joins outerJoin(ForeignKey fk, boolean inverse, boolean toMany) {
assertMutable();
return new SelectJoins(this).outerJoin(fk, inverse, toMany); return new SelectJoins(this).outerJoin(fk, inverse, toMany);
} }
public Joins joinRelation(String name, ForeignKey fk, ClassMapping target, public Joins joinRelation(String name, ForeignKey fk, ClassMapping target,
int subs, boolean inverse, boolean toMany) { int subs, boolean inverse, boolean toMany) {
assertMutable();
return new SelectJoins(this).joinRelation(name, fk, target, subs, return new SelectJoins(this).joinRelation(name, fk, target, subs,
inverse, toMany); inverse, toMany);
} }
public Joins outerJoinRelation(String name, ForeignKey fk, public Joins outerJoinRelation(String name, ForeignKey fk,
ClassMapping target, int subs, boolean inverse, boolean toMany) { ClassMapping target, int subs, boolean inverse, boolean toMany) {
assertMutable();
return new SelectJoins(this).outerJoinRelation(name, fk, target, subs, return new SelectJoins(this).outerJoinRelation(name, fk, target, subs,
inverse, toMany); inverse, toMany);
} }
public Joins setVariable(String var) { public Joins setVariable(String var) {
assertMutable();
if (var == null) if (var == null)
return this; return this;
return new SelectJoins(this).setVariable(var); return new SelectJoins(this).setVariable(var);
} }
public Joins setSubselect(String alias) { public Joins setSubselect(String alias) {
assertMutable();
if (alias == null) if (alias == null)
return this; return this;
return new SelectJoins(this).setSubselect(alias); return new SelectJoins(this).setSubselect(alias);
@ -2312,6 +2357,10 @@ public class SelectImpl
*/ */
public void setSelect(SelectImpl sel) { public void setSelect(SelectImpl sel) {
_sel = sel; _sel = sel;
if (_sel.isReadOnly()) {
_preJoins = new Stack<Joins>();
_preJoins.push(_sel.getJoins());
}
} }
public Object getEager(FieldMapping key) { public Object getEager(FieldMapping key) {
@ -3016,6 +3065,7 @@ public class SelectImpl
} }
protected Selects newSelects() { protected Selects newSelects() {
assertMutable();
return new Selects(); return new Selects();
} }
@ -3235,6 +3285,7 @@ public class SelectImpl
} }
public void moveJoinsToParent() { public void moveJoinsToParent() {
assertMutable();
} }
/** /**

View File

@ -27,19 +27,20 @@ import java.util.Comparator;
* @author Abe White * @author Abe White
* @nojavadoc * @nojavadoc
*/ */
@SuppressWarnings("serial")
public class InheritanceComparator public class InheritanceComparator
implements Comparator, Serializable { implements Comparator, Serializable {
private Class _base = Object.class; private Class<?> _base = Object.class;
/** /**
* Set the least-derived type possible; defaults to <code>null</code>. * Set the least-derived type possible; defaults to <code>null</code>.
*/ */
public void setBase(Class base) { public void setBase(Class<?> base) {
_base = base; _base = base;
} }
public Class getBase() { public Class<?> getBase() {
return _base; return _base;
} }
@ -47,8 +48,8 @@ public class InheritanceComparator
* Subclasses can override this method to extract the class to compare * Subclasses can override this method to extract the class to compare
* on from the elements of the collection. * on from the elements of the collection.
*/ */
protected Class toClass(Object elem) { protected Class<?> toClass(Object elem) {
return (Class) elem; return (Class<?>) elem;
} }
public int compare(Object o1, Object o2) { public int compare(Object o1, Object o2) {
@ -59,8 +60,8 @@ public class InheritanceComparator
if (o2 == null) if (o2 == null)
return 1; return 1;
Class c1 = toClass(o1); Class<?> c1 = toClass(o1);
Class c2 = toClass(o2); Class<?> c2 = toClass(o2);
if (c1 == c2) if (c1 == c2)
return 0; return 0;
if (c1 == null) if (c1 == null)
@ -89,7 +90,7 @@ public class InheritanceComparator
/** /**
* Count the levels of inheritance between this class and our base class. * Count the levels of inheritance between this class and our base class.
*/ */
private int levels(Class to) { private int levels(Class<?> to) {
if (to.isInterface()) if (to.isInterface())
return to.getInterfaces().length; return to.getInterfaces().length;
for (int i = 0; to != null; i++, to = to.getSuperclass()) for (int i = 0; to != null; i++, to = to.getSuperclass())

View File

@ -25,10 +25,11 @@ package org.apache.openjpa.meta;
* @author Abe White * @author Abe White
* @nojavadoc * @nojavadoc
*/ */
@SuppressWarnings("serial")
public class MetaDataInheritanceComparator public class MetaDataInheritanceComparator
extends InheritanceComparator { extends InheritanceComparator {
protected Class toClass(Object elem) { protected Class<?> toClass(Object elem) {
if (elem == null) if (elem == null)
return null; return null;
return ((ClassMetaData) elem).getDescribedType(); return ((ClassMetaData) elem).getDescribedType();

View File

@ -106,8 +106,7 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
// system sequence // system sequence
private SequenceMetaData _sysSeq = null; private SequenceMetaData _sysSeq = null;
// cache of parsed metadata, oid class to class, and interface class // cache of parsed metadata, oid class to class, and interface class to metadatas
// to metadatas
private Map<Class<?>, ClassMetaData> _metas = new HashMap<Class<?>, ClassMetaData>(); private Map<Class<?>, ClassMetaData> _metas = new HashMap<Class<?>, ClassMetaData>();
private Map<String, ClassMetaData> _metaStringMap = new ConcurrentHashMap<String, ClassMetaData>(); private Map<String, ClassMetaData> _metaStringMap = new ConcurrentHashMap<String, ClassMetaData>();
private Map<Class<?>, Class<?>> _oids = Collections.synchronizedMap(new HashMap<Class<?>, Class<?>>()); private Map<Class<?>, Class<?>> _oids = Collections.synchronizedMap(new HashMap<Class<?>, Class<?>>());
@ -124,7 +123,8 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
private Map<Class<?>, Class<?>> _metamodel = Collections.synchronizedMap(new HashMap<Class<?>, Class<?>>()); private Map<Class<?>, Class<?>> _metamodel = Collections.synchronizedMap(new HashMap<Class<?>, Class<?>>());
// map of classes to lists of their subclasses // map of classes to lists of their subclasses
private Map<Class<?>, List<Class<?>>> _subs = Collections.synchronizedMap(new HashMap<Class<?>, List<Class<?>>>()); private Map<Class<?>, Collection<Class<?>>> _subs =
Collections.synchronizedMap(new HashMap<Class<?>, Collection<Class<?>>>());
// xml mapping // xml mapping
protected final XMLMetaData[] EMPTY_XMLMETAS; protected final XMLMetaData[] EMPTY_XMLMETAS;
@ -283,7 +283,7 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
} }
/** /**
* Sets whether this repository will load all known persistent classes at initialization. * Affirms if this repository will load all known persistent classes at initialization.
* Defaults to false. * Defaults to false.
*/ */
public boolean getPreload() { public boolean getPreload() {
@ -304,11 +304,11 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
* MetaData for all persistent classes and will remove locking from this class. * MetaData for all persistent classes and will remove locking from this class.
*/ */
public synchronized void preload() { public synchronized void preload() {
if (_preload == false) { if (!_preload) {
return; return;
} }
// If pooling EMFs, this method may be invoked more than once. Only perform this work once. // If pooling EMFs, this method may be invoked more than once. Only perform this work once.
if (_preloadComplete == true) { if (_preloadComplete) {
return; return;
} }
@ -316,7 +316,7 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
MultiClassLoader multi = AccessController.doPrivileged(J2DoPrivHelper.newMultiClassLoaderAction()); MultiClassLoader multi = AccessController.doPrivileged(J2DoPrivHelper.newMultiClassLoaderAction());
multi.addClassLoader(AccessController.doPrivileged(J2DoPrivHelper.getContextClassLoaderAction())); multi.addClassLoader(AccessController.doPrivileged(J2DoPrivHelper.getContextClassLoaderAction()));
multi.addClassLoader(AccessController.doPrivileged(J2DoPrivHelper multi.addClassLoader(AccessController.doPrivileged(J2DoPrivHelper
.getClassLoaderAction(MetaDataRepository.class))); .getClassLoaderAction(MetaDataRepository.class)));
// If a ClassLoader was passed into Persistence.createContainerEntityManagerFactory on the PersistenceUnitInfo // If a ClassLoader was passed into Persistence.createContainerEntityManagerFactory on the PersistenceUnitInfo
// we need to add that loader to the chain of classloaders // we need to add that loader to the chain of classloaders
ClassResolver resolver = _conf.getClassResolverInstance(); ClassResolver resolver = _conf.getClassResolverInstance();
@ -359,8 +359,7 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
} }
} }
// Hook in this class as a listener and process registered classes list to populate _aliases // Hook in this class as a listener and process registered classes list to populate _aliases list.
// list.
PCRegistry.addRegisterClassListener(this); PCRegistry.addRegisterClassListener(this);
processRegisteredClasses(multi); processRegisteredClasses(multi);
_locking = false; _locking = false;
@ -856,9 +855,8 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
} }
private ClassMetaData[] getMetaDatasInternal() { private ClassMetaData[] getMetaDatasInternal() {
// prevent concurrent mod errors when resolving one metadata // prevent concurrent modification errors when resolving one metadata introduces others
// introduces others ClassMetaData[] metas = _metas.values().toArray(new ClassMetaData[_metas.size()]);
ClassMetaData[] metas = (ClassMetaData[]) _metas.values().toArray(new ClassMetaData[_metas.size()]);
for (int i = 0; i < metas.length; i++) for (int i = 0; i < metas.length; i++)
if (metas[i] != null) if (metas[i] != null)
getMetaData(metas[i].getDescribedType(), metas[i].getEnvClassLoader(), true); getMetaData(metas[i].getDescribedType(), metas[i].getEnvClassLoader(), true);
@ -1800,7 +1798,8 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
/** /**
* Add the given value to the collection cached in the given map under the given key. * Add the given value to the collection cached in the given map under the given key.
*/ */
private void addToCollection(Map map, Class<?> key, Class<?> value, boolean inheritance) { private void addToCollection(Map<Class<?>, Collection<Class<?>>> map, Class<?> key, Class<?> value,
boolean inheritance) {
if (_locking) { if (_locking) {
synchronized (map) { synchronized (map) {
addToCollectionInternal(map, key, value, inheritance); addToCollectionInternal(map, key, value, inheritance);
@ -1810,15 +1809,17 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
} }
} }
private void addToCollectionInternal(Map map, Class<?> key, Class<?> value, boolean inheritance) { private void addToCollectionInternal(Map<Class<?>, Collection<Class<?>>> map, Class<?> key,
Collection coll = (Collection) map.get(key); Class<?> value, boolean inheritance) {
Collection<Class<?>> coll = map.get(key);
if (coll == null) { if (coll == null) {
if (inheritance) { if (inheritance) {
InheritanceComparator comp = new InheritanceComparator(); InheritanceComparator comp = new InheritanceComparator();
comp.setBase(key); comp.setBase(key);
coll = new TreeSet<Class<?>>(comp); coll = new TreeSet<Class<?>>(comp);
} else } else {
coll = new LinkedList<Class<?>>(); coll = new LinkedList<Class<?>>();
}
map.put(key, coll); map.put(key, coll);
} }
coll.add(value); coll.add(value);
@ -1892,7 +1893,7 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
_aliases = new HashMap<String, List<Class<?>>>(); _aliases = new HashMap<String, List<Class<?>>>();
_pawares = new HashMap<Class<?>, NonPersistentMetaData>(); _pawares = new HashMap<Class<?>, NonPersistentMetaData>();
_nonMapped = new HashMap<Class<?>, NonPersistentMetaData>(); _nonMapped = new HashMap<Class<?>, NonPersistentMetaData>();
_subs = new HashMap<Class<?>, List<Class<?>>>(); _subs = new HashMap<Class<?>, Collection<Class<?>>>();
// Wait till we're done loading MetaData to flip _lock boolean. // Wait till we're done loading MetaData to flip _lock boolean.
} }
} }

View File

@ -0,0 +1,45 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.lib.conf;
/**
* An immutable boolean value can be set only once and can never be modified to a different value.
*
* @author Pinaki Poddar
*
*/
public class ImmutableBooleanValue extends BooleanValue {
private boolean _dirty;
public ImmutableBooleanValue(String prop) {
super(prop);
}
public void set(boolean value) {
if (_dirty) {
if (value != get().booleanValue())
throw new IllegalStateException(this + " can not be changed from " + get() + " to " + value);
} else {
_dirty = true;
super.set(value);
}
}
}

View File

@ -1511,11 +1511,9 @@ public class AnnotationPersistenceMetaDataSerializer
* then name order. * then name order.
*/ */
private class FieldComparator private class FieldComparator
implements Comparator { implements Comparator<FieldMetaData> {
public int compare(Object o1, Object o2) { public int compare(FieldMetaData fmd1, FieldMetaData fmd2) {
FieldMetaData fmd1 = (FieldMetaData) o1;
FieldMetaData fmd2 = (FieldMetaData) o2;
if (fmd1.isPrimaryKey()) { if (fmd1.isPrimaryKey()) {
if (fmd2.isPrimaryKey()) if (fmd2.isPrimaryKey())
return fmd1.compareTo(fmd2); return fmd1.compareTo(fmd2);