Don't use a subselect for non-distinct projections of DISTINCT_AUTO queries

with to-many joins in their filter if the projections are all for variable 
paths.  (As opposed to candidate path projections, where the subselect is 
necessary to filter out duplicates caused by relational joins).



git-svn-id: https://svn.apache.org/repos/asf/incubator/openjpa/trunk@443519 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
A. Abram White 2006-09-14 23:41:30 +00:00
parent c6c683e8ac
commit 47edcb8edc
2 changed files with 57 additions and 6 deletions

View File

@ -129,6 +129,13 @@ class PCPath
return _type == UNACCESSED_VAR;
}
/**
* Return whether this is a path involving a variable.
*/
public boolean isVariablePath() {
return _type != PATH;
}
/**
* If this path is part of a contains clause, then alias it to the
* proper contains id before initialization.

View File

@ -25,8 +25,11 @@ import org.apache.openjpa.jdbc.sql.DBDictionary;
import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.AbstractExpressionVisitor;
import org.apache.openjpa.kernel.exps.Constant;
import org.apache.openjpa.kernel.exps.Expression;
import org.apache.openjpa.kernel.exps.QueryExpressions;
import org.apache.openjpa.kernel.exps.Value;
/**
* Turns parsed queries into selects.
@ -120,8 +123,7 @@ public class SelectConstructor {
else if ((exps.distinct & exps.DISTINCT_FALSE) != 0)
sel.setDistinct(false);
} else if (exps.projections.length > 0) {
if (!sel.isDistinct() && (exps.distinct & exps.DISTINCT_TRUE) != 0)
{
if (!sel.isDistinct() && (exps.distinct & exps.DISTINCT_TRUE) != 0){
// if the select is not distinct but the query is, force
// the select to be distinct
sel.setDistinct(true);
@ -133,8 +135,11 @@ public class SelectConstructor {
// get unique candidate values) and needed field values and
// applies the where conditions; the outer select applies
// ordering, grouping, etc
if (exps.isAggregate()
|| (exps.distinct & exps.DISTINCT_TRUE) == 0) {
boolean agg = exps.isAggregate();
boolean candidate = ProjectionExpressionVisitor.
hasCandidateProjections(exps.projections);
if (agg || (candidate
&& (exps.distinct & exps.DISTINCT_TRUE) == 0)) {
DBDictionary dict = ctx.store.getDBDictionary();
dict.assertSupport(dict.supportsSubselect,
"SupportsSubselect");
@ -142,10 +147,16 @@ public class SelectConstructor {
Select inner = sel;
sel = ctx.store.getSQLFactory().newSelect();
sel.setParent(parent, alias);
sel.setDistinct(exps.isAggregate()
sel.setDistinct(agg
&& (exps.distinct & exps.DISTINCT_TRUE) != 0);
sel.setFromSelect(inner);
}
// auto-distincting happens to get unique candidate instances
// back; don't auto-distinct if the user isn't selecting
// candidate data
} else if (!candidate
&& (exps.distinct & exps.DISTINCT_TRUE) == 0)
sel.setDistinct(false);
}
}
return sel;
@ -295,4 +306,37 @@ public class SelectConstructor {
? inner : sel, subclasses, joins);
}
}
/**
* Used to check whether a query's result projections are on the candidate.
*/
private static class ProjectionExpressionVisitor
extends AbstractExpressionVisitor {
private boolean _candidate = false;
private int _level = 0;
public static boolean hasCandidateProjections(Value[] projs) {
ProjectionExpressionVisitor v = new ProjectionExpressionVisitor();
for (int i = 0; i < projs.length; i++) {
projs[i].acceptVisit(v);
if (v._candidate)
return true;
}
return false;
}
public void enter(Value val) {
if (!_candidate) {
_candidate = (_level == 0 && val instanceof Constant)
|| (val instanceof PCPath
&& !((PCPath) val).isVariablePath());
}
_level++;
}
public void exit(Value val) {
_level--;
}
}
}