Allow null discriminator values when adding class conditions on outer joins.

git-svn-id: https://svn.apache.org/repos/asf/incubator/openjpa/trunk@443447 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
A. Abram White 2006-09-14 19:36:09 +00:00
parent fcd072a2c5
commit a5d552f940
7 changed files with 56 additions and 27 deletions

View File

@ -367,7 +367,7 @@ public class JDBCStoreManager
throws SQLException { throws SQLException {
Select sel = _sql.newSelect(); Select sel = _sql.newSelect();
if (!select(sel, mapping, subs, sm, null, fetch, if (!select(sel, mapping, subs, sm, null, fetch,
JDBCFetchConfiguration.EAGER_JOIN, true)) JDBCFetchConfiguration.EAGER_JOIN, true, false))
return null; return null;
sel.wherePrimaryKey(sm.getObjectId(), mapping, this); sel.wherePrimaryKey(sm.getObjectId(), mapping, this);
@ -463,8 +463,8 @@ public class JDBCStoreManager
//### object that only creates a real select when actually used? //### object that only creates a real select when actually used?
Select sel = _sql.newSelect(); Select sel = _sql.newSelect();
if (select(sel, mapping, sel.SUBS_EXACT, sm, fields, jfetch, if (select(sel, mapping, Select.SUBS_EXACT, sm, fields, jfetch,
EagerFetchModes.EAGER_JOIN, true)) { EagerFetchModes.EAGER_JOIN, true, false)) {
sel.wherePrimaryKey(sm.getObjectId(), mapping, this); sel.wherePrimaryKey(sm.getObjectId(), mapping, this);
res = sel.execute(this, jfetch, lockLevel); res = sel.execute(this, jfetch, lockLevel);
try { try {
@ -854,18 +854,20 @@ public class JDBCStoreManager
* @param eager eager fetch mode to use * @param eager eager fetch mode to use
* @param ident whether to select primary key columns as distinct * @param ident whether to select primary key columns as distinct
* identifiers * identifiers
* @param outer whether we're outer-joining to this type
* @return true if the select is required, false otherwise * @return true if the select is required, false otherwise
*/ */
public boolean select(Select sel, ClassMapping mapping, int subs, public boolean select(Select sel, ClassMapping mapping, int subs,
OpenJPAStateManager sm, BitSet fields, JDBCFetchConfiguration fetch, OpenJPAStateManager sm, BitSet fields, JDBCFetchConfiguration fetch,
int eager, boolean ident) { int eager, boolean ident, boolean outer) {
// add class conditions so that they're cloned for any batched selects // add class conditions so that they're cloned for any batched selects
boolean joinedSupers = false; boolean joinedSupers = false;
if ((sm == null || sm.getPCState() == PCState.TRANSIENT) if ((sm == null || sm.getPCState() == PCState.TRANSIENT)
&& (subs == sel.SUBS_JOINABLE || subs == sel.SUBS_NONE)) { && (subs == Select.SUBS_JOINABLE || subs == Select.SUBS_NONE)) {
loadSubclasses(mapping); loadSubclasses(mapping);
Joins joins = (outer) ? sel.newOuterJoins() : null;
joinedSupers = mapping.getDiscriminator().addClassConditions(sel, joinedSupers = mapping.getDiscriminator().addClassConditions(sel,
subs == sel.SUBS_JOINABLE, null); subs == Select.SUBS_JOINABLE, joins);
} }
// create all our eager selects so that those fields are reserved // create all our eager selects so that those fields are reserved
@ -889,7 +891,7 @@ public class JDBCStoreManager
fetch.traverseJDBC(eagerToMany), eager); fetch.traverseJDBC(eagerToMany), eager);
// optionally select subclass mappings // optionally select subclass mappings
if (subs == sel.SUBS_JOINABLE || subs == sel.SUBS_ANY_JOINABLE) if (subs == Select.SUBS_JOINABLE || subs == Select.SUBS_ANY_JOINABLE)
selectSubclassMappings(sel, mapping, sm, fetch); selectSubclassMappings(sel, mapping, sm, fetch);
if (sm != null) if (sm != null)
sel.setDistinct(false); sel.setDistinct(false);

View File

@ -126,20 +126,29 @@ public abstract class InValueDiscriminatorStrategy
if (subs.length == 0 && base.getJoinablePCSuperclassMapping() == null) if (subs.length == 0 && base.getJoinablePCSuperclassMapping() == null)
return null; return null;
// if not selecting subclasses, limit to just the given class
Column col = disc.getColumns()[0]; Column col = disc.getColumns()[0];
SQLBuffer sql = new SQLBuffer(sel.getConfiguration(). SQLBuffer sql = new SQLBuffer(sel.getConfiguration().
getDBDictionaryInstance()); getDBDictionaryInstance());
sql.append(sel.getColumnAlias(col, joins)); boolean outer = joins != null && joins.isOuter();
if (!subclasses || subs.length == 0) if (outer)
sql.append("(");
String alias = sel.getColumnAlias(col, joins);
sql.append(alias);
// if not selecting subclasses, limit to just the given class
if (!outer && (!subclasses || subs.length == 0))
return sql.append(" = ").appendValue(getDiscriminatorValue(base), return sql.append(" = ").appendValue(getDiscriminatorValue(base),
col); col);
if (outer)
sql.append(" IS ").appendValue(null).append(" OR ").append(alias);
sql.append(" IN ("); sql.append(" IN (");
sql.appendValue(getDiscriminatorValue(base), col); sql.appendValue(getDiscriminatorValue(base), col);
for (int i = 0; i < subs.length; i++) for (int i = 0; i < subs.length; i++)
sql.append(", ").appendValue(getDiscriminatorValue(subs[i]), col); sql.append(", ").appendValue(getDiscriminatorValue(subs[i]), col);
sql.append(")"); sql.append(")");
if (outer)
sql.append(")");
return sql; return sql;
} }
} }

View File

@ -810,6 +810,10 @@ public abstract class AbstractResult
return true; return true;
} }
public boolean isOuter() {
return false;
}
public Joins crossJoin(Table localTable, Table foreignTable) { public Joins crossJoin(Table localTable, Table foreignTable) {
return this; return this;
} }

View File

@ -31,6 +31,11 @@ public interface Joins {
*/ */
public boolean isEmpty(); public boolean isEmpty();
/**
* Whether this joins path results in outer joins.
*/
public boolean isOuter();
/** /**
* Perform a cross join on the given tables. * Perform a cross join on the given tables.
*/ */

View File

@ -810,6 +810,10 @@ public class LogicalUnion
return sel.newJoins(); return sel.newJoins();
} }
public Joins newOuterJoins() {
return sel.newOuterJoins();
}
public void append(SQLBuffer buf, Joins joins) { public void append(SQLBuffer buf, Joins joins) {
sel.append(buf, joins); sel.append(buf, joins);
} }

View File

@ -652,6 +652,11 @@ public interface Select
*/ */
public Joins newJoins(); public Joins newJoins();
/**
* Return a new instance to use for outer joining.
*/
public Joins newOuterJoins();
/** /**
* Append the given joins to the given buffer. * Append the given joins to the given buffer.
*/ */

View File

@ -759,7 +759,7 @@ public class SelectImpl
// delegate to store manager to select in same order it loads result // delegate to store manager to select in same order it loads result
((JDBCStoreManager) store).select(wrapper, mapping, subclasses, null, ((JDBCStoreManager) store).select(wrapper, mapping, subclasses, null,
null, fetch, eager, ident); null, fetch, eager, ident, (_flags & OUTER) != 0);
// reset // reset
if (hasJoins) if (hasJoins)
@ -1626,6 +1626,10 @@ public class SelectImpl
return this; return this;
} }
public Joins newOuterJoins() {
return ((PathJoins) newJoins()).setOuter(true);
}
public void append(SQLBuffer buf, Joins joins) { public void append(SQLBuffer buf, Joins joins) {
if (joins == null || joins.isEmpty()) if (joins == null || joins.isEmpty())
return; return;
@ -1744,10 +1748,9 @@ public class SelectImpl
return joins; return joins;
// record that this is an outer join set, even if it's empty // record that this is an outer join set, even if it's empty
PathJoins pj = (PathJoins) joins; PathJoins pj = ((PathJoins) joins).setOuter(true);
pj.setOuter(true); if (pj.isEmpty())
if (joins.isEmpty()) return pj;
return joins;
Join join; Join join;
Join rec; Join rec;
@ -1928,7 +1931,8 @@ public class SelectImpl
return false; return false;
} }
public void setOuter(boolean outer) { public PathJoins setOuter(boolean outer) {
return new SelectJoins(this).setOuter(true);
} }
public boolean isDirty() { public boolean isDirty() {
@ -1994,14 +1998,12 @@ public class SelectImpl
* Represents a SQL string selected with null id. * Represents a SQL string selected with null id.
*/ */
private static class NullId { private static class NullId {
} }
/** /**
* Represents a placeholder SQL string. * Represents a placeholder SQL string.
*/ */
private static class Placeholder { private static class Placeholder {
} }
/** /**
@ -2269,7 +2271,8 @@ public class SelectImpl
return false; return false;
} }
public void setOuter(boolean outer) { public PathJoins setOuter(boolean outer) {
return this;
} }
public boolean isDirty() { public boolean isDirty() {
@ -2345,7 +2348,8 @@ public class SelectImpl
return false; return false;
} }
public void setOuter(boolean outer) { public PathJoins setOuter(boolean outer) {
return this;
} }
public boolean isDirty() { public boolean isDirty() {
@ -2452,8 +2456,9 @@ public class SelectImpl
return _outer; return _outer;
} }
public void setOuter(boolean outer) { public PathJoins setOuter(boolean outer) {
_outer = outer; _outer = outer;
return this;
} }
public boolean isDirty() { public boolean isDirty() {
@ -2796,15 +2801,10 @@ public class SelectImpl
interface PathJoins interface PathJoins
extends Joins { extends Joins {
/**
* Return whether this join set ended with an outer join.
*/
public boolean isOuter();
/** /**
* Mark this as an outer joins set. * Mark this as an outer joins set.
*/ */
public void setOuter(boolean outer); public PathJoins setOuter(boolean outer);
/** /**
* Return true if this instance has a path, any joins, or a variable. * Return true if this instance has a path, any joins, or a variable.