Cleanup and fixes to changes for OPENJPA-168.

git-svn-id: https://svn.apache.org/repos/asf/incubator/openjpa/trunk@523425 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
A. Abram White 2007-03-28 17:43:35 +00:00
parent 3a5d06436c
commit 1679c05c89
13 changed files with 123 additions and 213 deletions

View File

@ -43,7 +43,6 @@ import org.apache.openjpa.jdbc.sql.SQLExceptions;
import org.apache.openjpa.jdbc.sql.SQLFactory;
import org.apache.openjpa.jdbc.sql.Select;
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.kernel.FetchConfiguration;
import org.apache.openjpa.kernel.LockManager;
@ -370,10 +369,7 @@ public class JDBCStoreManager
JDBCFetchConfiguration.EAGER_JOIN, true, false))
return null;
sel.wherePrimaryKey(sm.getObjectId(), mapping, this);
// Set the expectedResultCount for the select as 1 as a single
// object is being loaded. force = true is an indicator that it is
// internally generated value
sel.setExpectedResultCount(1,true);
sel.setExpectedResultCount(1, false);
return sel.execute(this, fetch);
}
@ -389,7 +385,7 @@ public class JDBCStoreManager
JDBCFetchConfiguration.EAGER_JOIN);
Union union = _sql.newUnion(mappings.length);
union.setExpectedResultCount(1,true);
union.setExpectedResultCount(1, false);
if (fetch.getSubclassFetchMode(mapping) != fetch.EAGER_JOIN)
union.abortUnion();
union.select(new Union.Selector() {

View File

@ -310,32 +310,25 @@ public class JDBCStoreQuery
List selMappings, boolean subclasses, BitSet subclassBits,
BitSet nextBits, ExpressionFactory[] facts, QueryExpressions[] exps,
QueryExpressionsState[] states, ExpContext ctx, int subclassMode) {
Number optHint = (Number) ctx.fetch.getHint
(QueryHints.HINT_RESULT_COUNT);
ClassMapping[] verts;
boolean unionable = true;
Select sel;
Object optHint = null;
for (int i = 0; i < mappings.length; i++) {
// determine vertical mappings to select separately
verts = getVerticalMappings(mappings[i], subclasses, exps[i],
subclassMode);
if (verts.length == 1 && subclasses)
subclassBits.set(sels.size());
// create criteria select and clone for each vert mapping
sel = ((JDBCExpressionFactory) facts[i]).getSelectConstructor().
evaluate(ctx, null, null, exps[i], states[i]);
// It means it is coming from getSingleResult so set the
// expectedResultCount to 1.force = true indicates that this is
// internally generated value
if (this.ctx.isUnique())
sel.setExpectedResultCount(1,true);
// It means this is coming from getResultList so set the
// expectedResultCount based on any optimize hint if provided
else {
if ((optHint = ctx.fetch.getHint
(QueryHints.HINT_RESULT_COUNT))!= null)
sel.setExpectedResultCount
(((Integer)optHint).intValue(),false);
}
if (optHint != null)
sel.setExpectedResultCount(optHint.intValue(), true);
else if (this.ctx.isUnique())
sel.setExpectedResultCount(1, false);
for (int j = 0; j < verts.length; j++) {
selMappings.add(verts[j]);
if (j == verts.length - 1) {

View File

@ -236,9 +236,8 @@ class LRSProxyMap
final JDBCFetchConfiguration fetch = store.getFetchConfiguration();
final ClassMapping[] clss = _strat.getIndependentValueMappings(true);
final Joins[] resJoins = new Joins[Math.max(1, clss.length)];
Union union = store.getSQLFactory().newUnion
(Math.max(1, clss.length));
union.setExpectedResultCount(1,true);
Union union = store.getSQLFactory().newUnion(Math.max(1, clss.length));
union.setExpectedResultCount(1, false);
if (fetch.getSubclassFetchMode(_strat.getFieldMapping().
getElementMapping().getTypeMapping())
!= JDBCFetchConfiguration.EAGER_JOIN)

View File

@ -578,7 +578,7 @@ public class RelationFieldStrategy
// 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 = store.getSQLFactory().newUnion(rels.length);
union.setExpectedResultCount(1,true);
union.setExpectedResultCount(1, false);
if (fetch.getSubclassFetchMode(field.getTypeMapping())
!= JDBCFetchConfiguration.EAGER_JOIN)
union.abortUnion();

View File

@ -28,9 +28,10 @@ import org.apache.openjpa.jdbc.schema.Sequence;
*/
public class DB2Dictionary
extends AbstractDB2Dictionary {
// variables to support optimize clause
public String optimizeClause = "optimize for";
public String rowClause = "row";
public DB2Dictionary() {
platform = "DB2";
validationSQL = "SELECT DISTINCT(CURRENT TIMESTAMP) FROM "
@ -197,60 +198,13 @@ public class DB2Dictionary
}
}
/** Based on the expectedResultCount of the select create the optimize
* for clause
*/
public String getOptimizeClause(JDBCFetchConfiguration fetch,
int expectedResultCount) {
Integer rows = null;
StringBuffer optimizeString = new StringBuffer();
if (expectedResultCount != 0)
optimizeString.append(" ").append(optimizeClause).append(" ")
.append(expectedResultCount).append(" ")
.append(rowClause).append(" ");
return optimizeString.toString();
}
/** Override the DBDictionary toSelect to call getOptimizeClause and append
* to the select string
*/
public SQLBuffer toSelect(SQLBuffer selects, JDBCFetchConfiguration fetch,
SQLBuffer from, SQLBuffer where, SQLBuffer group,
SQLBuffer having, SQLBuffer order,
boolean distinct, boolean forUpdate, long start, long end,
int expectedResultCount) {
String optimizeString = null;
SQLBuffer selString = toOperation(getSelectOperation(fetch),
selects, from, where,
group, having, order, distinct,
forUpdate, start, end);
if (fetch != null)
optimizeString = getOptimizeClause(fetch, expectedResultCount);
if (optimizeString != null && optimizeString.length() > 0)
selString.append(optimizeString);
return selString;
}
/** Override the DBDictionary toSelect to pass expectedResultcount to the
* other toSelect method
*/
public SQLBuffer toSelect(Select sel, boolean forUpdate,
JDBCFetchConfiguration fetch) {
sel.addJoinClassConditions();
boolean update = forUpdate && sel.getFromSelect() == null;
SQLBuffer select = getSelects(sel, false, update);
SQLBuffer ordering = null;
if (!sel.isAggregate() || sel.getGrouping() != null)
ordering = sel.getOrdering();
SQLBuffer from;
if (sel.getFromSelect() != null)
from = getFromSelect(sel, forUpdate);
else
from = getFrom(sel, update);
SQLBuffer where = getWhere(sel, update);
return toSelect(select, fetch, from, where, sel.getGrouping(),
sel.getHaving(), ordering, sel.isDistinct(), forUpdate,
sel.getStartIndex(),
sel.getEndIndex(),sel.getExpectedResultCount());
SQLBuffer buf = super.toSelect(sel, forUpdate, fetch);
if (sel.getExpectedResultCount() > 0)
buf.append(" ").append(optimizeClause).append(" ").
append(String.valueOf(sel.getExpectedResultCount())).
append(" ").append(rowClause);
return buf;
}
}

View File

@ -47,8 +47,7 @@ public class LogicalUnion
private static final Localizer _loc = Localizer.forPackage
(LogicalUnion.class);
protected int expectedResultCount = 0;
protected boolean force = false;
protected final UnionSelect[] sels;
protected final DBDictionary dict;
protected final ClassMapping[] mappings;
@ -157,6 +156,16 @@ public class LogicalUnion
sels[i].setLRS(lrs);
}
public int getExpectedResultCount() {
return sels[0].getExpectedResultCount();
}
public void setExpectedResultCount(int expectedResultCount,
boolean force) {
for (int i = 0; i < sels.length; i++)
sels[i].setExpectedResultCount(expectedResultCount, force);
}
public int getJoinSyntax() {
return sels[0].getJoinSyntax();
}
@ -208,13 +217,9 @@ public class LogicalUnion
return res;
}
if (this.getExpectedResultCount()== 1) {
if (getExpectedResultCount() == 1) {
AbstractResult res;
for (int i = 0; i < sels.length; i++) {
// For each select set the expected result count to 1
// and force true indicating that this internally generated
// value
sels[i].sel.setExpectedResultCount(1,true);
res = (AbstractResult) sels[i].execute(store, fetch,
lockLevel);
res.setBaseMapping(mappings[i]);
@ -302,8 +307,6 @@ public class LogicalUnion
protected final int pos;
protected int orders = 0;
protected List orderIdxs = null;
protected int expectedResultCount = 0;
protected boolean force = false;
public UnionSelect(SelectImpl sel, int pos) {
this.sel = sel;
@ -839,17 +842,12 @@ public class LogicalUnion
}
public int getExpectedResultCount() {
return expectedResultCount;
return sel.getExpectedResultCount();
}
public void setExpectedResultCount(int expectedResultCount,
boolean force) {
this.expectedResultCount = expectedResultCount;
this.force = force;
}
public boolean isExpRsltCntForced() {
return force;
sel.setExpectedResultCount(expectedResultCount, force);
}
}
@ -931,18 +929,4 @@ public class LogicalUnion
return a1.length - a2.length;
}
}
public int getExpectedResultCount() {
return expectedResultCount;
}
public void setExpectedResultCount(int expectedResultCount,
boolean force) {
this.expectedResultCount = expectedResultCount;
this.force = force;
}
public boolean isExpRsltCntForced() {
return force;
}
}

View File

@ -79,6 +79,19 @@ public interface SelectExecutor {
*/
public void setLRS(boolean lrs);
/**
* The expected result count for the query.
*/
public int getExpectedResultCount();
/**
* The expected result count for the query.
*
* @param force if false, the count will be discarded if this select has
* any to-many eager joins that would throw off the result count
*/
public void setExpectedResultCount(int expectedResultCount, boolean force);
/**
* The join syntax for this select, as one of the syntax constants from
* {@link JoinSyntaxes}.
@ -119,21 +132,4 @@ public interface SelectExecutor {
public Result execute(JDBCStore store, JDBCFetchConfiguration fetch,
int lockLevel)
throws SQLException;
/**
* Return the expected result count for the query
*/
public int getExpectedResultCount() ;
/**
* Set the expected result count for the query
* force indicates whether the count is internally generated
* or given by the user as optimize hint
*/
public void setExpectedResultCount(int expectedResultCount,boolean force) ;
/**
* Indicates whether the expectedResultCount is internally generated
*/
public boolean isExpRsltCntForced();
}

View File

@ -82,6 +82,7 @@ public class SelectImpl
private static final int EAGER_TO_MANY = 2 << 10;
private static final int RECORD_ORDERED = 2 << 11;
private static final int GROUPING = 2 << 12;
private static final int FORCE_COUNT = 2 << 13;
private static final String[] TABLE_ALIASES = new String[16];
private static final String[] ORDER_ALIASES = new String[16];
@ -128,6 +129,7 @@ public class SelectImpl
private int _nullIds = 0;
private int _orders = 0;
private int _placeholders = 0;
private int _expectedResultCount = 0;
// query clauses
private SQLBuffer _ordering = null;
@ -154,9 +156,6 @@ public class SelectImpl
private SelectImpl _from = null;
private SelectImpl _outer = null;
private int expectedResultCount = 0;
private boolean force = false;
/**
* Helper method to return the proper table alias for the given alias index.
*/
@ -245,6 +244,22 @@ public class SelectImpl
_flags &= ~LRS;
}
public int getExpectedResultCount() {
// if the count isn't forced and we have to-many eager joins that could
// throw the count off, don't pay attention to it
if ((_flags & FORCE_COUNT) == 0 && hasEagerJoin(true))
return 0;
return _expectedResultCount;
}
public void setExpectedResultCount(int expectedResultCount, boolean force) {
_expectedResultCount = expectedResultCount;
if (force)
_flags |= FORCE_COUNT;
else
_flags &= ~FORCE_COUNT;
}
public int getJoinSyntax() {
return _joinSyntax;
}
@ -307,20 +322,6 @@ public class SelectImpl
JDBCFetchConfiguration fetch, int lockLevel)
throws SQLException {
boolean forUpdate = false;
// ExpectedResultCount = 1 and force means that it is internally
// generated value for getSingleResult,single valued relationship.
// We need to check if there are any eager joins in the select if
// there are then the optimize for 1 row clause is not generated
// else we do. if !force then it is set by the user through hint
// and we do not check the eager joins
if (this.expectedResultCount == 1 && force ) {
if (this.hasEagerJoin(true))
this.setExpectedResultCount(0,false);
else
this.setExpectedResultCount(1,false);
}
if (!isAggregate() && _grouping == null) {
JDBCLockManager lm = store.getLockManager();
if (lm != null)
@ -1503,6 +1504,7 @@ public class SelectImpl
sel._flags &= ~LRS;
sel._flags &= ~EAGER_TO_ONE;
sel._flags &= ~EAGER_TO_MANY;
sel._flags &= ~FORCE_COUNT;
sel._joinSyntax = _joinSyntax;
if (_aliases != null)
sel._aliases = new HashMap(_aliases);
@ -1548,6 +1550,7 @@ public class SelectImpl
for (int i = 0; i < sels; i++) {
sel = (SelectImpl) whereClone(1);
sel._flags = _flags;
sel._expectedResultCount = _expectedResultCount;
sel._selects.addAll(_selects);
if (_ordering != null)
sel._ordering = new SQLBuffer(_ordering);
@ -2816,20 +2819,6 @@ public class SelectImpl
_idents = null;
}
}
public int getExpectedResultCount() {
return expectedResultCount;
}
public void setExpectedResultCount(int expectedResultCount,
boolean force) {
this.expectedResultCount = expectedResultCount;
this.force = force;
}
public boolean isExpRsltCntForced() {
return force;
}
}
/**

View File

@ -15,10 +15,13 @@
*/
package org.apache.openjpa.kernel;
/**
* Standard query hint keys.
*/
public interface QueryHints {
/** Hint to specify the number of rows for the optimize
* clause for DB2
/**
* Hint to specify the number of rows to optimize for.
*/
public static final String HINT_RESULT_COUNT =
"openjpa.hint.OptimizeResultCount";

View File

@ -1273,14 +1273,17 @@ public class QueryImpl
boolean next = rop.next();
// extract single result; throw an exception if multiple results
// match and not constrainted by range, as per spec
// match and not constrainted by range, or if a unique query with
// no results
Object single = null;
if (next) {
single = rop.getResultObject();
if (range.end != range.start + 1 && rop.next())
throw new InvalidStateException(_loc.get("not-unique",
_class, _query));
}
} else if (_unique == Boolean.TRUE)
throw new InvalidStateException(_loc.get("no-result",
_class, _query));
// if unique set to false, use collection
if (_unique == Boolean.FALSE) {
@ -1290,10 +1293,6 @@ public class QueryImpl
return Arrays.asList(new Object[]{ single });
}
if (single == null)
throw new InvalidStateException(_loc.get("is-null",
_class, _query));
// return single result
return single;
} finally {

View File

@ -259,7 +259,7 @@ executing-query-with-params: Executing query: [{0}] with parameters: {1}
not-unique: The query on candidate type "{0}" with filter "{1}" was \
configured to have a unique result, but more than one instance matched \
the query.
is-null: The query on candidate type "{0}" with filter "{1}" was \
no-result: The query on candidate type "{0}" with filter "{1}" was \
configured to have a unique result, but no instance matched \
the query.
serialized: Queries that have been serialized do not support this operation.

View File

@ -279,12 +279,12 @@ public class QueryImpl
*/
public Object getSingleResult() {
_em.assertNotCloseInvoked();
// Indicate that this query returns single result.Later copied into
// select.expectedResultCount
// temporarily set query to unique so that a single result is validated
// and returned; unset again in case the user executes query again
// via getResultList
_query.setUnique(true);
try {
Object ob = execute();
return ob;
return execute();
} finally {
_query.setUnique(false);
}
@ -367,16 +367,17 @@ public class QueryImpl
Filters.hintToSetter(getFetchPlan(), k, value);
} else if (k.startsWith("hint.")) {
if ("hint.OptimizeResultCount".equals(k)) {
if ((!(value instanceof String)&&! (value instanceof Integer))
|| (value instanceof String &&(Integer.parseInt
((String)value)< 0))||
((value instanceof Integer)
&& (((Integer)value).intValue()<0)))
if (value instanceof String) {
try {
value = new Integer((String) value);
} catch (NumberFormatException nfe) {
}
}
if (!(value instanceof Number)
|| ((Number) value).intValue() < 0)
throw new ArgumentException(_loc.get
("bad-hint-value", key),
null, null, false);
if (value instanceof String)
value = new Integer((String)value);
("bad-query-hint-value", key, value), null, null,
false);
}
_query.getFetchConfiguration().setHint(key, value);
}
@ -384,12 +385,7 @@ public class QueryImpl
throw new ArgumentException(_loc.get("bad-query-hint", key),
null, null, false);
return this;
}
catch (NumberFormatException e1) {
throw new ArgumentException(_loc.get("bad-hint-value", key),
null, null, false);
}
catch (Exception e) {
} catch (Exception e) {
throw PersistenceExceptions.toPersistenceException(e);
}
}

View File

@ -64,6 +64,7 @@ mult-results: Query returned multiple results: "{0}".
no-pos-named-params-mix: Cannot mix named and positional parameters in query \
"{0}".
bad-query-hint: "{0}" is not a recognized query hint.
bad-query-hint-value: Invalid value specified for query hint "{0}": {1}
detached: Cannot perform this operation on detached entity "{0}".
removed: Cannot perform this operation on removed entity "{0}".
bad-alias: There is no known entity class for entity name "{0}". It is \