phoenix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From maryann...@apache.org
Subject git commit: PHOENIX-945 Support correlated subqueries in comparison without ANY/SOME/ALL
Date Wed, 08 Oct 2014 02:56:55 GMT
Repository: phoenix
Updated Branches:
  refs/heads/master 05971c0ca -> 5282a8a09


PHOENIX-945 Support correlated subqueries in comparison without ANY/SOME/ALL


Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/5282a8a0
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/5282a8a0
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/5282a8a0

Branch: refs/heads/master
Commit: 5282a8a09fec1ea7a6241565ff034246e3b30b92
Parents: 05971c0
Author: maryannxue <maryannxue@apache.org>
Authored: Tue Oct 7 22:56:36 2014 -0400
Committer: maryannxue <maryannxue@apache.org>
Committed: Tue Oct 7 22:56:36 2014 -0400

----------------------------------------------------------------------
 .../org/apache/phoenix/end2end/SubqueryIT.java  | 98 ++++++++++++++++++++
 .../phoenix/compile/ExpressionCompiler.java     |  7 +-
 .../phoenix/compile/StatementNormalizer.java    | 15 +--
 .../phoenix/compile/SubqueryRewriter.java       | 70 ++++++++++++--
 .../apache/phoenix/parse/ParseNodeFactory.java  | 24 +++++
 5 files changed, 188 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/5282a8a0/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryIT.java
index 3aecd29..58d92f3 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryIT.java
@@ -19,6 +19,7 @@ package org.apache.phoenix.end2end;
 
 import static org.apache.phoenix.util.TestUtil.JOIN_COITEM_TABLE_DISPLAY_NAME;
 import static org.apache.phoenix.util.TestUtil.JOIN_COITEM_TABLE_FULL_NAME;
+import static org.apache.phoenix.util.TestUtil.JOIN_CUSTOMER_TABLE_DISPLAY_NAME;
 import static org.apache.phoenix.util.TestUtil.JOIN_CUSTOMER_TABLE_FULL_NAME;
 import static org.apache.phoenix.util.TestUtil.JOIN_ITEM_TABLE_DISPLAY_NAME;
 import static org.apache.phoenix.util.TestUtil.JOIN_ITEM_TABLE_FULL_NAME;
@@ -31,12 +32,14 @@ import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.sql.Connection;
 import java.sql.Date;
 import java.sql.DriverManager;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
+import java.sql.SQLException;
 import java.sql.Timestamp;
 import java.text.SimpleDateFormat;
 import java.util.Collection;
@@ -154,6 +157,21 @@ public class SubqueryIT extends BaseHBaseManagedTimeIT {
                 "        CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME
+ "\n" +
                 "            SERVER AGGREGATE INTO DISTINCT ROWS BY [item_id]\n" +
                 "        CLIENT MERGE SORT",
+                
+                "CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_CUSTOMER_TABLE_DISPLAY_NAME
+ "\n" +
+                "    SKIP-SCAN-JOIN TABLE 0\n" +
+                "        CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ITEM_TABLE_DISPLAY_NAME
+ "\n" +
+                "            SERVER AGGREGATE INTO DISTINCT ROWS BY \\[O.customer_id\\]\n"
+
+                "        CLIENT MERGE SORT\n" +
+                "            PARALLEL INNER-JOIN TABLE 0\n" +
+                "                CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME
+ "\n" +
+                "            PARALLEL LEFT-JOIN TABLE 1\\(DELAYED EVALUATION\\)\n" +
+                "                CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME
+ "\n" +
+                "                    SERVER AGGREGATE INTO DISTINCT ROWS BY \\[item_id\\]\n"
+
+                "                CLIENT MERGE SORT\n" +
+                "            DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF \\(O.item_id\\)\n"
+
+                "            AFTER-JOIN SERVER FILTER BY \\(I.NAME = 'T2' OR O.QUANTITY >
\\$\\d+.\\$\\d+\\)\n" +
+                "    DYNAMIC SERVER FILTER BY customer_id IN \\(\\$\\d+.\\$\\d+\\)"
                 }});
         testCases.add(new String[][] {
                 {
@@ -207,6 +225,20 @@ public class SubqueryIT extends BaseHBaseManagedTimeIT {
                 "        CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME
+ "\n" +
                 "            SERVER AGGREGATE INTO DISTINCT ROWS BY [item_id]\n" +
                 "        CLIENT MERGE SORT",
+                
+                "CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SCHEMA + ".idx_customer\n"
+
+                "    PARALLEL SEMI-JOIN TABLE 0 \\(SKIP MERGE\\)\n" +
+                "        CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SCHEMA + ".idx_item\n"
+
+                "            SERVER FILTER BY FIRST KEY ONLY\n" +
+                "            SERVER AGGREGATE INTO DISTINCT ROWS BY \\[O.customer_id\\]\n"
+
+                "        CLIENT MERGE SORT\n" +
+                "            PARALLEL INNER-JOIN TABLE 0\n" +
+                "                CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME
+ "\n" +
+                "            PARALLEL LEFT-JOIN TABLE 1\\(DELAYED EVALUATION\\)\n" +
+                "                CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME
+ "\n" +
+                "                    SERVER AGGREGATE INTO DISTINCT ROWS BY \\[item_id\\]\n"
+
+                "                CLIENT MERGE SORT\n" +
+                "            AFTER-JOIN SERVER FILTER BY \\(I.0:NAME = 'T2' OR O.QUANTITY
> \\$\\d+.\\$\\d+\\)"
                 }});
         testCases.add(new String[][] {
                 {
@@ -266,6 +298,23 @@ public class SubqueryIT extends BaseHBaseManagedTimeIT {
                 "        CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME
+ "\n" +
                 "            SERVER AGGREGATE INTO DISTINCT ROWS BY [item_id]\n" +
                 "        CLIENT MERGE SORT",
+                
+                "CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + MetaDataUtil.LOCAL_INDEX_TABLE_PREFIX
+ JOIN_CUSTOMER_TABLE_DISPLAY_NAME + " \\[-32768\\]\n" +
+                "CLIENT MERGE SORT\n" +
+                "    PARALLEL SEMI-JOIN TABLE 0 \\(SKIP MERGE\\)\n" +
+                "        CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + MetaDataUtil.LOCAL_INDEX_TABLE_PREFIX
+ JOIN_ITEM_TABLE_DISPLAY_NAME + " \\[-32768\\]\n" +
+                "            SERVER FILTER BY FIRST KEY ONLY\n" +
+                "            SERVER AGGREGATE INTO DISTINCT ROWS BY \\[O.customer_id\\]\n"
+
+                "        CLIENT MERGE SORT\n" +
+                "            PARALLEL INNER-JOIN TABLE 0\n" +
+                "                CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME
+ "\n" +
+                "            PARALLEL LEFT-JOIN TABLE 1\\(DELAYED EVALUATION\\)\n" +
+                "                CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME
+ "\n" +
+                "                    SERVER AGGREGATE INTO DISTINCT ROWS BY \\[item_id\\]\n"
+
+                "                CLIENT MERGE SORT\n" +
+                "            DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF \\(O.item_id\\)\n"
+
+                "            AFTER-JOIN SERVER FILTER BY \\(I.0:NAME = 'T2' OR O.QUANTITY
> \\$\\d+.\\$\\d+\\)\n" +
+                "    DYNAMIC SERVER FILTER BY customer_id IN \\(\\$\\d+.\\$\\d+\\)"
                 }});
         return testCases;
     }
@@ -650,6 +699,14 @@ public class SubqueryIT extends BaseHBaseManagedTimeIT {
             assertEquals(rs.getString(4), "T1");
 
             assertFalse(rs.next());
+            
+            query = "SELECT \"item_id\", name FROM " + JOIN_ITEM_TABLE_FULL_NAME + " WHERE
\"item_id\" < (SELECT \"item_id\" FROM " + JOIN_ORDER_TABLE_FULL_NAME + ")";
+            statement = conn.prepareStatement(query);
+            try {
+                rs = statement.executeQuery();
+                fail("Should have got Exception.");
+            } catch (SQLException e) {
+            }
         } finally {
             conn.close();
         }
@@ -805,6 +862,47 @@ public class SubqueryIT extends BaseHBaseManagedTimeIT {
             conn.close();
         }
     }
+    
+    @Test
+    public void testComparisonSubquery() throws Exception {
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        try {
+            String query = "SELECT \"order_id\", name FROM " + JOIN_ORDER_TABLE_FULL_NAME
+ " o JOIN " + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" WHERE quantity
= (SELECT max(quantity) FROM " + JOIN_ORDER_TABLE_FULL_NAME + " q WHERE o.\"item_id\" = q.\"item_id\")";
+            PreparedStatement statement = conn.prepareStatement(query);
+            ResultSet rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(rs.getString(1), "000000000000001");
+            assertEquals(rs.getString(2), "T1");
+            assertTrue (rs.next());
+            assertEquals(rs.getString(1), "000000000000003");
+            assertEquals(rs.getString(2), "T2");
+            assertTrue (rs.next());
+            assertEquals(rs.getString(1), "000000000000004");
+            assertEquals(rs.getString(2), "T6");
+            assertTrue (rs.next());
+            assertEquals(rs.getString(1), "000000000000005");
+            assertEquals(rs.getString(2), "T3");
+
+            assertFalse(rs.next());
+
+            query = "SELECT name from " + JOIN_CUSTOMER_TABLE_FULL_NAME + " WHERE \"customer_id\"
IN (SELECT \"customer_id\" FROM " + JOIN_ITEM_TABLE_FULL_NAME + " i JOIN " + JOIN_ORDER_TABLE_FULL_NAME
+ " o ON o.\"item_id\" = i.\"item_id\" WHERE i.name = 'T2' OR quantity > (SELECT avg(quantity)
FROM " + JOIN_ORDER_TABLE_FULL_NAME + " q WHERE o.\"item_id\" = q.\"item_id\"))";
+            statement = conn.prepareStatement(query);
+            rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(rs.getString(1), "C2");
+            assertTrue (rs.next());
+            assertEquals(rs.getString(1), "C4");
+
+            assertFalse(rs.next());
+            
+            rs = conn.createStatement().executeQuery("EXPLAIN " + query);
+            String plan = QueryUtil.getExplainPlan(rs);
+            assertTrue("\"" + plan + "\" does not match \"" + plans[4] + "\"", Pattern.matches(plans[4],
plan));
+        } finally {
+            conn.close();
+        }
+    }
 
 }
 

http://git-wip-us.apache.org/repos/asf/phoenix/blob/5282a8a0/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java
b/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java
index a01c147..1f1313c 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java
@@ -55,6 +55,7 @@ import org.apache.phoenix.expression.LongAddExpression;
 import org.apache.phoenix.expression.LongDivideExpression;
 import org.apache.phoenix.expression.LongMultiplyExpression;
 import org.apache.phoenix.expression.LongSubtractExpression;
+import org.apache.phoenix.expression.ModulusExpression;
 import org.apache.phoenix.expression.NotExpression;
 import org.apache.phoenix.expression.OrExpression;
 import org.apache.phoenix.expression.RowKeyColumnExpression;
@@ -65,7 +66,6 @@ import org.apache.phoenix.expression.TimestampSubtractExpression;
 import org.apache.phoenix.expression.function.ArrayAllComparisonExpression;
 import org.apache.phoenix.expression.function.ArrayAnyComparisonExpression;
 import org.apache.phoenix.expression.function.InlineArrayElemRefExpression;
-import org.apache.phoenix.expression.ModulusExpression;
 import org.apache.phoenix.parse.AddParseNode;
 import org.apache.phoenix.parse.AndParseNode;
 import org.apache.phoenix.parse.ArithmeticParseNode;
@@ -82,11 +82,10 @@ import org.apache.phoenix.parse.DivideParseNode;
 import org.apache.phoenix.parse.ExistsParseNode;
 import org.apache.phoenix.parse.FunctionParseNode;
 import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunctionInfo;
-import org.apache.phoenix.parse.LikeParseNode.LikeType;
 import org.apache.phoenix.parse.InListParseNode;
-import org.apache.phoenix.parse.InParseNode;
 import org.apache.phoenix.parse.IsNullParseNode;
 import org.apache.phoenix.parse.LikeParseNode;
+import org.apache.phoenix.parse.LikeParseNode.LikeType;
 import org.apache.phoenix.parse.LiteralParseNode;
 import org.apache.phoenix.parse.ModulusParseNode;
 import org.apache.phoenix.parse.MultiplyParseNode;
@@ -120,8 +119,6 @@ import org.apache.phoenix.util.ExpressionUtil;
 import org.apache.phoenix.util.IndexUtil;
 import org.apache.phoenix.util.SchemaUtil;
 
-import com.google.common.collect.Lists;
-
 
 public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expression>
{
     private boolean isAggregate;

http://git-wip-us.apache.org/repos/asf/phoenix/blob/5282a8a0/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementNormalizer.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementNormalizer.java
b/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementNormalizer.java
index acab605..803f554 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementNormalizer.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementNormalizer.java
@@ -30,18 +30,17 @@ import org.apache.phoenix.parse.ComparisonParseNode;
 import org.apache.phoenix.parse.DerivedTableNode;
 import org.apache.phoenix.parse.FamilyWildcardParseNode;
 import org.apache.phoenix.parse.JoinTableNode;
+import org.apache.phoenix.parse.JoinTableNode.JoinType;
 import org.apache.phoenix.parse.LessThanOrEqualParseNode;
 import org.apache.phoenix.parse.NamedTableNode;
 import org.apache.phoenix.parse.ParseNode;
 import org.apache.phoenix.parse.ParseNodeRewriter;
 import org.apache.phoenix.parse.SelectStatement;
-import org.apache.phoenix.parse.SubqueryParseNode;
 import org.apache.phoenix.parse.TableName;
 import org.apache.phoenix.parse.TableNode;
 import org.apache.phoenix.parse.TableNodeVisitor;
 import org.apache.phoenix.parse.TableWildcardParseNode;
 import org.apache.phoenix.parse.WildcardParseNode;
-import org.apache.phoenix.parse.JoinTableNode.JoinType;
 import org.apache.phoenix.util.SchemaUtil;
 
 import com.google.common.collect.Lists;
@@ -154,18 +153,6 @@ public class StatementNormalizer extends ParseNodeRewriter {
              nodes = normNodes;
              node = NODE_FACTORY.comparison(node.getInvertFilterOp(), nodes.get(0), nodes.get(1));
          }
-         // Add limit 2 to direct comparison with sub-query without ANY/SOME/ALL modifiers.
-         ParseNode rhs = nodes.get(1);
-         if (rhs instanceof SubqueryParseNode) {
-             SelectStatement subquery = ((SubqueryParseNode) rhs).getSelectNode();
-             subquery = NODE_FACTORY.select(subquery, NODE_FACTORY.limit(NODE_FACTORY.literal(2)));
-             rhs = NODE_FACTORY.subquery(subquery, true);
-             List<ParseNode> normNodes = Lists.newArrayListWithExpectedSize(2);
-             normNodes.add(nodes.get(0));
-             normNodes.add(rhs);
-             nodes = normNodes;
-             node = NODE_FACTORY.comparison(node.getFilterOp(), nodes.get(0), nodes.get(1));
-         }
          return super.visitLeave(node, nodes);
     }
     

http://git-wip-us.apache.org/repos/asf/phoenix/blob/5282a8a0/phoenix-core/src/main/java/org/apache/phoenix/compile/SubqueryRewriter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/SubqueryRewriter.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/SubqueryRewriter.java
index 42d060f..6428155 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/SubqueryRewriter.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/SubqueryRewriter.java
@@ -79,7 +79,7 @@ public class SubqueryRewriter extends ParseNodeRewriter {
         if (normWhere == where)
             return select;
         
-        return NODE_FACTORY.select(Collections.singletonList(rewriter.tableNode), select.getHint(),
select.isDistinct(), select.getSelect(), normWhere, select.getGroupBy(), select.getHaving(),
select.getOrderBy(), select.getLimit(), select.getBindCount(), select.isAggregate(), select.hasSequence());
+        return NODE_FACTORY.select(select, Collections.singletonList(rewriter.tableNode),
normWhere);
     }
     
     protected SubqueryRewriter(SelectStatement select, ColumnResolver resolver, PhoenixConnection
connection) {
@@ -133,9 +133,7 @@ public class SubqueryRewriter extends ParseNodeRewriter {
         SelectStatement subquery = subqueryNode.getSelectNode();
         String rhsTableAlias = ParseNodeFactory.createTempAlias();
         List<AliasedNode> selectNodes = fixAliasedNodes(subquery.getSelect());
-        subquery = NODE_FACTORY.select(subquery.getFrom(), subquery.getHint(), true, 
-                selectNodes, subquery.getWhere(), subquery.getGroupBy(), subquery.getHaving(),
subquery.getOrderBy(), 
-                subquery.getLimit(), subquery.getBindCount(), subquery.isAggregate(), subquery.hasSequence());
+        subquery = NODE_FACTORY.select(subquery, true, selectNodes);
         ParseNode onNode = getJoinConditionNode(l.get(0), selectNodes, rhsTableAlias);
         TableNode rhsTable = NODE_FACTORY.derivedTable(rhsTableAlias, subquery);
         JoinType joinType = topNode == node ? (node.isNegate() ? JoinType.Anti : JoinType.Semi)
: JoinType.Left;
@@ -168,9 +166,7 @@ public class SubqueryRewriter extends ParseNodeRewriter {
         selectNodes.add(NODE_FACTORY.aliasedNode(ParseNodeFactory.createTempAlias(), LiteralParseNode.ONE));
         selectNodes.addAll(additionalSelectNodes);
         
-        subquery = NODE_FACTORY.select(subquery.getFrom(), subquery.getHint(), true, 
-                selectNodes, where, subquery.getGroupBy(), subquery.getHaving(), subquery.getOrderBy(),

-                subquery.getLimit(), subquery.getBindCount(), subquery.isAggregate(), subquery.hasSequence());
+        subquery = NODE_FACTORY.select(subquery, true, selectNodes, where);
         ParseNode onNode = conditionExtractor.getJoinCondition();
         TableNode rhsTable = NODE_FACTORY.derivedTable(rhsTableAlias, subquery);
         JoinType joinType = topNode == node ? (node.isNegate() ? JoinType.Anti : JoinType.Semi)
: JoinType.Left;
@@ -183,6 +179,66 @@ public class SubqueryRewriter extends ParseNodeRewriter {
         
         return ret;
     }
+
+    @Override
+    public ParseNode visitLeave(ComparisonParseNode node, List<ParseNode> l) throws
SQLException {
+        ParseNode secondChild = l.get(1);
+        if (!(secondChild instanceof SubqueryParseNode)) {
+            return super.visitLeave(node, l);
+        }
+        
+        SubqueryParseNode subqueryNode = (SubqueryParseNode) secondChild;
+        SelectStatement subquery = subqueryNode.getSelectNode();
+        String rhsTableAlias = ParseNodeFactory.createTempAlias();
+        JoinConditionExtractor conditionExtractor = new JoinConditionExtractor(subquery,
resolver, connection, rhsTableAlias);
+        ParseNode where = subquery.getWhere() == null ? null : subquery.getWhere().accept(conditionExtractor);
+        if (where == subquery.getWhere()) { // non-correlated comparison subquery, add LIMIT
2, expectSingleRow = true
+            subquery = NODE_FACTORY.select(subquery, NODE_FACTORY.limit(NODE_FACTORY.literal(2)));
+            subqueryNode = NODE_FACTORY.subquery(subquery, true);
+            l = Lists.newArrayList(l.get(0), subqueryNode);
+            node = NODE_FACTORY.comparison(node.getFilterOp(), l.get(0), l.get(1));
+            return super.visitLeave(node, l);
+        }
+        
+        if (!subquery.isAggregate() || !subquery.getGroupBy().isEmpty()) {
+            //TODO add runtime singleton check or add a "singleton" aggregate funtion
+            throw new SQLFeatureNotSupportedException("Do not support non-aggregate or groupby
subquery in comparison.");
+        }
+        
+        ParseNode rhsNode = null; 
+        List<AliasedNode> aliasedNodes = subquery.getSelect();
+        if (aliasedNodes.size() == 1) {
+            rhsNode = aliasedNodes.get(0).getNode();
+        } else {
+            List<ParseNode> nodes = Lists.<ParseNode> newArrayListWithExpectedSize(aliasedNodes.size());
+            for (AliasedNode aliasedNode : aliasedNodes) {
+                nodes.add(aliasedNode.getNode());
+            }
+            rhsNode = NODE_FACTORY.rowValueConstructor(nodes);
+        }
+        
+        List<AliasedNode> additionalSelectNodes = conditionExtractor.getAdditionalSelectNodes();
+        List<AliasedNode> selectNodes = Lists.newArrayListWithExpectedSize(additionalSelectNodes.size()
+ 1);        
+        selectNodes.add(NODE_FACTORY.aliasedNode(ParseNodeFactory.createTempAlias(), rhsNode));
+        selectNodes.addAll(additionalSelectNodes);
+        List<ParseNode> groupbyNodes = Lists.newArrayListWithExpectedSize(additionalSelectNodes.size());
+        for (AliasedNode aliasedNode : additionalSelectNodes) {
+            groupbyNodes.add(aliasedNode.getNode());
+        }
+        
+        subquery = NODE_FACTORY.select(subquery, selectNodes, where, groupbyNodes, true);
+        ParseNode onNode = conditionExtractor.getJoinCondition();
+        TableNode rhsTable = NODE_FACTORY.derivedTable(rhsTableAlias, subquery);
+        JoinType joinType = topNode == node ? JoinType.Inner : JoinType.Left;
+        ParseNode ret = NODE_FACTORY.comparison(node.getFilterOp(), l.get(0), NODE_FACTORY.column(NODE_FACTORY.table(null,
rhsTableAlias), selectNodes.get(0).getAlias(), null));
+        tableNode = NODE_FACTORY.join(joinType, tableNode, rhsTable, onNode);
+        
+        if (topNode == node) {
+            topNode = null;
+        }
+        
+        return ret;
+    }
     
     private List<AliasedNode> fixAliasedNodes(List<AliasedNode> nodes) {
         List<AliasedNode> normNodes = Lists.<AliasedNode> newArrayListWithExpectedSize(nodes.size()
+ 1);

http://git-wip-us.apache.org/repos/asf/phoenix/blob/5282a8a0/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java
index 2b9f914..951098e 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java
@@ -611,6 +611,30 @@ public class ParseNodeFactory {
                 statement.hasSequence());
     }
 
+    public SelectStatement select(SelectStatement statement, List<? extends TableNode>
tables, ParseNode where) {
+        return select(tables, statement.getHint(), statement.isDistinct(), statement.getSelect(),
where, statement.getGroupBy(),
+                statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(),
statement.isAggregate(),
+                statement.hasSequence());
+    }
+
+    public SelectStatement select(SelectStatement statement, boolean isDistinct, List<AliasedNode>
select) {
+        return select(statement.getFrom(), statement.getHint(), isDistinct, select, statement.getWhere(),
statement.getGroupBy(),
+                statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(),
statement.isAggregate(),
+                statement.hasSequence());
+    }
+
+    public SelectStatement select(SelectStatement statement, boolean isDistinct, List<AliasedNode>
select, ParseNode where) {
+        return select(statement.getFrom(), statement.getHint(), isDistinct, select, where,
statement.getGroupBy(),
+                statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(),
statement.isAggregate(),
+                statement.hasSequence());
+    }
+
+    public SelectStatement select(SelectStatement statement, List<AliasedNode> select,
ParseNode where, List<ParseNode> groupBy, boolean isAggregate) {
+        return select(statement.getFrom(), statement.getHint(), statement.isDistinct(), select,
where, groupBy,
+                statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(),
isAggregate,
+                statement.hasSequence());
+    }
+
     public SelectStatement select(SelectStatement statement, HintNode hint) {
         return hint == null || hint.isEmpty() ? statement : select(statement.getFrom(), hint,
statement.isDistinct(), statement.getSelect(),
                 statement.getWhere(), statement.getGroupBy(), statement.getHaving(), statement.getOrderBy(),
statement.getLimit(),


Mime
View raw message