From 4063328f97c0180ceab565cc3f411e3dcc07bca8 Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Fri, 26 Oct 2007 21:24:43 +0000 Subject: Added support for outer joins. --- .../amazon/carbonado/repo/jdbc/JDBCStorage.java | 74 ++++++++++++++++------ 1 file changed, 55 insertions(+), 19 deletions(-) (limited to 'src/main/java/com/amazon/carbonado/repo') diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorage.java b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorage.java index 855cce4..2a1212a 100644 --- a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorage.java +++ b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorage.java @@ -846,11 +846,45 @@ class JDBCStorage extends StandardQueryFactory private static class JoinNode { // Joined property which led to this node. For root node, it is null. private final JDBCStorableProperty mProperty; + private final boolean mOuterJoin; private final JDBCStorableInfo mInfo; private final String mAlias; - private final Map mSubNodes; + private static class SubNodeKey { + final String mPropertyName; + final boolean mOuterJoin; + + SubNodeKey(String propertyName, boolean outerJoin) { + mPropertyName = propertyName; + mOuterJoin = outerJoin; + } + + @Override + public int hashCode() { + return mPropertyName.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof SubNodeKey) { + SubNodeKey other = (SubNodeKey) obj; + return mPropertyName.equals(other.mPropertyName) + && mOuterJoin == other.mOuterJoin; + } + return false; + } + + @Override + public String toString() { + return "propertyName=" + mPropertyName + ", outerJoin=" + mOuterJoin; + } + } + + private final Map mSubNodes; private boolean mAliasRequired; @@ -858,15 +892,19 @@ class JDBCStorage extends StandardQueryFactory * @param alias table alias in SQL statement, i.e. "T1" */ JoinNode(JDBCStorableInfo info, String alias) { - this(null, info, alias); + this(null, false, info, alias); } - private JoinNode(JDBCStorableProperty property, JDBCStorableInfo info, String alias) + private JoinNode(JDBCStorableProperty property, + boolean outerJoin, + JDBCStorableInfo info, + String alias) { mProperty = property; + mOuterJoin = outerJoin; mInfo = info; mAlias = alias; - mSubNodes = new LinkedHashMap(); + mSubNodes = new LinkedHashMap(); } /** @@ -891,8 +929,9 @@ class JDBCStorage extends StandardQueryFactory } else { property = chained.getChainedProperty(offset - 1); } - String name = property.getName(); - JoinNode subNode = mSubNodes.get(name); + boolean outerJoin = chained.isOuterJoin(offset); + SubNodeKey key = new SubNodeKey(property.getName(), outerJoin); + JoinNode subNode = mSubNodes.get(key); if (subNode != null) { return subNode.findAliasFor(chained, offset + 1); } @@ -931,15 +970,11 @@ class JDBCStorage extends StandardQueryFactory private void appendTailJoinTo(StatementBuilder fromClause) { for (JoinNode jn : mSubNodes.values()) { - // TODO: By default, joins are all inner. A join could become - // LEFT OUTER JOIN if the query filter has a term like this: - // "address = ? | address.state = ?", and the runtime value of - // address is null. Because of DNF transformation and lack of - // short-circuit ops, this syntax might be difficult to parse. - // This might be a better way of expressing an outer join: - // "address(.)state = ?". - - fromClause.append(" INNER JOIN"); + if (jn.mOuterJoin) { + fromClause.append(" LEFT OUTER JOIN"); + } else { + fromClause.append(" INNER JOIN"); + } jn.appendTableNameAndAliasTo(fromClause); fromClause.append(" ON "); int count = jn.mProperty.getJoinElementCount(); @@ -984,13 +1019,14 @@ class JDBCStorage extends StandardQueryFactory } else { property = chained.getChainedProperty(offset - 1); } - String name = property.getName(); - JoinNode subNode = mSubNodes.get(name); + boolean outerJoin = chained.isOuterJoin(offset); + SubNodeKey key = new SubNodeKey(property.getName(), outerJoin); + JoinNode subNode = mSubNodes.get(key); if (subNode == null) { JDBCStorableInfo info = repository.examineStorable(property.getJoinedType()); JDBCStorableProperty jProperty = repository.getJDBCStorableProperty(property); - subNode = new JoinNode(jProperty, info, aliasGenerator.nextAlias()); - mSubNodes.put(name, subNode); + subNode = new JoinNode(jProperty, outerJoin, info, aliasGenerator.nextAlias()); + mSubNodes.put(key, subNode); } subNode.addJoin(repository, chained, aliasGenerator, offset + 1); } -- cgit v1.2.3