phoenix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From maryann...@apache.org
Subject phoenix git commit: PHOENIX-1807 Support UNION queries in subquery
Date Tue, 07 Apr 2015 03:30:54 GMT
Repository: phoenix
Updated Branches:
  refs/heads/4.x-HBase-0.98 b6c78e3f4 -> b198dbd6e


PHOENIX-1807 Support UNION queries in subquery


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

Branch: refs/heads/4.x-HBase-0.98
Commit: b198dbd6eeeaf34b70759aa5d07d5bcb055e5264
Parents: b6c78e3
Author: maryannxue <wei.xue@intel.com>
Authored: Mon Apr 6 23:30:38 2015 -0400
Committer: maryannxue <wei.xue@intel.com>
Committed: Mon Apr 6 23:30:38 2015 -0400

----------------------------------------------------------------------
 .../org/apache/phoenix/end2end/UnionAllIT.java  | 91 +++++++++++++++++---
 phoenix-core/src/main/antlr3/PhoenixSQL.g       |  2 +-
 .../apache/phoenix/compile/DeleteCompiler.java  |  2 +-
 .../apache/phoenix/compile/FromCompiler.java    |  2 +-
 .../apache/phoenix/compile/JoinCompiler.java    |  4 +-
 .../apache/phoenix/compile/QueryCompiler.java   |  4 +-
 .../phoenix/compile/SubqueryRewriter.java       | 19 ++--
 .../apache/phoenix/compile/UnionCompiler.java   |  6 +-
 .../apache/phoenix/jdbc/PhoenixStatement.java   | 10 +--
 .../apache/phoenix/optimize/QueryOptimizer.java |  2 +-
 .../apache/phoenix/parse/ParseNodeFactory.java  | 72 ++++++++++------
 .../apache/phoenix/parse/SelectStatement.java   | 33 ++++---
 12 files changed, 173 insertions(+), 74 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/b198dbd6/phoenix-core/src/it/java/org/apache/phoenix/end2end/UnionAllIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/UnionAllIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/UnionAllIT.java
index b3b2f7d..1d4055a 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/UnionAllIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/UnionAllIT.java
@@ -28,7 +28,6 @@ import java.sql.DriverManager;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
-import java.sql.SQLFeatureNotSupportedException;
 import java.sql.Statement;
 import java.util.Collections;
 import java.util.Map;
@@ -424,7 +423,7 @@ public class UnionAllIT extends BaseOwnClusterHBaseManagedTimeIT {
     }
 
     @Test
-    public void testUnionAllInSubquery() throws Exception {
+    public void testUnionAllInDerivedTable() throws Exception {
         Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
         Connection conn = DriverManager.getConnection(getUrl(), props);
         conn.setAutoCommit(false);
@@ -435,21 +434,63 @@ public class UnionAllIT extends BaseOwnClusterHBaseManagedTimeIT {
                     "  CONSTRAINT pk PRIMARY KEY (a_string))\n";
             createTestTable(getUrl(), ddl);
 
+            String dml = "UPSERT INTO test_table VALUES(?, ?)";
+            PreparedStatement stmt = conn.prepareStatement(dml);
+            stmt.setString(1, "a");
+            stmt.setInt(2, 10);
+            stmt.execute();
+            stmt.setString(1, "b");
+            stmt.setInt(2, 20);
+            stmt.execute();
+            conn.commit();
+
             ddl = "CREATE TABLE b_table " +
-                    "  (a_string varchar not null, col1 integer" +
+                    "  (a_string varchar not null, col2 integer" +
                     "  CONSTRAINT pk PRIMARY KEY (a_string))\n";
             createTestTable(getUrl(), ddl);
 
-            ddl = "select a_string, col1 from test_table where a_string in (select a_string
from test_table union all select a_string from b_table)";
-            conn.createStatement().executeQuery(ddl);
-        }  catch (SQLFeatureNotSupportedException e) {
+            dml = "UPSERT INTO b_table VALUES(?, ?)";
+            stmt = conn.prepareStatement(dml);
+            stmt.setString(1, "a");
+            stmt.setInt(2, 30);
+            stmt.execute();
+            stmt.setString(1, "c");
+            stmt.setInt(2, 60);
+            stmt.execute();
+            conn.commit();
+
+            String query = "select a_string from " +
+                    "(select a_string, col1 from test_table union all select a_string, col2
from b_table order by a_string)";
+            ResultSet rs = conn.createStatement().executeQuery(query);
+            assertTrue(rs.next());
+            assertEquals("a", rs.getString(1));
+            assertTrue(rs.next());
+            assertEquals("a", rs.getString(1));
+            assertTrue(rs.next());
+            assertEquals("b", rs.getString(1));
+            assertTrue(rs.next());
+            assertEquals("c", rs.getString(1));
+            assertFalse(rs.next());
+            
+            query = "select c from " +
+                    "(select a_string, col1 c from test_table union all select a_string,
col2 c from b_table order by c)";
+            rs = conn.createStatement().executeQuery(query);
+            assertTrue(rs.next());
+            assertEquals(10, rs.getInt(1));
+            assertTrue(rs.next());
+            assertEquals(20, rs.getInt(1));
+            assertTrue(rs.next());
+            assertEquals(30, rs.getInt(1));
+            assertTrue(rs.next());
+            assertEquals(60, rs.getInt(1));
+            assertFalse(rs.next());
         } finally {
             conn.close();
         }
     }
 
     @Test
-    public void testUnionAllInSubqueryDerived() throws Exception {
+    public void testUnionAllInSubquery() throws Exception {
         Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
         Connection conn = DriverManager.getConnection(getUrl(), props);
         conn.setAutoCommit(false);
@@ -460,15 +501,43 @@ public class UnionAllIT extends BaseOwnClusterHBaseManagedTimeIT {
                     "  CONSTRAINT pk PRIMARY KEY (a_string))\n";
             createTestTable(getUrl(), ddl);
 
+            String dml = "UPSERT INTO test_table VALUES(?, ?)";
+            PreparedStatement stmt = conn.prepareStatement(dml);
+            stmt.setString(1, "a");
+            stmt.setInt(2, 10);
+            stmt.execute();
+            stmt.setString(1, "b");
+            stmt.setInt(2, 20);
+            stmt.execute();
+            conn.commit();
+
             ddl = "CREATE TABLE b_table " +
                     "  (a_string varchar not null, col1 integer" +
                     "  CONSTRAINT pk PRIMARY KEY (a_string))\n";
             createTestTable(getUrl(), ddl);
 
-            ddl = "select a_string, col1 from test_table where a_string in (select a_string
from  " +
-                    "(select * from test_table union all select * from b_table))";
-            conn.createStatement().executeQuery(ddl);
-        }  catch (SQLException e) { 
+            dml = "UPSERT INTO b_table VALUES(?, ?)";
+            stmt = conn.prepareStatement(dml);
+            stmt.setString(1, "a");
+            stmt.setInt(2, 30);
+            stmt.execute();
+            stmt.setString(1, "c");
+            stmt.setInt(2, 60);
+            stmt.execute();
+            conn.commit();
+
+            String[] queries = new String[2];
+            queries[0] = "select a_string, col1 from test_table where a_string in " +
+                    "(select a_string aa from b_table where a_string != 'a' union all select
a_string bb from b_table)";
+            queries[1] = "select a_string, col1 from test_table where a_string in (select
a_string from  " +
+                    "(select a_string from b_table where a_string != 'a' union all select
a_string from b_table))";
+            for (String query : queries) {
+                ResultSet rs = conn.createStatement().executeQuery(query);
+                assertTrue(rs.next());
+                assertEquals("a", rs.getString(1));
+                assertEquals(10, rs.getInt(2));
+                assertFalse(rs.next());
+            }
         } finally {
             conn.close();
         }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/b198dbd6/phoenix-core/src/main/antlr3/PhoenixSQL.g
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/antlr3/PhoenixSQL.g b/phoenix-core/src/main/antlr3/PhoenixSQL.g
index 9ee1c93..97b7122 100644
--- a/phoenix-core/src/main/antlr3/PhoenixSQL.g
+++ b/phoenix-core/src/main/antlr3/PhoenixSQL.g
@@ -578,7 +578,7 @@ single_select returns [SelectStatement ret]
         (WHERE where=expression)?
         (GROUP BY group=group_by)?
         (HAVING having=expression)?
-        { ParseContext context = contextStack.peek(); $ret = factory.select(from, h, d!=null,
sel, where, group, having, null, null, getBindCount(), context.isAggregate(), context.hasSequences());
}
+        { ParseContext context = contextStack.peek(); $ret = factory.select(from, h, d!=null,
sel, where, group, having, null, null, getBindCount(), context.isAggregate(), context.hasSequences(),
null); }
     ;
 finally{ contextStack.pop(); }
 

http://git-wip-us.apache.org/repos/asf/phoenix/blob/b198dbd6/phoenix-core/src/main/java/org/apache/phoenix/compile/DeleteCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/DeleteCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/DeleteCompiler.java
index 322d24a..b8e68f9 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/DeleteCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/DeleteCompiler.java
@@ -322,7 +322,7 @@ public class DeleteCompiler {
                         hint, false, aliasedNodes, delete.getWhere(), 
                         Collections.<ParseNode>emptyList(), null, 
                         delete.getOrderBy(), delete.getLimit(),
-                        delete.getBindCount(), false, false);
+                        delete.getBindCount(), false, false, Collections.<SelectStatement>emptyList());
                 select = StatementNormalizer.normalize(select, resolver);
                 SelectStatement transformedSelect = SubqueryRewriter.transform(select, resolver,
connection);
                 if (transformedSelect != select) {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/b198dbd6/phoenix-core/src/main/java/org/apache/phoenix/compile/FromCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/FromCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/FromCompiler.java
index 98a1108..da78b24 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/FromCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/FromCompiler.java
@@ -469,7 +469,7 @@ public class FromCompiler {
                     if (node instanceof WildcardParseNode
                             || node instanceof TableWildcardParseNode
                             || node instanceof FamilyWildcardParseNode)
-                        throw new SQLException("Encountered wildcard in subqueries.");
+                        throw new SQLFeatureNotSupportedException("Wildcard in subqueries
not supported.");
 
                     alias = SchemaUtil.normalizeIdentifier(node.getAlias());
                 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/b198dbd6/phoenix-core/src/main/java/org/apache/phoenix/compile/JoinCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/JoinCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/JoinCompiler.java
index 98b7edb..af6c712 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/JoinCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/JoinCompiler.java
@@ -688,7 +688,7 @@ public class JoinCompiler {
             if (isSubselect())
                 return SubselectRewriter.applyOrderBy(SubselectRewriter.applyPostFilters(subselect,
preFilters, tableNode.getAlias()), orderBy, tableNode.getAlias());
 
-            return NODE_FACTORY.select(tableNode, select.getHint(), false, selectNodes, getPreFiltersCombined(),
null, null, orderBy, null, 0, false, select.hasSequence());
+            return NODE_FACTORY.select(tableNode, select.getHint(), false, selectNodes, getPreFiltersCombined(),
null, null, orderBy, null, 0, false, select.hasSequence(), Collections.<SelectStatement>emptyList());
         }
 
         public boolean hasFilters() {
@@ -1267,7 +1267,7 @@ public class JoinCompiler {
         String tableAlias = tableRef.getTableAlias();
         TableNode from = NODE_FACTORY.namedTable(tableAlias == null ? null : '"' + tableAlias
+ '"', tName, dynamicCols);
 
-        return NODE_FACTORY.select(from, hintNode, false, selectList, where, groupBy, null,
orderBy, null, 0, groupBy != null, hasSequence);
+        return NODE_FACTORY.select(from, hintNode, false, selectList, where, groupBy, null,
orderBy, null, 0, groupBy != null, hasSequence, Collections.<SelectStatement>emptyList());
     }
 
     public static PTable joinProjectedTables(PTable left, PTable right, JoinType type) throws
SQLException {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/b198dbd6/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java
index 68a81a5..16df85d 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java
@@ -174,7 +174,7 @@ public class QueryCompiler {
         }
         UnionCompiler.checkProjectionNumAndTypes(plans);
 
-        TableRef tableRef = UnionCompiler.contructSchemaTable(statement, plans.get(0));
+        TableRef tableRef = UnionCompiler.contructSchemaTable(statement, plans.get(0), select.hasWildcard()
? null : select.getSelect());
         ColumnResolver resolver = FromCompiler.getResolver(tableRef);
         StatementContext context = new StatementContext(statement, resolver, scan, sequenceManager);
 
@@ -422,7 +422,7 @@ public class QueryCompiler {
         context.setResolver(resolver);
         TableNode from = NODE_FACTORY.namedTable(tableRef.getTableAlias(), NODE_FACTORY.table(tableRef.getTable().getSchemaName().getString(),
tableRef.getTable().getTableName().getString()));
         ParseNode where = joinTable.getPostFiltersCombined();
-        SelectStatement select = asSubquery ? NODE_FACTORY.select(from, joinTable.getStatement().getHint(),
false, Collections.<AliasedNode> emptyList(), where, null, null, orderBy, null, 0, false,
joinTable.getStatement().hasSequence())
+        SelectStatement select = asSubquery ? NODE_FACTORY.select(from, joinTable.getStatement().getHint(),
false, Collections.<AliasedNode> emptyList(), where, null, null, orderBy, null, 0, false,
joinTable.getStatement().hasSequence(), Collections.<SelectStatement>emptyList())
                 : NODE_FACTORY.select(joinTable.getStatement(), from, where);
         
         return compileSingleFlatQuery(context, select, binds, asSubquery, false, innerPlan,
null, isInRowKeyOrder);

http://git-wip-us.apache.org/repos/asf/phoenix/blob/b198dbd6/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 60067e5..8e887a8 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
@@ -36,6 +36,7 @@ import org.apache.phoenix.parse.ColumnParseNode;
 import org.apache.phoenix.parse.ComparisonParseNode;
 import org.apache.phoenix.parse.CompoundParseNode;
 import org.apache.phoenix.parse.ExistsParseNode;
+import org.apache.phoenix.parse.HintNode;
 import org.apache.phoenix.parse.InParseNode;
 import org.apache.phoenix.parse.JoinTableNode.JoinType;
 import org.apache.phoenix.parse.LiteralParseNode;
@@ -139,7 +140,7 @@ public class SubqueryRewriter extends ParseNodeRewriter {
         }
         
         SubqueryParseNode subqueryNode = (SubqueryParseNode) l.get(1);
-        SelectStatement subquery = subqueryNode.getSelectNode();
+        SelectStatement subquery = fixSubqueryStatement(subqueryNode.getSelectNode());
         String rhsTableAlias = ParseNodeFactory.createTempAlias();
         List<AliasedNode> selectNodes = fixAliasedNodes(subquery.getSelect(), true);
         subquery = NODE_FACTORY.select(subquery, !node.isSubqueryDistinct(), selectNodes);
@@ -160,7 +161,7 @@ public class SubqueryRewriter extends ParseNodeRewriter {
         }
         
         SubqueryParseNode subqueryNode = (SubqueryParseNode) l.get(0);
-        SelectStatement subquery = subqueryNode.getSelectNode();
+        SelectStatement subquery = fixSubqueryStatement(subqueryNode.getSelectNode());
         String rhsTableAlias = ParseNodeFactory.createTempAlias();
         JoinConditionExtractor conditionExtractor = new JoinConditionExtractor(subquery,
resolver, connection, rhsTableAlias);
         ParseNode where = subquery.getWhere() == null ? null : subquery.getWhere().accept(conditionExtractor);
@@ -199,7 +200,7 @@ public class SubqueryRewriter extends ParseNodeRewriter {
         }
         
         SubqueryParseNode subqueryNode = (SubqueryParseNode) secondChild;
-        SelectStatement subquery = subqueryNode.getSelectNode();
+        SelectStatement subquery = fixSubqueryStatement(subqueryNode.getSelectNode());
         String rhsTableAlias = ParseNodeFactory.createTempAlias();
         JoinConditionExtractor conditionExtractor = new JoinConditionExtractor(subquery,
resolver, connection, rhsTableAlias);
         ParseNode where = subquery.getWhere() == null ? null : subquery.getWhere().accept(conditionExtractor);
@@ -282,7 +283,7 @@ public class SubqueryRewriter extends ParseNodeRewriter {
         }
         
         SubqueryParseNode subqueryNode = (SubqueryParseNode) firstChild;
-        SelectStatement subquery = subqueryNode.getSelectNode();
+        SelectStatement subquery = fixSubqueryStatement(subqueryNode.getSelectNode());
         String rhsTableAlias = ParseNodeFactory.createTempAlias();
         JoinConditionExtractor conditionExtractor = new JoinConditionExtractor(subquery,
resolver, connection, rhsTableAlias);
         ParseNode where = subquery.getWhere() == null ? null : subquery.getWhere().accept(conditionExtractor);
@@ -339,7 +340,7 @@ public class SubqueryRewriter extends ParseNodeRewriter {
                 groupbyNodes.set(i - 1, aliasedNode.getNode());
             }
             SelectStatement derivedTableStmt = NODE_FACTORY.select(subquery, subquery.isDistinct(),
derivedTableSelect, where, derivedTableGroupBy, true);
-            subquery = NODE_FACTORY.select(NODE_FACTORY.derivedTable(derivedTableAlias, derivedTableStmt),
subquery.getHint(), false, selectNodes, null, groupbyNodes, null, Collections.<OrderByNode>
emptyList(), null, subquery.getBindCount(), true, false);
+            subquery = NODE_FACTORY.select(NODE_FACTORY.derivedTable(derivedTableAlias, derivedTableStmt),
subquery.getHint(), false, selectNodes, null, groupbyNodes, null, Collections.<OrderByNode>
emptyList(), null, subquery.getBindCount(), true, false, Collections.<SelectStatement>emptyList());
         }
         
         ParseNode onNode = conditionExtractor.getJoinCondition();
@@ -357,6 +358,14 @@ public class SubqueryRewriter extends ParseNodeRewriter {
         return Lists.newArrayList(firstChild, secondChild);
     }
     
+    private SelectStatement fixSubqueryStatement(SelectStatement select) {
+        if (!select.isUnion())
+            return select;
+        
+        // Wrap as a derived table.
+        return NODE_FACTORY.select(NODE_FACTORY.derivedTable(ParseNodeFactory.createTempAlias(),
select), HintNode.EMPTY_HINT_NODE, false, select.getSelect(), null, null, null, null, null,
select.getBindCount(), false, false, Collections.<SelectStatement> emptyList());
+    }
+    
     private List<AliasedNode> fixAliasedNodes(List<AliasedNode> nodes, boolean
addSelectOne) {
         List<AliasedNode> normNodes = Lists.<AliasedNode> newArrayListWithExpectedSize(nodes.size()
+ (addSelectOne ? 1 : 0));
         if (addSelectOne) {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/b198dbd6/phoenix-core/src/main/java/org/apache/phoenix/compile/UnionCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/UnionCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/UnionCompiler.java
index 3f069ff..269232e 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/UnionCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/UnionCompiler.java
@@ -26,6 +26,7 @@ import org.apache.phoenix.exception.SQLExceptionCode;
 import org.apache.phoenix.exception.SQLExceptionInfo;
 import org.apache.phoenix.expression.Expression;
 import org.apache.phoenix.jdbc.PhoenixStatement;
+import org.apache.phoenix.parse.AliasedNode;
 import org.apache.phoenix.schema.PColumn;
 import org.apache.phoenix.schema.PColumnImpl;
 import org.apache.phoenix.schema.PName;
@@ -66,12 +67,13 @@ public class UnionCompiler {
         return selectPlans;
     }
 
-    public static TableRef contructSchemaTable(PhoenixStatement statement, QueryPlan plan)
throws SQLException {
+    public static TableRef contructSchemaTable(PhoenixStatement statement, QueryPlan plan,
List<AliasedNode> selectNodes) throws SQLException {
         List<PColumn> projectedColumns = new ArrayList<PColumn>();
         for (int i=0; i< plan.getProjector().getColumnCount(); i++) {
             ColumnProjector colProj = plan.getProjector().getColumnProjector(i);
             Expression sourceExpression = colProj.getExpression();
-            PColumnImpl projectedColumn = new PColumnImpl(PNameFactory.newName(colProj.getName()),
UNION_FAMILY_NAME,
+            String name = selectNodes == null ? colProj.getName() : selectNodes.get(i).getAlias();
+            PColumnImpl projectedColumn = new PColumnImpl(PNameFactory.newName(name), UNION_FAMILY_NAME,
                     sourceExpression.getDataType(), sourceExpression.getMaxLength(), sourceExpression.getScale(),
sourceExpression.isNullable(),
                     i, sourceExpression.getSortOrder(), 500, null, false, sourceExpression.toString());
             projectedColumns.add(projectedColumn);

http://git-wip-us.apache.org/repos/asf/phoenix/blob/b198dbd6/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixStatement.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixStatement.java b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixStatement.java
index 45cc502..465d84a 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixStatement.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixStatement.java
@@ -847,19 +847,11 @@ public class PhoenixStatement implements Statement, SQLCloseable, org.apache.pho
 
     protected static class ExecutableNodeFactory extends ParseNodeFactory {
         @Override
-        public ExecutableSelectStatement select(TableNode from, HintNode hint, boolean isDistinct,
List<AliasedNode> select,
-                ParseNode where, List<ParseNode> groupBy, ParseNode having,
-                List<OrderByNode> orderBy, LimitNode limit, int bindCount, boolean
isAggregate, boolean hasSequence) {
-            return this.select(from, hint, isDistinct, select, where, groupBy, having, orderBy,
limit, bindCount, isAggregate, hasSequence, 
-                Collections.<SelectStatement>emptyList());
-        }
-
-        @Override
         public ExecutableSelectStatement select(TableNode from, HintNode hint, boolean isDistinct,
List<AliasedNode> select, ParseNode where,
                 List<ParseNode> groupBy, ParseNode having, List<OrderByNode>
orderBy, LimitNode limit, int bindCount, boolean isAggregate,
                 boolean hasSequence, List<SelectStatement> selects) {
             return new ExecutableSelectStatement(from, hint, isDistinct, select, where, groupBy
== null ? Collections.<ParseNode>emptyList() : groupBy,
-                    having, orderBy == null ? Collections.<OrderByNode>emptyList()
: orderBy, limit, bindCount, isAggregate, hasSequence, selects);
+                    having, orderBy == null ? Collections.<OrderByNode>emptyList()
: orderBy, limit, bindCount, isAggregate, hasSequence, selects == null ? Collections.<SelectStatement>emptyList()
: selects);
         }
 
         @Override

http://git-wip-us.apache.org/repos/asf/phoenix/blob/b198dbd6/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java b/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java
index 382bba5..7b3a63a 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java
@@ -290,7 +290,7 @@ public class QueryOptimizer {
                             aliasedNodes.add(FACTORY.aliasedNode(null, indexColNode));
                             nodes.add(new ColumnParseNode(null, '"' + column.getName().getString()
+ '"'));
                         }
-                        SelectStatement innerSelect = FACTORY.select(indexSelect.getFrom(),
indexSelect.getHint(), false, aliasedNodes, where, null, null, null, indexSelect.getLimit(),
indexSelect.getBindCount(), false, indexSelect.hasSequence());
+                        SelectStatement innerSelect = FACTORY.select(indexSelect.getFrom(),
indexSelect.getHint(), false, aliasedNodes, where, null, null, null, indexSelect.getLimit(),
indexSelect.getBindCount(), false, indexSelect.hasSequence(), Collections.<SelectStatement>emptyList());
                         ParseNode outerWhere = FACTORY.in(nodes.size() == 1 ? nodes.get(0)
: FACTORY.rowValueConstructor(nodes), FACTORY.subquery(innerSelect, false), false, true);
                         ParseNode extractedCondition = whereRewriter.getExtractedCondition();
                         if (extractedCondition != null) {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/b198dbd6/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 e6d3de6..5fdf840 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
@@ -20,7 +20,6 @@ package org.apache.phoenix.parse;
 import java.lang.reflect.Constructor;
 import java.math.BigDecimal;
 import java.sql.SQLException;
-import java.sql.SQLFeatureNotSupportedException;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -29,6 +28,8 @@ import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
 import org.apache.hadoop.hbase.util.Pair;
+import org.apache.phoenix.exception.SQLExceptionCode;
+import org.apache.phoenix.exception.SQLExceptionInfo;
 import org.apache.phoenix.exception.UnknownFunctionException;
 import org.apache.phoenix.expression.Expression;
 import org.apache.phoenix.expression.ExpressionType;
@@ -655,15 +656,8 @@ public class ParseNodeFactory {
             boolean hasSequence, List<SelectStatement> selects) {
 
         return new SelectStatement(from, hint, isDistinct, select, where, groupBy == null
? Collections.<ParseNode>emptyList() : groupBy, having,
-                orderBy == null ? Collections.<OrderByNode>emptyList() : orderBy, limit,
bindCount, isAggregate, hasSequence, selects);
+                orderBy == null ? Collections.<OrderByNode>emptyList() : orderBy, limit,
bindCount, isAggregate, hasSequence, selects == null ? Collections.<SelectStatement>emptyList()
: selects);
     } 
-
-    public SelectStatement select(TableNode from, HintNode hint, boolean isDistinct, List<AliasedNode>
select, ParseNode where,
-            List<ParseNode> groupBy, ParseNode having, List<OrderByNode> orderBy,
LimitNode limit, int bindCount, boolean isAggregate, boolean hasSequence) {
-
-        return new SelectStatement(from, hint, isDistinct, select, where, groupBy == null
? Collections.<ParseNode>emptyList() : groupBy, having,
-                orderBy == null ? Collections.<OrderByNode>emptyList() : orderBy, limit,
bindCount, isAggregate, hasSequence);
-    }
     
     public UpsertStatement upsert(NamedTableNode table, HintNode hint, List<ColumnName>
columns, List<ParseNode> values, SelectStatement select, int bindCount) {
         return new UpsertStatement(table, hint, columns, values, select, bindCount);
@@ -675,53 +669,53 @@ public class ParseNodeFactory {
 
     public SelectStatement select(SelectStatement statement, ParseNode where) {
         return select(statement.getFrom(), statement.getHint(), statement.isDistinct(), statement.getSelect(),
where, statement.getGroupBy(), statement.getHaving(),
-                statement.getOrderBy(), statement.getLimit(), statement.getBindCount(), statement.isAggregate(),
statement.hasSequence());
+                statement.getOrderBy(), statement.getLimit(), statement.getBindCount(), statement.isAggregate(),
statement.hasSequence(), statement.getSelects());
     }
 
     public SelectStatement select(SelectStatement statement, ParseNode where, ParseNode having)
{
         return select(statement.getFrom(), statement.getHint(), statement.isDistinct(), statement.getSelect(),
where, statement.getGroupBy(), having,
-                statement.getOrderBy(), statement.getLimit(), statement.getBindCount(), statement.isAggregate(),
statement.hasSequence());
+                statement.getOrderBy(), statement.getLimit(), statement.getBindCount(), statement.isAggregate(),
statement.hasSequence(), statement.getSelects());
     }
     
     public SelectStatement select(SelectStatement statement, List<AliasedNode> select,
ParseNode where, List<ParseNode> groupBy, ParseNode having, List<OrderByNode>
orderBy) {
         return select(statement.getFrom(), statement.getHint(), statement.isDistinct(), 
-                select, where, groupBy, having, orderBy, statement.getLimit(), statement.getBindCount(),
statement.isAggregate(), statement.hasSequence());
+                select, where, groupBy, having, orderBy, statement.getLimit(), statement.getBindCount(),
statement.isAggregate(), statement.hasSequence(), statement.getSelects());
     }
     
     public SelectStatement select(SelectStatement statement, TableNode table) {
         return select(table, statement.getHint(), statement.isDistinct(), statement.getSelect(),
statement.getWhere(), statement.getGroupBy(),
                 statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(),
statement.isAggregate(),
-                statement.hasSequence());
+                statement.hasSequence(), statement.getSelects());
     }
 
     public SelectStatement select(SelectStatement statement, TableNode table, ParseNode where)
{
         return select(table, statement.getHint(), statement.isDistinct(), statement.getSelect(),
where, statement.getGroupBy(),
                 statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(),
statement.isAggregate(),
-                statement.hasSequence());
+                statement.hasSequence(), statement.getSelects());
     }
 
     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());
+                statement.hasSequence(), statement.getSelects());
     }
 
     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());
+                statement.hasSequence(), statement.getSelects());
     }
 
     public SelectStatement select(SelectStatement statement, boolean isDistinct, List<AliasedNode>
select, ParseNode where, List<ParseNode> groupBy, boolean isAggregate) {
         return select(statement.getFrom(), statement.getHint(), isDistinct, select, where,
groupBy,
                 statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(),
isAggregate,
-                statement.hasSequence());
+                statement.hasSequence(), statement.getSelects());
     }
 
     public SelectStatement select(SelectStatement statement, List<OrderByNode> orderBy)
{
         return select(statement.getFrom(), statement.getHint(), statement.isDistinct(), statement.getSelect(),
                 statement.getWhere(), statement.getGroupBy(), statement.getHaving(), orderBy,
statement.getLimit(),
-                statement.getBindCount(), statement.isAggregate(), statement.hasSequence());
+                statement.getBindCount(), statement.isAggregate(), statement.hasSequence(),
statement.getSelects());
     }
 
     public SelectStatement select(SelectStatement statement, HintNode hint) {
@@ -733,39 +727,65 @@ public class ParseNodeFactory {
     public SelectStatement select(SelectStatement statement, HintNode hint, ParseNode where)
{
         return select(statement.getFrom(), hint, statement.isDistinct(), statement.getSelect(),
where, statement.getGroupBy(),
                 statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(),
statement.isAggregate(),
-                statement.hasSequence());
+                statement.hasSequence(), statement.getSelects());
     }
 
     public SelectStatement select(SelectStatement statement, List<OrderByNode> orderBy,
LimitNode limit, int bindCount, boolean isAggregate) {
         return select(statement.getFrom(), statement.getHint(), statement.isDistinct(), statement.getSelect(),
             statement.getWhere(), statement.getGroupBy(), statement.getHaving(), orderBy,
limit,
-            bindCount, isAggregate || statement.isAggregate(), statement.hasSequence());
+            bindCount, isAggregate || statement.isAggregate(), statement.hasSequence(), statement.getSelects());
 
     }
 
     public SelectStatement select(SelectStatement statement, LimitNode limit) {
         return select(statement.getFrom(), statement.getHint(), statement.isDistinct(), statement.getSelect(),
             statement.getWhere(), statement.getGroupBy(), statement.getHaving(), statement.getOrderBy(),
limit,
-            statement.getBindCount(), statement.isAggregate(), statement.hasSequence());
+            statement.getBindCount(), statement.isAggregate(), statement.hasSequence(), statement.getSelects());
     }
 
     public SelectStatement select(SelectStatement statement, List<OrderByNode> orderBy,
LimitNode limit) {
         return select(statement.getFrom(), statement.getHint(), statement.isDistinct(), statement.getSelect(),
             statement.getWhere(), statement.getGroupBy(), statement.getHaving(), orderBy,
limit,
-            statement.getBindCount(), statement.isAggregate(), statement.hasSequence());
+            statement.getBindCount(), statement.isAggregate(), statement.hasSequence(), statement.getSelects());
     }
 
     public SelectStatement select(List<SelectStatement> statements, List<OrderByNode>
orderBy, LimitNode limit, int bindCount, boolean isAggregate) {
         if (statements.size() == 1)
-            return select(statements.get(0), orderBy, limit, bindCount, isAggregate);
+            return select(statements.get(0), orderBy, limit, bindCount, isAggregate);   
    
+
+        // Get a list of adjusted aliases from a non-wildcard sub-select if any. 
+        // We do not check the number of select nodes among all sub-selects, as 
+        // it will be done later at compile stage. Empty or different aliases 
+        // are ignored, since they cannot be referred by outer queries.
+        List<String> aliases = Lists.<String> newArrayList();
+        for (int i = 0; i < statements.size() && aliases.isEmpty(); i++) {
+            SelectStatement subselect = statements.get(i);
+            if (!subselect.hasWildcard()) {
+                for (AliasedNode aliasedNode : subselect.getSelect()) {
+                    String alias = aliasedNode.getAlias();
+                    if (alias == null) {
+                        alias = SchemaUtil.normalizeIdentifier(aliasedNode.getNode().getAlias());
+                    }
+                    aliases.add(alias == null ? createTempAlias() : alias);
+                }
+            }
+        }
+
+        List<AliasedNode> aliasedNodes;
+        if (aliases.isEmpty()) {
+            aliasedNodes = Lists.newArrayList(aliasedNode(null, wildcard()));
+        } else {
+            aliasedNodes = Lists.newArrayListWithExpectedSize(aliases.size());
+            for (String alias : aliases) {
+                aliasedNodes.add(aliasedNode(alias, column(null, alias, alias)));
+            }
+        }
         
-        return select(null, HintNode.EMPTY_HINT_NODE, false, Lists.newArrayList(aliasedNode(null,
wildcard())), 
+        return select(null, HintNode.EMPTY_HINT_NODE, false, aliasedNodes, 
                 null, null, null, orderBy, limit, bindCount, false, false, statements);
     }
 
     public SubqueryParseNode subquery(SelectStatement select, boolean expectSingleRow) {
-        if (select.isUnion()) 
-            throw new RuntimeException(new SQLFeatureNotSupportedException());
         return new SubqueryParseNode(select, expectSingleRow);
     }
 

http://git-wip-us.apache.org/repos/asf/phoenix/blob/b198dbd6/phoenix-core/src/main/java/org/apache/phoenix/parse/SelectStatement.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/SelectStatement.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/SelectStatement.java
index 08cec87..44b24af 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/parse/SelectStatement.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/SelectStatement.java
@@ -42,7 +42,7 @@ public class SelectStatement implements FilterableStatement {
                     Collections.<AliasedNode>singletonList(new AliasedNode(null, LiteralParseNode.ONE)),
                     null, Collections.<ParseNode>emptyList(),
                     null, Collections.<OrderByNode>emptyList(),
-                    null, 0, false, false);
+                    null, 0, false, false, Collections.<SelectStatement>emptyList());
     public static final SelectStatement COUNT_ONE =
             new SelectStatement(
                     null, null, false,
@@ -54,14 +54,14 @@ public class SelectStatement implements FilterableStatement {
                                 new BuiltInFunctionInfo(CountAggregateFunction.class, CountAggregateFunction.class.getAnnotation(BuiltInFunction.class))))),
                     null, Collections.<ParseNode>emptyList(), 
                     null, Collections.<OrderByNode>emptyList(), 
-                    null, 0, true, false);
+                    null, 0, true, false, Collections.<SelectStatement>emptyList());
     public static SelectStatement create(SelectStatement select, HintNode hint) {
         if (select.getHint() == hint || hint.isEmpty()) {
             return select;
         }
         return new SelectStatement(select.getFrom(), hint, select.isDistinct(), 
                 select.getSelect(), select.getWhere(), select.getGroupBy(), select.getHaving(),

-                select.getOrderBy(), select.getLimit(), select.getBindCount(), select.isAggregate(),
select.hasSequence());
+                select.getOrderBy(), select.getLimit(), select.getBindCount(), select.isAggregate(),
select.hasSequence(), select.getSelects());
     }
     
     public SelectStatement combine(ParseNode where) {
@@ -73,13 +73,13 @@ public class SelectStatement implements FilterableStatement {
         }
         return new SelectStatement(this.getFrom(), this.getHint(), this.isDistinct(), 
                 this.getSelect(), where, this.getGroupBy(), this.getHaving(), 
-                this.getOrderBy(), this.getLimit(), this.getBindCount(), this.isAggregate(),
this.hasSequence());
+                this.getOrderBy(), this.getLimit(), this.getBindCount(), this.isAggregate(),
this.hasSequence(), this.selects);
     }
     
     public static SelectStatement create(SelectStatement select, List<AliasedNode>
selects) {
         return new SelectStatement(select.getFrom(), select.getHint(), select.isDistinct(),

                 selects, select.getWhere(), select.getGroupBy(), select.getHaving(), 
-                select.getOrderBy(), select.getLimit(), select.getBindCount(), select.isAggregate(),
select.hasSequence());
+                select.getOrderBy(), select.getLimit(), select.getBindCount(), select.isAggregate(),
select.hasSequence(), select.getSelects());
     }
     
     // Copy constructor for sub select statements in a union
@@ -87,7 +87,7 @@ public class SelectStatement implements FilterableStatement {
             List<OrderByNode> orderBy, LimitNode limit, boolean isAggregate) {
         return new SelectStatement(select.getFrom(), select.getHint(), select.isDistinct(),

                 select.getSelect(), select.getWhere(), select.getGroupBy(), select.getHaving(),

-                orderBy, limit, select.getBindCount(), isAggregate, select.hasSequence());
+                orderBy, limit, select.getBindCount(), isAggregate, select.hasSequence(),
select.getSelects());
     }
 
     private final TableNode fromTable;
@@ -102,6 +102,7 @@ public class SelectStatement implements FilterableStatement {
     private final int bindCount;
     private final boolean isAggregate;
     private final boolean hasSequence;
+    private final boolean hasWildcard;
     private final List<SelectStatement> selects = new ArrayList<SelectStatement>();
     
     @Override
@@ -228,17 +229,19 @@ public class SelectStatement implements FilterableStatement {
         this.bindCount = bindCount;
         this.isAggregate = isAggregate || groupBy.size() != countConstants(groupBy) || this.having
!= null;
         this.hasSequence = hasSequence;
+        boolean hasWildcard = false;
+        for (AliasedNode aliasedNode : select) {
+            ParseNode node = aliasedNode.getNode();
+            if (node instanceof WildcardParseNode || node instanceof TableWildcardParseNode
|| node instanceof FamilyWildcardParseNode) {
+                hasWildcard = true;
+                break;
+            }
+        }
+        this.hasWildcard = hasWildcard;
         if (!selects.isEmpty()) {
             this.selects.addAll(selects);
         }
     }
-
-    public SelectStatement(TableNode from, HintNode hint, boolean isDistinct, List<AliasedNode>
select,
-            ParseNode where, List<ParseNode> groupBy, ParseNode having, List<OrderByNode>
orderBy, LimitNode limit,
-            int bindCount, boolean isAggregate, boolean hasSequence) {
-        this(from, hint, isDistinct, select, where, groupBy, having, orderBy, limit, bindCount,
isAggregate, hasSequence,
-                Collections.<SelectStatement>emptyList());
-    }
     
     @Override
     public boolean isDistinct() {
@@ -326,4 +329,8 @@ public class SelectStatement implements FilterableStatement {
     public List<SelectStatement> getSelects() {
         return selects;
     }
+    
+    public boolean hasWildcard() {
+        return hasWildcard;
+    }
 }


Mime
View raw message