OPENJPA-2099: Reuse internal select by parameter rebinding

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@1229690 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Pinaki Poddar 2012-01-10 19:08:31 +00:00
parent 6289157f9c
commit 2846f873c2
8 changed files with 308 additions and 237 deletions

View File

@ -39,10 +39,10 @@ import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.Result; import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.jdbc.sql.SelectExecutor; import org.apache.openjpa.jdbc.sql.SelectExecutor;
import org.apache.openjpa.jdbc.sql.SelectImpl;
import org.apache.openjpa.jdbc.sql.Union; import org.apache.openjpa.jdbc.sql.Union;
import org.apache.openjpa.kernel.OpenJPAStateManager; import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.kernel.StateManagerImpl; import org.apache.openjpa.kernel.StateManagerImpl;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.JavaTypes; import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.util.ChangeTracker; import org.apache.openjpa.util.ChangeTracker;
@ -60,9 +60,11 @@ import org.apache.openjpa.util.Proxy;
* *
* @author Abe White * @author Abe White
*/ */
@SuppressWarnings("serial")
public abstract class StoreCollectionFieldStrategy public abstract class StoreCollectionFieldStrategy
extends ContainerFieldStrategy { extends ContainerFieldStrategy {
protected SelectExecutor _executor;
/** /**
* Return the foreign key used to join to the owning field for the given * Return the foreign key used to join to the owning field for the given
* element mapping from {@link #getIndependentElementMappings} (or null). * element mapping from {@link #getIndependentElementMappings} (or null).
@ -94,8 +96,7 @@ public abstract class StoreCollectionFieldStrategy
* *
* @see FieldMapping#joinRelation * @see FieldMapping#joinRelation
*/ */
protected abstract Joins joinElementRelation(Joins joins, protected abstract Joins joinElementRelation(Joins joins, ClassMapping elem);
ClassMapping elem);
/** /**
* Join to the owning field table for the given element mapping from * Join to the owning field table for the given element mapping from
@ -112,9 +113,9 @@ public abstract class StoreCollectionFieldStrategy
* Convert the field value to a collection. Handles collections and * Convert the field value to a collection. Handles collections and
* arrays by default. * arrays by default.
*/ */
protected Collection toCollection(Object val) { protected Collection<?> toCollection(Object val) {
if (field.getTypeCode() == JavaTypes.COLLECTION) if (field.getTypeCode() == JavaTypes.COLLECTION)
return (Collection) val; return (Collection<?>) val;
return JavaTypes.toList(val, field.getElement().getType(), false); return JavaTypes.toList(val, field.getElement().getType(), false);
} }
@ -159,7 +160,7 @@ public abstract class StoreCollectionFieldStrategy
final ClassMapping[] elems = getIndependentElementMappings(true); final ClassMapping[] elems = getIndependentElementMappings(true);
Union union = (Union) sel; Union union = (Union) sel;
if (fetch.getSubclassFetchMode(field.getElementMapping(). if (fetch.getSubclassFetchMode(field.getElementMapping().
getTypeMapping()) != fetch.EAGER_JOIN) getTypeMapping()) != JDBCFetchConfiguration.EAGER_JOIN)
union.abortUnion(); union.abortUnion();
union.select(new Union.Selector() { union.select(new Union.Selector() {
public void select(Select sel, int idx) { public void select(Select sel, int idx) {
@ -180,8 +181,7 @@ public abstract class StoreCollectionFieldStrategy
if (fetch.hasFetchInnerJoin(field.getFullName(false))) if (fetch.hasFetchInnerJoin(field.getFullName(false)))
outer = false; outer = false;
selectEager(sel, getDefaultElementMapping(true), sm, store, fetch, selectEager(sel, getDefaultElementMapping(true), sm, store, fetch,
JDBCFetchConfiguration.EAGER_JOIN, false, JDBCFetchConfiguration.EAGER_JOIN, false, outer);
outer);
} }
public boolean isEagerSelectToMany() { public boolean isEagerSelectToMany() {
@ -194,7 +194,7 @@ public abstract class StoreCollectionFieldStrategy
private void selectEager(Select sel, ClassMapping elem, private void selectEager(Select sel, ClassMapping elem,
OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch, OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch,
int eagerMode, boolean selectOid, boolean outer) { int eagerMode, boolean selectOid, boolean outer) {
// force distinct if there was a to-many join to avoid dups, but // force distinct if there was a to-many join to avoid duplicates, but
// if this is a parallel select don't make distinct based on the // if this is a parallel select don't make distinct based on the
// eager joins alone if the original wasn't distinct // eager joins alone if the original wasn't distinct
if (eagerMode == JDBCFetchConfiguration.EAGER_PARALLEL) { if (eagerMode == JDBCFetchConfiguration.EAGER_PARALLEL) {
@ -214,8 +214,7 @@ public abstract class StoreCollectionFieldStrategy
joins = join(joins, elem); joins = join(joins, elem);
// order, ref cols // order, ref cols
if (field.getOrderColumn() != null || field.getOrders().length > 0 if (field.getOrderColumn() != null || field.getOrders().length > 0 || !selectOid) {
|| !selectOid) {
if (outer) if (outer)
joins = sel.outer(joins); joins = sel.outer(joins);
if (!selectOid) { if (!selectOid) {
@ -360,14 +359,11 @@ public abstract class StoreCollectionFieldStrategy
// get the StateManager of this toMany value // get the StateManager of this toMany value
// and find the value of the inverse mappedBy field (Customer) // and find the value of the inverse mappedBy field (Customer)
// for this toMacdny field // for this toMacdny field
PersistenceCapable pc = (PersistenceCapable) PersistenceCapable pc = (PersistenceCapable)((Collection) coll).iterator().next();
((Collection) coll).iterator().next(); OpenJPAStateManager sm1 = (OpenJPAStateManager) pc.pcGetStateManager();
OpenJPAStateManager sm1 = (OpenJPAStateManager) pc.
pcGetStateManager();
ClassMapping clm = ((ClassMapping) sm1.getMetaData()); ClassMapping clm = ((ClassMapping) sm1.getMetaData());
FieldMapping fm = (FieldMapping) clm.getField( FieldMapping fm = (FieldMapping) clm.getField(mappedByFieldMapping.getName());
mappedByFieldMapping.getName());
if (fm == mappedByFieldMapping) if (fm == mappedByFieldMapping)
res.setMappedByValue(sm1.fetchObject(fm.getIndex())); res.setMappedByValue(sm1.fetchObject(fm.getIndex()));
} else { } else {
@ -513,8 +509,7 @@ public abstract class StoreCollectionFieldStrategy
Result res = sel.execute(store, fetch); Result res = sel.execute(store, fetch);
try { try {
res.next(); res.next();
coll.getChangeTracker().setNextSequence coll.getChangeTracker().setNextSequence(res.getInt(field) + 1);
(res.getInt(field) + 1);
} finally { } finally {
res.close(); res.close();
} }
@ -522,17 +517,20 @@ public abstract class StoreCollectionFieldStrategy
sm.storeObjectField(field.getIndex(), coll); sm.storeObjectField(field.getIndex(), coll);
return; return;
} }
// select data for this state manager
// select data for this sm
final ClassMapping[] elems = getIndependentElementMappings(true); final ClassMapping[] elems = getIndependentElementMappings(true);
final Joins[] resJoins = new Joins[Math.max(1, elems.length)]; final Joins[] resJoins = new Joins[Math.max(1, elems.length)];
Union union = store.getSQLFactory().newUnion Union union;
(Math.max(1, elems.length)); if (_executor == null) {
union = store.getSQLFactory().newUnion(Math.max(1, elems.length));
_executor = union;
} else {
union = (Union)_executor;
}
union.select(new Union.Selector() { union.select(new Union.Selector() {
public void select(Select sel, int idx) { public void select(Select sel, int idx) {
ClassMapping elem = (elems.length == 0) ? null : elems[idx]; ClassMapping elem = (elems.length == 0) ? null : elems[idx];
resJoins[idx] = selectAll(sel, elem, sm, store, fetch, resJoins[idx] = selectAll(sel, elem, sm, store, fetch, JDBCFetchConfiguration.EAGER_PARALLEL);
JDBCFetchConfiguration.EAGER_PARALLEL);
} }
}); });
@ -555,8 +553,7 @@ public abstract class StoreCollectionFieldStrategy
if (ct != null && field.getOrderColumn() != null) if (ct != null && field.getOrderColumn() != null)
seq = res.getInt(field.getOrderColumn()); seq = res.getInt(field.getOrderColumn());
setMappedBy(sm.getObjectId(), sm, coll, res); setMappedBy(sm.getObjectId(), sm, coll, res);
add(store, coll, loadElement(sm, store, fetch, res, add(store, coll, loadElement(sm, store, fetch, res, resJoins[res.indexOf()]));
resJoins[res.indexOf()]));
} }
if (ct != null && field.getOrderColumn() != null) if (ct != null && field.getOrderColumn() != null)
ct.setNextSequence(seq + 1); ct.setNextSequence(seq + 1);
@ -565,11 +562,12 @@ public abstract class StoreCollectionFieldStrategy
} }
// set into sm // set into sm
if (field.getTypeCode() == JavaTypes.ARRAY) if (field.getTypeCode() == JavaTypes.ARRAY) {
sm.storeObject(field.getIndex(), JavaTypes.toArray sm.storeObject(field.getIndex(), JavaTypes.toArray
((Collection) coll, field.getElement().getType())); ((Collection) coll, field.getElement().getType()));
else } else {
sm.storeObject(field.getIndex(), coll); sm.storeObject(field.getIndex(), coll);
}
} }
/** /**
@ -581,13 +579,17 @@ public abstract class StoreCollectionFieldStrategy
ForeignKey fk = getJoinForeignKey(elem); ForeignKey fk = getJoinForeignKey(elem);
Object oid = getObjectIdForJoin(fk, sm); Object oid = getObjectIdForJoin(fk, sm);
sel.whereForeignKey(fk, oid, field.getDefiningMapping(), store); sel.whereForeignKey(fk, oid, field.getDefiningMapping(), store);
Joins joins;
// order first, then select so that if the projection introduces if (!sel.isReadOnly()) {
// additional ordering, it will be after our required ordering // order first, then select so that if the projection introduces
field.orderLocal(sel, elem, null); // additional ordering, it will be after our required ordering
Joins joins = joinElementRelation(sel.newJoins(), elem); field.orderLocal(sel, elem, null);
field.orderRelation(sel, elem, joins); joins = joinElementRelation(sel.newJoins(), elem);
selectElement(sel, elem, store, fetch, eagerMode, joins); field.orderRelation(sel, elem, joins);
selectElement(sel, elem, store, fetch, eagerMode, joins);
} else {
joins = joinElementRelation(sel.newJoins(), elem);
}
return joins; return joins;
} }
@ -624,4 +626,8 @@ public abstract class StoreCollectionFieldStrategy
} }
return oid; return oid;
} }
public String toString() {
return getClass().getSimpleName() + '[' + field.getName() + ']';
}
} }

View File

@ -74,7 +74,7 @@ public abstract class AbstractResult
private static final Joins JOINS = new NoOpJoins(); private static final Joins JOINS = new NoOpJoins();
private Map _eager = null; private Map<Object,Object> _eager = null;
private ClassMapping _base = null; private ClassMapping _base = null;
private int _index = 0; private int _index = 0;
private boolean _gotEager = false; private boolean _gotEager = false;
@ -86,14 +86,14 @@ public abstract class AbstractResult
private Object _mappedByValue = null; private Object _mappedByValue = null;
public Object getEager(FieldMapping key) { public Object getEager(FieldMapping key) {
Map map = getEagerMap(true); Map<Object,Object> map = getEagerMap(true);
return (map == null) ? null : map.get(key); return (map == null) ? null : map.get(key);
} }
public void putEager(FieldMapping key, Object res) { public void putEager(FieldMapping key, Object res) {
Map map = getEagerMap(false); Map<Object,Object> map = getEagerMap(false);
if (map == null) { if (map == null) {
map = new HashMap(); map = new HashMap<Object,Object>();
setEagerMap(map); setEagerMap(map);
} }
map.put(key, res); map.put(key, res);
@ -104,7 +104,7 @@ public abstract class AbstractResult
* *
* @param client whether the client is accessing eager information * @param client whether the client is accessing eager information
*/ */
protected Map getEagerMap(boolean client) { protected Map<Object,Object> getEagerMap(boolean client) {
if (client) if (client)
_gotEager = true; _gotEager = true;
return _eager; return _eager;
@ -113,7 +113,7 @@ public abstract class AbstractResult
/** /**
* Raw eager information. * Raw eager information.
*/ */
protected void setEagerMap(Map eager) { protected void setEagerMap(Map<Object,Object> eager) {
_eager = eager; _eager = eager;
} }
@ -129,11 +129,9 @@ public abstract class AbstractResult
/** /**
* Close all results in eager map. * Close all results in eager map.
*/ */
protected void closeEagerMap(Map eager) { protected void closeEagerMap(Map<Object,Object> eager) {
if (eager != null) { if (eager != null) {
Object res; for (Object res : eager.values()) {
for (Iterator itr = eager.values().iterator(); itr.hasNext();) {
res = itr.next();
if (res != this && res instanceof Closeable) if (res != this && res instanceof Closeable)
try { try {
((Closeable) res).close(); ((Closeable) res).close();
@ -891,9 +889,6 @@ public abstract class AbstractResult
return this; return this;
} }
public void appendTo(SQLBuffer buf) {
}
public Joins setCorrelatedVariable(String var) { public Joins setCorrelatedVariable(String var) {
return this; return this;
} }
@ -904,5 +899,10 @@ public abstract class AbstractResult
public void moveJoinsToParent() { public void moveJoinsToParent() {
} }
@Override
public StringBuilder path() {
return null;
}
} }
} }

View File

@ -39,9 +39,9 @@ class JoinSet {
// efficient representation with O(1) lookup, add, remove operations for // 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 // typical sets of joins, and it means we'd have to create a graph anyway
// when joinIterator() is called // when joinIterator() is called
private final List _graph = new ArrayList(); private final List<Node> _graph = new ArrayList<Node>();
private int _size = 0; private int _size = 0;
private List _sorted = null; private List<Join> _sorted = null;
public JoinSet() { public JoinSet() {
} }
@ -51,7 +51,7 @@ class JoinSet {
if (copy._graph.get(i) == null) if (copy._graph.get(i) == null)
_graph.add(null); _graph.add(null);
else else
_graph.add(((Node) copy._graph.get(i)).clone()); _graph.add((Node) copy._graph.get(i).clone());
} }
_size = copy._size; _size = copy._size;
_sorted = copy._sorted; _sorted = copy._sorted;
@ -95,23 +95,22 @@ class JoinSet {
/** /**
* Iterator over joins that prepares them for SQL translation. * Iterator over joins that prepares them for SQL translation.
*/ */
public Iterator joinIterator() { public Iterator<Join> joinIterator() {
if (_size < 2) if (_size < 2)
return iterator(); return iterator();
if (_sorted != null) if (_sorted != null)
return _sorted.iterator(); return _sorted.iterator();
List sorted = new ArrayList(_size); List<Join> sorted = new ArrayList<Join>(_size);
LinkedList queue = new LinkedList(); LinkedList<Node> queue = new LinkedList<Node>();
BitSet seen = new BitSet(_graph.size() * _graph.size() BitSet seen = new BitSet(_graph.size() * _graph.size() + _graph.size());
+ _graph.size());
// traverse graph // traverse graph
Node n; Node n;
int idx, sidx; int idx, sidx;
for (int i = 0; i < _graph.size(); i++) { for (int i = 0; i < _graph.size(); i++) {
// seed queue with next set of disconnected joins // seed queue with next set of disconnected joins
for (n = (Node) _graph.get(i); n != null; n = n.next) { for (n = _graph.get(i); n != null; n = n.next) {
sidx = getSeenIndex(n.join); sidx = getSeenIndex(n.join);
if (!seen.get(sidx)) { if (!seen.get(sidx)) {
seen.set(sidx); seen.set(sidx);
@ -183,8 +182,8 @@ class JoinSet {
return false; return false;
boolean added = false; boolean added = false;
for (Iterator itr = js.iterator(); itr.hasNext();) for (Iterator<Join> itr = js.iterator(); itr.hasNext();)
added = add((Join) itr.next()) || added; added = add(itr.next()) || added;
return added; return added;
} }
@ -218,8 +217,8 @@ class JoinSet {
_size++; _size++;
} }
public Iterator iterator() { public Iterator<Join> iterator() {
return new Iterator() { return new Iterator<Join>() {
private Node _next = null; private Node _next = null;
private int _idx = -1; private int _idx = -1;
@ -237,7 +236,7 @@ class JoinSet {
return false; return false;
} }
public Object next() { public Join next() {
if (!hasNext()) if (!hasNext())
throw new NoSuchElementException(); throw new NoSuchElementException();
Join j = _next.join; Join j = _next.join;
@ -289,16 +288,16 @@ class JoinSet {
public boolean removeAll(JoinSet js) { public boolean removeAll(JoinSet js) {
boolean remd = false; boolean remd = false;
for (Iterator itr = js.iterator(); itr.hasNext();) for (Iterator<Join> itr = js.iterator(); itr.hasNext();)
remd = remove((Join) itr.next()) || remd; remd = remove(itr.next()) || remd;
return remd; return remd;
} }
public boolean retainAll(JoinSet js) { public boolean retainAll(JoinSet js) {
boolean remd = false; boolean remd = false;
Join join; Join join;
for (Iterator itr = iterator(); itr.hasNext();) { for (Iterator<Join> itr = iterator(); itr.hasNext();) {
join = (Join) itr.next(); join = itr.next();
if (!js.contains(join)) if (!js.contains(join))
remd = remove(join); remd = remove(join);
} }
@ -318,8 +317,8 @@ class JoinSet {
public boolean containsAll(JoinSet js) { public boolean containsAll(JoinSet js) {
if (js._size > _size || js._graph.size() > _graph.size()) if (js._size > _size || js._graph.size() > _graph.size())
return false; return false;
for (Iterator itr = js.iterator(); itr.hasNext();) for (Iterator<Join> itr = js.iterator(); itr.hasNext();)
if (!contains((Join) itr.next())) if (!contains(itr.next()))
return false; return false;
return true; return true;
} }
@ -347,7 +346,7 @@ class JoinSet {
public String toString() { public String toString() {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
buf.append("["); buf.append("[");
for (Iterator itr = iterator(); itr.hasNext();) { for (Iterator<Join> itr = iterator(); itr.hasNext();) {
buf.append("<").append(itr.next()).append(">"); buf.append("<").append(itr.next()).append(">");
if (itr.hasNext()) if (itr.hasNext())
buf.append(", "); buf.append(", ");

View File

@ -102,4 +102,10 @@ public interface Joins {
* Move joins that belong to subquery's parent * Move joins that belong to subquery's parent
*/ */
public void moveJoinsToParent(); public void moveJoinsToParent();
/**
* Gets the current path as a mutable string.
* @return
*/
public StringBuilder path();
} }

View File

@ -915,6 +915,10 @@ public class LogicalUnion
public DBDictionary getDictionary() { public DBDictionary getDictionary() {
return dict; return dict;
} }
public boolean isReadOnly() {
return sel.isReadOnly();
}
} }
/** /**

View File

@ -584,4 +584,25 @@ public final class SQLBuffer
} }
} }
/**
* 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;
}
} }

View File

@ -751,22 +751,42 @@ public interface Select
/** /**
* Set joined table metadatas for polymorphic queries * Set joined table metadatas for polymorphic queries
*/ */
public void setJoinedTableClassMeta(List meta); public void setJoinedTableClassMeta(List<ClassMapping> meta);
/** /**
* get joined table metadatas for polymorphic queries * get joined table metadatas for polymorphic queries
*/ */
public List getJoinedTableClassMeta(); public List<ClassMapping> getJoinedTableClassMeta();
/** /**
* Set joined table metadatas excluded for polymorphic queries * Set joined table metadatas excluded for polymorphic queries
*/ */
public void setExcludedJoinedTableClassMeta(List meta); public void setExcludedJoinedTableClassMeta(List<ClassMapping> meta);
/** /**
* get joined table metadatas excluded for polymorphic queries * get joined table metadatas excluded for polymorphic queries
*/ */
public List getExcludedJoinedTableClassMeta(); public List<ClassMapping> getExcludedJoinedTableClassMeta();
/**
* Gets the database dictionary used by this select to form the target SQL
* statement.
*
* @return the immutable database dictionary.
*/
public DBDictionary getDictionary() ; public DBDictionary getDictionary() ;
/**
* 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();
} }

View File

@ -39,7 +39,6 @@ import java.util.Stack;
import java.util.TreeMap; import java.util.TreeMap;
import org.apache.commons.collections.iterators.EmptyIterator; import org.apache.commons.collections.iterators.EmptyIterator;
import org.apache.commons.lang.StringUtils;
import org.apache.openjpa.jdbc.conf.JDBCConfiguration; import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.jdbc.kernel.EagerFetchModes; import org.apache.openjpa.jdbc.kernel.EagerFetchModes;
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration; import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
@ -117,15 +116,15 @@ public class SelectImpl
// field of type Address: // field of type Address:
// 'address.street' should map to a different table alias than // 'address.street' should map to a different table alias than
// 'parent.address.street' for the purposes of comparisons // 'parent.address.street' for the purposes of comparisons
private Map _aliases = null; private Map<Object,Integer> _aliases = null;
// map of indexes to table aliases like 'TABLENAME t0' // map of indexes to table aliases like 'TABLENAME t0'
private SortedMap _tables = null; private SortedMap<Integer,String> _tables = null;
// combined list of selected ids and map of each id to its alias // combined list of selected ids and map of each id to its alias
protected final Selects _selects = newSelects(); protected final Selects _selects = newSelects();
private List _ordered = null; private List<Object> _ordered = null;
private List _grouped = null; private List<Object> _grouped = null;
// flags // flags
private int _flags = 0; private int _flags = 0;
@ -147,15 +146,15 @@ public class SelectImpl
// joins to add to the end of our where clause, and joins to prepend to // joins to add to the end of our where clause, and joins to prepend to
// all selects (see select(classmapping) method) // all selects (see select(classmapping) method)
private SelectJoins _joins = null; private SelectJoins _joins = null;
private Stack _preJoins = null; private Stack<PathJoins> _preJoins = null;
// map of joins+keys to eager selects and global set of eager keys; the // map of joins+keys to eager selects and global set of eager keys; the
// same key can't be used more than once // same key can't be used more than once
private Map _eager = null; private Map<Object,SelectExecutor> _eager = null;
private Set _eagerKeys = null; private Set<FieldMapping> _eagerKeys = null;
// subselect support // subselect support
private List<SelectImpl> _subsels = null; private List<Select> _subsels = null;
private SelectImpl _parent = null; private SelectImpl _parent = null;
private String _subPath = null; private String _subPath = null;
private boolean _hasSub = false; private boolean _hasSub = false;
@ -170,8 +169,10 @@ public class SelectImpl
// A path navigation is begin with this schema alias // A path navigation is begin with this schema alias
private String _schemaAlias = null; private String _schemaAlias = null;
private ClassMapping _tpcMeta = null; private ClassMapping _tpcMeta = null;
private List _joinedTables = null; private List<ClassMapping> _joinedTables = null;
private List _exJoinedTables = null; private List<ClassMapping> _exJoinedTables = null;
private boolean _readOnly = false;
public ClassMapping getTablePerClassMeta() { public ClassMapping getTablePerClassMeta() {
return _tpcMeta; return _tpcMeta;
@ -180,19 +181,19 @@ public class SelectImpl
_tpcMeta = meta; _tpcMeta = meta;
} }
public void setJoinedTableClassMeta(List meta) { public void setJoinedTableClassMeta(List<ClassMapping> meta) {
_joinedTables = meta; _joinedTables = meta;
} }
public List getJoinedTableClassMeta() { public List<ClassMapping> getJoinedTableClassMeta() {
return _joinedTables; return _joinedTables;
} }
public void setExcludedJoinedTableClassMeta(List meta) { public void setExcludedJoinedTableClassMeta(List<ClassMapping> meta) {
_exJoinedTables = meta; _exJoinedTables = meta;
} }
public List getExcludedJoinedTableClassMeta() { public List<ClassMapping> getExcludedJoinedTableClassMeta() {
return _exJoinedTables; return _exJoinedTables;
} }
@ -341,10 +342,8 @@ public class SelectImpl
public boolean hasMultipleSelects() { public boolean hasMultipleSelects() {
if (_eager == null) if (_eager == null)
return false; return false;
Map.Entry entry; for (Iterator<Map.Entry<Object,SelectExecutor>> itr = _eager.entrySet().iterator(); itr.hasNext();) {
for (Iterator itr = _eager.entrySet().iterator(); itr.hasNext();) { if (itr.next().getValue() != this)
entry = (Map.Entry) itr.next();
if (entry.getValue() != this)
return true; return true;
} }
return false; return false;
@ -429,9 +428,13 @@ public class SelectImpl
try { conn.close(); } catch (SQLException se2) {} try { conn.close(); } catch (SQLException se2) {}
throw se; throw se;
} }
return getEagerResult(conn, stmnt, rs, store, fetch, forUpdate, sql); try {
return getEagerResult(conn, stmnt, rs, store, fetch, forUpdate, sql);
} finally {
makeReadOnly();
}
} }
/** /**
* Execute our eager selects, adding the results under the same keys * Execute our eager selects, adding the results under the same keys
* to the given result. * to the given result.
@ -443,11 +446,9 @@ public class SelectImpl
return; return;
// execute eager selects // execute eager selects
Map.Entry entry;
Result eres; Result eres;
Map eager; Map<Object,Object> eager;
for (Iterator itr = sel._eager.entrySet().iterator(); itr.hasNext();) { for (Map.Entry<Object,SelectExecutor> entry : sel._eager.entrySet()) {
entry = (Map.Entry) itr.next();
// simulated batched selects for inner/outer joins; for separate // simulated batched selects for inner/outer joins; for separate
// selects, don't pass on lock level, because they're probably // selects, don't pass on lock level, because they're probably
@ -455,12 +456,11 @@ public class SelectImpl
if (entry.getValue() == sel) if (entry.getValue() == sel)
eres = res; eres = res;
else else
eres = ((SelectExecutor) entry.getValue()).execute(store, eres = entry.getValue().execute(store, fetch);
fetch);
eager = res.getEagerMap(false); eager = res.getEagerMap(false);
if (eager == null) { if (eager == null) {
eager = new HashMap(); eager = new HashMap<Object,Object>();
res.setEagerMap(eager); res.setEagerMap(eager);
} }
eager.put(entry.getKey(), eres); eager.put(entry.getKey(), eres);
@ -547,8 +547,10 @@ public class SelectImpl
return 0; return 0;
} }
public List getSubselects() { public List<Select> getSubselects() {
return (_subsels == null) ? Collections.EMPTY_LIST : _subsels; if (_subsels == null)
return Collections.emptyList();
return _subsels;
} }
public Select getParent() { public Select getParent() {
@ -579,7 +581,7 @@ public class SelectImpl
_parent = (SelectImpl) parent; _parent = (SelectImpl) parent;
if (_parent != null) { if (_parent != null) {
if (_parent._subsels == null) if (_parent._subsels == null)
_parent._subsels = new ArrayList(2); _parent._subsels = new ArrayList<Select>(2);
_parent._subsels.add(this); _parent._subsels.add(this);
if (_parent._joinSyntax == JoinSyntaxes.SYNTAX_SQL92) if (_parent._joinSyntax == JoinSyntaxes.SYNTAX_SQL92)
_joinSyntax = JoinSyntaxes.SYNTAX_TRADITIONAL; _joinSyntax = JoinSyntaxes.SYNTAX_TRADITIONAL;
@ -596,7 +598,7 @@ public class SelectImpl
return _hasSub; return _hasSub;
} }
public Map getAliases() { public Map<Object,Integer> getAliases() {
return _aliases; return _aliases;
} }
@ -604,7 +606,7 @@ public class SelectImpl
_aliases.remove(key); _aliases.remove(key);
} }
public Map getTables() { public Map<Integer,String> getTables() {
return _tables; return _tables;
} }
@ -641,19 +643,21 @@ public class SelectImpl
return getTableIndex(table, pj, false) != -1; return getTableIndex(table, pj, false) != -1;
} }
public Collection getTableAliases() { public Collection<String> getTableAliases() {
return (_tables == null) ? Collections.EMPTY_SET : _tables.values(); if (_tables == null)
return Collections.emptySet();
return _tables.values();
} }
public List getSelects() { public List<Object> getSelects() {
return Collections.unmodifiableList(_selects); return Collections.unmodifiableList(_selects);
} }
public List getSelectAliases() { public List<Object> getSelectAliases() {
return _selects.getAliases(false, _outer != null); return _selects.getAliases(false, _outer != null);
} }
public List getIdentifierAliases() { public List<Object> getIdentifierAliases() {
return _selects.getAliases(true, _outer != null); return _selects.getAliases(true, _outer != null);
} }
@ -679,8 +683,8 @@ public class SelectImpl
// join set iterator allows concurrent modification // join set iterator allows concurrent modification
Join j; Join j;
for (Iterator itr = _joins.joins().iterator(); itr.hasNext();) { for (Iterator<Join> itr = _joins.joins().iterator(); itr.hasNext();) {
j = (Join) itr.next(); j = itr.next();
if (j.getRelationTarget() != null) { if (j.getRelationTarget() != null) {
j.getRelationTarget().getDiscriminator().addClassConditions j.getRelationTarget().getDiscriminator().addClassConditions
(this, j.getSubclasses() == SUBS_JOINABLE, (this, j.getSubclasses() == SUBS_JOINABLE,
@ -694,7 +698,7 @@ public class SelectImpl
return _joins; return _joins;
} }
public Iterator getJoinIterator() { public Iterator<Join> getJoinIterator() {
if (_joins == null || _joins.isEmpty()) if (_joins == null || _joins.isEmpty())
return EmptyIterator.INSTANCE; return EmptyIterator.INSTANCE;
return _joins.joins().joinIterator(); return _joins.joins().joinIterator();
@ -742,9 +746,9 @@ public class SelectImpl
public String getColumnAlias(Column col, Object path) { public String getColumnAlias(Column col, Object path) {
Table table = col.getTable(); Table table = col.getTable();
String tableAlias = null; String tableAlias = null;
Iterator itr = getJoinIterator(); Iterator<Join> itr = getJoinIterator();
while (itr.hasNext()) { while (itr.hasNext()) {
Join join = (Join) itr.next(); Join join = itr.next();
if (join != null) { if (join != null) {
if (join.getTable1() == table) if (join.getTable1() == table)
tableAlias = join.getAlias1(); tableAlias = join.getAlias1();
@ -951,6 +955,7 @@ public class SelectImpl
void select(Select wrapper, ClassMapping mapping, int subclasses, void select(Select wrapper, ClassMapping mapping, int subclasses,
JDBCStore store, JDBCFetchConfiguration fetch, int eager, JDBCStore store, JDBCFetchConfiguration fetch, int eager,
Joins joins, boolean ident) { Joins joins, boolean ident) {
assertMutable();
// note that this is one case where we don't want to use the result // note that this is one case where we don't want to use the result
// of getJoins(); just use the given joins, which will either be clean // of getJoins(); just use the given joins, which will either be clean
// or the result of previous pre-joins. this way we don't push extra // or the result of previous pre-joins. this way we don't push extra
@ -967,7 +972,7 @@ public class SelectImpl
boolean hasJoins = pj != null && pj.isDirty(); boolean hasJoins = pj != null && pj.isDirty();
if (hasJoins) { if (hasJoins) {
if (_preJoins == null) if (_preJoins == null)
_preJoins = new Stack(); _preJoins = new Stack<PathJoins>();
_preJoins.push(pj); _preJoins.push(pj);
} }
@ -1098,6 +1103,7 @@ public class SelectImpl
*/ */
private boolean columnOperation(Column col, boolean sel, Boolean asc, private boolean columnOperation(Column col, boolean sel, Boolean asc,
PathJoins pj, boolean aliasOrder) { PathJoins pj, boolean aliasOrder) {
assertMutable();
String as = null; String as = null;
if (asc != null && (aliasOrder || (_flags & RECORD_ORDERED) != 0)) { if (asc != null && (aliasOrder || (_flags & RECORD_ORDERED) != 0)) {
Object id; Object id;
@ -1107,7 +1113,7 @@ public class SelectImpl
id = getColumnAlias(col, pj); id = getColumnAlias(col, pj);
if ((_flags & RECORD_ORDERED) != 0) { if ((_flags & RECORD_ORDERED) != 0) {
if (_ordered == null) if (_ordered == null)
_ordered = new ArrayList(5); _ordered = new ArrayList<Object>(5);
_ordered.add(id); _ordered.add(id);
} }
if (aliasOrder) { if (aliasOrder) {
@ -1224,6 +1230,7 @@ public class SelectImpl
*/ */
private boolean orderBy(Object sql, boolean asc, Joins joins, boolean sel, private boolean orderBy(Object sql, boolean asc, Joins joins, boolean sel,
boolean aliasOrder, Value selAs) { boolean aliasOrder, Value selAs) {
assertMutable();
Object order = sql; Object order = sql;
if (aliasOrder) { if (aliasOrder) {
order = toOrderAlias(_orders++); order = toOrderAlias(_orders++);
@ -1231,7 +1238,7 @@ public class SelectImpl
} }
if ((_flags & RECORD_ORDERED) != 0) { if ((_flags & RECORD_ORDERED) != 0) {
if (_ordered == null) if (_ordered == null)
_ordered = new ArrayList(5); _ordered = new ArrayList<Object>(5);
_ordered.add(selAs == null ? sql : selAs); _ordered.add(selAs == null ? sql : selAs);
} }
@ -1284,10 +1291,10 @@ public class SelectImpl
* Return the indexes in the select list of all items we're ordering * Return the indexes in the select list of all items we're ordering
* by, or null if none. For use with unions. * by, or null if none. For use with unions.
*/ */
List getOrderedIndexes() { List<Integer> getOrderedIndexes() {
if (_ordered == null) if (_ordered == null)
return null; return null;
List idxs = new ArrayList(_ordered.size()); List<Integer> idxs = new ArrayList<Integer>(_ordered.size());
for (int i = 0; i < _ordered.size(); i++) for (int i = 0; i < _ordered.size(); i++)
idxs.add(_selects.indexOf(_ordered.get(i))); idxs.add(_selects.indexOf(_ordered.get(i)));
return idxs; return idxs;
@ -1376,15 +1383,16 @@ public class SelectImpl
} }
SQLBuffer buf = new SQLBuffer(_dict); SQLBuffer buf = isReadOnly() ? _where : new SQLBuffer(_dict);
Object[] params = getBindParameter(oid, mapping, toCols, fromCols, pj, store); Object[] params = getBindParameter(oid, mapping, toCols, fromCols, pj, store);
bindParameter(buf, params, fromCols, pj); bindParameter(buf, params, fromCols, pj);
if (constCols != null && constCols.length > 0) { if (constCols != null && constCols.length > 0) {
bindParameter(buf, vals, constCols, pj); bindParameter(buf, vals, constCols, pj);
} }
if (buf != _where) {
where(buf, pj); where(buf, pj);
}
} }
/** /**
@ -1423,16 +1431,26 @@ public class SelectImpl
/** /**
* Binds the parameters to the given SQL buffer. * Binds the parameters to the given SQL buffer.
* @param buf * @param buf a sql buffer
* @param params * @param params the parameter values to bind
* @param fromCols * @param fromCols the corresponding columns to which the parameters bind. Same size of the values.
* @param pj * @param pj the joins, if any, for the columns
*/ */
void bindParameter(SQLBuffer buf, Object[] params, Column[] fromCols, PathJoins pj) { void bindParameter(SQLBuffer buf, Object[] params, Column[] fromCols, PathJoins pj) {
if (isReadOnly()) {
for (int i = 0; i < params.length; i++) {
buf.bind(params[i], fromCols[i]);
}
return;
}
for (int i = 0; i < params.length; i++) { for (int i = 0; i < params.length; i++) {
if (i > 0) if (i > 0)
buf.append(" AND "); buf.append(" AND ");
buf.append(getColumnAlias(fromCols[i], pj)); buf.append(getColumnAlias(fromCols[i], pj));
// WARNING: Potential bug hides here
// A parameter value appearing as null and non-null in two binding operation
// will expose this bug. Requires more structure to BindParameter to accept
// an opcode.
buf.append(params[i] == null ? " IS " : " = "); buf.append(params[i] == null ? " IS " : " = ");
buf.appendValue(params[i], fromCols[i]); buf.appendValue(params[i], fromCols[i]);
} }
@ -1551,7 +1569,7 @@ public class SelectImpl
if (_grouped == null || !_grouped.contains(sql)) { if (_grouped == null || !_grouped.contains(sql)) {
if (_grouping == null) { if (_grouping == null) {
_grouping = new SQLBuffer(_dict); _grouping = new SQLBuffer(_dict);
_grouped = new ArrayList(); _grouped = new ArrayList<Object>();
} else } else
_grouping.append(", "); _grouping.append(", ");
@ -1590,7 +1608,7 @@ public class SelectImpl
private boolean isGrouping() { private boolean isGrouping() {
return (_flags & GROUPING) != 0; return (_flags & GROUPING) != 0;
} }
/** /**
* Return the joins to use for column aliases, etc. * Return the joins to use for column aliases, etc.
* *
@ -1602,7 +1620,7 @@ public class SelectImpl
boolean pre = (pj == null || !pj.isDirty()) boolean pre = (pj == null || !pj.isDirty())
&& _preJoins != null && !_preJoins.isEmpty(); && _preJoins != null && !_preJoins.isEmpty();
if (pre) if (pre)
pj = (PathJoins) _preJoins.peek(); pj = (PathJoins)_preJoins.peek();
if (pj == null || !pj.isDirty()) if (pj == null || !pj.isDirty())
pj = _joins; pj = _joins;
@ -1641,9 +1659,9 @@ public class SelectImpl
sel._joinSyntax = _joinSyntax; sel._joinSyntax = _joinSyntax;
sel._schemaAlias = _schemaAlias; sel._schemaAlias = _schemaAlias;
if (_aliases != null) if (_aliases != null)
sel._aliases = new HashMap(_aliases); sel._aliases = new HashMap<Object,Integer>(_aliases);
if (_tables != null) if (_tables != null)
sel._tables = new TreeMap(_tables); sel._tables = new TreeMap<Integer,String>(_tables);
if (_joins != null) if (_joins != null)
sel._joins = _joins.clone(sel); sel._joins = _joins.clone(sel);
if (_where != null) if (_where != null)
@ -1653,7 +1671,7 @@ public class SelectImpl
sel._from._outer = sel; sel._from._outer = sel;
} }
if (_subsels != null) { if (_subsels != null) {
sel._subsels = new ArrayList(_subsels.size()); sel._subsels = new ArrayList<Select>(_subsels.size());
SelectImpl sub, selSub; SelectImpl sub, selSub;
for (int j = 0; j < _subsels.size(); j++) { for (int j = 0; j < _subsels.size(); j++) {
sub = (SelectImpl) _subsels.get(j); sub = (SelectImpl) _subsels.get(j);
@ -1717,7 +1735,7 @@ public class SelectImpl
// global set of eager keys // global set of eager keys
if (_eagerKeys == null) if (_eagerKeys == null)
_eagerKeys = new HashSet(); _eagerKeys = new HashSet<FieldMapping>();
_eagerKeys.add(key); _eagerKeys.add(key);
SelectExecutor sel; SelectExecutor sel;
@ -1737,7 +1755,7 @@ public class SelectImpl
} }
if (_eager == null) if (_eager == null)
_eager = new HashMap(); _eager = new HashMap<Object,SelectExecutor>();
_eager.put(toEagerKey(key, getJoins(null, false)), sel); _eager.put(toEagerKey(key, getJoins(null, false)), sel);
return sel; return sel;
} }
@ -1750,9 +1768,8 @@ public class SelectImpl
sel._flags &= ~NONAUTO_DISTINCT; sel._flags &= ~NONAUTO_DISTINCT;
sel._eagerKeys = _eagerKeys; sel._eagerKeys = _eagerKeys;
if (_preJoins != null && !_preJoins.isEmpty()) { if (_preJoins != null && !_preJoins.isEmpty()) {
sel._preJoins = new Stack(); sel._preJoins = new Stack<PathJoins>();
sel._preJoins.push(((SelectJoins) _preJoins.peek()). sel._preJoins.push(((SelectJoins) _preJoins.peek()).clone(sel));
clone(sel));
} }
return sel; return sel;
} }
@ -1760,7 +1777,7 @@ public class SelectImpl
/** /**
* Return view of eager selects. May be null. * Return view of eager selects. May be null.
*/ */
public Map getEagerMap() { public Map<Object,SelectExecutor> getEagerMap() {
return _eager; return _eager;
} }
@ -1809,9 +1826,9 @@ public class SelectImpl
if (!buf.isEmpty()) if (!buf.isEmpty())
buf.append(" AND "); buf.append(" AND ");
Join join = null; Join join = null;
for (Iterator itr = ((PathJoins) joins).joins().joinIterator(); for (Iterator<Join> itr = ((PathJoins) joins).joins().joinIterator();
itr.hasNext();) { itr.hasNext();) {
join = (Join) itr.next(); join = itr.next();
switch (_joinSyntax) { switch (_joinSyntax) {
case JoinSyntaxes.SYNTAX_TRADITIONAL: case JoinSyntaxes.SYNTAX_TRADITIONAL:
buf.append(_dict.toTraditionalJoin(join)); buf.append(_dict.toTraditionalJoin(join));
@ -1936,8 +1953,8 @@ public class SelectImpl
Join join; Join join;
Join rec; Join rec;
boolean hasJoins = _joins != null && _joins.joins() != null; boolean hasJoins = _joins != null && _joins.joins() != null;
for (Iterator itr = pj.joins().iterator(); itr.hasNext();) { for (Iterator<Join> itr = pj.joins().iterator(); itr.hasNext();) {
join = (Join) itr.next(); join = itr.next();
if (join.getType() == Join.TYPE_INNER) { if (join.getType() == Join.TYPE_INNER) {
if (!hasJoins) if (!hasJoins)
join.setType(Join.TYPE_OUTER); join.setType(Join.TYPE_OUTER);
@ -1969,8 +1986,8 @@ public class SelectImpl
} }
Join join; Join join;
for (Iterator itr = pj.joins().iterator(); itr.hasNext();) { for (Iterator<Join> itr = pj.joins().iterator(); itr.hasNext();) {
join = (Join) itr.next(); join = itr.next();
if (join.getType() == Join.TYPE_INNER) { if (join.getType() == Join.TYPE_INNER) {
if (join.getForeignKey() != null if (join.getForeignKey() != null
&& !_dict.canOuterJoin(_joinSyntax, join.getForeignKey())) { && !_dict.canOuterJoin(_joinSyntax, join.getForeignKey())) {
@ -1999,7 +2016,7 @@ public class SelectImpl
Integer i = null; Integer i = null;
Object key = table.getFullIdentifier().getName(); Object key = table.getFullIdentifier().getName();
if (pj != null && pj.path() != null) if (pj != null && pj.path() != null)
key = new Key(pj.getPathStr(), key); key = new Key(pj.path().toString(), key);
if (_ctx != null && (_parent != null || _subsels != null || _hasSub)) { if (_ctx != null && (_parent != null || _subsels != null || _hasSub)) {
i = findAliasForQuery(table, pj, key, create); i = findAliasForQuery(table, pj, key, create);
@ -2067,11 +2084,11 @@ public class SelectImpl
(corrVar == null || (thisCtx != null && ctx() == thisCtx))); (corrVar == null || (thisCtx != null && ctx() == thisCtx)));
} }
/**
* Find the alias for the key starting lookup in this instance only.
*/
private Integer getAlias(Table table, Object key) { private Integer getAlias(Table table, Object key) {
Integer alias = null; return _aliases == null ? null : _aliases.get(key);
if (_aliases != null)
alias = (Integer) _aliases.get(key);
return alias;
} }
private int createAlias(Table table, Object key) { private int createAlias(Table table, Object key) {
@ -2080,21 +2097,16 @@ public class SelectImpl
return i.intValue(); return i.intValue();
} }
/**
* Find the alias for the key starting lookup in this instance and searching the parents
* as well if necessary.
*/
private Integer findAlias(Table table, Object key) { private Integer findAlias(Table table, Object key) {
Integer alias = null; Integer alias = getAlias(table, key);
if (_aliases != null) { if (alias != null) {
alias = (Integer) _aliases.get(key); return alias;
if (alias != null) {
return alias;
}
} }
if (_parent != null) { return (_parent != null) ? _parent.findAlias(table, key) : null;
alias = _parent.findAlias(table, key);
if (alias != null) {
return alias;
}
}
return alias;
} }
/** /**
@ -2102,13 +2114,13 @@ public class SelectImpl
*/ */
private void recordTableAlias(Table table, Object key, Integer alias) { private void recordTableAlias(Table table, Object key, Integer alias) {
if (_aliases == null) if (_aliases == null)
_aliases = new HashMap(); _aliases = new HashMap<Object,Integer>();
_aliases.put(key, alias); _aliases.put(key, alias);
String tableString = _dict.getFullName(table, false) + " " String tableString = _dict.getFullName(table, false) + " "
+ toAlias(alias.intValue()); + toAlias(alias.intValue());
if (_tables == null) if (_tables == null)
_tables = new TreeMap(); _tables = new TreeMap<Integer,String>();
_tables.put(alias, tableString); _tables.put(alias, tableString);
} }
@ -2122,9 +2134,9 @@ public class SelectImpl
int aliases = (fromParent || _parent == null) ? 0 : _parent.aliasSize(false, this); int aliases = (fromParent || _parent == null) ? 0 : _parent.aliasSize(false, this);
aliases += (_aliases == null) ? 0 : _aliases.size(); aliases += (_aliases == null) ? 0 : _aliases.size();
if (_subsels != null) { if (_subsels != null) {
for (SelectImpl sub : _subsels) { for (Select sub : _subsels) {
if (sub != fromSub) if (sub != fromSub)
aliases += sub.aliasSize(true, null); aliases += ((SelectImpl)sub).aliasSize(true, null);
} }
} }
return aliases; return aliases;
@ -2264,10 +2276,6 @@ public class SelectImpl
public String toString() { public String toString() {
return _path + "|" + _key; return _path + "|" + _key;
} }
Object getKey() {
return _key;
}
} }
/** /**
@ -2278,11 +2286,11 @@ public class SelectImpl
implements PathJoins { implements PathJoins {
private SelectImpl _sel = null; private SelectImpl _sel = null;
private Map<Column, Object> cachedColumnAlias_ = null; private Map<Column, Object> _cachedColumnAlias = null;
// position in selected columns list where we expect the next load // position in selected columns list where we expect the next load
private int _pos = 0; private int _pos = 0;
private Stack _preJoins = null; private Stack<Joins> _preJoins = null;
/** /**
* Constructor. * Constructor.
@ -2291,7 +2299,7 @@ public class SelectImpl
DBDictionary dict) { DBDictionary dict) {
super(conn, stmnt, rs, dict); super(conn, stmnt, rs, dict);
} }
/** /**
* Select for this result. * Select for this result.
*/ */
@ -2311,29 +2319,28 @@ public class SelectImpl
// eager results // eager results
if (_sel._eager == null || !_sel._eagerKeys.contains(key)) if (_sel._eager == null || !_sel._eagerKeys.contains(key))
return null; return null;
Map map = SelectResult.this.getEagerMap(true); Map<Object,Object> map = SelectResult.this.getEagerMap(true);
if (map == null) if (map == null)
return null; return null;
return map.get(_sel.toEagerKey(key, getJoins(null))); return map.get(SelectImpl.toEagerKey(key, getJoins(null)));
} }
public void putEager(FieldMapping key, Object res) { public void putEager(FieldMapping key, Object res) {
Map map = SelectResult.this.getEagerMap(true); Map<Object,Object> map = SelectResult.this.getEagerMap(true);
if (map == null) { if (map == null) {
map = new HashMap(); map = new HashMap<Object,Object>();
setEagerMap(map); setEagerMap(map);
} }
map.put(_sel.toEagerKey(key, getJoins(null)), res); map.put(SelectImpl.toEagerKey(key, getJoins(null)), res);
} }
public Object load(ClassMapping mapping, JDBCStore store, public Object load(ClassMapping mapping, JDBCStore store,
JDBCFetchConfiguration fetch, Joins joins) JDBCFetchConfiguration fetch, Joins joins)
throws SQLException { throws SQLException {
boolean hasJoins = joins != null boolean hasJoins = joins != null && ((PathJoins) joins).path() != null;
&& ((PathJoins) joins).path() != null;
if (hasJoins) { if (hasJoins) {
if (_preJoins == null) if (_preJoins == null)
_preJoins = new Stack(); _preJoins = new Stack<Joins>();
_preJoins.push(joins); _preJoins.push(joins);
} }
@ -2362,9 +2369,9 @@ public class SelectImpl
if (pj != null && pj.path() != null) { if (pj != null && pj.path() != null) {
Object columnAlias = getColumnAlias((Column) obj, pj); Object columnAlias = getColumnAlias((Column) obj, pj);
if (joins == null) { if (joins == null) {
if (cachedColumnAlias_ == null) if (_cachedColumnAlias == null)
cachedColumnAlias_ = new HashMap<Column, Object>(); _cachedColumnAlias = new HashMap<Column, Object>();
cachedColumnAlias_.put((Column) obj, columnAlias); _cachedColumnAlias.put((Column) obj, columnAlias);
} }
return columnAlias != null && _sel._selects.contains(columnAlias); return columnAlias != null && _sel._selects.contains(columnAlias);
} }
@ -2416,8 +2423,8 @@ public class SelectImpl
if (pj != null && pj.path() != null) { if (pj != null && pj.path() != null) {
Column col = (Column) obj; Column col = (Column) obj;
pk = (col.isPrimaryKey()) ? Boolean.TRUE : Boolean.FALSE; pk = (col.isPrimaryKey()) ? Boolean.TRUE : Boolean.FALSE;
if (joins == null && cachedColumnAlias_ != null) { if (joins == null && _cachedColumnAlias != null) {
obj = cachedColumnAlias_.get(col); obj = _cachedColumnAlias.get(col);
if (obj == null) if (obj == null)
obj = getColumnAlias(col, pj); obj = getColumnAlias(col, pj);
} else { } else {
@ -2468,6 +2475,8 @@ public class SelectImpl
/** /**
* Return the joins to use to find column data. * Return the joins to use to find column data.
* If the given join is non-null and has a path then it is returned.
* Otherwise, returns the {@link #getPreJoins() pre joins}.
*/ */
private PathJoins getJoins(Joins joins) { private PathJoins getJoins(Joins joins) {
PathJoins pj = (PathJoins) joins; PathJoins pj = (PathJoins) joins;
@ -2477,7 +2486,7 @@ public class SelectImpl
} }
/** /**
* Return the pre joins for the result, or null if none. Note that * Return the pre joins for this result, or null if none. Note that
* we have to take the Select's pre joins into account too, since * we have to take the Select's pre joins into account too, since
* batched selects can have additional pre joins on the stack even * batched selects can have additional pre joins on the stack even
* on execution. * on execution.
@ -2497,15 +2506,14 @@ public class SelectImpl
private String getColumnAlias(Column col, PathJoins pj) { private String getColumnAlias(Column col, PathJoins pj) {
String alias; String alias;
if (_sel._from != null) { if (_sel._from != null) {
alias = _sel.toAlias(_sel._from.getTableIndex alias = SelectImpl.toAlias(_sel._from.getTableIndex(col.getTable(), pj, false));
(col.getTable(), pj, false));
if (alias == null) if (alias == null)
return null; return null;
if (_sel._dict.requiresAliasForSubselect) if (_sel._dict.requiresAliasForSubselect)
return FROM_SELECT_ALIAS + "." + alias + "_" + col; return FROM_SELECT_ALIAS + "." + alias + "_" + col;
return alias + "_" + col; return alias + "_" + col;
} }
alias = _sel.toAlias(_sel.getTableIndex(col.getTable(), pj, false)); alias = SelectImpl.toAlias(_sel.getTableIndex(col.getTable(), pj, false));
return (alias == null) ? null : alias + "." + col; return (alias == null) ? null : alias + "." + col;
} }
@ -2611,7 +2619,6 @@ public class SelectImpl
protected String correlatedVar = null; protected String correlatedVar = null;
protected Context context = null; protected Context context = null;
protected Context lastContext = null; protected Context lastContext = null;
protected String pathStr = null;
public Select getSelect() { public Select getSelect() {
return null; return null;
@ -2649,10 +2656,6 @@ public class SelectImpl
return this; return this;
} }
public String getVariable() {
return var;
}
public Joins setCorrelatedVariable(String var) { public Joins setCorrelatedVariable(String var) {
this.correlatedVar = var; this.correlatedVar = var;
return this; return this;
@ -2716,20 +2719,12 @@ public class SelectImpl
path = new StringBuilder(str); path = new StringBuilder(str);
else else
path.append('.').append(str); path.append('.').append(str);
pathStr = null;
} }
} }
public String getPathStr() {
if (pathStr == null) {
pathStr = path.toString();
}
return pathStr;
}
public String toString() { public String toString() {
return "PathJoinsImpl<" + hashCode() + ">: " return "PathJoinsImpl<" + hashCode() + ">: " + String.valueOf(path);
+ String.valueOf(path);
} }
public void moveJoinsToParent() { public void moveJoinsToParent() {
@ -2937,25 +2932,24 @@ public class SelectImpl
return; return;
} }
Object aliases[] = _sel._aliases.values().toArray(); Integer aliases[] = _sel._aliases.values().toArray(new Integer[_sel._aliases.size()]);
boolean found1 = false; boolean found1 = false;
boolean found2 = false; boolean found2 = false;
for (int i = 0; i < aliases.length; i++) { for (int i = 0; i < aliases.length; i++) {
int alias = ((Integer)aliases[i]).intValue(); int alias = aliases[i].intValue();
if (alias == j.getIndex1()) if (alias == j.getIndex1())
found1 = true; found1 = true;
if (alias == j.getIndex2()) if (alias == j.getIndex2())
found2 = true; found2 = true;
} }
if (found1 && found2) if (found1 && found2) {
return; return;
else if (!found1 && !found2) { } else if (!found1 && !found2) {
j.setIsNotMyJoin(); j.setIsNotMyJoin();
return; return;
} } else {
else {
j.setCorrelated(); j.setCorrelated();
} }
} }
@ -2965,8 +2959,8 @@ public class SelectImpl
return; return;
Join j = null; Join j = null;
List<Join> removed = new ArrayList<Join>(5); List<Join> removed = new ArrayList<Join>(5);
for (Iterator itr = _joins.iterator(); itr.hasNext();) { for (Iterator<Join> itr = _joins.iterator(); itr.hasNext();) {
j = (Join) itr.next(); j = itr.next();
if (j.isNotMyJoin()) { if (j.isNotMyJoin()) {
addJoinsToParent(_sel._parent, j); addJoinsToParent(_sel._parent, j);
removed.add(j); removed.add(j);
@ -3035,12 +3029,12 @@ public class SelectImpl
* the alias of each selected id. * the alias of each selected id.
*/ */
protected static class Selects protected static class Selects
extends AbstractList { extends AbstractList<Object> {
protected List _ids = null; protected List<Object> _ids = null;
protected List _idents = null; protected List<Object> _idents = null;
protected Map _aliases = null; protected Map<Object,Object> _aliases = null;
protected Map _selectAs = null; protected Map<Object,String> _selectAs = null;
protected DBDictionary _dict = null; protected DBDictionary _dict = null;
/** /**
@ -3048,22 +3042,22 @@ public class SelectImpl
*/ */
public void addAll(Selects sels) { public void addAll(Selects sels) {
if (_ids == null && sels._ids != null) if (_ids == null && sels._ids != null)
_ids = new ArrayList(sels._ids); _ids = new ArrayList<Object>(sels._ids);
else if (sels._ids != null) else if (sels._ids != null)
_ids.addAll(sels._ids); _ids.addAll(sels._ids);
if (_idents == null && sels._idents != null) if (_idents == null && sels._idents != null)
_idents = new ArrayList(sels._idents); _idents = new ArrayList<Object>(sels._idents);
else if (sels._idents != null) else if (sels._idents != null)
_idents.addAll(sels._idents); _idents.addAll(sels._idents);
if (_aliases == null && sels._aliases != null) if (_aliases == null && sels._aliases != null)
_aliases = new HashMap(sels._aliases); _aliases = new HashMap<Object,Object>(sels._aliases);
else if (sels._aliases != null) else if (sels._aliases != null)
_aliases.putAll(sels._aliases); _aliases.putAll(sels._aliases);
if (_selectAs == null && sels._selectAs != null) if (_selectAs == null && sels._selectAs != null)
_selectAs = new HashMap(sels._selectAs); _selectAs = new HashMap<Object,String>(sels._selectAs);
else if (sels._selectAs != null) else if (sels._selectAs != null)
_selectAs.putAll(sels._selectAs); _selectAs.putAll(sels._selectAs);
} }
@ -3080,8 +3074,8 @@ public class SelectImpl
*/ */
public int setAlias(Object id, Object alias, boolean ident) { public int setAlias(Object id, Object alias, boolean ident) {
if (_ids == null) { if (_ids == null) {
_ids = new ArrayList(); _ids = new ArrayList<Object>();
_aliases = new HashMap(); _aliases = new HashMap<Object,Object>();
} }
int idx; int idx;
@ -3093,7 +3087,7 @@ public class SelectImpl
if (ident) { if (ident) {
if (_idents == null) if (_idents == null)
_idents = new ArrayList(3); _idents = new ArrayList<Object>(3);
_idents.add(id); _idents.add(id);
} }
} }
@ -3136,11 +3130,11 @@ public class SelectImpl
* A list representation of the aliases, in select order, with * A list representation of the aliases, in select order, with
* AS aliases present. * AS aliases present.
*/ */
public List getAliases(final boolean ident, final boolean inner) { public List<Object> getAliases(final boolean ident, final boolean inner) {
if (_ids == null) if (_ids == null)
return Collections.EMPTY_LIST; return Collections.emptyList();
return new AbstractList() { return new AbstractList<Object>() {
public int size() { public int size() {
return (ident && _idents != null) ? _idents.size() return (ident && _idents != null) ? _idents.size()
: _ids.size(); : _ids.size();
@ -3181,7 +3175,7 @@ public class SelectImpl
*/ */
public void setSelectAs(Object id, String as) { public void setSelectAs(Object id, String as) {
if (_selectAs == null) if (_selectAs == null)
_selectAs = new HashMap((int) (5 * 1.33 + 1)); _selectAs = new HashMap<Object,String>((int) (5 * 1.33 + 1));
_selectAs.put(id, as); _selectAs.put(id, as);
} }
@ -3193,7 +3187,7 @@ public class SelectImpl
return; return;
Object id; Object id;
for (Iterator itr = _ids.iterator(); itr.hasNext();) { for (Iterator<Object> itr = _ids.iterator(); itr.hasNext();) {
id = itr.next(); id = itr.next();
if (id instanceof Placeholder) { if (id instanceof Placeholder) {
itr.remove(); itr.remove();
@ -3242,6 +3236,30 @@ public class SelectImpl
public void moveJoinsToParent() { public void moveJoinsToParent() {
} }
/**
* Affirms if this instance is (structurally) immutable.
*/
public boolean isReadOnly() {
return _readOnly;
}
/**
* Marks this instance immutable.
*/
private void makeReadOnly() {
_readOnly = true;
}
/**
* Raises illegal state exception if this instance is immutable.
*/
public void assertMutable() {
if (_readOnly) {
throw new IllegalStateException("Select@" + Integer.toHexString(System.identityHashCode(this)) +
" is read-only");
}
}
} }
/** /**
@ -3283,11 +3301,8 @@ interface PathJoins
public void nullJoins(); public void nullJoins();
/** /**
* The select owner of this join * Gets the select who owns this join.
* @return
*/ */
public Select getSelect(); public Select getSelect();
public String getPathStr();
} }