mirror of https://github.com/apache/openjpa.git
OPENJPA-2099. With Pinaki's green light, we're going to back out the changes for OpenJPA-2099 and OpenJPA-2111 so that we can make progress on the OpenJPA 2.2.0 release.
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@1243702 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
e6d667e6db
commit
2bbbcc9d73
|
@ -628,27 +628,5 @@ public interface JDBCConfiguration
|
|||
* @param util instance of the identifier utility
|
||||
*/
|
||||
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.
|
||||
* <br>
|
||||
* This setting can be changed once and only once.
|
||||
*
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public void setSelectCacheEnabled(boolean enable);
|
||||
|
||||
}
|
||||
|
|
|
@ -43,8 +43,6 @@ import org.apache.openjpa.jdbc.sql.MaxDBDictionary;
|
|||
import org.apache.openjpa.jdbc.sql.SQLFactory;
|
||||
import org.apache.openjpa.kernel.BrokerImpl;
|
||||
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.ObjectValue;
|
||||
import org.apache.openjpa.lib.conf.PluginValue;
|
||||
|
@ -89,7 +87,6 @@ public class JDBCConfigurationImpl
|
|||
public PluginValue driverDataSourcePlugin;
|
||||
public MappingFactoryValue mappingFactoryPlugin;
|
||||
public ObjectValue identifierUtilPlugin;
|
||||
public ImmutableBooleanValue cacheSelect;
|
||||
|
||||
// used internally
|
||||
private String firstUser = null;
|
||||
|
@ -353,10 +350,6 @@ public class JDBCConfigurationImpl
|
|||
identifierUtilPlugin.setString(aliases[0]);
|
||||
identifierUtilPlugin.setInstantiatingGetter("getIdentifierUtilInstance");
|
||||
|
||||
cacheSelect = new ImmutableBooleanValue("jdbc.CachesSelect");
|
||||
addValue(cacheSelect);
|
||||
cacheSelect.setDefault("false");
|
||||
cacheSelect.set(false); // Disable openjpa.CachesSelect until openjpa-2099 is complete
|
||||
|
||||
// this static initializer is to get past a weird
|
||||
// ClassCircularityError that happens only under IBM's
|
||||
|
@ -1003,13 +996,5 @@ public class JDBCConfigurationImpl
|
|||
public void setIdentifierUtil(DBIdentifierUtil util) {
|
||||
identifierUtilPlugin.set(util);
|
||||
}
|
||||
|
||||
public boolean getSelectCacheEnabled() {
|
||||
return cacheSelect.get();
|
||||
}
|
||||
public void setSelectCacheEnabled(boolean enable) {
|
||||
cacheSelect.set(enable);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -83,14 +83,13 @@ import org.apache.openjpa.util.UserException;
|
|||
* @author Abe White
|
||||
* @nojavadoc
|
||||
*/
|
||||
@SuppressWarnings({ "serial", "deprecation" })
|
||||
public class JDBCStoreQuery
|
||||
extends ExpressionStoreQuery {
|
||||
|
||||
private static final Table INVALID = new Table();
|
||||
|
||||
// add all standard filter and aggregate listeners to these maps
|
||||
private static final Map<String,FilterListener> _listeners = new HashMap<String, FilterListener>();
|
||||
private static final Map _listeners = new HashMap();
|
||||
|
||||
static {
|
||||
// deprecated extensions
|
||||
|
@ -187,8 +186,8 @@ public class JDBCStoreQuery
|
|||
ExpContext ctx = new ExpContext(_store, params, fetch);
|
||||
|
||||
// add selects with populate WHERE conditions to list
|
||||
List<Select> sels = new ArrayList<Select>(mappings.length);
|
||||
List<ClassMapping> selMappings = new ArrayList<ClassMapping>(mappings.length);
|
||||
List sels = new ArrayList(mappings.length);
|
||||
List selMappings = new ArrayList(mappings.length);
|
||||
BitSet subclassBits = new BitSet();
|
||||
BitSet nextBits = new BitSet();
|
||||
boolean unionable = createWhereSelects(sels, mappings, selMappings,
|
||||
|
@ -336,8 +335,8 @@ public class JDBCStoreQuery
|
|||
* Generate the selects with WHERE conditions needed to execute the query
|
||||
* for the given mappings.
|
||||
*/
|
||||
private boolean createWhereSelects(List<Select> sels, ClassMapping[] mappings,
|
||||
List<ClassMapping> selMappings, boolean subclasses, BitSet subclassBits,
|
||||
private boolean createWhereSelects(List sels, ClassMapping[] mappings,
|
||||
List selMappings, boolean subclasses, BitSet subclassBits,
|
||||
BitSet nextBits, ExpressionFactory[] facts, QueryExpressions[] exps,
|
||||
QueryExpressionsState[] states, ExpContext ctx, int subclassMode) {
|
||||
Number optHint = (Number) ctx.fetch.getHint
|
||||
|
@ -365,12 +364,12 @@ public class JDBCStoreQuery
|
|||
else if (this.ctx.isUnique())
|
||||
sel.setExpectedResultCount(1, false);
|
||||
|
||||
List<ClassMapping> selectFrom = getJoinedTableMeta(sel);
|
||||
List selectFrom = getJoinedTableMeta(sel);
|
||||
int size = 0;
|
||||
if (selectFrom != null) {
|
||||
size = selectFrom.size();
|
||||
for (int j = 0; j < size; j++) {
|
||||
ClassMapping vert = selectFrom.get(j);
|
||||
ClassMapping vert = (ClassMapping)selectFrom.get(j);
|
||||
selMappings.add(vert);
|
||||
if (j == size - 1) {
|
||||
nextBits.set(sels.size());
|
||||
|
@ -389,7 +388,7 @@ public class JDBCStoreQuery
|
|||
nextBits.set(sels.size());
|
||||
sels.add(sel);
|
||||
} else
|
||||
sels.add((Select)sel.fullClone(1));
|
||||
sels.add(sel.fullClone(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -401,17 +400,17 @@ public class JDBCStoreQuery
|
|||
return unionable;
|
||||
}
|
||||
|
||||
private List<ClassMapping> getJoinedTableMeta(Select sel) {
|
||||
List<ClassMapping> selectFrom = sel.getJoinedTableClassMeta();
|
||||
List<ClassMapping> exSelectFrom = sel.getExcludedJoinedTableClassMeta();
|
||||
private List getJoinedTableMeta(Select sel) {
|
||||
List selectFrom = sel.getJoinedTableClassMeta();
|
||||
List exSelectFrom = sel.getExcludedJoinedTableClassMeta();
|
||||
if (exSelectFrom == null)
|
||||
return selectFrom;
|
||||
if (selectFrom == null)
|
||||
return null;
|
||||
int size = selectFrom.size();
|
||||
List<ClassMapping> retList = new ArrayList<ClassMapping>(size);
|
||||
List retList = new ArrayList(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
ClassMapping obj = selectFrom.get(i);
|
||||
Object obj = selectFrom.get(i);
|
||||
if (!exSelectFrom.contains(obj))
|
||||
retList.add(obj);
|
||||
}
|
||||
|
@ -431,15 +430,15 @@ public class JDBCStoreQuery
|
|||
|| !hasVerticalSubclasses(mapping))
|
||||
return new ClassMapping[] { mapping };
|
||||
|
||||
List<ClassMapping> subs = new ArrayList<ClassMapping>(4);
|
||||
List subs = new ArrayList(4);
|
||||
addSubclasses(mapping, subs);
|
||||
return subs.toArray(new ClassMapping[subs.size()]);
|
||||
return (ClassMapping[]) subs.toArray(new ClassMapping[subs.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive helper to add mappings for subclasses to the given list.
|
||||
*/
|
||||
private void addSubclasses(ClassMapping mapping, Collection<ClassMapping> subs) {
|
||||
private void addSubclasses(ClassMapping mapping, Collection subs) {
|
||||
// possible future optimizations:
|
||||
// - if no fields in meta or its subclasses (and not in an
|
||||
// already-selected table) are in the current fetch
|
||||
|
@ -700,8 +699,8 @@ public class JDBCStoreQuery
|
|||
ExpContext ctx = new ExpContext(_store, params, fetch);
|
||||
|
||||
// add selects with populate WHERE conditions to list
|
||||
List<Select> sels = new ArrayList<Select>(mappings.length);
|
||||
List<ClassMapping> selMappings = new ArrayList<ClassMapping>(mappings.length);
|
||||
List sels = new ArrayList(mappings.length);
|
||||
List selMappings = new ArrayList(mappings.length);
|
||||
BitSet subclassBits = new BitSet();
|
||||
BitSet nextBits = new BitSet();
|
||||
boolean unionable = createWhereSelects(sels, mappings, selMappings,
|
||||
|
@ -798,11 +797,11 @@ public class JDBCStoreQuery
|
|||
(org.apache.openjpa.jdbc.kernel.exps.Math) value;
|
||||
Val value1 = mathVal.getVal1();
|
||||
Object val1 = getValue(value1, ob, params, sm);
|
||||
Class<?> c1 = value1.getType();
|
||||
Class c1 = value1.getType();
|
||||
|
||||
Val value2 = mathVal.getVal2();
|
||||
Object val2 = getValue(value2, ob, params, sm);
|
||||
Class<?> c2 = value2.getType();
|
||||
Class c2 = value2.getType();
|
||||
|
||||
String op = mathVal.getOperation();
|
||||
if (op.equals(org.apache.openjpa.jdbc.kernel.exps.Math.ADD))
|
||||
|
@ -943,7 +942,7 @@ public class JDBCStoreQuery
|
|||
org.apache.openjpa.jdbc.kernel.exps.Abs absVal =
|
||||
(org.apache.openjpa.jdbc.kernel.exps.Abs) value;
|
||||
Object val = getValue(absVal.getValue(), ob, params, sm);
|
||||
Class<?> c = val.getClass();
|
||||
Class c = val.getClass();
|
||||
if (c == Integer.class)
|
||||
return Integer.valueOf(java.lang.Math.abs(((Integer) val).intValue()));
|
||||
else if (c == Float.class)
|
||||
|
@ -960,7 +959,7 @@ public class JDBCStoreQuery
|
|||
org.apache.openjpa.jdbc.kernel.exps.Sqrt sqrtVal =
|
||||
(org.apache.openjpa.jdbc.kernel.exps.Sqrt) value;
|
||||
Object val = getValue(sqrtVal.getValue(), ob, params, sm);
|
||||
Class<?> c = val.getClass();
|
||||
Class c = val.getClass();
|
||||
if (c == Integer.class)
|
||||
return Double.valueOf(java.lang.Math.sqrt(((Integer) val).doubleValue()));
|
||||
else if (c == Float.class)
|
||||
|
|
|
@ -32,7 +32,6 @@ import org.apache.openjpa.jdbc.meta.ClassMapping;
|
|||
import org.apache.openjpa.jdbc.meta.FieldMapping;
|
||||
import org.apache.openjpa.jdbc.meta.MappingRepository;
|
||||
import org.apache.openjpa.jdbc.schema.Column;
|
||||
import org.apache.openjpa.jdbc.sql.BindParameter;
|
||||
import org.apache.openjpa.jdbc.sql.LogicalUnion;
|
||||
import org.apache.openjpa.jdbc.sql.SQLBuffer;
|
||||
import org.apache.openjpa.jdbc.sql.SelectExecutor;
|
||||
|
@ -431,10 +430,10 @@ public class PreparedQueryImpl implements PreparedQuery {
|
|||
}
|
||||
}
|
||||
|
||||
void setParameters(List<BindParameter> list) {
|
||||
void setParameters(List list) {
|
||||
Map<Integer, Object> tmp = new HashMap<Integer, Object>();
|
||||
for (int i = 0; list != null && i < list.size(); i++) {
|
||||
tmp.put(i, list.get(i).getValue());
|
||||
tmp.put(i, list.get(i));
|
||||
}
|
||||
_template = Collections.unmodifiableMap(tmp);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
|
||||
import org.apache.openjpa.enhance.PersistenceCapable;
|
||||
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.JDBCStore;
|
||||
import org.apache.openjpa.jdbc.meta.strats.NoneClassStrategy;
|
||||
|
@ -45,8 +44,6 @@ import org.apache.openjpa.jdbc.sql.Joins;
|
|||
import org.apache.openjpa.jdbc.sql.Result;
|
||||
import org.apache.openjpa.jdbc.sql.RowManager;
|
||||
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.OpenJPAStateManager;
|
||||
import org.apache.openjpa.kernel.PCState;
|
||||
|
@ -63,22 +60,17 @@ import org.apache.openjpa.util.OpenJPAId;
|
|||
|
||||
/**
|
||||
* 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 Pinaki Poddar (select caching)
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ClassMapping
|
||||
extends ClassMetaData
|
||||
implements ClassStrategy {
|
||||
|
||||
public static final ClassMapping[] EMPTY_MAPPINGS = new ClassMapping[0];
|
||||
|
||||
private static final Localizer _loc = Localizer.forPackage(ClassMapping.class);
|
||||
private static final Localizer _loc = Localizer.forPackage
|
||||
(ClassMapping.class);
|
||||
|
||||
private final ClassMappingInfo _info;
|
||||
private final Discriminator _discrim;
|
||||
|
@ -96,9 +88,6 @@ public class ClassMapping
|
|||
|
||||
// maps columns to joinables
|
||||
private final Map _joinables = new ConcurrentHashMap();
|
||||
|
||||
private Select _select;
|
||||
private Union _union;
|
||||
|
||||
/**
|
||||
* Constructor. Supply described type and owning repository.
|
||||
|
@ -1120,48 +1109,4 @@ public class ClassMapping
|
|||
return true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,19 +81,19 @@ public class FieldMapping
|
|||
private boolean _outer = false;
|
||||
private int _fetchMode = Integer.MAX_VALUE;
|
||||
private Unique[] _joinTableUniques; // Unique constraints on JoinTable
|
||||
private Boolean _bidirectionalJoinTableOwner;
|
||||
private Boolean _bidirectionalJoinTableNonOwner;
|
||||
private Boolean _bidirectionalJoinTableOwner = null;
|
||||
private Boolean _bidirectionalJoinTableNonOwner = null;
|
||||
|
||||
private Boolean _bidirectionalManyToOneJoinTable;
|
||||
private Boolean _unidirectionalOneToManyForeignKey;
|
||||
private Boolean _unidirectionalManyToOneJoinTable;
|
||||
private Boolean _unidirectionalOneToOneJoinTable;
|
||||
private Boolean _bidirectionalOneToOneJoinTable;
|
||||
private Boolean _bi_MTo1_JT = null;
|
||||
private Boolean _uni_1ToM_FK = null;
|
||||
private Boolean _uni_MTo1_JT = null;
|
||||
private Boolean _uni_1To1_JT = null;
|
||||
private Boolean _bi_1To1_JT = null;
|
||||
|
||||
private FieldMapping _bidirectionalOneToManyJoinTableField;
|
||||
private FieldMapping _bidirectionalManyToOneJoinTableField;
|
||||
private ForeignKey _bidirectionalOneToManyJoinForeignKey;
|
||||
private ForeignKey _bidirectionalOneToManyElementForeignKey;
|
||||
private FieldMapping _bi_1ToM_JT_Field = null;
|
||||
private FieldMapping _bi_MTo1_JT_Field = null;
|
||||
private ForeignKey _bi_1ToM_Join_FK = null;
|
||||
private ForeignKey _bi_1ToM_Elem_FK = null;
|
||||
|
||||
private boolean _hasMapsIdCols = false;
|
||||
|
||||
|
@ -1271,90 +1271,85 @@ public class FieldMapping
|
|||
return _bidirectionalJoinTableNonOwner.booleanValue();
|
||||
}
|
||||
|
||||
public boolean isBidirectionalManyToOneJoinTable() {
|
||||
if (_bidirectionalManyToOneJoinTable == null) {
|
||||
_bidirectionalManyToOneJoinTable = getMappingRepository().isBidirectionalManyToOneJoinTable(this);
|
||||
public boolean isBiMTo1JT() {
|
||||
if (_bi_MTo1_JT == null) {
|
||||
_bi_MTo1_JT = getMappingRepository().isBiMTo1JT(this);
|
||||
}
|
||||
return _bidirectionalManyToOneJoinTable;
|
||||
return _bi_MTo1_JT;
|
||||
}
|
||||
|
||||
public boolean isUnidirectionalOneToManyForeignKey() {
|
||||
if (_unidirectionalOneToManyForeignKey == null)
|
||||
_unidirectionalOneToManyForeignKey = getMappingRepository().isUnidirectionalOneToManyForeignKey(this);
|
||||
return _unidirectionalOneToManyForeignKey;
|
||||
public boolean isUni1ToMFK() {
|
||||
if (_uni_1ToM_FK == null)
|
||||
_uni_1ToM_FK = getMappingRepository().isUni1ToMFK(this);
|
||||
return _uni_1ToM_FK;
|
||||
}
|
||||
|
||||
public boolean isUnidirectionalManyToOneJoinTable() {
|
||||
if (_unidirectionalManyToOneJoinTable == null)
|
||||
_unidirectionalManyToOneJoinTable = getMappingRepository().isUnidirectionalManyToOneJoinTable(this);
|
||||
return _unidirectionalManyToOneJoinTable;
|
||||
public boolean isUniMTo1JT() {
|
||||
if (_uni_MTo1_JT == null)
|
||||
_uni_MTo1_JT = getMappingRepository().isUniMTo1JT(this);
|
||||
return _uni_MTo1_JT;
|
||||
}
|
||||
|
||||
public boolean isUnidirectionalOneToOneJoinTable() {
|
||||
if (_unidirectionalOneToOneJoinTable == null)
|
||||
_unidirectionalOneToOneJoinTable = getMappingRepository().isUnidirectionalOneToOneJoinTable(this);
|
||||
return _unidirectionalOneToOneJoinTable;
|
||||
public boolean isUni1To1JT() {
|
||||
if (_uni_1To1_JT == null)
|
||||
_uni_1To1_JT = getMappingRepository().isUni1To1JT(this);
|
||||
return _uni_1To1_JT;
|
||||
}
|
||||
|
||||
public boolean isBidirectionalOneToOneJoinTable() {
|
||||
if (_bidirectionalOneToOneJoinTable == null)
|
||||
_bidirectionalOneToOneJoinTable = getMappingRepository().isBidirectionalOneToOneJoinTable(this);
|
||||
return _bidirectionalOneToOneJoinTable;
|
||||
public boolean isBi1To1JT() {
|
||||
if (_bi_1To1_JT == null)
|
||||
_bi_1To1_JT = getMappingRepository().isBi1To1JT(this);
|
||||
return _bi_1To1_JT;
|
||||
}
|
||||
|
||||
public FieldMapping getBidirectionalOneToManyJoinTableField() {
|
||||
if (_bidirectionalOneToManyJoinTableField == null) {
|
||||
_bidirectionalOneToManyJoinTableField =
|
||||
getMappingRepository().getBidirectionalOneToManyJoinTableField(this);
|
||||
public FieldMapping getBi_1ToM_JTField() {
|
||||
if (_bi_1ToM_JT_Field == null) {
|
||||
_bi_1ToM_JT_Field = getMappingRepository().getBi_1ToM_JoinTableField(this);
|
||||
}
|
||||
return _bidirectionalOneToManyJoinTableField;
|
||||
return _bi_1ToM_JT_Field;
|
||||
}
|
||||
|
||||
public FieldMapping getBidirectionalManyToOneJoinTableField() {
|
||||
if (_bidirectionalManyToOneJoinTableField == null) {
|
||||
_bidirectionalManyToOneJoinTableField =
|
||||
getMappingRepository().getBidirectionalManyToOneJoinTableField(this);
|
||||
public FieldMapping getBi_MTo1_JTField() {
|
||||
if (_bi_MTo1_JT_Field == null) {
|
||||
_bi_MTo1_JT_Field = getMappingRepository().getBi_MTo1_JoinTableField(this);
|
||||
}
|
||||
return _bidirectionalManyToOneJoinTableField;
|
||||
return _bi_MTo1_JT_Field;
|
||||
}
|
||||
|
||||
public ForeignKey getBidirectionalOneToManyJoinForeignKey() {
|
||||
if (_bidirectionalOneToManyJoinForeignKey == null) {
|
||||
getBidirectionalOneToManyJoinTableField();
|
||||
if (_bidirectionalOneToManyJoinTableField != null)
|
||||
_bidirectionalOneToManyJoinForeignKey = _bidirectionalOneToManyJoinTableField.getJoinForeignKey();
|
||||
public ForeignKey getBi1ToMJoinFK() {
|
||||
if (_bi_1ToM_Join_FK == null) {
|
||||
getBi_1ToM_JTField();
|
||||
if (_bi_1ToM_JT_Field != null)
|
||||
_bi_1ToM_Join_FK = _bi_1ToM_JT_Field.getJoinForeignKey();
|
||||
}
|
||||
return _bidirectionalOneToManyJoinForeignKey;
|
||||
return _bi_1ToM_Join_FK;
|
||||
}
|
||||
|
||||
public ForeignKey getBidirectionalOneToManyElementForeignKey() {
|
||||
if (_bidirectionalOneToManyElementForeignKey == null) {
|
||||
getBidirectionalOneToManyJoinTableField();
|
||||
if (_bidirectionalOneToManyJoinTableField != null)
|
||||
_bidirectionalOneToManyElementForeignKey =
|
||||
_bidirectionalOneToManyJoinTableField.getElementMapping().getForeignKey();
|
||||
public ForeignKey getBi1ToMElemFK() {
|
||||
if (_bi_1ToM_Elem_FK == null) {
|
||||
getBi_1ToM_JTField();
|
||||
if (_bi_1ToM_JT_Field != null)
|
||||
_bi_1ToM_Elem_FK = _bi_1ToM_JT_Field.getElementMapping().getForeignKey();
|
||||
}
|
||||
return _bidirectionalOneToManyElementForeignKey;
|
||||
return _bi_1ToM_Elem_FK;
|
||||
}
|
||||
|
||||
public void setBidirectionalOneToManyJoinTableInfo() {
|
||||
public void setBi1MJoinTableInfo() {
|
||||
if (getAssociationType() == FieldMetaData.ONE_TO_MANY) {
|
||||
FieldMapping mapped = getBidirectionalManyToOneJoinTableField();
|
||||
FieldMapping mapped = getBi_MTo1_JTField();
|
||||
if (mapped != null) {
|
||||
FieldMappingInfo info = getMappingInfo();
|
||||
FieldMappingInfo mappedInfo = mapped.getMappingInfo();
|
||||
info.setTableIdentifier(mappedInfo.getTableIdentifier());
|
||||
info.setColumns(mapped.getElementMapping().getValueInfo().getColumns());
|
||||
getElementMapping().getValueInfo().setColumns(mappedInfo.getColumns());
|
||||
getElementMapping().getValueInfo().setColumns(
|
||||
mappedInfo.getColumns());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isNonDefaultMappingUsingJoinTableStrategy() {
|
||||
return isBidirectionalOneToOneJoinTable()
|
||||
|| isUnidirectionalOneToOneJoinTable()
|
||||
|| isUnidirectionalManyToOneJoinTable()
|
||||
|| isBidirectionalManyToOneJoinTable();
|
||||
return isBi1To1JT() || isUni1To1JT() || isUniMTo1JT() || isBiMTo1JT();
|
||||
}
|
||||
|
||||
public void setMapsIdCols(boolean hasMapsIdCols) {
|
||||
|
|
|
@ -165,7 +165,7 @@ public class FieldMappingInfo
|
|||
|
||||
public ForeignKey getJoinForeignKey (final FieldMapping field, Table table,
|
||||
boolean adapt) {
|
||||
if (field.isUnidirectionalOneToManyForeignKey()) {
|
||||
if (field.isUni1ToMFK()) {
|
||||
List<Column> cols = field.getElementMapping().getValueInfo().getColumns();
|
||||
return getJoin(field, table, adapt, cols);
|
||||
}
|
||||
|
|
|
@ -105,14 +105,15 @@ import org.apache.openjpa.util.UserException;
|
|||
*
|
||||
* @author Abe White
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class MappingRepository extends MetaDataRepository {
|
||||
|
||||
private static final Localizer _loc = Localizer.forPackage(MappingRepository.class);
|
||||
private static final Localizer _loc = Localizer.forPackage
|
||||
(MappingRepository.class);
|
||||
|
||||
private transient DBDictionary _dict = null;
|
||||
private transient MappingDefaults _defaults = null;
|
||||
|
||||
// object->queryresultmapping
|
||||
private Map<Object, QueryResultMapping> _results = new HashMap<Object, QueryResultMapping>();
|
||||
private SchemaGroup _schema = null;
|
||||
private StrategyInstaller _installer = null;
|
||||
|
@ -259,10 +260,12 @@ public class MappingRepository extends MetaDataRepository {
|
|||
public QueryResultMapping[] getQueryResultMappings() {
|
||||
if (_locking) {
|
||||
synchronized (this) {
|
||||
return _results.values().toArray(new QueryResultMapping[_results.size()]);
|
||||
Collection values = _results.values();
|
||||
return (QueryResultMapping[]) values.toArray(new QueryResultMapping[values.size()]);
|
||||
}
|
||||
} else {
|
||||
return _results.values().toArray(new QueryResultMapping[_results.size()]);
|
||||
Collection values = _results.values();
|
||||
return (QueryResultMapping[]) values.toArray(new QueryResultMapping[values.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,7 +273,7 @@ public class MappingRepository extends MetaDataRepository {
|
|||
* Return the cached query result mapping with the given name, or null if
|
||||
* none.
|
||||
*/
|
||||
public QueryResultMapping getCachedQueryResultMapping(Class<?> cls, String name) {
|
||||
public QueryResultMapping getCachedQueryResultMapping(Class cls, String name) {
|
||||
if (_locking) {
|
||||
synchronized (this) {
|
||||
return (QueryResultMapping) _results.get(getQueryResultKey(cls, name));
|
||||
|
@ -283,7 +286,7 @@ public class MappingRepository extends MetaDataRepository {
|
|||
/**
|
||||
* Add a query result mapping.
|
||||
*/
|
||||
public QueryResultMapping addQueryResultMapping(Class<?> cls, String name) {
|
||||
public QueryResultMapping addQueryResultMapping(Class cls, String name) {
|
||||
if (_locking) {
|
||||
synchronized (this) {
|
||||
return addQueryResultMappingInternal(cls, name);
|
||||
|
@ -293,7 +296,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);
|
||||
res.setDefiningType(cls);
|
||||
_results.put(getQueryResultKey(res), res);
|
||||
|
@ -316,7 +319,7 @@ public class MappingRepository extends MetaDataRepository {
|
|||
/**
|
||||
* Remove a query result mapping.
|
||||
*/
|
||||
public boolean removeQueryResultMapping(Class<?> cls, String name) {
|
||||
public boolean removeQueryResultMapping(Class cls, String name) {
|
||||
if (_locking) {
|
||||
synchronized (this) {
|
||||
if (name == null)
|
||||
|
@ -1005,7 +1008,8 @@ public class MappingRepository extends MetaDataRepository {
|
|||
protected FieldStrategy handlerCollectionStrategy(FieldMapping field,
|
||||
ValueHandler ehandler, boolean installHandlers) {
|
||||
// TODO: JPA 2.0 should ignore this flag and not to serialize
|
||||
if (getConfiguration().getCompatibilityInstance().getStoreMapCollectionInEntityAsBlob())
|
||||
if (getConfiguration().getCompatibilityInstance()
|
||||
.getStoreMapCollectionInEntityAsBlob())
|
||||
return null;
|
||||
if (installHandlers)
|
||||
field.getElementMapping().setHandler(ehandler);
|
||||
|
@ -1020,7 +1024,8 @@ public class MappingRepository extends MetaDataRepository {
|
|||
ValueHandler khandler, ValueHandler vhandler, boolean krel,
|
||||
boolean vrel, boolean installHandlers) {
|
||||
// TODO: JPA 2.0 should ignore this flag and not to serialize
|
||||
if (getConfiguration().getCompatibilityInstance().getStoreMapCollectionInEntityAsBlob())
|
||||
if (getConfiguration().getCompatibilityInstance()
|
||||
.getStoreMapCollectionInEntityAsBlob())
|
||||
return null;
|
||||
if (installHandlers) {
|
||||
field.getKeyMapping().setHandler(khandler);
|
||||
|
@ -1043,13 +1048,14 @@ public class MappingRepository extends MetaDataRepository {
|
|||
FieldMapping mapped = field.getMappedByMapping();
|
||||
if (mapped != null) {
|
||||
//bi-/M-1/JoinTable ==> join table strategy
|
||||
if (isBidirectionalManyToOneJoinTable(field))
|
||||
if (isBiMTo1JT(field))
|
||||
return false;
|
||||
if (mapped.getTypeCode() == JavaTypes.PC || mapped.getTypeCode() == JavaTypes.PC_UNTYPED)
|
||||
return true;
|
||||
if (mapped.getElement().getTypeCode() == JavaTypes.PC)
|
||||
return false;
|
||||
throw new MetaDataException(_loc.get("bad-mapped-by", field, mapped));
|
||||
throw new MetaDataException(_loc.get("bad-mapped-by", field,
|
||||
mapped));
|
||||
}
|
||||
|
||||
// without a mapped-by, we have to look for clues as to the mapping.
|
||||
|
@ -1058,84 +1064,82 @@ public class MappingRepository extends MetaDataRepository {
|
|||
// an association table
|
||||
FieldMappingInfo info = field.getMappingInfo();
|
||||
ValueMapping elem = field.getElementMapping();
|
||||
boolean useInverseKeyMapping = DBIdentifier.isNull(info.getTableIdentifier())
|
||||
&& info.getColumns().isEmpty()
|
||||
&& !elem.getValueInfo().getColumns().isEmpty();
|
||||
boolean useInverseKeyMapping = DBIdentifier.isNull(info.getTableIdentifier()) && info.getColumns().isEmpty()
|
||||
&& !elem.getValueInfo().getColumns().isEmpty();
|
||||
|
||||
// JPA 2.0: non-default mapping: uni-/1-M/JoinColumn ==> foreign key strategy
|
||||
if (isUnidirectionalOneToManyForeignKey(field)) {
|
||||
if (isUni1ToMFK(field)) {
|
||||
return true;
|
||||
}
|
||||
return useInverseKeyMapping;
|
||||
}
|
||||
|
||||
public boolean isNonDefaultMappingAllowed() {
|
||||
return getMetaDataFactory().getDefaults().isNonDefaultMappingAllowed(getConfiguration());
|
||||
OpenJPAConfiguration conf = getConfiguration();
|
||||
return getMetaDataFactory().getDefaults().isNonDefaultMappingAllowed(conf);
|
||||
}
|
||||
|
||||
public boolean isUnidirectionalManyToOneJoinTable(FieldMapping field) {
|
||||
if (isNonDefaultMappingAllowed()
|
||||
&& field.getAssociationType() == FieldMetaData.MANY_TO_ONE
|
||||
&& hasJoinTable(field)
|
||||
&& !isBidirectional(field)) {
|
||||
public boolean isUniMTo1JT(FieldMapping field) {
|
||||
if (isNonDefaultMappingAllowed() &&
|
||||
field.getAssociationType() == FieldMetaData.MANY_TO_ONE &&
|
||||
hasJoinTable(field) &&
|
||||
!isBidirectional(field)) {
|
||||
field.getValueMapping().getValueInfo().setColumns(field.getElementMapping().getValueInfo().getColumns());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isUnidirectionalOneToOneJoinTable(FieldMapping field) {
|
||||
if (isNonDefaultMappingAllowed()
|
||||
&& field.getAssociationType() == FieldMetaData.ONE_TO_ONE
|
||||
&& hasJoinTable(field)
|
||||
&& !isBidirectional(field)) {
|
||||
public boolean isUni1To1JT(FieldMapping field) {
|
||||
if (isNonDefaultMappingAllowed() &&
|
||||
field.getAssociationType() == FieldMetaData.ONE_TO_ONE &&
|
||||
hasJoinTable(field) &&
|
||||
!isBidirectional(field)) {
|
||||
field.getValueMapping().getValueInfo().setColumns(field.getElementMapping().getValueInfo().getColumns());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isBidirectionalOneToOneJoinTable(FieldMapping field) {
|
||||
if (isNonDefaultMappingAllowed()
|
||||
&& field.getAssociationType() == FieldMetaData.ONE_TO_ONE
|
||||
&& hasJoinTable(field)
|
||||
&& isBidirectional(field)) {
|
||||
public boolean isBi1To1JT(FieldMapping field) {
|
||||
if (isNonDefaultMappingAllowed() &&
|
||||
field.getAssociationType() == FieldMetaData.ONE_TO_ONE &&
|
||||
hasJoinTable(field) &&
|
||||
isBidirectional(field)) {
|
||||
field.getValueMapping().getValueInfo().setColumns(field.getElementMapping().getValueInfo().getColumns());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isUnidirectionalOneToManyForeignKey(FieldMapping field) {
|
||||
if (isNonDefaultMappingAllowed()
|
||||
&& field.getAssociationType() == FieldMetaData.ONE_TO_MANY
|
||||
&& hasJoinColumn(field)
|
||||
&& !isBidirectional(field)) {
|
||||
public boolean isUni1ToMFK(FieldMapping field) {
|
||||
if (isNonDefaultMappingAllowed() &&
|
||||
field.getAssociationType() == FieldMetaData.ONE_TO_MANY &&
|
||||
hasJoinColumn(field) &&
|
||||
!isBidirectional(field)) {
|
||||
field.getElementMapping().getValueInfo().setColumns(field.getValueInfo().getColumns());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isBidirectionalManyToOneJoinTable(FieldMapping field) {
|
||||
public boolean isBiMTo1JT(FieldMapping field) {
|
||||
FieldMapping mapped = field.getMappedByMapping();
|
||||
if (isNonDefaultMappingAllowed()) {
|
||||
if (field.getAssociationType() == FieldMetaData.ONE_TO_MANY ) {
|
||||
if (mapped != null && hasJoinTable(mapped))
|
||||
return true;
|
||||
} else if (field.getAssociationType() == FieldMetaData.MANY_TO_ONE) {
|
||||
if (getBidirectionalOneToManyJoinTableField(field) != null)
|
||||
if (getBi_1ToM_JoinTableField(field) != null)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the inverse field of bidirectional many to one relation using join table strategy
|
||||
* for the given field.
|
||||
*/
|
||||
public FieldMapping getBidirectionalOneToManyJoinTableField(FieldMapping field) {
|
||||
// return the inverse field of bidirectional many to one
|
||||
// relation using join table strategy
|
||||
public FieldMapping getBi_1ToM_JoinTableField(FieldMapping field) {
|
||||
if (isNonDefaultMappingAllowed()) {
|
||||
if (field.getAssociationType() == FieldMetaData.ONE_TO_MANY) {
|
||||
FieldMapping mappedBy = field.getMappedByMapping();
|
||||
|
@ -1155,10 +1159,9 @@ public class MappingRepository extends MetaDataRepository {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the owning field of bidirectional one to many relation using join table strategy of the given field.
|
||||
*/
|
||||
public FieldMapping getBidirectionalManyToOneJoinTableField(FieldMapping field) {
|
||||
// return the owning field of bidirectional one to many
|
||||
// relation using join table strategy
|
||||
public FieldMapping getBi_MTo1_JoinTableField(FieldMapping field) {
|
||||
if (isNonDefaultMappingAllowed()) {
|
||||
if (field.getAssociationType() == FieldMetaData.MANY_TO_ONE) {
|
||||
if (!hasJoinTable(field))
|
||||
|
|
|
@ -37,10 +37,8 @@ import org.apache.openjpa.jdbc.sql.Row;
|
|||
import org.apache.openjpa.jdbc.sql.RowManager;
|
||||
import org.apache.openjpa.jdbc.sql.SQLBuffer;
|
||||
import org.apache.openjpa.jdbc.sql.Select;
|
||||
import org.apache.openjpa.jdbc.sql.SelectExecutor;
|
||||
import org.apache.openjpa.kernel.OpenJPAStateManager;
|
||||
import org.apache.openjpa.lib.util.Localizer;
|
||||
import org.apache.openjpa.lib.util.ThreadGate;
|
||||
import org.apache.openjpa.meta.JavaTypes;
|
||||
import org.apache.openjpa.meta.ValueStrategies;
|
||||
import org.apache.openjpa.util.InternalException;
|
||||
|
@ -51,26 +49,23 @@ import org.apache.openjpa.util.UserException;
|
|||
* Mapping for a single-valued field that delegates to a {@link ValueHandler}.
|
||||
*
|
||||
* @author Abe White
|
||||
* @author Pinaki Poddar (select cache)
|
||||
* @since 0.4.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class HandlerFieldStrategy
|
||||
extends AbstractFieldStrategy
|
||||
implements Joinable, Embeddable {
|
||||
|
||||
private static final Object NULL = new Object();
|
||||
|
||||
private static final Localizer _loc = Localizer.forPackage(HandlerFieldStrategy.class);
|
||||
private static final Localizer _loc = Localizer.forPackage
|
||||
(HandlerFieldStrategy.class);
|
||||
|
||||
protected Column[] _cols = null;
|
||||
protected ColumnIO _io = null;
|
||||
protected Object[] _args = null;
|
||||
protected boolean _load = false;
|
||||
protected boolean _lob = false;
|
||||
private Select _executor;
|
||||
private ThreadGate _lock = new ThreadGate();
|
||||
|
||||
|
||||
public void map(boolean adapt) {
|
||||
if (field.getHandler() == null)
|
||||
throw new MetaDataException(_loc.get("no-handler", field));
|
||||
|
@ -225,34 +220,21 @@ public class HandlerFieldStrategy
|
|||
return;
|
||||
}
|
||||
}
|
||||
Select sel;
|
||||
|
||||
Select sel = store.getSQLFactory().newSelect();
|
||||
sel.select(_cols);
|
||||
field.wherePrimaryKey(sel, sm, store);
|
||||
|
||||
Result res = sel.execute(store, fetch);
|
||||
Object val = null;
|
||||
try {
|
||||
_lock.lock();
|
||||
if (_executor == null) {
|
||||
sel = store.getSQLFactory().newSelect();
|
||||
if (store.getConfiguration().getSelectCacheEnabled()) {
|
||||
_executor = sel;
|
||||
}
|
||||
sel.select(_cols);
|
||||
} else {
|
||||
sel = _executor;
|
||||
}
|
||||
|
||||
field.wherePrimaryKey(sel, sm, store);
|
||||
|
||||
Result res = sel.execute(store, fetch);
|
||||
Object val = null;
|
||||
try {
|
||||
if (res.next())
|
||||
val = HandlerStrategies.loadDataStore(field, res, null, _cols);
|
||||
} finally {
|
||||
res.close();
|
||||
}
|
||||
|
||||
loadEmbedded(sm, store, fetch, val);
|
||||
if (res.next())
|
||||
val = HandlerStrategies.loadDataStore(field, res, null, _cols);
|
||||
} finally {
|
||||
_lock.unlock();
|
||||
res.close();
|
||||
}
|
||||
|
||||
loadEmbedded(sm, store, fetch, val);
|
||||
}
|
||||
|
||||
public Object toDataStoreValue(Object val, JDBCStore store) {
|
||||
|
|
|
@ -87,7 +87,7 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
union.select(new Union.Selector() {
|
||||
public void select(Select sel, int idx) {
|
||||
sel.select(_kcols);
|
||||
if (field.isUnidirectionalOneToManyForeignKey()) {
|
||||
if (field.isUni1ToMFK()) {
|
||||
sel.whereForeignKey(field.getElementMapping().getForeignKey(),
|
||||
sm.getObjectId(), field.getElementMapping().getDeclaredTypeMapping(), store);
|
||||
sel.select(vals[idx], field.getElementMapping().
|
||||
|
@ -146,11 +146,10 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
throw new MetaDataException(_loc.get("not-relation", val));
|
||||
|
||||
FieldMapping mapped = field.getMappedByMapping();
|
||||
if (field.isUnidirectionalOneToManyForeignKey()
|
||||
|| (!field.isBidirectionalManyToOneJoinTable() && mapped != null)) {
|
||||
if (field.isUni1ToMFK() || (!field.isBiMTo1JT() && mapped != null)) {
|
||||
// map to the owner table
|
||||
handleMappedByForeignKey(adapt);
|
||||
} else if (field.isBidirectionalManyToOneJoinTable() || mapped == null) {
|
||||
} else if (field.isBiMTo1JT() || mapped == null) {
|
||||
// map to a separate table
|
||||
field.mapJoin(adapt, true);
|
||||
if (val.getTypeMapping().isMapped()) {
|
||||
|
@ -187,11 +186,11 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
if (map == null || map.isEmpty())
|
||||
return;
|
||||
|
||||
if (!field.isBidirectionalManyToOneJoinTable() && field.getMappedBy() != null)
|
||||
if (!field.isBiMTo1JT() && field.getMappedBy() != null)
|
||||
return;
|
||||
|
||||
Row row = null;
|
||||
if (!field.isUnidirectionalOneToManyForeignKey()) {
|
||||
if (!field.isUni1ToMFK()) {
|
||||
row = rm.getSecondaryRow(field.getTable(), Row.ACTION_INSERT);
|
||||
row.setForeignKey(field.getJoinForeignKey(), field.getJoinColumnIO(),
|
||||
sm);
|
||||
|
@ -205,7 +204,7 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
entry = (Map.Entry) itr.next();
|
||||
valsm = RelationStrategies.getStateManager(entry.getValue(),
|
||||
ctx);
|
||||
if (field.isUnidirectionalOneToManyForeignKey()){
|
||||
if (field.isUni1ToMFK()){
|
||||
row = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(),
|
||||
Row.ACTION_UPDATE, valsm, true);
|
||||
row.wherePrimaryKey(valsm);
|
||||
|
@ -224,7 +223,7 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
// from the view point of the owned side
|
||||
PersistenceCapable obj = sm.getPersistenceCapable();
|
||||
if (!populateKey(row, valsm, obj, ctx, rm, store)) {
|
||||
if (!field.isUnidirectionalOneToManyForeignKey())
|
||||
if (!field.isUni1ToMFK())
|
||||
rm.flushSecondaryRow(row);
|
||||
}
|
||||
}
|
||||
|
@ -239,7 +238,7 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
|
||||
public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
|
||||
throws SQLException {
|
||||
if (field.getMappedBy() != null && !field.isBidirectionalManyToOneJoinTable())
|
||||
if (field.getMappedBy() != null && !field.isBiMTo1JT())
|
||||
return;
|
||||
|
||||
Map map = (Map) sm.fetchObject(field.getIndex());
|
||||
|
@ -270,7 +269,7 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
Object mkey;
|
||||
if (canChange && !change.isEmpty()) {
|
||||
Row changeRow = null;
|
||||
if (!field.isUnidirectionalOneToManyForeignKey()) {
|
||||
if (!field.isUni1ToMFK()) {
|
||||
changeRow = rm.getSecondaryRow(field.getTable(),
|
||||
Row.ACTION_UPDATE);
|
||||
changeRow.whereForeignKey(field.getJoinForeignKey(), sm);
|
||||
|
@ -279,7 +278,7 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
for (Iterator itr = change.iterator(); itr.hasNext();) {
|
||||
mkey = itr.next();
|
||||
valsm = RelationStrategies.getStateManager(map.get(mkey), ctx);
|
||||
if (field.isUnidirectionalOneToManyForeignKey()){
|
||||
if (field.isUni1ToMFK()){
|
||||
changeRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(),
|
||||
Row.ACTION_UPDATE, valsm, true);
|
||||
changeRow.wherePrimaryKey(valsm);
|
||||
|
@ -289,7 +288,7 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
}
|
||||
|
||||
HandlerStrategies.where(key, mkey, store, changeRow, _kcols);
|
||||
if (!field.isUnidirectionalOneToManyForeignKey())
|
||||
if (!field.isUni1ToMFK())
|
||||
rm.flushSecondaryRow(changeRow);
|
||||
}
|
||||
}
|
||||
|
@ -298,14 +297,14 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
Collection rem = ct.getRemoved();
|
||||
if (!rem.isEmpty() || (!canChange && !change.isEmpty())) {
|
||||
Row delRow = null;
|
||||
if (!field.isUnidirectionalOneToManyForeignKey()) {
|
||||
if (!field.isUni1ToMFK()) {
|
||||
delRow = rm.getSecondaryRow(field.getTable(),
|
||||
Row.ACTION_DELETE);
|
||||
delRow.whereForeignKey(field.getJoinForeignKey(), sm);
|
||||
}
|
||||
for (Iterator itr = rem.iterator(); itr.hasNext();) {
|
||||
mkey = itr.next();
|
||||
if (field.isUnidirectionalOneToManyForeignKey()){
|
||||
if (field.isUni1ToMFK()){
|
||||
updateSetNull(sm, mkey, store, rm);
|
||||
} else {
|
||||
HandlerStrategies.where(key, mkey, store, delRow, _kcols);
|
||||
|
@ -315,7 +314,7 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
if (!canChange && !change.isEmpty()) {
|
||||
for (Iterator itr = change.iterator(); itr.hasNext();) {
|
||||
mkey = itr.next();
|
||||
if (field.isUnidirectionalOneToManyForeignKey()){
|
||||
if (field.isUni1ToMFK()){
|
||||
updateSetNull(sm, mkey, store, rm);
|
||||
} else {
|
||||
HandlerStrategies.where(key, itr.next(), store, delRow, _kcols);
|
||||
|
@ -329,7 +328,7 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
Collection add = ct.getAdded();
|
||||
if (!add.isEmpty() || (!canChange && !change.isEmpty())) {
|
||||
Row addRow = null;
|
||||
if (!field.isUnidirectionalOneToManyForeignKey()) {
|
||||
if (!field.isUni1ToMFK()) {
|
||||
addRow = rm.getSecondaryRow(field.getTable(),
|
||||
Row.ACTION_INSERT);
|
||||
addRow.setForeignKey(field.getJoinForeignKey(),
|
||||
|
@ -338,7 +337,7 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
for (Iterator itr = add.iterator(); itr.hasNext();) {
|
||||
mkey = itr.next();
|
||||
valsm = RelationStrategies.getStateManager(map.get(mkey), ctx);
|
||||
if (field.isUnidirectionalOneToManyForeignKey()){
|
||||
if (field.isUni1ToMFK()){
|
||||
addRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(),
|
||||
Row.ACTION_UPDATE, valsm, true);
|
||||
addRow.wherePrimaryKey(valsm);
|
||||
|
@ -349,14 +348,14 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
|
||||
HandlerStrategies.set(key, mkey, store, addRow, _kcols,
|
||||
_kio, true);
|
||||
if (!field.isUnidirectionalOneToManyForeignKey())
|
||||
if (!field.isUni1ToMFK())
|
||||
rm.flushSecondaryRow(addRow);
|
||||
}
|
||||
if (!canChange && !change.isEmpty()) {
|
||||
for (Iterator itr = change.iterator(); itr.hasNext();) {
|
||||
mkey = itr.next();
|
||||
valsm = RelationStrategies.getStateManager(map.get(mkey), ctx);
|
||||
if (field.isUnidirectionalOneToManyForeignKey()){
|
||||
if (field.isUni1ToMFK()){
|
||||
addRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(),
|
||||
Row.ACTION_UPDATE, valsm, true);
|
||||
addRow.wherePrimaryKey(valsm);
|
||||
|
@ -367,7 +366,7 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
|
||||
HandlerStrategies.set(key, mkey, store, addRow, _kcols,
|
||||
_kio, true);
|
||||
if (!field.isUnidirectionalOneToManyForeignKey())
|
||||
if (!field.isUni1ToMFK())
|
||||
rm.flushSecondaryRow(addRow);
|
||||
}
|
||||
}
|
||||
|
@ -414,9 +413,9 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
|
||||
public void delete(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
|
||||
throws SQLException {
|
||||
if ((field.getMappedBy() != null && !field.isBidirectionalManyToOneJoinTable()))
|
||||
if ((field.getMappedBy() != null && !field.isBiMTo1JT()))
|
||||
return;
|
||||
if (field.isUnidirectionalOneToManyForeignKey()) {
|
||||
if (field.isUni1ToMFK()) {
|
||||
Map mapObj = (Map)sm.fetchObject(field.getIndex());
|
||||
updateSetNull(sm, store, rm, mapObj.keySet());
|
||||
return;
|
||||
|
|
|
@ -112,10 +112,10 @@ public abstract class MapTableFieldStrategy
|
|||
throw new MetaDataException(_loc.get("mapped-by-key", field));
|
||||
|
||||
// Non-default mapping Uni-/OneToMany/ForeignKey allows schema components
|
||||
if (field.isUnidirectionalOneToManyForeignKey())
|
||||
if (field.isUni1ToMFK())
|
||||
return;
|
||||
if (field.isBidirectionalManyToOneJoinTable())
|
||||
field.setBidirectionalOneToManyJoinTableInfo();
|
||||
if (field.isBiMTo1JT())
|
||||
field.setBi1MJoinTableInfo();
|
||||
field.getValueInfo().assertNoSchemaComponents(field, !adapt);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ import java.util.Set;
|
|||
|
||||
import org.apache.openjpa.enhance.PersistenceCapable;
|
||||
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.kernel.JDBCFetchConfiguration;
|
||||
import org.apache.openjpa.jdbc.kernel.JDBCStore;
|
||||
|
@ -38,6 +37,7 @@ import org.apache.openjpa.jdbc.meta.FieldMapping;
|
|||
import org.apache.openjpa.jdbc.meta.FieldStrategy;
|
||||
import org.apache.openjpa.jdbc.meta.Joinable;
|
||||
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.ValueMappingImpl;
|
||||
import org.apache.openjpa.jdbc.meta.ValueMappingInfo;
|
||||
|
@ -55,14 +55,13 @@ import org.apache.openjpa.jdbc.sql.SQLBuffer;
|
|||
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.LockManager;
|
||||
import org.apache.openjpa.kernel.OpenJPAStateManager;
|
||||
import org.apache.openjpa.lib.log.Log;
|
||||
import org.apache.openjpa.lib.util.Localizer;
|
||||
import org.apache.openjpa.lib.util.ThreadGate;
|
||||
import org.apache.openjpa.meta.ClassMetaData;
|
||||
import org.apache.openjpa.meta.FieldMetaData;
|
||||
import org.apache.openjpa.meta.JavaTypes;
|
||||
import org.apache.openjpa.meta.MetaDataModes;
|
||||
import org.apache.openjpa.util.ApplicationIds;
|
||||
import org.apache.openjpa.util.ImplHelper;
|
||||
import org.apache.openjpa.util.InternalException;
|
||||
|
@ -75,34 +74,27 @@ import org.apache.openjpa.util.UnsupportedException;
|
|||
/**
|
||||
* 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 Pinaki Poddar (select caching)
|
||||
* @since 0.4.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class RelationFieldStrategy
|
||||
extends AbstractFieldStrategy
|
||||
implements Joinable, Embeddable {
|
||||
|
||||
private static final Localizer _loc = Localizer.forPackage(RelationFieldStrategy.class);
|
||||
private static final Localizer _loc = Localizer.forPackage
|
||||
(RelationFieldStrategy.class);
|
||||
|
||||
private Boolean _fkOid = null;
|
||||
|
||||
private SelectExecutor _executor;
|
||||
private ThreadGate _lock = new ThreadGate();
|
||||
|
||||
public void map(boolean adapt) {
|
||||
if (field.getTypeCode() != JavaTypes.PC || field.isEmbeddedPC())
|
||||
throw new MetaDataException(_loc.get("not-relation", field));
|
||||
|
||||
field.getKeyMapping().getValueInfo().assertNoSchemaComponents(field.getKey(), !adapt);
|
||||
field.getKeyMapping().getValueInfo().assertNoSchemaComponents
|
||||
(field.getKey(), !adapt);
|
||||
if (!field.isNonDefaultMappingUsingJoinTableStrategy())
|
||||
field.getElementMapping().getValueInfo().assertNoSchemaComponents(field.getElement(), !adapt);
|
||||
field.getElementMapping().getValueInfo().assertNoSchemaComponents
|
||||
(field.getElement(), !adapt);
|
||||
boolean criteria = field.getValueInfo().getUseClassCriteria();
|
||||
|
||||
// check for named inverse
|
||||
|
@ -110,33 +102,40 @@ public class RelationFieldStrategy
|
|||
if (mapped != null) {
|
||||
field.getMappingInfo().assertNoSchemaComponents(field, !adapt);
|
||||
field.getValueInfo().assertNoSchemaComponents(field, !adapt);
|
||||
mapped.resolve(MetaDataModes.MODE_META | MetaDataModes.MODE_MAPPING);
|
||||
mapped.resolve(mapped.MODE_META | mapped.MODE_MAPPING);
|
||||
|
||||
if (!mapped.isMapped() || mapped.isSerialized())
|
||||
throw new MetaDataException(_loc.get("mapped-by-unmapped", field, mapped));
|
||||
throw new MetaDataException(_loc.get("mapped-by-unmapped",
|
||||
field, mapped));
|
||||
|
||||
if (mapped.getTypeCode() == JavaTypes.PC) {
|
||||
if (mapped.getJoinDirection() == FieldMapping.JOIN_FORWARD) {
|
||||
field.setJoinDirection(FieldMapping.JOIN_INVERSE);
|
||||
field.setColumns(mapped.getDefiningMapping().getPrimaryKeyColumns());
|
||||
if (mapped.getJoinDirection() == mapped.JOIN_FORWARD) {
|
||||
field.setJoinDirection(field.JOIN_INVERSE);
|
||||
field.setColumns(mapped.getDefiningMapping().
|
||||
getPrimaryKeyColumns());
|
||||
} else if (isTypeUnjoinedSubclass(mapped))
|
||||
throw new MetaDataException(_loc.get
|
||||
("mapped-inverse-unjoined", field.getName(), field.getDefiningMapping(), mapped));
|
||||
("mapped-inverse-unjoined", field.getName(),
|
||||
field.getDefiningMapping(), mapped));
|
||||
|
||||
field.setForeignKey(mapped.getForeignKey(field.getDefiningMapping()));
|
||||
field.setForeignKey(mapped.getForeignKey
|
||||
(field.getDefiningMapping()));
|
||||
} else if (mapped.getElement().getTypeCode() == JavaTypes.PC) {
|
||||
if (isTypeUnjoinedSubclass(mapped.getElementMapping()))
|
||||
throw new MetaDataException(_loc.get
|
||||
("mapped-inverse-unjoined", field.getName(), field.getDefiningMapping(), mapped));
|
||||
("mapped-inverse-unjoined", field.getName(),
|
||||
field.getDefiningMapping(), mapped));
|
||||
|
||||
// warn the user about making the collection side the owner
|
||||
Log log = field.getRepository().getLog();
|
||||
if (log.isInfoEnabled())
|
||||
log.info(_loc.get("coll-owner", field, mapped));
|
||||
field.setForeignKey(mapped.getElementMapping().getForeignKey());
|
||||
} else {
|
||||
throw new MetaDataException(_loc.get("not-inv-relation", field, mapped));
|
||||
}
|
||||
field.setForeignKey(mapped.getElementMapping().
|
||||
getForeignKey());
|
||||
} else
|
||||
throw new MetaDataException(_loc.get("not-inv-relation",
|
||||
field, mapped));
|
||||
|
||||
field.setUseClassCriteria(criteria);
|
||||
return;
|
||||
}
|
||||
|
@ -158,22 +157,24 @@ public class RelationFieldStrategy
|
|||
field.getMappingInfo().setColumns(null);
|
||||
}
|
||||
|
||||
if (!field.isBidirectionalManyToOneJoinTable())
|
||||
if (!field.isBiMTo1JT())
|
||||
field.mapJoin(adapt, false);
|
||||
if (field.getTypeMapping().isMapped()) {
|
||||
if (field.getMappedByIdValue() != null)
|
||||
setMappedByIdColumns();
|
||||
|
||||
if (!field.isBidirectionalManyToOneJoinTable()) {
|
||||
ForeignKey fk = vinfo.getTypeJoin(field, field.getName(), true, adapt);
|
||||
if (!field.isBiMTo1JT()) {
|
||||
ForeignKey fk = vinfo.getTypeJoin(field, field.getName(), true,
|
||||
adapt);
|
||||
field.setForeignKey(fk);
|
||||
}
|
||||
field.setColumnIO(vinfo.getColumnIO());
|
||||
if (vinfo.getJoinDirection() == MappingInfo.JOIN_INVERSE)
|
||||
field.setJoinDirection(FieldMapping.JOIN_INVERSE);
|
||||
} else {
|
||||
RelationStrategies.mapRelationToUnmappedPC(field, field.getName(), adapt);
|
||||
}
|
||||
if (vinfo.getJoinDirection() == vinfo.JOIN_INVERSE)
|
||||
field.setJoinDirection(field.JOIN_INVERSE);
|
||||
} else
|
||||
RelationStrategies.mapRelationToUnmappedPC(field, field.getName(),
|
||||
adapt);
|
||||
|
||||
field.setUseClassCriteria(criteria);
|
||||
field.mapPrimaryKey(adapt);
|
||||
PrimaryKey pk = field.getTable().getPrimaryKey();
|
||||
|
@ -208,10 +209,11 @@ public class RelationFieldStrategy
|
|||
}
|
||||
}
|
||||
|
||||
private List<Column> getMappedByIdColumns(FieldMapping pk) {
|
||||
ClassMetaData embeddedId = ((ValueMappingImpl)pk.getValue()).getEmbeddedMetaData();
|
||||
private List getMappedByIdColumns(FieldMapping pk) {
|
||||
ClassMetaData embeddedId = ((ValueMappingImpl)pk.getValue()).
|
||||
getEmbeddedMetaData();
|
||||
Column[] pkCols = null;
|
||||
List<Column> cols = new ArrayList<Column>();
|
||||
List cols = new ArrayList();
|
||||
String mappedByIdValue = field.getMappedByIdValue();
|
||||
if (embeddedId != null) {
|
||||
FieldMetaData[] fmds = embeddedId.getFields();
|
||||
|
@ -219,19 +221,20 @@ public class RelationFieldStrategy
|
|||
if ((fmds[i].getName().equals(mappedByIdValue)) ||
|
||||
mappedByIdValue.length() == 0) {
|
||||
if (fmds[i].getValue().getEmbeddedMetaData() != null) {
|
||||
EmbedValueHandler.getEmbeddedIdCols((FieldMapping)fmds[i], cols);
|
||||
} else {
|
||||
EmbedValueHandler.getIdColumns((FieldMapping)fmds[i], cols);
|
||||
}
|
||||
EmbedValueHandler.getEmbeddedIdCols(
|
||||
(FieldMapping)fmds[i], cols);
|
||||
} else
|
||||
EmbedValueHandler.getIdColumns(
|
||||
(FieldMapping)fmds[i], cols);
|
||||
}
|
||||
}
|
||||
return cols;
|
||||
} else { // primary key is single-value
|
||||
Class<?> pkType = pk.getDeclaredType();
|
||||
Class pkType = pk.getDeclaredType();
|
||||
FieldMetaData[] pks = field.getValue().getDeclaredTypeMetaData().
|
||||
getPrimaryKeyFields();
|
||||
if (pks.length != 1 || pks[0].getDeclaredType() != pkType)
|
||||
return Collections.emptyList();
|
||||
return Collections.EMPTY_LIST;
|
||||
pkCols = pk.getColumns();
|
||||
for (int i = 0; i < pkCols.length; i++)
|
||||
cols.add(pkCols[i]);
|
||||
|
@ -268,11 +271,11 @@ public class RelationFieldStrategy
|
|||
|
||||
OpenJPAStateManager rel = RelationStrategies.getStateManager
|
||||
(sm.fetchObjectField(field.getIndex()), store.getContext());
|
||||
if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE)
|
||||
if (field.getJoinDirection() == field.JOIN_INVERSE)
|
||||
updateInverse(sm, rel, store, rm);
|
||||
else {
|
||||
Row row = field.getRow(sm, store, rm, Row.ACTION_INSERT);
|
||||
if (row != null && !field.isBidirectionalManyToOneJoinTable()) {
|
||||
if (row != null && !field.isBiMTo1JT()) {
|
||||
field.setForeignKey(row, rel);
|
||||
// this is for bi-directional maps, the key and value of the
|
||||
// map are stored in the table of the mapped-by entity
|
||||
|
@ -292,7 +295,7 @@ public class RelationFieldStrategy
|
|||
if (mapField == null)
|
||||
return;
|
||||
|
||||
Map<Object,Object> mapObj = (Map<Object,Object>)rel.fetchObjectField(mapField.getIndex());
|
||||
Map mapObj = (Map)rel.fetchObjectField(mapField.getIndex());
|
||||
Object keyObj = getMapKeyObj(mapObj, sm.getPersistenceCapable());
|
||||
ValueMapping key = mapField.getKeyMapping();
|
||||
if (!key.isEmbedded()) {
|
||||
|
@ -308,11 +311,14 @@ public class RelationFieldStrategy
|
|||
} else {
|
||||
// key is an embeddable or basic type
|
||||
FieldStrategy strategy = mapField.getStrategy();
|
||||
if (strategy instanceof HandlerRelationMapTableFieldStrategy) {
|
||||
HandlerRelationMapTableFieldStrategy strat = (HandlerRelationMapTableFieldStrategy) strategy;
|
||||
if (strategy instanceof
|
||||
HandlerRelationMapTableFieldStrategy) {
|
||||
HandlerRelationMapTableFieldStrategy strat =
|
||||
(HandlerRelationMapTableFieldStrategy) strategy;
|
||||
Column[] kcols = strat.getKeyColumns((ClassMapping)meta);
|
||||
ColumnIO kio = strat.getKeyColumnIO();
|
||||
HandlerStrategies.set(key, keyObj, store, row, kcols, kio, true);
|
||||
HandlerStrategies.set(key, keyObj, store, row, kcols,
|
||||
kio, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -321,18 +327,19 @@ public class RelationFieldStrategy
|
|||
FieldMapping[] fields = ((ClassMapping)meta).getFieldMappings();
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
FieldMetaData mappedBy = fields[i].getMappedByMetaData();
|
||||
if (fields[i].getDeclaredTypeCode() == JavaTypes.MAP && mappedBy == field)
|
||||
if (fields[i].getDeclaredTypeCode() == JavaTypes.MAP &&
|
||||
mappedBy == field)
|
||||
return fields[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Object getMapKeyObj(Map<Object,Object> mapObj, Object value) {
|
||||
private Object getMapKeyObj(Map mapObj, Object value) {
|
||||
if (value instanceof ReflectingPersistenceCapable)
|
||||
value = ((ReflectingPersistenceCapable)value).getManagedInstance();
|
||||
|
||||
Set<Map.Entry<Object,Object>> entries = mapObj.entrySet();
|
||||
for (Map.Entry<Object,Object> entry : entries) {
|
||||
Set<Map.Entry> entries = mapObj.entrySet();
|
||||
for (Map.Entry entry : entries) {
|
||||
if (entry.getValue() == value)
|
||||
return entry.getKey();
|
||||
}
|
||||
|
@ -348,7 +355,7 @@ public class RelationFieldStrategy
|
|||
OpenJPAStateManager rel = RelationStrategies.getStateManager
|
||||
(sm.fetchObjectField(field.getIndex()), store.getContext());
|
||||
|
||||
if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE) {
|
||||
if (field.getJoinDirection() == field.JOIN_INVERSE) {
|
||||
nullInverse(sm, rm);
|
||||
updateInverse(sm, rel, store, rm);
|
||||
} else {
|
||||
|
@ -356,22 +363,22 @@ public class RelationFieldStrategy
|
|||
field.isBidirectionalJoinTableMappingNonOwner()) ?
|
||||
Row.ACTION_DELETE : Row.ACTION_UPDATE;
|
||||
Row row = field.getRow(sm, store, rm, action);
|
||||
if (row != null && !field.isBidirectionalManyToOneJoinTable()) {
|
||||
if (row != null && !field.isBiMTo1JT()) {
|
||||
field.setForeignKey(row, rel);
|
||||
// this is for bi-directional maps, the key and value of the
|
||||
// map are stored in the table of the mapped-by entity
|
||||
setMapKey(sm, rel, store, row);
|
||||
}
|
||||
|
||||
if (field.isBidirectionalManyToOneJoinTable()) { // also need to update the join table
|
||||
if (field.isBiMTo1JT()) { // also need to update the join table
|
||||
PersistenceCapable invPC = (PersistenceCapable)sm.fetchObject(
|
||||
field.getBidirectionalOneToManyJoinTableField().getIndex());
|
||||
field.getBi_1ToM_JTField().getIndex());
|
||||
Row secondaryRow = null;
|
||||
if (invPC != null) {
|
||||
secondaryRow = rm.getSecondaryRow(field.getBidirectionalOneToManyJoinForeignKey().getTable(),
|
||||
secondaryRow = rm.getSecondaryRow(field.getBi1ToMJoinFK().getTable(),
|
||||
Row.ACTION_INSERT);
|
||||
secondaryRow.setForeignKey(field.getBidirectionalOneToManyElementForeignKey(), null, sm);
|
||||
secondaryRow.setForeignKey(field.getBidirectionalOneToManyJoinForeignKey(), null,
|
||||
secondaryRow.setForeignKey(field.getBi1ToMElemFK(), null, sm);
|
||||
secondaryRow.setForeignKey(field.getBi1ToMJoinFK(), null,
|
||||
RelationStrategies.getStateManager(invPC,
|
||||
store.getContext()));
|
||||
rm.flushSecondaryRow(secondaryRow);
|
||||
|
@ -385,7 +392,7 @@ public class RelationFieldStrategy
|
|||
if (field.getMappedBy() != null)
|
||||
return;
|
||||
|
||||
if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE) {
|
||||
if (field.getJoinDirection() == field.JOIN_INVERSE) {
|
||||
if (sm.getLoaded().get(field.getIndex())) {
|
||||
OpenJPAStateManager rel = RelationStrategies.getStateManager(sm.
|
||||
fetchObjectField(field.getIndex()), store.getContext());
|
||||
|
@ -497,7 +504,7 @@ public class RelationFieldStrategy
|
|||
public int supportsSelect(Select sel, int type, OpenJPAStateManager sm,
|
||||
JDBCStore store, JDBCFetchConfiguration fetch) {
|
||||
if (type == Select.TYPE_JOINLESS)
|
||||
return (field.getJoinDirection() != FieldMapping.JOIN_INVERSE
|
||||
return (field.getJoinDirection() != field.JOIN_INVERSE
|
||||
&& sel.isSelected(field.getTable())) ? 1 : 0;
|
||||
if (type == Select.TYPE_TWO_PART)
|
||||
return 1;
|
||||
|
@ -528,15 +535,17 @@ public class RelationFieldStrategy
|
|||
final OpenJPAStateManager sm, final JDBCStore store,
|
||||
final JDBCFetchConfiguration fetch, final int eagerMode) {
|
||||
final ClassMapping[] clss = field.getIndependentTypeMappings();
|
||||
if (!(sel instanceof Union)) {
|
||||
if (!(sel instanceof Union))
|
||||
selectEagerParallel((Select) sel, clss[0], store, fetch, eagerMode);
|
||||
} else {
|
||||
else {
|
||||
Union union = (Union) sel;
|
||||
if (fetch.getSubclassFetchMode (field.getTypeMapping()) != JDBCFetchConfiguration.EAGER_JOIN)
|
||||
if (fetch.getSubclassFetchMode (field.getTypeMapping())
|
||||
!= JDBCFetchConfiguration.EAGER_JOIN)
|
||||
union.abortUnion();
|
||||
union.select(new Union.Selector() {
|
||||
public void select(Select sel, int idx) {
|
||||
selectEagerParallel(sel, clss[idx], store, fetch, eagerMode);
|
||||
selectEagerParallel(sel, clss[idx], store, fetch,
|
||||
eagerMode);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -547,7 +556,7 @@ public class RelationFieldStrategy
|
|||
*/
|
||||
private void selectEagerParallel(Select sel, ClassMapping cls,
|
||||
JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) {
|
||||
if (field.isBidirectionalManyToOneJoinTable())
|
||||
if (field.isBiMTo1JT())
|
||||
return;
|
||||
sel.selectPrimaryKey(field.getDefiningMapping());
|
||||
// set a variable name that does not conflict with any in the query;
|
||||
|
@ -562,7 +571,7 @@ public class RelationFieldStrategy
|
|||
|
||||
public void selectEagerJoin(Select sel, OpenJPAStateManager sm,
|
||||
JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) {
|
||||
if (field.isBidirectionalManyToOneJoinTable())
|
||||
if (field.isBiMTo1JT())
|
||||
return;
|
||||
|
||||
// limit the eager mode to single on recursive eager fetching b/c
|
||||
|
@ -581,7 +590,7 @@ public class RelationFieldStrategy
|
|||
* Add the joins needed to select/load eager data.
|
||||
*/
|
||||
private Joins eagerJoin(Joins joins, ClassMapping cls, boolean forceInner) {
|
||||
boolean inverse = field.getJoinDirection() == FieldMapping.JOIN_INVERSE;
|
||||
boolean inverse = field.getJoinDirection() == field.JOIN_INVERSE;
|
||||
if (!inverse) {
|
||||
joins = join(joins, false);
|
||||
joins = setEmbeddedVariable(joins);
|
||||
|
@ -609,7 +618,7 @@ public class RelationFieldStrategy
|
|||
|
||||
public int select(Select sel, OpenJPAStateManager sm, JDBCStore store,
|
||||
JDBCFetchConfiguration fetch, int eagerMode) {
|
||||
if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE)
|
||||
if (field.getJoinDirection() == field.JOIN_INVERSE)
|
||||
return -1;
|
||||
// already cached oid?
|
||||
if (sm != null && sm.getIntermediate(field.getIndex()) != null)
|
||||
|
@ -624,11 +633,11 @@ public class RelationFieldStrategy
|
|||
JDBCFetchConfiguration fetch, Object res)
|
||||
throws SQLException {
|
||||
// process batched results if we haven't already
|
||||
Map<Object,Object> rels;
|
||||
Map rels;
|
||||
if (res instanceof Result)
|
||||
rels = processEagerParallelResult(sm, store, fetch, (Result) res);
|
||||
else
|
||||
rels = (Map<Object,Object>) res;
|
||||
rels = (Map) res;
|
||||
|
||||
// store object for this oid in instance
|
||||
sm.storeObject(field.getIndex(), rels.remove(sm.getObjectId()));
|
||||
|
@ -638,7 +647,7 @@ public class RelationFieldStrategy
|
|||
/**
|
||||
* Process the given batched result.
|
||||
*/
|
||||
private Map<Object,Object> processEagerParallelResult(OpenJPAStateManager sm,
|
||||
private Map processEagerParallelResult(OpenJPAStateManager sm,
|
||||
JDBCStore store, JDBCFetchConfiguration fetch, Result res)
|
||||
throws SQLException {
|
||||
// do same joins as for load
|
||||
|
@ -648,7 +657,7 @@ public class RelationFieldStrategy
|
|||
Joins joins = res.newJoins().setVariable("*");
|
||||
eagerJoin(joins, clss[0], true);
|
||||
|
||||
Map<Object,Object> rels = new HashMap<Object,Object>();
|
||||
Map rels = new HashMap();
|
||||
ClassMapping owner = field.getDefiningMapping();
|
||||
ClassMapping cls;
|
||||
Object oid;
|
||||
|
@ -667,7 +676,7 @@ public class RelationFieldStrategy
|
|||
public void loadEagerJoin(OpenJPAStateManager sm, JDBCStore store,
|
||||
JDBCFetchConfiguration fetch, Result res)
|
||||
throws SQLException {
|
||||
if (field.isBidirectionalManyToOneJoinTable())
|
||||
if (field.isBiMTo1JT())
|
||||
return;
|
||||
ClassMapping cls = field.getIndependentTypeMappings()[0];
|
||||
|
||||
|
@ -710,7 +719,7 @@ public class RelationFieldStrategy
|
|||
public void load(OpenJPAStateManager sm, JDBCStore store,
|
||||
JDBCFetchConfiguration fetch, Result res)
|
||||
throws SQLException {
|
||||
if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE)
|
||||
if (field.getJoinDirection() == field.JOIN_INVERSE)
|
||||
return;
|
||||
// cached oid?
|
||||
if (sm != null && sm.getIntermediate(field.getIndex()) != null)
|
||||
|
@ -723,7 +732,7 @@ public class RelationFieldStrategy
|
|||
// get the related object's oid
|
||||
ClassMapping relMapping = field.getTypeMapping();
|
||||
Object oid = null;
|
||||
if (relMapping.isMapped() && !field.isBidirectionalManyToOneJoinTable()) {
|
||||
if (relMapping.isMapped() && !field.isBiMTo1JT()) {
|
||||
oid = relMapping.getObjectId(store, res, field.getForeignKey(),
|
||||
field.getPolymorphic() != ValueMapping.POLY_FALSE, null);
|
||||
} else {
|
||||
|
@ -737,7 +746,8 @@ public class RelationFieldStrategy
|
|||
if (cols.length == 1) {
|
||||
Object val = res.getObject(cols[0], null, null);
|
||||
if (val != null)
|
||||
oid = ApplicationIds.fromPKValues(new Object[]{ val }, relMapping);
|
||||
oid = ApplicationIds.fromPKValues(new Object[]{ val },
|
||||
relMapping);
|
||||
} else {
|
||||
Object[] vals = new Object[cols.length];
|
||||
for (int i = 0; i < cols.length; i++) {
|
||||
|
@ -757,7 +767,8 @@ public class RelationFieldStrategy
|
|||
sm.setIntermediate(field.getIndex(), oid);
|
||||
}
|
||||
|
||||
public void load(final OpenJPAStateManager sm, final JDBCStore store, final JDBCFetchConfiguration fetch)
|
||||
public void load(final OpenJPAStateManager sm, final JDBCStore store,
|
||||
final JDBCFetchConfiguration fetch)
|
||||
throws SQLException {
|
||||
// check for cached oid value, or load oid if no way to join
|
||||
if (Boolean.TRUE.equals(_fkOid)) {
|
||||
|
@ -776,64 +787,44 @@ public class RelationFieldStrategy
|
|||
// select related mapping columns; joining from the related type
|
||||
// back to our fk table if not an inverse mapping (in which case we
|
||||
// can just make sure the inverse cols == our pk values)
|
||||
Union union;
|
||||
Union union = store.getSQLFactory().newUnion(rels.length);
|
||||
union.setExpectedResultCount(1, false);
|
||||
if (fetch.getSubclassFetchMode(field.getTypeMapping())
|
||||
!= JDBCFetchConfiguration.EAGER_JOIN)
|
||||
union.abortUnion();
|
||||
union.select(new Union.Selector() {
|
||||
public void select(Select sel, int idx) {
|
||||
if (field.getJoinDirection() == field.JOIN_INVERSE)
|
||||
sel.whereForeignKey(field.getForeignKey(rels[idx]),
|
||||
sm.getObjectId(), field.getDefiningMapping(), store);
|
||||
else {
|
||||
if (!field.isBiMTo1JT()) {
|
||||
resJoins[idx] = sel.newJoins().joinRelation(field.getName(),
|
||||
field.getForeignKey(rels[idx]), rels[idx],
|
||||
field.getSelectSubclasses(), false, false);
|
||||
field.wherePrimaryKey(sel, sm, store);
|
||||
} else {
|
||||
resJoins[idx] = sel.newJoins().joinRelation(null,
|
||||
field.getBi1ToMJoinFK(), rels[idx],
|
||||
field.getSelectSubclasses(), false, false);
|
||||
sel.whereForeignKey(field.getBi1ToMElemFK(), sm.getObjectId(),
|
||||
field.getDefiningMapping(), store);
|
||||
}
|
||||
}
|
||||
sel.select(rels[idx], subs, store, fetch, fetch.EAGER_JOIN,
|
||||
resJoins[idx]);
|
||||
}
|
||||
});
|
||||
|
||||
Result res = union.execute(store, fetch);
|
||||
try {
|
||||
_lock.lock();
|
||||
if (_executor == null) {
|
||||
union = store.getSQLFactory().newUnion(rels.length);
|
||||
union.setExpectedResultCount(1, false);
|
||||
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() {
|
||||
public void select(Select sel, int idx) {
|
||||
ForeignKey fk = field.getForeignKey(rels[idx]);
|
||||
ClassMapping mapping = field.getDefiningMapping();
|
||||
Object oid = sm.getObjectId();
|
||||
if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE) {
|
||||
sel.whereForeignKey(fk, oid, mapping, store);
|
||||
} else {
|
||||
if (!field.isBidirectionalManyToOneJoinTable()) {
|
||||
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);
|
||||
} else {
|
||||
if (sel.isReadOnly()) {
|
||||
resJoins[idx] = sel.getJoins();
|
||||
} else {
|
||||
resJoins[idx] = sel.newJoins().joinRelation(null,
|
||||
field.getBidirectionalOneToManyJoinForeignKey(), rels[idx],
|
||||
subs, false, false);
|
||||
}
|
||||
sel.whereForeignKey(field.getBidirectionalOneToManyElementForeignKey(),
|
||||
oid, mapping, store);
|
||||
}
|
||||
}
|
||||
if (!sel.isReadOnly()) {
|
||||
sel.select(rels[idx], subs, store, fetch,
|
||||
JDBCFetchConfiguration.EAGER_JOIN, resJoins[idx]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Result res = union.execute(store, fetch);
|
||||
try {
|
||||
sm.storeObject(field.getIndex(), res.next()
|
||||
? res.load(rels[res.indexOf()], store, fetch, resJoins[res.indexOf()]) : null);
|
||||
} finally {
|
||||
res.close();
|
||||
}
|
||||
Object val = null;
|
||||
if (res.next())
|
||||
val = res.load(rels[res.indexOf()], store, fetch,
|
||||
resJoins[res.indexOf()]);
|
||||
sm.storeObject(field.getIndex(), val);
|
||||
} finally {
|
||||
_lock.unlock();
|
||||
res.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -846,7 +837,7 @@ public class RelationFieldStrategy
|
|||
// 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
|
||||
// objects point back to this field's owner
|
||||
if (field.getJoinDirection() != FieldMapping.JOIN_INVERSE) {
|
||||
if (field.getJoinDirection() != field.JOIN_INVERSE) {
|
||||
//### probably need some sort of subselect here on fk constants
|
||||
joins = join(joins, false);
|
||||
Column[] cols = field.getColumns();
|
||||
|
@ -855,9 +846,8 @@ public class RelationFieldStrategy
|
|||
else
|
||||
sql.append(sel.getColumnAlias(cols[0], joins)).
|
||||
append(" IS ").appendValue(null, cols[0]);
|
||||
} else {
|
||||
} else
|
||||
testInverseNull(sql, sel, joins, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void appendIsNotNull(SQLBuffer sql, Select sel, Joins joins) {
|
||||
|
@ -865,7 +855,7 @@ public class RelationFieldStrategy
|
|||
// 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
|
||||
// inverse objects point back to this field's owner
|
||||
if (field.getJoinDirection() != FieldMapping.JOIN_INVERSE) {
|
||||
if (field.getJoinDirection() != field.JOIN_INVERSE) {
|
||||
//### probably need some sort of subselect here on fk constants
|
||||
joins = join(joins, false);
|
||||
Column[] cols = field.getColumns();
|
||||
|
@ -896,27 +886,30 @@ public class RelationFieldStrategy
|
|||
sql.append("0 < ");
|
||||
|
||||
ForeignKey fk = field.getForeignKey();
|
||||
ContainerFieldStrategy.appendJoinCount(sql, sel, joins, dict, field, fk);
|
||||
ContainerFieldStrategy.appendJoinCount(sql, sel, joins, dict, field,
|
||||
fk);
|
||||
}
|
||||
|
||||
public Joins join(Joins joins, boolean forceOuter) {
|
||||
// if we're not in an inverse object table join normally, otherwise
|
||||
// already traversed the relation; just join back to owner table
|
||||
if (field.getJoinDirection() != FieldMapping.JOIN_INVERSE)
|
||||
if (field.getJoinDirection() != field.JOIN_INVERSE)
|
||||
return field.join(joins, forceOuter, false);
|
||||
ClassMapping[] clss = field.getIndependentTypeMappings();
|
||||
if (clss.length != 1)
|
||||
throw RelationStrategies.uninversable(field);
|
||||
if (forceOuter)
|
||||
return joins.outerJoinRelation(field.getName(),
|
||||
field.getForeignKey(), clss[0], field.getSelectSubclasses(), true, false);
|
||||
field.getForeignKey(), clss[0], field.getSelectSubclasses(),
|
||||
true, false);
|
||||
return joins.joinRelation(field.getName(), field.getForeignKey(),
|
||||
clss[0], field.getSelectSubclasses(), true, false);
|
||||
}
|
||||
|
||||
public Joins joinRelation(Joins joins, boolean forceOuter, boolean traverse) {
|
||||
public Joins joinRelation(Joins joins, boolean forceOuter,
|
||||
boolean traverse) {
|
||||
// if this is an inverse mapping it's already joined to the relation
|
||||
if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE)
|
||||
if (field.getJoinDirection() == field.JOIN_INVERSE)
|
||||
return joins;
|
||||
ClassMapping[] clss = field.getIndependentTypeMappings();
|
||||
if (clss.length != 1) {
|
||||
|
@ -953,7 +946,8 @@ public class RelationFieldStrategy
|
|||
long id = res.getLong(col, joins);
|
||||
if (field.getObjectIdFieldTypeCode() == JavaTypes.LONG)
|
||||
return id;
|
||||
return store.newDataStoreId(id, relmapping, field.getPolymorphic() != ValueMapping.POLY_FALSE);
|
||||
return store.newDataStoreId(id, relmapping, field.getPolymorphic()
|
||||
!= ValueMapping.POLY_FALSE);
|
||||
}
|
||||
|
||||
if (relmapping.isOpenJPAIdentity())
|
||||
|
@ -1006,21 +1000,27 @@ public class RelationFieldStrategy
|
|||
fieldVal = store.getContext().getObjectId(fieldVal);
|
||||
if (fieldVal instanceof OpenJPAId)
|
||||
fieldVal = ((OpenJPAId) fieldVal).getIdObject();
|
||||
if (relmapping.getObjectIdType() != null && relmapping.getObjectIdType().isInstance(fieldVal)) {
|
||||
if (relmapping.getObjectIdType() != null
|
||||
&& relmapping.getObjectIdType().isInstance(fieldVal)) {
|
||||
Object[] pks = ApplicationIds.toPKValues(fieldVal, relmapping);
|
||||
fieldVal = pks[relmapping.getField(j.getFieldIndex()).getPrimaryKeyIndex()];
|
||||
fieldVal = pks[relmapping.getField(j.getFieldIndex()).
|
||||
getPrimaryKeyIndex()];
|
||||
} else if (relmapping.getObjectIdType() == ObjectId.class &&
|
||||
relmapping.getPrimaryKeyFieldMappings()[0].getValueMapping().isEmbedded()) {
|
||||
return j.getJoinValue((fieldVal == null) ? savedFieldVal : fieldVal, col, store);
|
||||
if (fieldVal == null)
|
||||
return j.getJoinValue(savedFieldVal, col, store);
|
||||
return j.getJoinValue(fieldVal, col, store);
|
||||
}
|
||||
return j.getJoinValue(fieldVal, col, store);
|
||||
}
|
||||
|
||||
public Object getJoinValue(OpenJPAStateManager sm, Column col, JDBCStore store) {
|
||||
public Object getJoinValue(OpenJPAStateManager sm, Column col,
|
||||
JDBCStore store) {
|
||||
return getJoinValue(sm.fetch(field.getIndex()), col, store);
|
||||
}
|
||||
|
||||
public void setAutoAssignedValue(OpenJPAStateManager sm, JDBCStore store, Column col, Object autoInc) {
|
||||
public void setAutoAssignedValue(OpenJPAStateManager sm, JDBCStore store,
|
||||
Column col, Object autoInc) {
|
||||
throw new UnsupportedException();
|
||||
}
|
||||
|
||||
|
@ -1048,7 +1048,8 @@ public class RelationFieldStrategy
|
|||
return UNSUPPORTED;
|
||||
}
|
||||
|
||||
public void loadEmbedded(OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch, Object val)
|
||||
public void loadEmbedded(OpenJPAStateManager sm, JDBCStore store,
|
||||
JDBCFetchConfiguration fetch, Object val)
|
||||
throws SQLException {
|
||||
ClassMapping relMapping = field.getTypeMapping();
|
||||
Object oid;
|
||||
|
@ -1058,7 +1059,8 @@ public class RelationFieldStrategy
|
|||
oid = store.newDataStoreId(((Number) val).longValue(), relMapping,
|
||||
field.getPolymorphic() != ValueMapping.POLY_FALSE);
|
||||
else {
|
||||
Object[] pks = (getColumns().length == 1) ? new Object[]{ val } : (Object[]) val;
|
||||
Object[] pks = (getColumns().length == 1) ? new Object[]{ val }
|
||||
: (Object[]) val;
|
||||
boolean nulls = true;
|
||||
for (int i = 0; nulls && i < pks.length; i++)
|
||||
nulls = pks[i] == null;
|
||||
|
@ -1066,15 +1068,17 @@ public class RelationFieldStrategy
|
|||
oid = null;
|
||||
else {
|
||||
oid = ApplicationIds.fromPKValues(pks, relMapping);
|
||||
if (field.getPolymorphic() == ValueMapping.POLY_FALSE && oid instanceof OpenJPAId) {
|
||||
((OpenJPAId) oid).setManagedInstanceType(relMapping.getDescribedType());
|
||||
if (field.getPolymorphic() == ValueMapping.POLY_FALSE
|
||||
&& oid instanceof OpenJPAId) {
|
||||
((OpenJPAId) oid).setManagedInstanceType(relMapping.
|
||||
getDescribedType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (oid == null) {
|
||||
if (oid == null)
|
||||
sm.storeObject(field.getIndex(), null);
|
||||
} else {
|
||||
else {
|
||||
if (JavaTypes.maybePC(field.getValue()) &&
|
||||
field.getElement().getEmbeddedMetaData() == null) {
|
||||
Object obj = store.find(oid, field, fetch);
|
||||
|
|
|
@ -82,7 +82,7 @@ public class RelationRelationMapTableFieldStrategy
|
|||
kunion.select(new Union.Selector() {
|
||||
public void select(Select sel, int idx) {
|
||||
ForeignKey joinFK = null;
|
||||
if (field.isUnidirectionalOneToManyForeignKey()) {
|
||||
if (field.isUni1ToMFK()) {
|
||||
ValueMapping val = field.getElementMapping();
|
||||
ValueMappingInfo vinfo = val.getValueInfo();
|
||||
Table table = vinfo.getTable(val);
|
||||
|
@ -117,7 +117,7 @@ public class RelationRelationMapTableFieldStrategy
|
|||
vunion.setLRS(lrs);
|
||||
vunion.select(new Union.Selector() {
|
||||
public void select(Select sel, int idx) {
|
||||
if (field.isUnidirectionalOneToManyForeignKey()) {
|
||||
if (field.isUni1ToMFK()) {
|
||||
sel.orderBy(field.getKeyMapping().getColumns(), true, true);
|
||||
sel.select(vals[idx], field.getElementMapping().
|
||||
getSelectSubclasses(), store, fetch, eagerMode, null);
|
||||
|
@ -203,11 +203,10 @@ public class RelationRelationMapTableFieldStrategy
|
|||
FieldMapping mapped = field.getMappedByMapping();
|
||||
DBDictionary dict = field.getMappingRepository().getDBDictionary();
|
||||
DBIdentifier keyName = null;
|
||||
if (field.isUnidirectionalOneToManyForeignKey()
|
||||
|| (!field.isBidirectionalManyToOneJoinTable() && mapped != null)) {
|
||||
if (field.isUni1ToMFK() || (!field.isBiMTo1JT() && mapped != null)) {
|
||||
handleMappedByForeignKey(adapt);
|
||||
keyName = dict.getValidColumnName(DBIdentifier.newColumn("vkey"), field.getTable());
|
||||
} else if (field.isBidirectionalManyToOneJoinTable() || mapped == null) {
|
||||
} else if (field.isBiMTo1JT() || mapped == null) {
|
||||
field.mapJoin(adapt, true);
|
||||
mapTypeJoin(val, DBIdentifier.newColumn("value"), adapt);
|
||||
keyName = dict.getValidColumnName(DBIdentifier.newColumn("key"), field.getTable());
|
||||
|
@ -246,11 +245,11 @@ public class RelationRelationMapTableFieldStrategy
|
|||
if (map == null || map.isEmpty())
|
||||
return;
|
||||
|
||||
if (!field.isBidirectionalManyToOneJoinTable() && field.getMappedBy() != null)
|
||||
if (!field.isBiMTo1JT() && field.getMappedBy() != null)
|
||||
return;
|
||||
|
||||
Row row = null;
|
||||
if (!field.isUnidirectionalOneToManyForeignKey()) {
|
||||
if (!field.isUni1ToMFK()) {
|
||||
row = rm.getSecondaryRow(field.getTable(), Row.ACTION_INSERT);
|
||||
row.setForeignKey(field.getJoinForeignKey(), field.getJoinColumnIO(),
|
||||
sm);
|
||||
|
@ -264,7 +263,7 @@ public class RelationRelationMapTableFieldStrategy
|
|||
entry = (Map.Entry) itr.next();
|
||||
keysm = RelationStrategies.getStateManager(entry.getKey(), ctx);
|
||||
valsm = RelationStrategies.getStateManager(entry.getValue(), ctx);
|
||||
if (field.isUnidirectionalOneToManyForeignKey()){
|
||||
if (field.isUni1ToMFK()){
|
||||
row = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(),
|
||||
Row.ACTION_UPDATE, valsm, true);
|
||||
row.wherePrimaryKey(valsm);
|
||||
|
@ -282,14 +281,14 @@ public class RelationRelationMapTableFieldStrategy
|
|||
// from the view point of the owned side
|
||||
PersistenceCapable obj = sm.getPersistenceCapable();
|
||||
if (!populateKey(row, valsm, obj, ctx, rm, store))
|
||||
if (!field.isUnidirectionalOneToManyForeignKey())
|
||||
if (!field.isUni1ToMFK())
|
||||
rm.flushSecondaryRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
|
||||
throws SQLException {
|
||||
if (field.getMappedBy() != null && !field.isBidirectionalManyToOneJoinTable())
|
||||
if (field.getMappedBy() != null && !field.isBiMTo1JT())
|
||||
return;
|
||||
|
||||
Map map = (Map) sm.fetchObject(field.getIndex());
|
||||
|
@ -320,7 +319,7 @@ public class RelationRelationMapTableFieldStrategy
|
|||
Object mkey;
|
||||
if (canChange && !change.isEmpty()) {
|
||||
Row changeRow = null;
|
||||
if (!field.isUnidirectionalOneToManyForeignKey()) {
|
||||
if (!field.isUni1ToMFK()) {
|
||||
changeRow = rm.getSecondaryRow(field.getTable(),
|
||||
Row.ACTION_UPDATE);
|
||||
changeRow.whereForeignKey(field.getJoinForeignKey(), sm);
|
||||
|
@ -340,7 +339,7 @@ public class RelationRelationMapTableFieldStrategy
|
|||
keysm = RelationStrategies.getStateManager(mkey, ctx);
|
||||
valsm = RelationStrategies.getStateManager(mval, ctx);
|
||||
key.whereForeignKey(changeRow, keysm);
|
||||
if (field.isUnidirectionalOneToManyForeignKey()){
|
||||
if (field.isUni1ToMFK()){
|
||||
changeRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(),
|
||||
Row.ACTION_UPDATE, valsm, true);
|
||||
changeRow.wherePrimaryKey(valsm);
|
||||
|
@ -356,7 +355,7 @@ public class RelationRelationMapTableFieldStrategy
|
|||
Collection rem = ct.getRemoved();
|
||||
if (!rem.isEmpty() || (!canChange && !change.isEmpty())) {
|
||||
Row delRow = null;
|
||||
if (!field.isUnidirectionalOneToManyForeignKey()) {
|
||||
if (!field.isUni1ToMFK()) {
|
||||
delRow = rm.getSecondaryRow(field.getTable(),
|
||||
Row.ACTION_DELETE);
|
||||
delRow.whereForeignKey(field.getJoinForeignKey(), sm);
|
||||
|
@ -364,7 +363,7 @@ public class RelationRelationMapTableFieldStrategy
|
|||
|
||||
for (Iterator itr = rem.iterator(); itr.hasNext();) {
|
||||
Object pc = itr.next();
|
||||
if (field.isUnidirectionalOneToManyForeignKey()){
|
||||
if (field.isUni1ToMFK()){
|
||||
updateSetNull(sm, rm, pc);
|
||||
} else {
|
||||
keysm = RelationStrategies.getStateManager(pc, ctx);
|
||||
|
@ -375,7 +374,7 @@ public class RelationRelationMapTableFieldStrategy
|
|||
if (!canChange && !change.isEmpty()) {
|
||||
for (Iterator itr = change.iterator(); itr.hasNext();) {
|
||||
Object pc = itr.next();
|
||||
if (field.isUnidirectionalOneToManyForeignKey()){
|
||||
if (field.isUni1ToMFK()){
|
||||
updateSetNull(sm, rm, pc);
|
||||
} else {
|
||||
keysm = RelationStrategies.getStateManager(pc, ctx);
|
||||
|
@ -390,7 +389,7 @@ public class RelationRelationMapTableFieldStrategy
|
|||
Collection add = ct.getAdded();
|
||||
if (!add.isEmpty() || (!canChange && !change.isEmpty())) {
|
||||
Row addRow = null;
|
||||
if (!field.isUnidirectionalOneToManyForeignKey()) {
|
||||
if (!field.isUni1ToMFK()) {
|
||||
addRow = rm.getSecondaryRow(field.getTable(),
|
||||
Row.ACTION_INSERT);
|
||||
addRow.setForeignKey(field.getJoinForeignKey(),
|
||||
|
@ -410,7 +409,7 @@ public class RelationRelationMapTableFieldStrategy
|
|||
continue;
|
||||
keysm = RelationStrategies.getStateManager(mkey, ctx);
|
||||
valsm = RelationStrategies.getStateManager(mval, ctx);
|
||||
if (field.isUnidirectionalOneToManyForeignKey()){
|
||||
if (field.isUni1ToMFK()){
|
||||
addRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(),
|
||||
Row.ACTION_UPDATE, valsm, true);
|
||||
addRow.wherePrimaryKey(valsm);
|
||||
|
@ -437,7 +436,7 @@ public class RelationRelationMapTableFieldStrategy
|
|||
continue;
|
||||
keysm = RelationStrategies.getStateManager(mkey, ctx);
|
||||
valsm = RelationStrategies.getStateManager(mval, ctx);
|
||||
if (field.isUnidirectionalOneToManyForeignKey()){
|
||||
if (field.isUni1ToMFK()){
|
||||
addRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(),
|
||||
Row.ACTION_UPDATE, valsm, true);
|
||||
addRow.wherePrimaryKey(valsm);
|
||||
|
@ -504,7 +503,7 @@ public class RelationRelationMapTableFieldStrategy
|
|||
|
||||
public void delete(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
|
||||
throws SQLException {
|
||||
if (field.isUnidirectionalOneToManyForeignKey()) {
|
||||
if (field.isUni1ToMFK()) {
|
||||
Map mapObj = (Map)sm.fetchObject(field.getIndex());
|
||||
updateSetNull(sm, store, rm, mapObj.keySet());
|
||||
return;
|
||||
|
|
|
@ -113,7 +113,7 @@ public abstract class RelationToManyTableFieldStrategy
|
|||
// Bi-directional oneToMany relation with join table strategy
|
||||
// ==> should not mapped in the owner's table
|
||||
if (mapped != null) {
|
||||
if (!field.isBidirectionalManyToOneJoinTable()) {
|
||||
if (!field.isBiMTo1JT()) {
|
||||
if (mapped.getElement().getTypeCode() != JavaTypes.PC) {
|
||||
throw new MetaDataException(_loc.get("not-inv-relation-coll",
|
||||
field, mapped));
|
||||
|
@ -134,9 +134,9 @@ public abstract class RelationToManyTableFieldStrategy
|
|||
}
|
||||
}
|
||||
|
||||
if (mapped == null || field.isBidirectionalManyToOneJoinTable()) {
|
||||
if (field.isBidirectionalManyToOneJoinTable())
|
||||
field.setBidirectionalOneToManyJoinTableInfo();
|
||||
if (mapped == null || field.isBiMTo1JT()) {
|
||||
if (field.isBiMTo1JT())
|
||||
field.setBi1MJoinTableInfo();
|
||||
field.mapJoin(adapt, true);
|
||||
if (elem.getTypeMapping().isMapped()) {
|
||||
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)
|
||||
throws SQLException {
|
||||
if (field.getMappedBy() == null || field.isBidirectionalManyToOneJoinTable())
|
||||
if (field.getMappedBy() == null || field.isBiMTo1JT())
|
||||
insert(sm, rm, sm.fetchObject(field.getIndex()));
|
||||
}
|
||||
|
||||
|
@ -188,7 +188,7 @@ public abstract class RelationToManyTableFieldStrategy
|
|||
|
||||
public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
|
||||
throws SQLException {
|
||||
if (field.getMappedBy() != null && !field.isBidirectionalManyToOneJoinTable())
|
||||
if (field.getMappedBy() != null && !field.isBiMTo1JT())
|
||||
return;
|
||||
|
||||
Object obj = sm.fetchObject(field.getIndex());
|
||||
|
|
|
@ -26,7 +26,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
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.JDBCStore;
|
||||
import org.apache.openjpa.jdbc.meta.ClassMapping;
|
||||
|
@ -43,7 +42,7 @@ import org.apache.openjpa.jdbc.sql.SelectExecutor;
|
|||
import org.apache.openjpa.jdbc.sql.Union;
|
||||
import org.apache.openjpa.kernel.OpenJPAStateManager;
|
||||
import org.apache.openjpa.kernel.StateManagerImpl;
|
||||
import org.apache.openjpa.lib.util.ThreadGate;
|
||||
import org.apache.openjpa.lib.util.Localizer;
|
||||
import org.apache.openjpa.meta.ClassMetaData;
|
||||
import org.apache.openjpa.meta.JavaTypes;
|
||||
import org.apache.openjpa.util.ChangeTracker;
|
||||
|
@ -58,20 +57,12 @@ import org.apache.openjpa.util.Proxy;
|
|||
* insert/update/delete behavior as well as overriding
|
||||
* {@link FieldStrategy#toDataStoreValue}, {@link FieldStrategy#join}, and
|
||||
* {@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 Pinaki Poddar (select caching)
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class StoreCollectionFieldStrategy
|
||||
extends ContainerFieldStrategy {
|
||||
protected SelectExecutor _executor;
|
||||
protected ThreadGate _lock = new ThreadGate();
|
||||
|
||||
|
||||
/**
|
||||
* Return the foreign key used to join to the owning field for the given
|
||||
* element mapping from {@link #getIndependentElementMappings} (or null).
|
||||
|
@ -103,7 +94,8 @@ public abstract class StoreCollectionFieldStrategy
|
|||
*
|
||||
* @see FieldMapping#joinRelation
|
||||
*/
|
||||
protected abstract Joins joinElementRelation(Joins joins, ClassMapping elem);
|
||||
protected abstract Joins joinElementRelation(Joins joins,
|
||||
ClassMapping elem);
|
||||
|
||||
/**
|
||||
* Join to the owning field table for the given element mapping from
|
||||
|
@ -120,9 +112,9 @@ public abstract class StoreCollectionFieldStrategy
|
|||
* Convert the field value to a collection. Handles collections and
|
||||
* arrays by default.
|
||||
*/
|
||||
protected Collection<?> toCollection(Object val) {
|
||||
protected Collection toCollection(Object val) {
|
||||
if (field.getTypeCode() == JavaTypes.COLLECTION)
|
||||
return (Collection<?>) val;
|
||||
return (Collection) val;
|
||||
return JavaTypes.toList(val, field.getElement().getType(), false);
|
||||
}
|
||||
|
||||
|
@ -166,9 +158,8 @@ public abstract class StoreCollectionFieldStrategy
|
|||
else {
|
||||
final ClassMapping[] elems = getIndependentElementMappings(true);
|
||||
Union union = (Union) sel;
|
||||
if (union.isReadOnly())
|
||||
if (fetch.getSubclassFetchMode(field.getElementMapping().
|
||||
getTypeMapping()) != JDBCFetchConfiguration.EAGER_JOIN)
|
||||
getTypeMapping()) != fetch.EAGER_JOIN)
|
||||
union.abortUnion();
|
||||
union.select(new Union.Selector() {
|
||||
public void select(Select sel, int idx) {
|
||||
|
@ -184,13 +175,13 @@ public abstract class StoreCollectionFieldStrategy
|
|||
// we limit further eager fetches to joins, because after this point
|
||||
// the select has been modified such that parallel clones may produce
|
||||
// invalid sql
|
||||
if (sel.isReadOnly()) return;
|
||||
boolean outer = field.getNullValue() != FieldMapping.NULL_EXCEPTION;
|
||||
// force inner join for inner join fetch
|
||||
if (fetch.hasFetchInnerJoin(field.getFullName(false)))
|
||||
outer = false;
|
||||
selectEager(sel, getDefaultElementMapping(true), sm, store, fetch,
|
||||
JDBCFetchConfiguration.EAGER_JOIN, false, outer);
|
||||
JDBCFetchConfiguration.EAGER_JOIN, false,
|
||||
outer);
|
||||
}
|
||||
|
||||
public boolean isEagerSelectToMany() {
|
||||
|
@ -203,8 +194,7 @@ public abstract class StoreCollectionFieldStrategy
|
|||
private void selectEager(Select sel, ClassMapping elem,
|
||||
OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch,
|
||||
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 dups, but
|
||||
// if this is a parallel select don't make distinct based on the
|
||||
// eager joins alone if the original wasn't distinct
|
||||
if (eagerMode == JDBCFetchConfiguration.EAGER_PARALLEL) {
|
||||
|
@ -224,7 +214,8 @@ public abstract class StoreCollectionFieldStrategy
|
|||
joins = join(joins, elem);
|
||||
|
||||
// order, ref cols
|
||||
if (field.getOrderColumn() != null || field.getOrders().length > 0 || !selectOid) {
|
||||
if (field.getOrderColumn() != null || field.getOrders().length > 0
|
||||
|| !selectOid) {
|
||||
if (outer)
|
||||
joins = sel.outer(joins);
|
||||
if (!selectOid) {
|
||||
|
@ -362,17 +353,21 @@ public abstract class StoreCollectionFieldStrategy
|
|||
mappedByValue = owner.getPersistenceCapable();
|
||||
res.setMappedByFieldMapping(mappedByFieldMapping);
|
||||
res.setMappedByValue(mappedByValue);
|
||||
} else if (coll instanceof Collection && !((Collection) coll).isEmpty()) {
|
||||
} else if (coll instanceof Collection &&
|
||||
((Collection) coll).size() > 0) {
|
||||
// Customer (1) <--> Orders(n)
|
||||
// coll contains the values of the toMany field (Orders)
|
||||
// get the StateManager of this toMany value
|
||||
// and find the value of the inverse mappedBy field (Customer)
|
||||
// for this toMacdny field
|
||||
PersistenceCapable pc = (PersistenceCapable)((Collection) coll).iterator().next();
|
||||
OpenJPAStateManager sm1 = (OpenJPAStateManager) pc.pcGetStateManager();
|
||||
PersistenceCapable pc = (PersistenceCapable)
|
||||
((Collection) coll).iterator().next();
|
||||
OpenJPAStateManager sm1 = (OpenJPAStateManager) pc.
|
||||
pcGetStateManager();
|
||||
|
||||
ClassMapping clm = ((ClassMapping) sm1.getMetaData());
|
||||
FieldMapping fm = (FieldMapping) clm.getField(mappedByFieldMapping.getName());
|
||||
FieldMapping fm = (FieldMapping) clm.getField(
|
||||
mappedByFieldMapping.getName());
|
||||
if (fm == mappedByFieldMapping)
|
||||
res.setMappedByValue(sm1.fetchObject(fm.getIndex()));
|
||||
} else {
|
||||
|
@ -518,7 +513,8 @@ public abstract class StoreCollectionFieldStrategy
|
|||
Result res = sel.execute(store, fetch);
|
||||
try {
|
||||
res.next();
|
||||
coll.getChangeTracker().setNextSequence(res.getInt(field) + 1);
|
||||
coll.getChangeTracker().setNextSequence
|
||||
(res.getInt(field) + 1);
|
||||
} finally {
|
||||
res.close();
|
||||
}
|
||||
|
@ -526,87 +522,72 @@ public abstract class StoreCollectionFieldStrategy
|
|||
sm.storeObjectField(field.getIndex(), coll);
|
||||
return;
|
||||
}
|
||||
// select data for this state manager
|
||||
// Select can be configured for reuse. The locking mechanics ensures that
|
||||
// under reuse scenario, the Select structure is built under a thread gate
|
||||
// but later usage is unguarded because a reused select is (almost) immutable.
|
||||
try {
|
||||
_lock.lock();
|
||||
final ClassMapping[] elems = getIndependentElementMappings(true);
|
||||
final Joins[] resJoins = new Joins[Math.max(1, elems.length)];
|
||||
Union union;
|
||||
if (_executor == null) {
|
||||
union = store.getSQLFactory().newUnion(Math.max(1, elems.length));
|
||||
if (store.getConfiguration().getSelectCacheEnabled()) {
|
||||
_executor = union;
|
||||
}
|
||||
} else {
|
||||
union = (Union)_executor;
|
||||
}
|
||||
union.select(new Union.Selector() {
|
||||
public void select(Select sel, int idx) {
|
||||
ClassMapping elem = (elems.length == 0) ? null : elems[idx];
|
||||
resJoins[idx] = selectAll(sel, elem, sm, store, fetch, JDBCFetchConfiguration.EAGER_PARALLEL);
|
||||
}
|
||||
});
|
||||
|
||||
// create proxy
|
||||
Object coll;
|
||||
ChangeTracker ct = null;
|
||||
if (field.getTypeCode() == JavaTypes.ARRAY)
|
||||
coll = new ArrayList();
|
||||
else {
|
||||
coll = sm.newProxy(field.getIndex());
|
||||
if (coll instanceof Proxy)
|
||||
ct = ((Proxy) coll).getChangeTracker();
|
||||
}
|
||||
|
||||
// load values
|
||||
Result res = union.execute(store, fetch);
|
||||
try {
|
||||
int seq = -1;
|
||||
boolean ordered = ct != null && field.getOrderColumn() != null;
|
||||
while (res.next()) {
|
||||
if (ordered) seq = res.getInt(field.getOrderColumn());
|
||||
setMappedBy(sm.getObjectId(), sm, coll, res);
|
||||
add(store, coll, loadElement(sm, store, fetch, res, resJoins[res.indexOf()]));
|
||||
}
|
||||
if (ordered) ct.setNextSequence(seq + 1);
|
||||
} finally {
|
||||
res.close();
|
||||
}
|
||||
|
||||
// set into sm
|
||||
if (field.getTypeCode() == JavaTypes.ARRAY) {
|
||||
sm.storeObject(field.getIndex(),
|
||||
JavaTypes.toArray((Collection<?>) coll, field.getElement().getType()));
|
||||
} else {
|
||||
sm.storeObject(field.getIndex(), coll);
|
||||
}
|
||||
} finally {
|
||||
_lock.unlock();
|
||||
|
||||
// select data for this sm
|
||||
final ClassMapping[] elems = getIndependentElementMappings(true);
|
||||
final Joins[] resJoins = new Joins[Math.max(1, elems.length)];
|
||||
Union union = store.getSQLFactory().newUnion
|
||||
(Math.max(1, elems.length));
|
||||
union.select(new Union.Selector() {
|
||||
public void select(Select sel, int idx) {
|
||||
ClassMapping elem = (elems.length == 0) ? null : elems[idx];
|
||||
resJoins[idx] = selectAll(sel, elem, sm, store, fetch,
|
||||
JDBCFetchConfiguration.EAGER_PARALLEL);
|
||||
}
|
||||
});
|
||||
|
||||
// create proxy
|
||||
Object coll;
|
||||
ChangeTracker ct = null;
|
||||
if (field.getTypeCode() == JavaTypes.ARRAY)
|
||||
coll = new ArrayList();
|
||||
else {
|
||||
coll = sm.newProxy(field.getIndex());
|
||||
if (coll instanceof Proxy)
|
||||
ct = ((Proxy) coll).getChangeTracker();
|
||||
}
|
||||
|
||||
// load values
|
||||
Result res = union.execute(store, fetch);
|
||||
try {
|
||||
int seq = -1;
|
||||
while (res.next()) {
|
||||
if (ct != null && field.getOrderColumn() != null)
|
||||
seq = res.getInt(field.getOrderColumn());
|
||||
setMappedBy(sm.getObjectId(), sm, coll, res);
|
||||
add(store, coll, loadElement(sm, store, fetch, res,
|
||||
resJoins[res.indexOf()]));
|
||||
}
|
||||
if (ct != null && field.getOrderColumn() != null)
|
||||
ct.setNextSequence(seq + 1);
|
||||
} finally {
|
||||
res.close();
|
||||
}
|
||||
|
||||
// set into sm
|
||||
if (field.getTypeCode() == JavaTypes.ARRAY)
|
||||
sm.storeObject(field.getIndex(), JavaTypes.toArray
|
||||
((Collection) coll, field.getElement().getType()));
|
||||
else
|
||||
sm.storeObject(field.getIndex(), coll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects data for loading, starting in field table.
|
||||
*
|
||||
* Select data for loading, starting in field table.
|
||||
*/
|
||||
protected Joins selectAll(Select sel, ClassMapping elem,
|
||||
OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) {
|
||||
OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch,
|
||||
int eagerMode) {
|
||||
ForeignKey fk = getJoinForeignKey(elem);
|
||||
Object oid = getObjectIdForJoin(fk, sm);
|
||||
sel.whereForeignKey(fk, oid, field.getDefiningMapping(), store);
|
||||
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 joins = joinElementRelation(sel.newJoins(), elem);
|
||||
field.orderRelation(sel, elem, joins);
|
||||
selectElement(sel, elem, store, fetch, eagerMode, joins);
|
||||
|
||||
return joins;
|
||||
}
|
||||
|
||||
|
@ -643,9 +624,4 @@ public abstract class StoreCollectionFieldStrategy
|
|||
}
|
||||
return oid;
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + '[' + field.getName() + ']';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ public abstract class AbstractResult
|
|||
|
||||
private static final Joins JOINS = new NoOpJoins();
|
||||
|
||||
private Map<Object,Object> _eager = null;
|
||||
private Map _eager = null;
|
||||
private ClassMapping _base = null;
|
||||
private int _index = 0;
|
||||
private boolean _gotEager = false;
|
||||
|
@ -86,14 +86,14 @@ public abstract class AbstractResult
|
|||
private Object _mappedByValue = null;
|
||||
|
||||
public Object getEager(FieldMapping key) {
|
||||
Map<Object,Object> map = getEagerMap(true);
|
||||
Map map = getEagerMap(true);
|
||||
return (map == null) ? null : map.get(key);
|
||||
}
|
||||
|
||||
public void putEager(FieldMapping key, Object res) {
|
||||
Map<Object,Object> map = getEagerMap(false);
|
||||
Map map = getEagerMap(false);
|
||||
if (map == null) {
|
||||
map = new HashMap<Object,Object>();
|
||||
map = new HashMap();
|
||||
setEagerMap(map);
|
||||
}
|
||||
map.put(key, res);
|
||||
|
@ -104,7 +104,7 @@ public abstract class AbstractResult
|
|||
*
|
||||
* @param client whether the client is accessing eager information
|
||||
*/
|
||||
protected Map<Object,Object> getEagerMap(boolean client) {
|
||||
protected Map getEagerMap(boolean client) {
|
||||
if (client)
|
||||
_gotEager = true;
|
||||
return _eager;
|
||||
|
@ -113,7 +113,7 @@ public abstract class AbstractResult
|
|||
/**
|
||||
* Raw eager information.
|
||||
*/
|
||||
protected void setEagerMap(Map<Object,Object> eager) {
|
||||
protected void setEagerMap(Map eager) {
|
||||
_eager = eager;
|
||||
}
|
||||
|
||||
|
@ -129,9 +129,11 @@ public abstract class AbstractResult
|
|||
/**
|
||||
* Close all results in eager map.
|
||||
*/
|
||||
protected void closeEagerMap(Map<Object,Object> eager) {
|
||||
protected void closeEagerMap(Map eager) {
|
||||
if (eager != null) {
|
||||
for (Object res : eager.values()) {
|
||||
Object res;
|
||||
for (Iterator itr = eager.values().iterator(); itr.hasNext();) {
|
||||
res = itr.next();
|
||||
if (res != this && res instanceof Closeable)
|
||||
try {
|
||||
((Closeable) res).close();
|
||||
|
@ -889,6 +891,9 @@ public abstract class AbstractResult
|
|||
return this;
|
||||
}
|
||||
|
||||
public void appendTo(SQLBuffer buf) {
|
||||
}
|
||||
|
||||
public Joins setCorrelatedVariable(String var) {
|
||||
return this;
|
||||
}
|
||||
|
@ -899,10 +904,5 @@ public abstract class AbstractResult
|
|||
|
||||
public void moveJoinsToParent() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilder path() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,112 +0,0 @@
|
|||
/*
|
||||
* 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.jdbc.sql;
|
||||
|
||||
import org.apache.openjpa.jdbc.schema.Column;
|
||||
import org.apache.openjpa.lib.util.FlexibleThreadLocal;
|
||||
|
||||
|
||||
/**
|
||||
* A binding parameter in a SQL statement.
|
||||
* <br>
|
||||
* A binding parameter is used in <tt>WHERE</tt> clause. The parameter is identified by an
|
||||
* immutable key and has a value. The value of a parameter is bound to a thread and hence
|
||||
* different thread may see different value. These parameters are associated with a {@link Select}
|
||||
* and they are the only mutable components of an otherwise {@link SelectExecutor#isReadOnly() immutable}
|
||||
* select.
|
||||
* <br><b>NOTE:</b>
|
||||
* The primary assumption of usage is that the binding parameter values to a cached select and
|
||||
* executing it are carried out in the same (or <em>equivalent</em>) thread.
|
||||
* <br>
|
||||
* The parameter is further qualified by whether it is user specified (e.g. from a query parameter)
|
||||
* or internally generated (e.g. a discriminator value for inheritance join). A database column can
|
||||
* also be optionally associated with a binding parameter. Currently {@link SQLBuffer#bind(Object, Column)
|
||||
* rebinding} a parameter to a value is only possible if the parameter is associated with a column.
|
||||
*
|
||||
* @see SQLBuffer#appendValue(Object, Column, org.apache.openjpa.kernel.exps.Parameter)
|
||||
* @see SQLBuffer#bind(Object, Column)
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public class BindParameter {
|
||||
// Is this parameter specified by user or our own runtime
|
||||
private final boolean _user;
|
||||
// the column
|
||||
private final Column _column;
|
||||
// key of this parameter
|
||||
private final Object _key;
|
||||
private FlexibleThreadLocal _values = new FlexibleThreadLocal();
|
||||
|
||||
/**
|
||||
* Constructs a parameter with given key, column and user flag.
|
||||
*
|
||||
* @param key the identifier. Can be null only if not a user-defined parameter.
|
||||
* @param user flags if this key is originally specified by the user.
|
||||
* @param column a column represented by this parameter. Can be null.
|
||||
*/
|
||||
public BindParameter(Object key, boolean user, Column column, Object value) {
|
||||
super();
|
||||
if (user && key == null)
|
||||
throw new IllegalArgumentException("User-defined parameter can not have null key");
|
||||
_key = key;
|
||||
_user = user;
|
||||
_column = column;
|
||||
_values.set(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value bound to this parameter for the calling thread. Can be null.
|
||||
*
|
||||
* @exception if the current thread or its equivalent never bound a value
|
||||
* to this parameter.
|
||||
*/
|
||||
public Object getValue() {
|
||||
return _values.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the given value to this parameter. Can be null.
|
||||
*/
|
||||
public void setValue(Object value) {
|
||||
_values.set(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Affirms if this parameter is specified by the user.
|
||||
*/
|
||||
public boolean isUser() {
|
||||
return _user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the column associated with this parameter, if any.
|
||||
*/
|
||||
public Column getColumn() {
|
||||
return _column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the key associated with this parameter.
|
||||
* The user-defined parameter must have a non-null key.
|
||||
*/
|
||||
public Object getKey() {
|
||||
return _key;
|
||||
}
|
||||
}
|
|
@ -1399,9 +1399,6 @@ public class DBDictionary
|
|||
} else if (val instanceof Calendard) {
|
||||
cald = (Calendard) val;
|
||||
val = cald.value;
|
||||
} else if (val instanceof BindParameter) {
|
||||
BindParameter bParm = (BindParameter) val;
|
||||
val = bParm.getValue();
|
||||
}
|
||||
|
||||
if (val == null)
|
||||
|
@ -1894,8 +1891,7 @@ public class DBDictionary
|
|||
public SQLBuffer toSelectCount(Select sel) {
|
||||
SQLBuffer selectSQL = new SQLBuffer(this);
|
||||
SQLBuffer from;
|
||||
if (!sel.isReadOnly())
|
||||
sel.addJoinClassConditions();
|
||||
sel.addJoinClassConditions();
|
||||
if (sel.getFromSelect() != null)
|
||||
from = getFromSelect(sel, false);
|
||||
else
|
||||
|
@ -2287,7 +2283,7 @@ public class DBDictionary
|
|||
if (join.isCorrelated() && join.getForeignKey() != null) {
|
||||
SQLBuffer where = new SQLBuffer(this);
|
||||
where.append("(").append(toTraditionalJoin(join)).append(")");
|
||||
sel.where(where);
|
||||
sel.where(where.getSQL());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2347,7 +2343,7 @@ public class DBDictionary
|
|||
if (join.getForeignKey() != null){
|
||||
SQLBuffer where = new SQLBuffer(this);
|
||||
where.append("(").append(toTraditionalJoin(join)).append(")");
|
||||
sel.where(where);
|
||||
sel.where(where.getSQL());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -2497,7 +2493,7 @@ public class DBDictionary
|
|||
if (join.getForeignKey() != null){
|
||||
SQLBuffer where = new SQLBuffer(this);
|
||||
where.append("(").append(toTraditionalJoin(join)).append(")");
|
||||
sel.where(where);
|
||||
sel.where(where.getSQL());
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -39,9 +39,9 @@ class JoinSet {
|
|||
// efficient representation with O(1) lookup, add, remove operations for
|
||||
// typical sets of joins, and it means we'd have to create a graph anyway
|
||||
// when joinIterator() is called
|
||||
private final List<Node> _graph = new ArrayList<Node>();
|
||||
private final List _graph = new ArrayList();
|
||||
private int _size = 0;
|
||||
private List<Join> _sorted = null;
|
||||
private List _sorted = null;
|
||||
|
||||
public JoinSet() {
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ class JoinSet {
|
|||
if (copy._graph.get(i) == null)
|
||||
_graph.add(null);
|
||||
else
|
||||
_graph.add((Node) copy._graph.get(i).clone());
|
||||
_graph.add(((Node) copy._graph.get(i)).clone());
|
||||
}
|
||||
_size = copy._size;
|
||||
_sorted = copy._sorted;
|
||||
|
@ -95,22 +95,23 @@ class JoinSet {
|
|||
/**
|
||||
* Iterator over joins that prepares them for SQL translation.
|
||||
*/
|
||||
public Iterator<Join> joinIterator() {
|
||||
public Iterator joinIterator() {
|
||||
if (_size < 2)
|
||||
return iterator();
|
||||
if (_sorted != null)
|
||||
return _sorted.iterator();
|
||||
|
||||
List<Join> sorted = new ArrayList<Join>(_size);
|
||||
LinkedList<Node> queue = new LinkedList<Node>();
|
||||
BitSet seen = new BitSet(_graph.size() * _graph.size() + _graph.size());
|
||||
List sorted = new ArrayList(_size);
|
||||
LinkedList queue = new LinkedList();
|
||||
BitSet seen = new BitSet(_graph.size() * _graph.size()
|
||||
+ _graph.size());
|
||||
|
||||
// traverse graph
|
||||
Node n;
|
||||
int idx, sidx;
|
||||
for (int i = 0; i < _graph.size(); i++) {
|
||||
// seed queue with next set of disconnected joins
|
||||
for (n = _graph.get(i); n != null; n = n.next) {
|
||||
for (n = (Node) _graph.get(i); n != null; n = n.next) {
|
||||
sidx = getSeenIndex(n.join);
|
||||
if (!seen.get(sidx)) {
|
||||
seen.set(sidx);
|
||||
|
@ -182,8 +183,8 @@ class JoinSet {
|
|||
return false;
|
||||
|
||||
boolean added = false;
|
||||
for (Iterator<Join> itr = js.iterator(); itr.hasNext();)
|
||||
added = add(itr.next()) || added;
|
||||
for (Iterator itr = js.iterator(); itr.hasNext();)
|
||||
added = add((Join) itr.next()) || added;
|
||||
return added;
|
||||
}
|
||||
|
||||
|
@ -217,8 +218,8 @@ class JoinSet {
|
|||
_size++;
|
||||
}
|
||||
|
||||
public Iterator<Join> iterator() {
|
||||
return new Iterator<Join>() {
|
||||
public Iterator iterator() {
|
||||
return new Iterator() {
|
||||
private Node _next = null;
|
||||
private int _idx = -1;
|
||||
|
||||
|
@ -236,7 +237,7 @@ class JoinSet {
|
|||
return false;
|
||||
}
|
||||
|
||||
public Join next() {
|
||||
public Object next() {
|
||||
if (!hasNext())
|
||||
throw new NoSuchElementException();
|
||||
Join j = _next.join;
|
||||
|
@ -288,16 +289,16 @@ class JoinSet {
|
|||
|
||||
public boolean removeAll(JoinSet js) {
|
||||
boolean remd = false;
|
||||
for (Iterator<Join> itr = js.iterator(); itr.hasNext();)
|
||||
remd = remove(itr.next()) || remd;
|
||||
for (Iterator itr = js.iterator(); itr.hasNext();)
|
||||
remd = remove((Join) itr.next()) || remd;
|
||||
return remd;
|
||||
}
|
||||
|
||||
public boolean retainAll(JoinSet js) {
|
||||
boolean remd = false;
|
||||
Join join;
|
||||
for (Iterator<Join> itr = iterator(); itr.hasNext();) {
|
||||
join = itr.next();
|
||||
for (Iterator itr = iterator(); itr.hasNext();) {
|
||||
join = (Join) itr.next();
|
||||
if (!js.contains(join))
|
||||
remd = remove(join);
|
||||
}
|
||||
|
@ -317,8 +318,8 @@ class JoinSet {
|
|||
public boolean containsAll(JoinSet js) {
|
||||
if (js._size > _size || js._graph.size() > _graph.size())
|
||||
return false;
|
||||
for (Iterator<Join> itr = js.iterator(); itr.hasNext();)
|
||||
if (!contains(itr.next()))
|
||||
for (Iterator itr = js.iterator(); itr.hasNext();)
|
||||
if (!contains((Join) itr.next()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -346,7 +347,7 @@ class JoinSet {
|
|||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("[");
|
||||
for (Iterator<Join> itr = iterator(); itr.hasNext();) {
|
||||
for (Iterator itr = iterator(); itr.hasNext();) {
|
||||
buf.append("<").append(itr.next()).append(">");
|
||||
if (itr.hasNext())
|
||||
buf.append(", ");
|
||||
|
|
|
@ -102,10 +102,4 @@ public interface Joins {
|
|||
* Move joins that belong to subquery's parent
|
||||
*/
|
||||
public void moveJoinsToParent();
|
||||
|
||||
/**
|
||||
* Gets the current path as a mutable string.
|
||||
* @return
|
||||
*/
|
||||
public StringBuilder path();
|
||||
}
|
||||
|
|
|
@ -112,15 +112,6 @@ public class LogicalUnion
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
for (int i = 0; i < sels.length; i++) {
|
||||
if (sels[i].isReadOnly())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void abortUnion() {
|
||||
}
|
||||
|
||||
|
@ -244,7 +235,8 @@ public class LogicalUnion
|
|||
if (getExpectedResultCount() == 1) {
|
||||
AbstractResult res;
|
||||
for (int i = 0; i < sels.length; i++) {
|
||||
res = (AbstractResult) sels[i].execute(store, fetch, lockLevel);
|
||||
res = (AbstractResult) sels[i].execute(store, fetch,
|
||||
lockLevel);
|
||||
res.setBaseMapping(mappings[i]);
|
||||
res.setIndexOf(i);
|
||||
|
||||
|
@ -275,7 +267,8 @@ public class LogicalUnion
|
|||
try {
|
||||
List l;
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
res[i] = (AbstractResult) sels[i].execute(store, fetch, lockLevel);
|
||||
res[i] = (AbstractResult) sels[i].execute(store, fetch,
|
||||
lockLevel);
|
||||
res[i].setBaseMapping(mappings[i]);
|
||||
res[i].setIndexOf(i);
|
||||
|
||||
|
@ -775,6 +768,14 @@ public class LogicalUnion
|
|||
sel.where(sql, joins);
|
||||
}
|
||||
|
||||
public void where(String sql) {
|
||||
sel.where(sql);
|
||||
}
|
||||
|
||||
public void where(String sql, Joins joins) {
|
||||
sel.where(sql, joins);
|
||||
}
|
||||
|
||||
public void having(SQLBuffer sql) {
|
||||
sel.having(sql);
|
||||
}
|
||||
|
@ -783,6 +784,14 @@ public class LogicalUnion
|
|||
sel.having(sql, joins);
|
||||
}
|
||||
|
||||
public void having(String sql) {
|
||||
sel.having(sql);
|
||||
}
|
||||
|
||||
public void having(String sql, Joins joins) {
|
||||
sel.having(sql, joins);
|
||||
}
|
||||
|
||||
public void groupBy(SQLBuffer sql) {
|
||||
sel.groupBy(sql);
|
||||
}
|
||||
|
@ -922,10 +931,6 @@ public class LogicalUnion
|
|||
public DBDictionary getDictionary() {
|
||||
return dict;
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return sel.isReadOnly();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1006,5 +1011,4 @@ public class LogicalUnion
|
|||
return a1.length - a2.length;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import java.util.List;
|
|||
import org.apache.commons.lang.ObjectUtils;
|
||||
import org.apache.openjpa.jdbc.identifier.DBIdentifier;
|
||||
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
|
||||
import org.apache.openjpa.jdbc.kernel.exps.CollectionParam;
|
||||
import org.apache.openjpa.jdbc.kernel.exps.Val;
|
||||
import org.apache.openjpa.jdbc.schema.Column;
|
||||
import org.apache.openjpa.jdbc.schema.Sequence;
|
||||
|
@ -52,7 +53,6 @@ import org.apache.openjpa.kernel.exps.Parameter;
|
|||
*
|
||||
* @since 0.2.4
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public final class SQLBuffer
|
||||
implements Serializable, Cloneable {
|
||||
|
||||
|
@ -60,8 +60,14 @@ public final class SQLBuffer
|
|||
|
||||
private final DBDictionary _dict;
|
||||
private final StringBuilder _sql = new StringBuilder();
|
||||
private List<Subselect> _subsels = null;
|
||||
private List<BindParameter> _params = null;
|
||||
private List _subsels = null;
|
||||
private List _params = null;
|
||||
private List _cols = null;
|
||||
|
||||
// Even element refers to an index of the _params list
|
||||
// Odd element refers to the user parameter
|
||||
private List _userIndex = null;
|
||||
private List _userParams = null;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
|
@ -86,7 +92,7 @@ public final class SQLBuffer
|
|||
}
|
||||
|
||||
/**
|
||||
* Return true if the buffer is empty.
|
||||
* Return true if the buffer is emtpy.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return _sql.length() == 0;
|
||||
|
@ -96,42 +102,87 @@ public final class SQLBuffer
|
|||
* Append all SQL and parameters of the given buffer.
|
||||
*/
|
||||
public SQLBuffer append(SQLBuffer buf) {
|
||||
append(buf, _sql.length(), (_params == null) ? 0 : _params.size(), true);
|
||||
append(buf, _sql.length(), (_params == null) ? 0 : _params.size(),
|
||||
true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append all SQL and parameters of the given buffer at the given positions.
|
||||
*/
|
||||
private void append(SQLBuffer buf, int sqlIndex, int paramIndex, boolean subsels) {
|
||||
private void append(SQLBuffer buf, int sqlIndex, int paramIndex,
|
||||
boolean subsels) {
|
||||
if (subsels) {
|
||||
// only allow appending of buffers with subselects, not insertion
|
||||
if (_subsels != null && !_subsels.isEmpty() && sqlIndex != _sql.length())
|
||||
if (_subsels != null && !_subsels.isEmpty()
|
||||
&& sqlIndex != _sql.length())
|
||||
throw new IllegalStateException();
|
||||
if (buf._subsels != null && !buf._subsels.isEmpty()) {
|
||||
if (sqlIndex != _sql.length())
|
||||
throw new IllegalStateException();
|
||||
if (_subsels == null)
|
||||
_subsels = new ArrayList<Subselect>(buf._subsels.size());
|
||||
_subsels = new ArrayList(buf._subsels.size());
|
||||
for (int i = 0; i < buf._subsels.size(); i++)
|
||||
_subsels.add((buf._subsels.get(i)).clone(sqlIndex, paramIndex));
|
||||
_subsels.add(((Subselect) buf._subsels.get(i)).
|
||||
clone(sqlIndex, paramIndex));
|
||||
}
|
||||
}
|
||||
|
||||
if (sqlIndex == _sql.length()) {
|
||||
if (sqlIndex == _sql.length())
|
||||
_sql.append(buf._sql.toString());
|
||||
} else {
|
||||
else
|
||||
_sql.insert(sqlIndex, buf._sql.toString());
|
||||
}
|
||||
|
||||
|
||||
if (buf._params != null) {
|
||||
if (_params == null)
|
||||
_params = new ArrayList<BindParameter>();
|
||||
_params = new ArrayList();
|
||||
if (_cols == null && buf._cols != null) {
|
||||
_cols = new ArrayList();
|
||||
while (_cols.size() < _params.size())
|
||||
_cols.add(null);
|
||||
}
|
||||
|
||||
if (paramIndex == _params.size()) {
|
||||
_params.addAll(buf._params);
|
||||
if (buf._userParams != null) {
|
||||
if (_userParams == null)
|
||||
_userParams = new ArrayList();
|
||||
_userParams.addAll(paramIndex, buf._userParams);
|
||||
}
|
||||
if (buf._userIndex != null) {
|
||||
if (_userIndex == null)
|
||||
_userIndex = new ArrayList();
|
||||
_userIndex.addAll(buf._userIndex);
|
||||
}
|
||||
if (buf._cols != null)
|
||||
_cols.addAll(buf._cols);
|
||||
else if (_cols != null)
|
||||
while (_cols.size() < _params.size())
|
||||
_cols.add(null);
|
||||
} else {
|
||||
_params.addAll(paramIndex, buf._params);
|
||||
if ( buf._userParams != null) {
|
||||
if (_userParams == null)
|
||||
_userParams = new ArrayList();
|
||||
_userParams.addAll(paramIndex, buf._userParams);
|
||||
}
|
||||
if (buf._userIndex != null) {
|
||||
if (_userIndex == null)
|
||||
_userIndex = new ArrayList();
|
||||
_userIndex.addAll(buf._userIndex);
|
||||
}
|
||||
if (buf._cols != null)
|
||||
_cols.addAll(paramIndex, buf._cols);
|
||||
else if (_cols != null)
|
||||
while (_cols.size() < _params.size())
|
||||
_cols.add(paramIndex, null);
|
||||
}
|
||||
}
|
||||
|
||||
if (_userIndex != null) {
|
||||
// fix up user parameter index
|
||||
for (int i = 0; i < _userIndex.size(); i+=2) {
|
||||
_userIndex.set(i, _userParams.indexOf(_userIndex.get(i+1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -190,7 +241,7 @@ public final class SQLBuffer
|
|||
_sql.append(")");
|
||||
|
||||
if (_subsels == null)
|
||||
_subsels = new ArrayList<Subselect>(2);
|
||||
_subsels = new ArrayList(2);
|
||||
_subsels.add(sub);
|
||||
return this;
|
||||
}
|
||||
|
@ -216,7 +267,7 @@ public final class SQLBuffer
|
|||
* Append a parameter value.
|
||||
*/
|
||||
public SQLBuffer appendValue(Object o) {
|
||||
return appendValue(o, null, null);
|
||||
return appendValue(o, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -242,11 +293,34 @@ public final class SQLBuffer
|
|||
else {
|
||||
_sql.append(PARAMETER_TOKEN);
|
||||
|
||||
// initialize param and col lists; we hold off on col list until
|
||||
// we get the first non-null col
|
||||
if (_params == null)
|
||||
_params = new ArrayList<BindParameter>();
|
||||
BindParameter param = new BindParameter(userParam == null ? col : userParam,
|
||||
userParam != null, col, o);
|
||||
_params.add(param);
|
||||
_params = new ArrayList();
|
||||
if (_userParams == null)
|
||||
_userParams = new ArrayList();
|
||||
if (col != null && _cols == null) {
|
||||
_cols = new ArrayList();
|
||||
while (_cols.size() < _params.size())
|
||||
_cols.add(null);
|
||||
}
|
||||
|
||||
_params.add(o);
|
||||
if (userParam != null) {
|
||||
Object param = userParam;
|
||||
if (userParam instanceof CollectionParam)
|
||||
param = ((CollectionParam) userParam).clone();
|
||||
_userParams.add(param);
|
||||
if (_userIndex == null)
|
||||
_userIndex = new ArrayList();
|
||||
int index = _params.size()-1;
|
||||
_userIndex.add(index);
|
||||
_userIndex.add(param);
|
||||
}
|
||||
else
|
||||
_userParams.add(o);
|
||||
if (_cols != null)
|
||||
_cols.add(col);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -254,9 +328,8 @@ public final class SQLBuffer
|
|||
/**
|
||||
* Return the list of parameter values.
|
||||
*/
|
||||
public List<BindParameter> getParameters() {
|
||||
if (_params == null) return Collections.emptyList();
|
||||
return _params;
|
||||
public List getParameters() {
|
||||
return (_params == null) ? Collections.EMPTY_LIST : _params;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -267,33 +340,10 @@ public final class SQLBuffer
|
|||
* This structure is preferred over a normal map because a user parameter
|
||||
* may occur more than one in the parameters.
|
||||
*/
|
||||
public List<Object> getUserParameters() {
|
||||
if (_params == null)
|
||||
return Collections.emptyList();
|
||||
List<Object> userParam = new ArrayList<Object>();
|
||||
for (int i = 0; i < _params.size(); i++) {
|
||||
BindParameter param = _params.get(i);
|
||||
if (param.isUser()) {
|
||||
userParam.add(i);
|
||||
userParam.add(param.getKey());
|
||||
}
|
||||
}
|
||||
return userParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the columns associated with the binding parameters.
|
||||
* All binding parameter may not have an associated column.
|
||||
*/
|
||||
public List<Column> getColumns() {
|
||||
if (_params == null)
|
||||
return Collections.emptyList();
|
||||
List<Column> columns = new ArrayList<Column>();
|
||||
for (BindParameter param : _params) {
|
||||
columns.add(param.getColumn());
|
||||
}
|
||||
return columns;
|
||||
|
||||
public List getUserParameters() {
|
||||
if (_userIndex == null)
|
||||
return Collections.EMPTY_LIST;
|
||||
return _userIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -316,14 +366,14 @@ public final class SQLBuffer
|
|||
return sql;
|
||||
|
||||
StringBuilder buf = new StringBuilder();
|
||||
Iterator<BindParameter> pi = _params.iterator();
|
||||
Iterator pi = _params.iterator();
|
||||
for (int i = 0; i < sql.length(); i++) {
|
||||
if (sql.charAt(i) != '?') {
|
||||
buf.append(sql.charAt(i));
|
||||
continue;
|
||||
}
|
||||
|
||||
Object param = pi.hasNext() ? pi.next().getValue() : null;
|
||||
Object param = pi.hasNext() ? pi.next() : null;
|
||||
if (param == null)
|
||||
buf.append("NULL");
|
||||
else if (param instanceof Number || param instanceof Boolean)
|
||||
|
@ -380,7 +430,7 @@ public final class SQLBuffer
|
|||
}
|
||||
|
||||
/**
|
||||
* Create and populate the parameters of a prepared statement using the
|
||||
* Create and populate the parameters of a prepred statement using the
|
||||
* SQL in this buffer and the given fetch configuration.
|
||||
*/
|
||||
public PreparedStatement prepareStatement(Connection conn,
|
||||
|
@ -488,9 +538,10 @@ public final class SQLBuffer
|
|||
if (_params == null)
|
||||
return;
|
||||
|
||||
Column col;
|
||||
for (int i = 0; i < _params.size(); i++) {
|
||||
BindParameter param = _params.get(i);
|
||||
_dict.setUnknown(ps, i + 1, param.getValue(), param.getColumn());
|
||||
col = (_cols == null) ? null : (Column) _cols.get(i);
|
||||
_dict.setUnknown(ps, i + 1, _params.get(i), col);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -567,42 +618,11 @@ public final class SQLBuffer
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the binding parameters, clearing all existing parameters.
|
||||
*
|
||||
* @param params a non-null list of parameters.
|
||||
*/
|
||||
public void setParameters(List<?> params) {
|
||||
if (params == null) {
|
||||
throw new IllegalArgumentException("Can not set null parameter");
|
||||
}
|
||||
_params = new ArrayList<BindParameter>();
|
||||
int i = 0;
|
||||
for (Object p : params) {
|
||||
BindParameter param = new BindParameter(i, false, null, p);
|
||||
_params.add(param);
|
||||
}
|
||||
public void setParameters(List params) {
|
||||
_params = params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the given value to a parameter representing the given column.
|
||||
* The column must be bound before this call.
|
||||
* @param o a parameter value
|
||||
* @param col a column to which the value is to be bound
|
||||
* @return this same buffer
|
||||
* @exception IllegalArgumentException is no parameter represents the given column
|
||||
*/
|
||||
public SQLBuffer bind(Object o, Column col) {
|
||||
boolean bound = false;
|
||||
for (int i = 0; i < _params.size(); i++) {
|
||||
BindParameter param = _params.get(i);
|
||||
if (param.getColumn() == col) {
|
||||
param.setValue(o);
|
||||
bound = true;
|
||||
}
|
||||
}
|
||||
if (!bound)
|
||||
throw new IllegalArgumentException("Column " + col + " does not exist to bind " + o);
|
||||
return this;
|
||||
public List getColumns() {
|
||||
return _cols;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -546,12 +546,12 @@ public interface Select
|
|||
/**
|
||||
* Add the given where conditions.
|
||||
*/
|
||||
// public void where(String sql);
|
||||
public void where(String sql);
|
||||
|
||||
/**
|
||||
* Add the given where conditions.
|
||||
*/
|
||||
// public void where(String sql, Joins joins);
|
||||
public void where(String sql, Joins joins);
|
||||
|
||||
/**
|
||||
* Add the given having conditions.
|
||||
|
@ -566,12 +566,12 @@ public interface Select
|
|||
/**
|
||||
* Add the given having conditions.
|
||||
*/
|
||||
// public void having(String sql);
|
||||
public void having(String sql);
|
||||
|
||||
/**
|
||||
* Add the given having conditions.
|
||||
*/
|
||||
// public void having(String sql, Joins joins);
|
||||
public void having(String sql, Joins joins);
|
||||
|
||||
/**
|
||||
* Group by the given column.
|
||||
|
@ -606,12 +606,12 @@ public interface Select
|
|||
/**
|
||||
* Add a GROUP BY clause.
|
||||
*/
|
||||
// public void groupBy(String sql);
|
||||
public void groupBy(String sql);
|
||||
|
||||
/**
|
||||
* Add a GROUP BY clause.
|
||||
*/
|
||||
// public void groupBy(String sql, Joins joins);
|
||||
public void groupBy(String sql, Joins joins);
|
||||
|
||||
/**
|
||||
* Group by the columns of the given mapping, possibly including subclasses.
|
||||
|
@ -751,29 +751,22 @@ public interface Select
|
|||
/**
|
||||
* Set joined table metadatas for polymorphic queries
|
||||
*/
|
||||
public void setJoinedTableClassMeta(List<ClassMapping> meta);
|
||||
public void setJoinedTableClassMeta(List meta);
|
||||
|
||||
/**
|
||||
* get joined table metadatas for polymorphic queries
|
||||
*/
|
||||
public List<ClassMapping> getJoinedTableClassMeta();
|
||||
public List getJoinedTableClassMeta();
|
||||
|
||||
/**
|
||||
* Set joined table metadatas excluded for polymorphic queries
|
||||
*/
|
||||
public void setExcludedJoinedTableClassMeta(List<ClassMapping> meta);
|
||||
public void setExcludedJoinedTableClassMeta(List meta);
|
||||
|
||||
/**
|
||||
* get joined table metadatas excluded for polymorphic queries
|
||||
*/
|
||||
public List<ClassMapping> getExcludedJoinedTableClassMeta();
|
||||
public List getExcludedJoinedTableClassMeta();
|
||||
|
||||
/**
|
||||
* Gets the database dictionary used by this select to form the target SQL
|
||||
* statement.
|
||||
*
|
||||
* @return the immutable database dictionary.
|
||||
*/
|
||||
public DBDictionary getDictionary() ;
|
||||
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ import java.sql.SQLException;
|
|||
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
|
||||
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
|
||||
import org.apache.openjpa.jdbc.kernel.JDBCStore;
|
||||
import org.apache.openjpa.jdbc.schema.Column;
|
||||
|
||||
/**
|
||||
* Interface for configuring and executing a SQL select.
|
||||
|
@ -152,19 +151,4 @@ public interface SelectExecutor {
|
|||
* @since 2.0.0
|
||||
*/
|
||||
public boolean hasMultipleSelects();
|
||||
|
||||
/**
|
||||
* Affirms if this select is structurally immutable.
|
||||
* A select becomes immutable upon {@link #execute(JDBCStore, JDBCFetchConfiguration) execution}.
|
||||
* There is no explicit way to turn a select into read-only status.
|
||||
* <br>
|
||||
* The immutable contract does not prevent {@link SQLBuffer#bind(Object, Column) binding}
|
||||
* new values to {@link BindParameter parameters}.
|
||||
*
|
||||
* @return false on construction, true after execution.
|
||||
*
|
||||
* @since 2.2.0
|
||||
*/
|
||||
boolean isReadOnly();
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -271,14 +271,11 @@ public class DelegatingQuery
|
|||
}
|
||||
}
|
||||
|
||||
public void setCandidateType(Class<?> cls, boolean subs) {
|
||||
public void setCandidateType(Class cls, boolean subs) {
|
||||
try {
|
||||
lock();
|
||||
_query.setCandidateType(cls, subs);
|
||||
} catch (RuntimeException re) {
|
||||
throw translate(re);
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -292,12 +289,9 @@ public class DelegatingQuery
|
|||
|
||||
public void setReadOnly(boolean readOnly) {
|
||||
try {
|
||||
lock();
|
||||
_query.setReadOnly(readOnly);
|
||||
} catch (RuntimeException re) {
|
||||
throw translate(re);
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,20 +27,19 @@ import java.util.Comparator;
|
|||
* @author Abe White
|
||||
* @nojavadoc
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class InheritanceComparator
|
||||
implements Comparator, Serializable {
|
||||
|
||||
private Class<?> _base = Object.class;
|
||||
private Class _base = Object.class;
|
||||
|
||||
/**
|
||||
* Set the least-derived type possible; defaults to <code>null</code>.
|
||||
*/
|
||||
public void setBase(Class<?> base) {
|
||||
public void setBase(Class base) {
|
||||
_base = base;
|
||||
}
|
||||
|
||||
public Class<?> getBase() {
|
||||
public Class getBase() {
|
||||
return _base;
|
||||
}
|
||||
|
||||
|
@ -48,8 +47,8 @@ public class InheritanceComparator
|
|||
* Subclasses can override this method to extract the class to compare
|
||||
* on from the elements of the collection.
|
||||
*/
|
||||
protected Class<?> toClass(Object elem) {
|
||||
return (Class<?>) elem;
|
||||
protected Class toClass(Object elem) {
|
||||
return (Class) elem;
|
||||
}
|
||||
|
||||
public int compare(Object o1, Object o2) {
|
||||
|
@ -60,8 +59,8 @@ public class InheritanceComparator
|
|||
if (o2 == null)
|
||||
return 1;
|
||||
|
||||
Class<?> c1 = toClass(o1);
|
||||
Class<?> c2 = toClass(o2);
|
||||
Class c1 = toClass(o1);
|
||||
Class c2 = toClass(o2);
|
||||
if (c1 == c2)
|
||||
return 0;
|
||||
if (c1 == null)
|
||||
|
@ -90,7 +89,7 @@ public class InheritanceComparator
|
|||
/**
|
||||
* 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())
|
||||
return to.getInterfaces().length;
|
||||
for (int i = 0; to != null; i++, to = to.getSuperclass())
|
||||
|
|
|
@ -25,11 +25,10 @@ package org.apache.openjpa.meta;
|
|||
* @author Abe White
|
||||
* @nojavadoc
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class MetaDataInheritanceComparator
|
||||
extends InheritanceComparator {
|
||||
|
||||
protected Class<?> toClass(Object elem) {
|
||||
protected Class toClass(Object elem) {
|
||||
if (elem == null)
|
||||
return null;
|
||||
return ((ClassMetaData) elem).getDescribedType();
|
||||
|
|
|
@ -106,7 +106,8 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
|
|||
|
||||
// system sequence
|
||||
private SequenceMetaData _sysSeq = null;
|
||||
// cache of parsed metadata, oid class to class, and interface class to metadatas
|
||||
// cache of parsed metadata, oid class to class, and interface class
|
||||
// to metadatas
|
||||
private Map<Class<?>, ClassMetaData> _metas = new HashMap<Class<?>, ClassMetaData>();
|
||||
private Map<String, ClassMetaData> _metaStringMap = new ConcurrentHashMap<String, ClassMetaData>();
|
||||
private Map<Class<?>, Class<?>> _oids = Collections.synchronizedMap(new HashMap<Class<?>, Class<?>>());
|
||||
|
@ -123,8 +124,7 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
|
|||
private Map<Class<?>, Class<?>> _metamodel = Collections.synchronizedMap(new HashMap<Class<?>, Class<?>>());
|
||||
|
||||
// map of classes to lists of their subclasses
|
||||
private Map<Class<?>, Collection<Class<?>>> _subs =
|
||||
Collections.synchronizedMap(new HashMap<Class<?>, Collection<Class<?>>>());
|
||||
private Map<Class<?>, List<Class<?>>> _subs = Collections.synchronizedMap(new HashMap<Class<?>, List<Class<?>>>());
|
||||
|
||||
// xml mapping
|
||||
protected final XMLMetaData[] EMPTY_XMLMETAS;
|
||||
|
@ -283,7 +283,7 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
|
|||
}
|
||||
|
||||
/**
|
||||
* Affirms if this repository will load all known persistent classes at initialization.
|
||||
* Sets whether this repository will load all known persistent classes at initialization.
|
||||
* Defaults to false.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public synchronized void preload() {
|
||||
if (!_preload) {
|
||||
if (_preload == false) {
|
||||
return;
|
||||
}
|
||||
// If pooling EMFs, this method may be invoked more than once. Only perform this work once.
|
||||
if (_preloadComplete) {
|
||||
if (_preloadComplete == true) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -316,7 +316,7 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
|
|||
MultiClassLoader multi = AccessController.doPrivileged(J2DoPrivHelper.newMultiClassLoaderAction());
|
||||
multi.addClassLoader(AccessController.doPrivileged(J2DoPrivHelper.getContextClassLoaderAction()));
|
||||
multi.addClassLoader(AccessController.doPrivileged(J2DoPrivHelper
|
||||
.getClassLoaderAction(MetaDataRepository.class)));
|
||||
.getClassLoaderAction(MetaDataRepository.class)));
|
||||
// If a ClassLoader was passed into Persistence.createContainerEntityManagerFactory on the PersistenceUnitInfo
|
||||
// we need to add that loader to the chain of classloaders
|
||||
ClassResolver resolver = _conf.getClassResolverInstance();
|
||||
|
@ -359,7 +359,8 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
|
|||
}
|
||||
}
|
||||
|
||||
// Hook in this class as a listener and process registered classes list to populate _aliases list.
|
||||
// Hook in this class as a listener and process registered classes list to populate _aliases
|
||||
// list.
|
||||
PCRegistry.addRegisterClassListener(this);
|
||||
processRegisteredClasses(multi);
|
||||
_locking = false;
|
||||
|
@ -855,8 +856,9 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
|
|||
}
|
||||
|
||||
private ClassMetaData[] getMetaDatasInternal() {
|
||||
// prevent concurrent modification errors when resolving one metadata introduces others
|
||||
ClassMetaData[] metas = _metas.values().toArray(new ClassMetaData[_metas.size()]);
|
||||
// prevent concurrent mod errors when resolving one metadata
|
||||
// introduces others
|
||||
ClassMetaData[] metas = (ClassMetaData[]) _metas.values().toArray(new ClassMetaData[_metas.size()]);
|
||||
for (int i = 0; i < metas.length; i++)
|
||||
if (metas[i] != null)
|
||||
getMetaData(metas[i].getDescribedType(), metas[i].getEnvClassLoader(), true);
|
||||
|
@ -1798,8 +1800,7 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
|
|||
/**
|
||||
* Add the given value to the collection cached in the given map under the given key.
|
||||
*/
|
||||
private void addToCollection(Map<Class<?>, Collection<Class<?>>> map, Class<?> key, Class<?> value,
|
||||
boolean inheritance) {
|
||||
private void addToCollection(Map map, Class<?> key, Class<?> value, boolean inheritance) {
|
||||
if (_locking) {
|
||||
synchronized (map) {
|
||||
addToCollectionInternal(map, key, value, inheritance);
|
||||
|
@ -1809,17 +1810,15 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
|
|||
}
|
||||
}
|
||||
|
||||
private void addToCollectionInternal(Map<Class<?>, Collection<Class<?>>> map, Class<?> key,
|
||||
Class<?> value, boolean inheritance) {
|
||||
Collection<Class<?>> coll = map.get(key);
|
||||
private void addToCollectionInternal(Map map, Class<?> key, Class<?> value, boolean inheritance) {
|
||||
Collection coll = (Collection) map.get(key);
|
||||
if (coll == null) {
|
||||
if (inheritance) {
|
||||
InheritanceComparator comp = new InheritanceComparator();
|
||||
comp.setBase(key);
|
||||
coll = new TreeSet<Class<?>>(comp);
|
||||
} else {
|
||||
} else
|
||||
coll = new LinkedList<Class<?>>();
|
||||
}
|
||||
map.put(key, coll);
|
||||
}
|
||||
coll.add(value);
|
||||
|
@ -1893,7 +1892,7 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
|
|||
_aliases = new HashMap<String, List<Class<?>>>();
|
||||
_pawares = new HashMap<Class<?>, NonPersistentMetaData>();
|
||||
_nonMapped = new HashMap<Class<?>, NonPersistentMetaData>();
|
||||
_subs = new HashMap<Class<?>, Collection<Class<?>>>();
|
||||
_subs = new HashMap<Class<?>, List<Class<?>>>();
|
||||
// Wait till we're done loading MetaData to flip _lock boolean.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,11 +58,11 @@ import org.apache.openjpa.conf.OpenJPAConfiguration;
|
|||
public class ImplHelper {
|
||||
|
||||
// Cache for from/to type assignments
|
||||
private static final Map<Class<?>,Map<?,?>> _assignableTypes =
|
||||
private static final Map _assignableTypes =
|
||||
new ConcurrentReferenceHashMap(ReferenceMap.WEAK, ReferenceMap.HARD);
|
||||
|
||||
// map of all new unenhanced instances active in this classloader
|
||||
public static final Map<Object,PersistenceCapable> _unenhancedInstanceMap =
|
||||
public static final Map _unenhancedInstanceMap =
|
||||
new ConcurrentReferenceHashMap(ReferenceMap.WEAK, ReferenceMap.HARD) {
|
||||
|
||||
protected boolean eq(Object x, Object y) {
|
||||
|
@ -91,13 +91,13 @@ public class ImplHelper {
|
|||
* @see StoreManager#loadAll
|
||||
* @since 0.4.0
|
||||
*/
|
||||
public static Collection<Object> loadAll(Collection<OpenJPAStateManager> sms, StoreManager store,
|
||||
public static Collection loadAll(Collection sms, StoreManager store,
|
||||
PCState state, int load, FetchConfiguration fetch, Object context) {
|
||||
Collection<Object> failed = null;
|
||||
Collection failed = null;
|
||||
OpenJPAStateManager sm;
|
||||
LockManager lm;
|
||||
for (Iterator<OpenJPAStateManager> itr = sms.iterator(); itr.hasNext();) {
|
||||
sm = itr.next();
|
||||
for (Iterator itr = sms.iterator(); itr.hasNext();) {
|
||||
sm = (OpenJPAStateManager) itr.next();
|
||||
if (sm.getManagedInstance() == null) {
|
||||
if (!store.initialize(sm, state, fetch, context))
|
||||
failed = addFailedId(sm, failed);
|
||||
|
@ -110,23 +110,23 @@ public class ImplHelper {
|
|||
} else if (!store.exists(sm, context))
|
||||
failed = addFailedId(sm, failed);
|
||||
}
|
||||
if (failed == null) return Collections.emptyList();
|
||||
return failed;
|
||||
return (failed == null) ? Collections.EMPTY_LIST : failed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add identity of given instance to collection.
|
||||
*/
|
||||
private static Collection<Object> addFailedId(OpenJPAStateManager sm, Collection<Object> failed) {
|
||||
private static Collection addFailedId(OpenJPAStateManager sm,
|
||||
Collection failed) {
|
||||
if (failed == null)
|
||||
failed = new ArrayList<Object>();
|
||||
failed = new ArrayList();
|
||||
failed.add(sm.getId());
|
||||
return failed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a value for the given metadata, or return null. Generates
|
||||
* values for the following strategies: {@link ValueStrategies#SEQUENCE},
|
||||
* values for hte following strategies: {@link ValueStrategies#SEQUENCE},
|
||||
* {@link ValueStrategies#UUID_STRING}, {@link ValueStrategies#UUID_HEX}
|
||||
*/
|
||||
public static Object generateIdentityValue(StoreContext ctx,
|
||||
|
@ -136,7 +136,7 @@ public class ImplHelper {
|
|||
|
||||
/**
|
||||
* Generate a value for the given metadata, or return null. Generates
|
||||
* values for the following strategies: {@link ValueStrategies#SEQUENCE},
|
||||
* values for hte following strategies: {@link ValueStrategies#SEQUENCE},
|
||||
* {@link ValueStrategies#UUID_STRING}, {@link ValueStrategies#UUID_HEX}
|
||||
*/
|
||||
public static Object generateFieldValue(StoreContext ctx,
|
||||
|
@ -218,9 +218,11 @@ public class ImplHelper {
|
|||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static boolean isManagedType(OpenJPAConfiguration conf, Class<?> type) {
|
||||
return (type != null && PersistenceCapable.class.isAssignableFrom(type)
|
||||
|| ((conf == null || conf.getRuntimeUnenhancedClassesConstant()== RuntimeUnenhancedClassesModes.SUPPORTED)
|
||||
public static boolean isManagedType(OpenJPAConfiguration conf, Class type) {
|
||||
return (PersistenceCapable.class.isAssignableFrom(type)
|
||||
|| (type != null
|
||||
&& (conf == null || conf.getRuntimeUnenhancedClassesConstant()
|
||||
== RuntimeUnenhancedClassesModes.SUPPORTED)
|
||||
&& PCRegistry.isRegistered(type)));
|
||||
}
|
||||
|
||||
|
@ -244,7 +246,7 @@ public class ImplHelper {
|
|||
* @param to second class instance to be checked for assignability
|
||||
* @return true if the "to" class is assignable to the "from" class
|
||||
*/
|
||||
public static boolean isAssignable(Class<?> from, Class<?> to) {
|
||||
public static boolean isAssignable(Class from, Class to) {
|
||||
if (from == null || to == null)
|
||||
return false;
|
||||
|
||||
|
@ -306,7 +308,8 @@ public class ImplHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public static void registerPersistenceCapable(ReflectingPersistenceCapable pc) {
|
||||
public static void registerPersistenceCapable(
|
||||
ReflectingPersistenceCapable pc) {
|
||||
_unenhancedInstanceMap.put(pc.getManagedInstance(), pc);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* 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 ImmutableBooleanValue(String prop, boolean value) {
|
||||
super(prop);
|
||||
set(value);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* 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.util;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap;
|
||||
|
||||
|
||||
/**
|
||||
* A thread-specific storage similar to {@link ThreadLocal} that
|
||||
* <em>heuristically</em> relaxes the affinity of a value to a thread.
|
||||
* <br>
|
||||
* A thread <tt>t1</tt> can {@linkplain #set(Object) set} a value, while
|
||||
* a different thread <tt>t2</tt> can {@linkplain #get() access} the same
|
||||
* value, if <tt>t1</tt> and <tt>t2</tt> are <em>{@link #eq(Object, Object)
|
||||
* equivalent}</em>.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public class FlexibleThreadLocal extends ConcurrentReferenceHashMap {
|
||||
|
||||
/**
|
||||
* Must not hold hard reference to the threads used as keys.
|
||||
*/
|
||||
public FlexibleThreadLocal() {
|
||||
super(ReferenceMap.WEAK, ReferenceMap.HARD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value associated with the calling thread or its equivalent.
|
||||
*
|
||||
* @see #eq(Object, Object)
|
||||
*/
|
||||
public Object get() {
|
||||
Thread current = Thread.currentThread();
|
||||
if (containsKey(current)) {
|
||||
return super.get(current);
|
||||
} else {
|
||||
if (size() == 1)
|
||||
return ((Map.Entry)entrySet().iterator().next()).getValue();
|
||||
throw new RuntimeException(current + " is not a known thread. Known threads are " + keySet());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates the value to the current thread.
|
||||
*/
|
||||
public void set(Object t) {
|
||||
super.put(Thread.currentThread(), t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Affirms if the two given thread are equivalent.
|
||||
* Two threads are equivalent if the they are identical (of course),
|
||||
* or they belong to the same thread group or they are <em>equal</em>.
|
||||
* The equality can be defined <em>asymmetrically</em> by the
|
||||
* thread implementation. For example, a child thread (as done in Slice)
|
||||
* can equal its parent thread which is a native thread. But the parent
|
||||
* (native) thread is not equal to the child thread.
|
||||
*/
|
||||
@Override
|
||||
protected boolean eq(Object a, Object b) {
|
||||
if (a == b) return true;
|
||||
if (a == null || b == null) return false;
|
||||
if (a instanceof Thread && b instanceof Thread)
|
||||
if (((Thread)a).getThreadGroup() == ((Thread)b).getThreadGroup())
|
||||
return true;
|
||||
return a.equals(b) || b.equals(a);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* 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.util;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* A thread gate that guards on first invocation and remains open after the first invocation.
|
||||
* Used when a structure (such as Select) is constructed and populated first-time in a
|
||||
* thread-safe manner and can be used later with minimal thread synchronization overhead.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ThreadGate extends ReentrantLock {
|
||||
private AtomicBoolean _once = new AtomicBoolean(false);
|
||||
|
||||
/**
|
||||
* Lock the gate only if it has never been locked.
|
||||
*/
|
||||
@Override
|
||||
public void lock() {
|
||||
synchronized (_once) {
|
||||
if (!_once.get()) {
|
||||
super.lock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock the gate and keep it open for ever.
|
||||
*/
|
||||
@Override
|
||||
public void unlock() {
|
||||
if (_once.compareAndSet(false, true)) {
|
||||
super.unlock();
|
||||
synchronized (_once) {
|
||||
_once.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
* 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 agEmployee_Last_Name 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.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class TestFlexibleThreadLocal extends TestCase {
|
||||
private static final int MAX_THREAD = 10;
|
||||
|
||||
public void testCorrectValuesAreRetrievedWhenThreadsAreInSameGroup() throws Exception {
|
||||
ExecutorService threadPool = Executors.newCachedThreadPool();
|
||||
List<Future<?>> futures = new ArrayList<Future<?>>();
|
||||
for (int i = 0; i < MAX_THREAD; i++) {
|
||||
Future<?> f = threadPool.submit(new User());
|
||||
futures.add(f);
|
||||
}
|
||||
waitForTermination(futures);
|
||||
threadPool.shutdown();
|
||||
threadPool.awaitTermination(10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public void testCorrectValuesAreRetrievedWhenThreadsAreNotInSameGroup() throws Exception {
|
||||
Thread[] threads = new Thread[MAX_THREAD];
|
||||
for (int i = 0; i < MAX_THREAD; i++) {
|
||||
threads[i] = new Thread(new User());
|
||||
threads[i].start();
|
||||
}
|
||||
waitForTermination(threads);
|
||||
}
|
||||
|
||||
|
||||
void waitForTermination(Thread[] threads) {
|
||||
for (int i = 0; i < MAX_THREAD; i++) {
|
||||
try {
|
||||
threads[i].join();
|
||||
threads[i].interrupt();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void waitForTermination(List<Future<?>> futures) {
|
||||
for (Future<?> f : futures) {
|
||||
try {
|
||||
f.get();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets and gets random values in a flexible thread local.
|
||||
*
|
||||
*/
|
||||
class User implements Runnable {
|
||||
private static final Random _rng = new Random();
|
||||
Integer[] randoms = new Integer[20];
|
||||
static final FlexibleThreadLocal test = new FlexibleThreadLocal();
|
||||
|
||||
public User() {
|
||||
for (int i = 0; i < randoms.length; i++) {
|
||||
randoms[i] = _rng.nextInt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < randoms.length; i++) {
|
||||
test.set(randoms[i]);
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Assert.assertEquals(Thread.currentThread() + " item " + i, randoms[i], test.get());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,161 +0,0 @@
|
|||
/*
|
||||
* 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.util;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.openjpa.lib.util.ThreadGate;
|
||||
|
||||
/**
|
||||
* Tests a thread gate.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class TestGate extends TestCase {
|
||||
public static enum Op {ENTER, EXIT};
|
||||
public static int MAX_THREAD = 4;
|
||||
public static int THREAD_TIME = 10;
|
||||
private ExecutorService threadPool;
|
||||
|
||||
public void testAllThreadsBlockUntilFirstAccessIsComplete() throws Exception {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
threadPool = Executors.newFixedThreadPool(MAX_THREAD);
|
||||
allThreadsBlockUntilFirstAccessIsComplete();
|
||||
}
|
||||
}
|
||||
public void allThreadsBlockUntilFirstAccessIsComplete() throws Exception {
|
||||
final Info info = new Info();
|
||||
final ThreadGate gate = new ThreadGate();
|
||||
final AtomicBoolean first = new AtomicBoolean(true);
|
||||
List<Future<?>> futures = new ArrayList<Future<?>>();
|
||||
for (int i = 0; i < MAX_THREAD; i++) {
|
||||
Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
gate.lock();
|
||||
try {
|
||||
info.enter();
|
||||
Thread.sleep(THREAD_TIME);
|
||||
info.exit();
|
||||
} catch (InterruptedException e) {
|
||||
fail();
|
||||
} finally {
|
||||
gate.unlock();
|
||||
}
|
||||
}
|
||||
};
|
||||
futures.add(threadPool.submit(r));
|
||||
}
|
||||
|
||||
for (Future<?> f : futures) {
|
||||
try {
|
||||
f.get();
|
||||
assertTrue(f.isDone());
|
||||
assertFalse(f.isCancelled());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
}
|
||||
// assertEquals(2*MAX_THREAD, info.msg.size());
|
||||
Token enter = info.msg.get(0);
|
||||
Token exit = info.msg.get(1);
|
||||
assertEquals(Op.ENTER, enter.op);
|
||||
assertEquals(Op.EXIT, exit.op);
|
||||
assertSame(enter.thread, exit.thread);
|
||||
|
||||
for (int i = 2; i < info.msg.size(); i++) {
|
||||
Token token = info.msg.get(i);
|
||||
if (token.op == Op.ENTER) {
|
||||
Token pair = info.find(i+1, token);
|
||||
assertNotNull("No pair for " + token.thread, pair);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Records starting and stopping of threads.
|
||||
*
|
||||
*/
|
||||
public class Info {
|
||||
Vector<Token> msg = new Vector<Token>();
|
||||
|
||||
/**
|
||||
* Record entry of the current thread.
|
||||
*/
|
||||
public void enter() {
|
||||
msg.add(new Token(Thread.currentThread(), Op.ENTER));
|
||||
}
|
||||
|
||||
/**
|
||||
* Record exit of the current thread.
|
||||
*/
|
||||
public void exit() {
|
||||
msg.add(new Token(Thread.currentThread(), Op.EXIT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the exit record corresponding to a given entry record.
|
||||
*/
|
||||
|
||||
public Token find(int start, Token t) {
|
||||
for (int i = start; i < msg.size(); i++) {
|
||||
if (msg.get(i).thread.getName().equals(t.thread.getName()))
|
||||
return msg.get(i);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void print(PrintStream out) {
|
||||
for (Token t : msg) {
|
||||
out.println(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Info about a thread activity.
|
||||
*/
|
||||
public class Token {
|
||||
final Thread thread;
|
||||
final Op op;
|
||||
final long time;
|
||||
|
||||
public Token(Thread t, Op op) {
|
||||
super();
|
||||
this.thread = t;
|
||||
this.op = op;
|
||||
this.time = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return time + " " + op + " " + thread.getName();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* 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.util;
|
||||
|
||||
import org.apache.openjpa.lib.conf.ImmutableBooleanValue;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests behavior of immutable boolean value.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class TestImmutableValue extends TestCase {
|
||||
|
||||
public void testDefaultValueIsFalse() {
|
||||
ImmutableBooleanValue value = new ImmutableBooleanValue("a");
|
||||
assertEquals(Boolean.FALSE, value.get());
|
||||
}
|
||||
|
||||
public void testValueCanBeSetOnce() {
|
||||
ImmutableBooleanValue value = new ImmutableBooleanValue("a");
|
||||
value.set(true);
|
||||
assertEquals(Boolean.TRUE, value.get());
|
||||
}
|
||||
|
||||
public void testSameValueCanBeSetMoreThanOnce() {
|
||||
ImmutableBooleanValue value = new ImmutableBooleanValue("a");
|
||||
value.set(true);
|
||||
assertEquals(Boolean.TRUE, value.get());
|
||||
value.set(true);
|
||||
assertEquals(Boolean.TRUE, value.get());
|
||||
}
|
||||
|
||||
public void testDifferentValueCanNotBeSetMoreThanOnce() {
|
||||
ImmutableBooleanValue value = new ImmutableBooleanValue("a");
|
||||
value.set(true);
|
||||
assertEquals(Boolean.TRUE, value.get());
|
||||
try {
|
||||
value.set(false);
|
||||
fail("Expected IllegalStateException");
|
||||
} catch (IllegalStateException e) {
|
||||
// expected exception
|
||||
}
|
||||
assertEquals(Boolean.TRUE, value.get());
|
||||
}
|
||||
|
||||
public void testInitializedAsTrue() {
|
||||
ImmutableBooleanValue value = new ImmutableBooleanValue("a", true);
|
||||
assertEquals(Boolean.TRUE, value.get());
|
||||
}
|
||||
|
||||
public void testInitializedAsFalse() {
|
||||
ImmutableBooleanValue value = new ImmutableBooleanValue("a", false);
|
||||
assertEquals(Boolean.FALSE, value.get());
|
||||
}
|
||||
|
||||
public void testInitializedValueCanNotBeMutated() {
|
||||
ImmutableBooleanValue value = new ImmutableBooleanValue("a", true);
|
||||
assertEquals(Boolean.TRUE, value.get());
|
||||
try {
|
||||
value.set(false);
|
||||
fail("Expected IllegalStateException");
|
||||
} catch (IllegalStateException e) {
|
||||
// expected exception
|
||||
}
|
||||
assertEquals(Boolean.TRUE, value.get());
|
||||
}
|
||||
}
|
|
@ -1511,9 +1511,11 @@ public class AnnotationPersistenceMetaDataSerializer
|
|||
* then name order.
|
||||
*/
|
||||
private class FieldComparator
|
||||
implements Comparator<FieldMetaData> {
|
||||
implements Comparator {
|
||||
|
||||
public int compare(FieldMetaData fmd1, FieldMetaData fmd2) {
|
||||
public int compare(Object o1, Object o2) {
|
||||
FieldMetaData fmd1 = (FieldMetaData) o1;
|
||||
FieldMetaData fmd2 = (FieldMetaData) o2;
|
||||
if (fmd1.isPrimaryKey()) {
|
||||
if (fmd2.isPrimaryKey())
|
||||
return fmd1.compareTo(fmd2);
|
||||
|
|
|
@ -87,22 +87,22 @@ public interface OpenJPAQuery<X> extends TypedQuery<X> {
|
|||
* Return the candidate collection, or <code>null</code> if an
|
||||
* extent was specified instead of a collection.
|
||||
*/
|
||||
public Collection<?> getCandidateCollection();
|
||||
public Collection getCandidateCollection();
|
||||
|
||||
/**
|
||||
* Set a collection of candidates.
|
||||
*/
|
||||
public OpenJPAQuery<X> setCandidateCollection(Collection<?> coll);
|
||||
public OpenJPAQuery<X> setCandidateCollection(Collection coll);
|
||||
|
||||
/**
|
||||
* Query result element type.
|
||||
*/
|
||||
public Class<?> getResultClass();
|
||||
public Class getResultClass();
|
||||
|
||||
/**
|
||||
* Query result element type.
|
||||
*/
|
||||
public OpenJPAQuery<X> setResultClass(Class<?> type);
|
||||
public OpenJPAQuery<X> setResultClass(Class type);
|
||||
|
||||
/**
|
||||
* Whether subclasses are included in the query results.
|
||||
|
@ -150,7 +150,7 @@ public interface OpenJPAQuery<X> extends TypedQuery<X> {
|
|||
/**
|
||||
* Set parameters.
|
||||
*/
|
||||
public OpenJPAQuery<X> setParameters(Map<?,?> params);
|
||||
public OpenJPAQuery<X> setParameters(Map params);
|
||||
|
||||
/**
|
||||
* Set parameters.
|
||||
|
@ -169,7 +169,7 @@ public interface OpenJPAQuery<X> extends TypedQuery<X> {
|
|||
*
|
||||
* @param params the named parameter map for the query invocation
|
||||
*/
|
||||
public String[] getDataStoreActions(Map<?,?> params);
|
||||
public String[] getDataStoreActions(Map params);
|
||||
|
||||
public OpenJPAQuery<X> setMaxResults(int maxResult);
|
||||
|
||||
|
@ -207,7 +207,7 @@ public interface OpenJPAQuery<X> extends TypedQuery<X> {
|
|||
* Gets whether the type of user-supplied bind parameter value and the type of target persistent
|
||||
* property they bind to are checked with strong or weak constraint.
|
||||
*
|
||||
* @return the boolean state. False by default, i.e. the type of a bind parameter value is checked
|
||||
* @return the booelan state. False by default, i.e. the type of a bind parameter value is checked
|
||||
* strongly against the target property type.
|
||||
*/
|
||||
public boolean getRelaxBindParameterTypeChecking();
|
||||
|
|
|
@ -213,14 +213,14 @@ public class QueryImpl<X> extends AbstractQuery<X> implements Serializable {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Class<?> getResultClass() {
|
||||
Class<?> res = _query.getResultType();
|
||||
public Class getResultClass() {
|
||||
Class res = _query.getResultType();
|
||||
if (res != null)
|
||||
return res;
|
||||
return _query.getCandidateType();
|
||||
}
|
||||
|
||||
public OpenJPAQuery<X> setResultClass(Class<?> cls) {
|
||||
public OpenJPAQuery<X> setResultClass(Class cls) {
|
||||
_em.assertNotCloseInvoked();
|
||||
if (ImplHelper.isManagedType(_em.getConfiguration(), cls))
|
||||
_query.setCandidateType(cls, true);
|
||||
|
|
|
@ -1351,29 +1351,4 @@ for a JPQL query.
|
|||
</para>
|
||||
|
||||
</section>
|
||||
<section id="ref_guide_cache_select">
|
||||
<title>Select Cache</title>
|
||||
<indexterm zone="ref_guide_cache_select">
|
||||
<primary>caching</primary>
|
||||
<secondary>Select Cache</secondary>
|
||||
</indexterm>
|
||||
<para>
|
||||
OpenJPA generates SQL SELECT statements to fetch database records and populates the persistent entity states
|
||||
from the result data. Under certain assumptions, these select statements are invariant for an entity
|
||||
or its relations except that their binding parameters vary between executions. In version 2.2.0, OpenJPA
|
||||
allows these select statements be reused. Such reuse avoids the cost of regenerating these statements in
|
||||
every execution.
|
||||
</para>
|
||||
<para>
|
||||
This facility can be activated by <programlisting>openjpa.jdbc.CachesSelect</programlisting> configuration
|
||||
property. This property accepts boolean value of <programlisting>true</programlisting> or
|
||||
<programlisting>false</programlisting>. By default, the property value is <programlisting>false</programlisting>.
|
||||
The property value can be changed once and only once.
|
||||
</para>
|
||||
<para>
|
||||
The assumption that a select statement for a persistent entity is invariant holds only if the fetch plan
|
||||
is not dynamically modified. OpenJPA runtime currently makes no attempt to ensure that the assumption
|
||||
is held true i.e. the application is not modifying the fetch plan dynamically.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
|
@ -3427,43 +3427,6 @@ levels are equivalent. Lock levels <literal>pessimistic-read</literal>,
|
|||
<para>
|
||||
The following properties apply exclusively to the OpenJPA JDBC back-end.
|
||||
</para>
|
||||
|
||||
<section id="openjpa.jdbc.CachesSelect">
|
||||
<title>
|
||||
openjpa.jdbc.CachesSelect
|
||||
</title>
|
||||
<indexterm zone="openjpa.jdbc.CachesSelect">
|
||||
<primary>
|
||||
Select Cache
|
||||
</primary>
|
||||
</indexterm>
|
||||
<indexterm zone="openjpa.jdbc.CachesSelect">
|
||||
<primary>
|
||||
caching
|
||||
</primary>
|
||||
<secondary>
|
||||
Select Cache
|
||||
</secondary>
|
||||
</indexterm>
|
||||
<para>
|
||||
<emphasis role="bold">Property name:</emphasis>
|
||||
<literal>openjpa.jdbc.CachesSelect</literal>
|
||||
</para>
|
||||
<para>
|
||||
<emphasis role="bold">Resource adaptor config-property:</emphasis>
|
||||
<literal>CachesSelect</literal>
|
||||
</para>
|
||||
<para>
|
||||
<emphasis role="bold">Default:</emphasis> <literal>false</literal>.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis role="bold">Description:</emphasis> A plugin string (see
|
||||
<xref linkend="ref_guide_conf_plugins"/>) describing the options to reuse SQL SELECT
|
||||
statements generated to load persistent entity and its relations.
|
||||
See <xref linkend="ref_guide_cache_select"/> for details.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="openjpa.jdbc.ConnectionDecorators">
|
||||
<title>
|
||||
openjpa.jdbc.ConnectionDecorators
|
||||
|
|
|
@ -50,36 +50,6 @@ public class SliceThread extends Thread {
|
|||
return _parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* This thread equals itself (of course), its parent and any of its siblings.
|
||||
* Essentially all slice threads are equal.
|
||||
* <br>
|
||||
* Note: this definition of equality breaks the core definition i.e. if
|
||||
* <tt>P</tt> is parent thread of a slice child <tt>S</tt>, then
|
||||
* <tt>S.equals(P)</tt>, but <em>not</em> <tt>P.equals(S)</tt>.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) return true;
|
||||
if (other instanceof SliceThread) {
|
||||
return ((SliceThread)other)._parent == this._parent;
|
||||
}
|
||||
return this._parent == other;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash code of this thread is same as its parent.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return _parent.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return '[' + getClass().getSimpleName() + '-'+ getName() + " child of " + _parent + ']';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a cached pool of <em>slice</em> threads.
|
||||
* The thread factory creates specialized threads for preferential locking treatment.
|
||||
|
|
|
@ -356,18 +356,5 @@ public class TestBasic extends SliceTestCase {
|
|||
assertNotNull(newP);
|
||||
assertEquals("newslice", SlicePersistence.getSlice(newP));
|
||||
}
|
||||
|
||||
public void testSliceThreadEqualsParentAndSiblings() {
|
||||
Thread parent = new Thread();
|
||||
SliceThread s1 = new SliceThread(parent, null);
|
||||
SliceThread s2 = new SliceThread(parent, null);
|
||||
|
||||
assertEquals(s1, parent);
|
||||
assertEquals(s2, parent);
|
||||
assertEquals(s1, s2);
|
||||
assertNotSame(parent, s1);
|
||||
assertNotSame(parent, s2);
|
||||
assertNotSame(s1, s2);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue