You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ma...@apache.org on 2014/04/23 01:33:10 UTC

[1/2] git commit: PHOENIX-136 Support derived tables

Repository: incubator-phoenix
Updated Branches:
  refs/heads/master db481c552 -> 76908006c


PHOENIX-136 Support derived tables


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

Branch: refs/heads/master
Commit: 43c788779d0d62aa7d7022802d6064490046ee23
Parents: a615ceb
Author: maryannxue <ma...@apache.org>
Authored: Tue Apr 22 19:23:42 2014 -0400
Committer: maryannxue <ma...@apache.org>
Committed: Tue Apr 22 19:23:42 2014 -0400

----------------------------------------------------------------------
 .../apache/phoenix/end2end/DerivedTableIT.java  | 654 +++++++++++++++++++
 .../org/apache/phoenix/end2end/HashJoinIT.java  |  19 +-
 phoenix-core/src/main/antlr3/PhoenixSQL.g       |   1 -
 .../apache/phoenix/compile/FromCompiler.java    |  21 +-
 .../phoenix/compile/IndexStatementRewriter.java |   5 -
 .../apache/phoenix/compile/JoinCompiler.java    | 115 +---
 .../apache/phoenix/compile/LimitCompiler.java   |   4 +
 .../apache/phoenix/compile/QueryCompiler.java   |  11 +-
 .../phoenix/compile/SubselectRewriter.java      | 244 +++++++
 .../apache/phoenix/compile/UpsertCompiler.java  |   1 +
 .../apache/phoenix/jdbc/PhoenixStatement.java   |   6 +-
 .../java/org/apache/phoenix/parse/HintNode.java |   6 +
 .../apache/phoenix/parse/ParseNodeRewriter.java |  14 +-
 .../phoenix/compile/JoinQueryCompilerTest.java  |   8 +-
 14 files changed, 975 insertions(+), 134 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/43c78877/phoenix-core/src/it/java/org/apache/phoenix/end2end/DerivedTableIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/DerivedTableIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/DerivedTableIT.java
new file mode 100644
index 0000000..3906ec8
--- /dev/null
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/DerivedTableIT.java
@@ -0,0 +1,654 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.phoenix.end2end;
+
+import static org.apache.phoenix.util.TestUtil.A_VALUE;
+import static org.apache.phoenix.util.TestUtil.B_VALUE;
+import static org.apache.phoenix.util.TestUtil.C_VALUE;
+import static org.apache.phoenix.util.TestUtil.E_VALUE;
+import static org.apache.phoenix.util.TestUtil.ROW1;
+import static org.apache.phoenix.util.TestUtil.ROW2;
+import static org.apache.phoenix.util.TestUtil.ROW3;
+import static org.apache.phoenix.util.TestUtil.ROW4;
+import static org.apache.phoenix.util.TestUtil.ROW5;
+import static org.apache.phoenix.util.TestUtil.ROW6;
+import static org.apache.phoenix.util.TestUtil.ROW7;
+import static org.apache.phoenix.util.TestUtil.ROW8;
+import static org.apache.phoenix.util.TestUtil.ROW9;
+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.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.Collection;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.phoenix.util.PhoenixRuntime;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import com.google.common.collect.Lists;
+
+@RunWith(Parameterized.class)
+public class DerivedTableIT extends BaseClientManagedTimeIT {
+    private static final String tenantId = getOrganizationId();
+    private static final String MSG = "Complex nested queries not supported.";
+    
+    private long ts;
+    private String indexDDL;
+    
+    public DerivedTableIT(String indexDDL) {
+        this.indexDDL = indexDDL;
+    }
+    
+    @Before
+    public void initTable() throws Exception {
+         ts = nextTimestamp();
+        initATableValues(tenantId, getDefaultSplits(tenantId), null, ts);
+        if (indexDDL != null && indexDDL.length() > 0) {
+            Properties props = new Properties(TEST_PROPERTIES);
+            props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts));
+            Connection conn = DriverManager.getConnection(getUrl(), props);
+            conn.createStatement().execute(indexDDL);
+        }
+    }
+    
+    @Parameters(name="{0}")
+    public static Collection<Object> data() {
+        List<Object> testCases = Lists.newArrayList();
+        testCases.add(new String[] { "CREATE INDEX ATABLE_DERIVED_IDX ON aTable (a_byte) INCLUDE ("
+                + "    A_STRING, " + "    B_STRING)" });
+        testCases.add(new String[] { "" });
+        return testCases;
+    }
+
+    @Test
+    public void testDerivedTableWithWhere() throws Exception {
+        long ts = nextTimestamp();
+        Properties props = new Properties(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 1));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        try {
+            // (where)
+            String query = "SELECT t.eid, t.x + 9 FROM (SELECT entity_id eid, b_string b, a_byte + 1 x FROM aTable WHERE a_byte + 1 < 9) AS t";
+            PreparedStatement statement = conn.prepareStatement(query);
+            ResultSet rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(ROW1,rs.getString(1));
+            assertEquals(11,rs.getInt(2));
+            assertTrue (rs.next());
+            assertEquals(ROW2,rs.getString(1));
+            assertEquals(12,rs.getInt(2));
+            assertTrue (rs.next());
+            assertEquals(ROW3,rs.getString(1));
+            assertEquals(13,rs.getInt(2));
+            assertTrue (rs.next());
+            assertEquals(ROW4,rs.getString(1));
+            assertEquals(14,rs.getInt(2));
+            assertTrue (rs.next());
+            assertEquals(ROW5,rs.getString(1));
+            assertEquals(15,rs.getInt(2));
+            assertTrue (rs.next());
+            assertEquals(ROW6,rs.getString(1));
+            assertEquals(16,rs.getInt(2));
+            assertTrue (rs.next());
+            assertEquals(ROW7,rs.getString(1));
+            assertEquals(17,rs.getInt(2));
+
+            assertFalse(rs.next());
+            
+            // () where
+            query = "SELECT t.eid, t.x + 9 FROM (SELECT entity_id eid, b_string b, a_byte + 1 x FROM aTable) AS t WHERE t.b = '" + C_VALUE + "'";
+            statement = conn.prepareStatement(query);
+            rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(ROW2,rs.getString(1));
+            assertEquals(12,rs.getInt(2));
+            assertTrue (rs.next());
+            assertEquals(ROW5,rs.getString(1));
+            assertEquals(15,rs.getInt(2));
+            assertTrue (rs.next());
+            assertEquals(ROW8,rs.getString(1));
+            assertEquals(18,rs.getInt(2));
+
+            assertFalse(rs.next());
+            
+            // (where) where
+            query = "SELECT t.eid, t.x + 9 FROM (SELECT entity_id eid, b_string b, a_byte + 1 x FROM aTable WHERE a_byte + 1 < 9) AS t WHERE t.b = '" + C_VALUE + "'";
+            statement = conn.prepareStatement(query);
+            rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(ROW2,rs.getString(1));
+            assertEquals(12,rs.getInt(2));
+            assertTrue (rs.next());
+            assertEquals(ROW5,rs.getString(1));
+            assertEquals(15,rs.getInt(2));
+
+            assertFalse(rs.next());
+
+            // (groupby where) where
+            query = "SELECT t.a, t.c, t.m FROM (SELECT a_string a, count(*) c, max(a_byte) m FROM aTable WHERE a_byte != 8 GROUP BY a_string) AS t WHERE t.c > 1";
+            statement = conn.prepareStatement(query);
+            rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(A_VALUE,rs.getString(1));
+            assertEquals(4,rs.getInt(2));
+            assertEquals(4,rs.getInt(3));
+            assertTrue (rs.next());
+            assertEquals(B_VALUE,rs.getString(1));
+            assertEquals(3,rs.getInt(2));
+            assertEquals(7,rs.getInt(3));
+
+            assertFalse(rs.next());
+            
+            // (groupby having where) where
+            query = "SELECT t.a, t.c, t.m FROM (SELECT a_string a, count(*) c, max(a_byte) m FROM aTable WHERE a_byte != 8 GROUP BY a_string HAVING count(*) >= 2) AS t WHERE t.a != '" + A_VALUE + "'";
+            statement = conn.prepareStatement(query);
+            rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(B_VALUE,rs.getString(1));
+            assertEquals(3,rs.getInt(2));
+            assertEquals(7,rs.getInt(3));
+
+            assertFalse(rs.next());
+            
+            // (limit) where
+            query = "SELECT t.eid FROM (SELECT entity_id eid, b_string b FROM aTable LIMIT 2) AS t WHERE t.b = '" + C_VALUE + "'";
+            try {
+                conn.createStatement().executeQuery(query);
+                fail("Should have got SQLFeatureNotSupportedException");
+            } catch (SQLFeatureNotSupportedException e) {
+                assertEquals(MSG, e.getMessage());
+            }
+
+            // (count) where
+            query = "SELECT t.c FROM (SELECT count(*) c FROM aTable) AS t WHERE t.c > 0";
+            try {
+                conn.createStatement().executeQuery(query);
+                fail("Should have got SQLFeatureNotSupportedException");
+            } catch (SQLFeatureNotSupportedException e) {                
+                assertEquals(MSG, e.getMessage());
+            }
+        } finally {
+            conn.close();
+        }
+    }
+    
+    @Test
+    public void testDerivedTableWithGroupBy() throws Exception {
+        long ts = nextTimestamp();
+        Properties props = new Properties(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 1));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        try {
+            // () groupby having
+            String query = "SELECT t.a, count(*), max(t.s) FROM (SELECT a_string a, a_byte s FROM aTable WHERE a_byte != 8) AS t GROUP BY t.a HAVING count(*) > 1";
+            PreparedStatement statement = conn.prepareStatement(query);
+            ResultSet rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(A_VALUE,rs.getString(1));
+            assertEquals(4,rs.getInt(2));
+            assertEquals(4,rs.getInt(3));
+            assertTrue (rs.next());
+            assertEquals(B_VALUE,rs.getString(1));
+            assertEquals(3,rs.getInt(2));
+            assertEquals(7,rs.getInt(3));
+
+            assertFalse(rs.next());
+            
+            // (groupby) groupby
+            query = "SELECT t.c, count(*) FROM (SELECT count(*) c FROM aTable GROUP BY a_string) AS t GROUP BY t.c";
+            try {
+                conn.createStatement().executeQuery(query);
+                fail("Should have got SQLFeatureNotSupportedException");
+            } catch (SQLFeatureNotSupportedException e) {                
+                assertEquals(MSG, e.getMessage());
+            }
+        } finally {
+            conn.close();
+        }
+    }
+    
+    @Test
+    public void testDerivedTableWithOrderBy() throws Exception {
+        long ts = nextTimestamp();
+        Properties props = new Properties(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 1));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        try {
+            // (orderby)
+            String query = "SELECT t.eid FROM (SELECT entity_id eid, b_string b FROM aTable ORDER BY b, eid) AS t";
+            PreparedStatement statement = conn.prepareStatement(query);
+            ResultSet rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(ROW1,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW4,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW7,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW2,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW5,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW8,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW3,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW6,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW9,rs.getString(1));
+
+            assertFalse(rs.next());
+            
+            // () orderby
+            query = "SELECT t.eid FROM (SELECT entity_id eid, b_string b FROM aTable) AS t ORDER BY t.b, t.eid";
+            statement = conn.prepareStatement(query);
+            rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(ROW1,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW4,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW7,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW2,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW5,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW8,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW3,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW6,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW9,rs.getString(1));
+
+            assertFalse(rs.next());
+            
+            // (orderby) orderby
+            query = "SELECT t.eid FROM (SELECT entity_id eid, b_string b FROM aTable ORDER BY b, eid) AS t ORDER BY t.b DESC, t.eid DESC";
+            statement = conn.prepareStatement(query);
+            rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(ROW9,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW6,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW3,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW8,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW5,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW2,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW7,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW4,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW1,rs.getString(1));
+
+            assertFalse(rs.next());
+            
+            // (limit) orderby
+            query = "SELECT t.eid FROM (SELECT entity_id eid, b_string b FROM aTable LIMIT 2) AS t ORDER BY t.b, t.eid";
+            try {
+                conn.createStatement().executeQuery(query);
+                fail("Should have got SQLFeatureNotSupportedException");
+            } catch (SQLFeatureNotSupportedException e) {                
+                assertEquals(MSG, e.getMessage());
+            }
+        } finally {
+            conn.close();
+        }
+    }
+    
+    @Test
+    public void testDerivedTableWithLimit() throws Exception {
+        long ts = nextTimestamp();
+        Properties props = new Properties(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 1));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        try {
+            // (limit)
+            String query = "SELECT t.eid FROM (SELECT entity_id eid FROM aTable LIMIT 2) AS t";
+            PreparedStatement statement = conn.prepareStatement(query);
+            ResultSet rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(ROW1,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW2,rs.getString(1));
+
+            assertFalse(rs.next());
+            
+            // () limit
+            query = "SELECT t.eid FROM (SELECT entity_id eid FROM aTable) AS t LIMIT 2";
+            statement = conn.prepareStatement(query);
+            rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(ROW1,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW2,rs.getString(1));
+
+            assertFalse(rs.next());
+            
+            // (limit 2) limit 4
+            query = "SELECT t.eid FROM (SELECT entity_id eid FROM aTable LIMIT 2) AS t LIMIT 4";
+            statement = conn.prepareStatement(query);
+            rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(ROW1,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW2,rs.getString(1));
+
+            assertFalse(rs.next());
+            
+            // (limit 4) limit 2
+            query = "SELECT t.eid FROM (SELECT entity_id eid FROM aTable LIMIT 4) AS t LIMIT 2";
+            statement = conn.prepareStatement(query);
+            rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(ROW1,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW2,rs.getString(1));
+
+            assertFalse(rs.next());                        
+            
+            // limit ? limit ?            
+            query = "SELECT t.eid FROM (SELECT entity_id eid FROM aTable LIMIT ?) AS t LIMIT ?";
+            try {
+                statement = conn.prepareStatement(query);
+                statement.setInt(1, 4);
+                statement.setInt(2, 2);
+                statement.executeQuery();
+                fail("Should have got SQLFeatureNotSupportedException");
+            } catch (SQLFeatureNotSupportedException e) {                
+                assertEquals(MSG, e.getMessage());
+            }
+        } finally {
+            conn.close();
+        }
+    }
+    
+    @Test
+    public void testDerivedTableWithDistinct() throws Exception {
+        long ts = nextTimestamp();
+        Properties props = new Properties(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 1));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        try {
+            // (distinct)
+            String query = "SELECT * FROM (SELECT DISTINCT a_string, b_string FROM aTable) AS t WHERE t.b_string != '" + C_VALUE + "' ORDER BY t.b_string, t.a_string";
+            PreparedStatement statement = conn.prepareStatement(query);
+            ResultSet rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(A_VALUE,rs.getString(1));
+            assertEquals(B_VALUE,rs.getString(2));
+            assertTrue (rs.next());
+            assertEquals(B_VALUE,rs.getString(1));
+            assertEquals(B_VALUE,rs.getString(2));
+            assertTrue (rs.next());
+            assertEquals(A_VALUE,rs.getString(1));
+            assertEquals(E_VALUE,rs.getString(2));
+            assertTrue (rs.next());
+            assertEquals(B_VALUE,rs.getString(1));
+            assertEquals(E_VALUE,rs.getString(2));
+            assertTrue (rs.next());
+            assertEquals(C_VALUE,rs.getString(1));
+            assertEquals(E_VALUE,rs.getString(2));
+
+            assertFalse(rs.next());
+            
+            // distinct ()
+            query = "SELECT DISTINCT t.a, t.b FROM (SELECT a_string a, b_string b FROM aTable) AS t WHERE t.b != '" + C_VALUE + "' ORDER BY t.b, t.a";
+            statement = conn.prepareStatement(query);
+            rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(A_VALUE,rs.getString(1));
+            assertEquals(B_VALUE,rs.getString(2));
+            assertTrue (rs.next());
+            assertEquals(B_VALUE,rs.getString(1));
+            assertEquals(B_VALUE,rs.getString(2));
+            assertTrue (rs.next());
+            assertEquals(A_VALUE,rs.getString(1));
+            assertEquals(E_VALUE,rs.getString(2));
+            assertTrue (rs.next());
+            assertEquals(B_VALUE,rs.getString(1));
+            assertEquals(E_VALUE,rs.getString(2));
+            assertTrue (rs.next());
+            assertEquals(C_VALUE,rs.getString(1));
+            assertEquals(E_VALUE,rs.getString(2));
+
+            assertFalse(rs.next());
+            
+            // distinct (distinct)
+            query = "SELECT DISTINCT t.a FROM (SELECT DISTINCT a_string a, b_string b FROM aTable) AS t";
+            try {
+                conn.createStatement().executeQuery(query);
+                fail("Should have got SQLFeatureNotSupportedException");
+            } catch (SQLFeatureNotSupportedException e) {                
+                assertEquals(MSG, e.getMessage());
+            }
+            
+            // distinct (groupby)
+            query = "SELECT distinct t.c FROM (SELECT count(*) c FROM aTable GROUP BY a_string) AS t";
+            try {
+                conn.createStatement().executeQuery(query);
+                fail("Should have got SQLFeatureNotSupportedException");
+            } catch (SQLFeatureNotSupportedException e) {                
+                assertEquals(MSG, e.getMessage());
+            }
+            
+            // distinct (limit)
+            query = "SELECT DISTINCT t.a, t.b FROM (SELECT a_string a, b_string b FROM aTable LIMIT 2) AS t";
+            try {
+                conn.createStatement().executeQuery(query);
+                fail("Should have got SQLFeatureNotSupportedException");
+            } catch (SQLFeatureNotSupportedException e) {                
+                assertEquals(MSG, e.getMessage());
+            }
+        } finally {
+            conn.close();
+        }
+    }
+    
+    @Test
+    public void testDerivedTableWithAggregate() throws Exception {
+        long ts = nextTimestamp();
+        Properties props = new Properties(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 1));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        try {
+            // (count)
+            String query = "SELECT * FROM (SELECT count(*) FROM aTable WHERE a_byte != 8) AS t";
+            PreparedStatement statement = conn.prepareStatement(query);
+            ResultSet rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(8,rs.getInt(1));
+
+            assertFalse(rs.next());
+            
+            // count ()
+            query = "SELECT count(*) FROM (SELECT a_byte FROM aTable) AS t WHERE t.a_byte != 8";
+            statement = conn.prepareStatement(query);
+            rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(8,rs.getInt(1));
+
+            assertFalse(rs.next());
+            
+            // count (distinct)
+            query = "SELECT count(*) FROM (SELECT DISTINCT a_string FROM aTable) AS t";
+            try {
+                conn.createStatement().executeQuery(query);
+                fail("Should have got SQLFeatureNotSupportedException");
+            } catch (SQLFeatureNotSupportedException e) {                
+                assertEquals(MSG, e.getMessage());
+            }
+            
+            // count (groupby)
+            query = "SELECT count(*) FROM (SELECT count(*) c FROM aTable GROUP BY a_string) AS t";
+            try {
+                conn.createStatement().executeQuery(query);
+                fail("Should have got SQLFeatureNotSupportedException");
+            } catch (SQLFeatureNotSupportedException e) {                
+                assertEquals(MSG, e.getMessage());
+            }
+            
+            // count (limit)
+            query = "SELECT count(*) FROM (SELECT entity_id FROM aTable LIMIT 2) AS t";
+            try {
+                conn.createStatement().executeQuery(query);
+                fail("Should have got SQLFeatureNotSupportedException");
+            } catch (SQLFeatureNotSupportedException e) {                
+                assertEquals(MSG, e.getMessage());
+            }
+        } finally {
+            conn.close();
+        }
+    }
+    
+    @Test
+    public void testDerivedTableWithJoin() throws Exception {
+        long ts = nextTimestamp();
+        Properties props = new Properties(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 1));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        try {
+            // groupby (join)
+            String query = "SELECT q.id1, count(q.id2) FROM (SELECT t1.entity_id id1, t2.entity_id id2, t2.a_byte b2" 
+                        + " FROM aTable t1 JOIN aTable t2 ON t1.a_string = t2.b_string" 
+                        + " WHERE t1.a_byte >= 8) AS q WHERE q.b2 != 5 GROUP BY q.id1";
+            PreparedStatement statement = conn.prepareStatement(query);
+            ResultSet rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(ROW8,rs.getString(1));
+            assertEquals(3,rs.getInt(2));
+            assertTrue (rs.next());
+            assertEquals(ROW9,rs.getString(1));
+            assertEquals(2,rs.getInt(2));
+
+            assertFalse(rs.next());
+            
+            // distinct (join)
+            query = "SELECT DISTINCT q.id1 FROM (SELECT t1.entity_id id1, t2.a_byte b2" 
+                        + " FROM aTable t1 JOIN aTable t2 ON t1.a_string = t2.b_string" 
+                        + " WHERE t1.a_byte >= 8) AS q WHERE q.b2 != 5";
+            statement = conn.prepareStatement(query);
+            rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(ROW8,rs.getString(1));
+            assertTrue (rs.next());
+            assertEquals(ROW9,rs.getString(1));
+
+            assertFalse(rs.next());
+
+            // count (join)
+            query = "SELECT COUNT(*) FROM (SELECT t2.a_byte b2" 
+                        + " FROM aTable t1 JOIN aTable t2 ON t1.a_string = t2.b_string" 
+                        + " WHERE t1.a_byte >= 8) AS q WHERE q.b2 != 5";
+            statement = conn.prepareStatement(query);
+            rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(5,rs.getInt(1));
+
+            assertFalse(rs.next());
+        } finally {
+            conn.close();
+        }
+    }
+    
+    @Test
+    public void testNestedDerivedTable() throws Exception {
+        long ts = nextTimestamp();
+        Properties props = new Properties(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 1));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        try {
+            // select(select(select))
+            String query = "SELECT q.id, q.x10 * 10 FROM (SELECT t.eid id, t.x + 9 x10, t.astr a, t.bstr b FROM (SELECT entity_id eid, a_string astr, b_string bstr, a_byte + 1 x FROM aTable WHERE a_byte + 1 < ?) AS t ORDER BY b, id) AS q WHERE q.a = ? OR q.b = ? OR q.b = ?";
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.setInt(1, 9);
+            statement.setString(2, A_VALUE);
+            statement.setString(3, C_VALUE);
+            statement.setString(4, E_VALUE);
+            ResultSet rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(ROW1,rs.getString(1));
+            assertEquals(110,rs.getInt(2));
+            assertTrue (rs.next());
+            assertEquals(ROW4,rs.getString(1));
+            assertEquals(140,rs.getInt(2));
+            assertTrue (rs.next());
+            assertEquals(ROW2,rs.getString(1));
+            assertEquals(120,rs.getInt(2));
+            assertTrue (rs.next());
+            assertEquals(ROW5,rs.getString(1));
+            assertEquals(150,rs.getInt(2));
+            assertTrue (rs.next());
+            assertEquals(ROW3,rs.getString(1));
+            assertEquals(130,rs.getInt(2));
+            assertTrue (rs.next());
+            assertEquals(ROW6,rs.getString(1));
+            assertEquals(160,rs.getInt(2));
+
+            assertFalse(rs.next());
+            
+            // select(select(select) join (select(select)))
+            query = "SELECT q1.id, q2.id FROM (SELECT t.eid id, t.astr a, t.bstr b FROM (SELECT entity_id eid, a_string astr, b_string bstr, a_byte abyte FROM aTable) AS t WHERE t.abyte >= ?) AS q1" 
+                        + " JOIN (SELECT t.eid id, t.astr a, t.bstr b, t.abyte x FROM (SELECT entity_id eid, a_string astr, b_string bstr, a_byte abyte FROM aTable) AS t) AS q2 ON q1.a = q2.b" 
+                        + " WHERE q2.x != ? ORDER BY q1.id, q2.id DESC";
+            statement = conn.prepareStatement(query);
+            statement.setInt(1, 8);
+            statement.setInt(2, 5);
+            rs = statement.executeQuery();
+            assertTrue (rs.next());
+            assertEquals(ROW8,rs.getString(1));
+            assertEquals(ROW7,rs.getString(2));
+            assertTrue (rs.next());
+            assertEquals(ROW8,rs.getString(1));
+            assertEquals(ROW4,rs.getString(2));
+            assertTrue (rs.next());
+            assertEquals(ROW8,rs.getString(1));
+            assertEquals(ROW1,rs.getString(2));
+            assertTrue (rs.next());
+            assertEquals(ROW9,rs.getString(1));
+            assertEquals(ROW8,rs.getString(2));
+            assertTrue (rs.next());
+            assertEquals(ROW9,rs.getString(1));
+            assertEquals(ROW2,rs.getString(2));
+
+            assertFalse(rs.next());
+        } finally {
+            conn.close();
+        }
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/43c78877/phoenix-core/src/it/java/org/apache/phoenix/end2end/HashJoinIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/HashJoinIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/HashJoinIT.java
index 41b673b..2e0d329 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/HashJoinIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/HashJoinIT.java
@@ -374,7 +374,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
                 /*
                  * testNestedSubqueries()
                  *     SELECT * FROM (SELECT customer_id cid, name, phone, address, loc_id, date FROM joinCustomerTable) AS c 
-                 *     INNER JOIN (SELECT o.oid ooid, o.cid ocid, o.iid oiid, o.price oprice, o.quantity oquantity, o.date odate, 
+                 *     INNER JOIN (SELECT o.oid ooid, o.cid ocid, o.iid oiid, o.price * o.quantity, o.date odate, 
                  *     qi.iiid iiid, qi.iname iname, qi.iprice iprice, qi.idiscount1 idiscount1, qi.idiscount2 idiscount2, qi.isid isid, qi.idescription idescription, 
                  *     qi.ssid ssid, qi.sname sname, qi.sphone sphone, qi.saddress saddress, qi.sloc_id sloc_id 
                  *         FROM (SELECT item_id iid, customer_id cid, order_id oid, price, quantity, date FROM joinOrderTable) AS o 
@@ -680,7 +680,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
                 /*
                  * testNestedSubqueries()
                  *     SELECT * FROM (SELECT customer_id cid, name, phone, address, loc_id, date FROM joinCustomerTable) AS c 
-                 *     INNER JOIN (SELECT o.oid ooid, o.cid ocid, o.iid oiid, o.price oprice, o.quantity oquantity, o.date odate, 
+                 *     INNER JOIN (SELECT o.oid ooid, o.cid ocid, o.iid oiid, o.price * o.quantity, o.date odate, 
                  *     qi.iiid iiid, qi.iname iname, qi.iprice iprice, qi.idiscount1 idiscount1, qi.idiscount2 idiscount2, qi.isid isid, qi.idescription idescription, 
                  *     qi.ssid ssid, qi.sname sname, qi.sphone sphone, qi.saddress saddress, qi.sloc_id sloc_id 
                  *         FROM (SELECT item_id iid, customer_id cid, order_id oid, price, quantity, date FROM joinOrderTable) AS o 
@@ -2727,8 +2727,8 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
     
     @Test
     public void testJoinWithSubquery() throws Exception {
-        String query1 = "SELECT item.\"item_id\", item.name, supp.sid, supp.name FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item INNER JOIN (SELECT \"supplier_id\" sid, name FROM " + JOIN_SUPPLIER_TABLE_FULL_NAME + " WHERE name BETWEEN 'S1' AND 'S5') AS supp ON item.\"supplier_id\" = supp.sid";
-        String query2 = "SELECT item.\"item_id\", item.name, supp.\"supplier_id\", supp.name FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item INNER JOIN (SELECT \"supplier_id\", name FROM " + JOIN_SUPPLIER_TABLE_FULL_NAME + ") AS supp ON item.\"supplier_id\" = supp.\"supplier_id\" AND (supp.name = 'S1' OR supp.name = 'S5')";
+        String query1 = "SELECT item.\"item_id\", item.name, supp.sid, supp.name FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item INNER JOIN (SELECT reverse(loc_id), \"supplier_id\" sid, name FROM " + JOIN_SUPPLIER_TABLE_FULL_NAME + " WHERE name BETWEEN 'S1' AND 'S5') AS supp ON item.\"supplier_id\" = supp.sid";
+        String query2 = "SELECT item.\"item_id\", item.name, supp.\"supplier_id\", supp.name FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item INNER JOIN (SELECT reverse(loc_id), \"supplier_id\", name FROM " + JOIN_SUPPLIER_TABLE_FULL_NAME + ") AS supp ON item.\"supplier_id\" = supp.\"supplier_id\" AND (supp.name = 'S1' OR supp.name = 'S5')";
         Properties props = new Properties(TEST_PROPERTIES);
         Connection conn = DriverManager.getConnection(getUrl(), props);
         try {
@@ -2900,7 +2900,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
                 + " ON o.iid = q.iid LEFT JOIN (SELECT \"customer_id\" cid, name FROM " 
                 + JOIN_CUSTOMER_TABLE_FULL_NAME + ") AS c ON c.cid = o.cid GROUP BY q.iname ORDER BY q.iname";
         String query2 = "SELECT * FROM (SELECT \"customer_id\" cid, name, phone, address, loc_id, date FROM " + JOIN_CUSTOMER_TABLE_FULL_NAME + ") AS c INNER JOIN " 
-                + "(SELECT o.oid ooid, o.cid ocid, o.iid oiid, o.price oprice, o.quantity oquantity, o.date odate, qi.iiid iiid, qi.iname iname, qi.iprice iprice, qi.idiscount1 idiscount1, qi.idiscount2 idiscount2, qi.isid isid, qi.idescription idescription, qi.ssid ssid, qi.sname sname, qi.sphone sphone, qi.saddress saddress, qi.sloc_id sloc_id FROM (SELECT \"item_id\" iid, \"customer_id\" cid, \"order_id\" oid, price, quantity, date FROM " + JOIN_ORDER_TABLE_FULL_NAME + ") AS o INNER JOIN " 
+                + "(SELECT o.oid ooid, o.cid ocid, o.iid oiid, o.price * o.quantity, o.date odate, qi.iiid iiid, qi.iname iname, qi.iprice iprice, qi.idiscount1 idiscount1, qi.idiscount2 idiscount2, qi.isid isid, qi.idescription idescription, qi.ssid ssid, qi.sname sname, qi.sphone sphone, qi.saddress saddress, qi.sloc_id sloc_id FROM (SELECT \"item_id\" iid, \"customer_id\" cid, \"order_id\" oid, price, quantity, date FROM " + JOIN_ORDER_TABLE_FULL_NAME + ") AS o INNER JOIN " 
                 + "(SELECT i.iid iiid, i.name iname, i.price iprice, i.discount1 idiscount1, i.discount2 idiscount2, i.sid isid, i.description idescription, s.sid ssid, s.name sname, s.phone sphone, s.address saddress, s.loc_id sloc_id FROM (SELECT \"supplier_id\" sid, name, phone, address, loc_id FROM " + JOIN_SUPPLIER_TABLE_FULL_NAME + ") AS s RIGHT JOIN (SELECT \"item_id\" iid, name, price, discount1, discount2, \"supplier_id\" sid, description FROM " + JOIN_ITEM_TABLE_FULL_NAME + ") AS i ON i.sid = s.sid) as qi" 
                 + " ON o.iid = qi.iiid) as qo ON c.cid = qo.ocid" 
                 + " WHERE c.cid <= '0000000005' AND qo.ooid != '000000000000003' AND qo.iname != 'T3' ORDER BY c.cid, qo.iname";
@@ -2944,8 +2944,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
             assertEquals(rs.getString("qo.ooid"), "000000000000002");
             assertEquals(rs.getString("qo.ocid"), "0000000003");
             assertEquals(rs.getString("qo.oiid"), "0000000006");
-            assertEquals(rs.getInt("qo.oprice"), 552);
-            assertEquals(rs.getInt("qo.oquantity"), 2000);
+            assertEquals(rs.getInt(10), 1104000);
             assertEquals(rs.getTimestamp("qo.odate"), new Timestamp(format.parse("2013-11-25 10:06:29").getTime()));
             assertEquals(rs.getString("qo.iiid"), "0000000006");
             assertEquals(rs.getString("qo.iname"), "T6");
@@ -2969,8 +2968,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
             assertEquals(rs.getString("qo.ooid"), "000000000000001");
             assertEquals(rs.getString("qo.ocid"), "0000000004");
             assertEquals(rs.getString("qo.oiid"), "0000000001");
-            assertEquals(rs.getInt("qo.oprice"), 100);
-            assertEquals(rs.getInt("qo.oquantity"), 1000);
+            assertEquals(rs.getInt(10), 100000);
             assertEquals(rs.getTimestamp("qo.odate"), new Timestamp(format.parse("2013-11-22 14:22:56").getTime()));
             assertEquals(rs.getString("qo.iiid"), "0000000001");
             assertEquals(rs.getString("qo.iname"), "T1");
@@ -2994,8 +2992,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
             assertEquals(rs.getString("qo.ooid"), "000000000000004");
             assertEquals(rs.getString("qo.ocid"), "0000000004");
             assertEquals(rs.getString("qo.oiid"), "0000000006");
-            assertEquals(rs.getInt("qo.oprice"), 510);
-            assertEquals(rs.getInt("qo.oquantity"), 4000);
+            assertEquals(rs.getInt(10), 2040000);
             assertEquals(rs.getTimestamp("qo.odate"), new Timestamp(format.parse("2013-11-26 13:26:04").getTime()));
             assertEquals(rs.getString("qo.iiid"), "0000000006");
             assertEquals(rs.getString("qo.iname"), "T6");

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/43c78877/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 4f1d107..13b824d 100644
--- a/phoenix-core/src/main/antlr3/PhoenixSQL.g
+++ b/phoenix-core/src/main/antlr3/PhoenixSQL.g
@@ -551,7 +551,6 @@ select_node returns [SelectStatement ret]
 
 // Parse a full select expression structure.
 hinted_select_node returns [SelectStatement ret]
-@init{ contextStack.push(new ParseContext()); }
     :   (hint=hintClause)? 
         s=select_node
         { $ret = factory.select(s, hint); }

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/43c78877/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 b0e28b4..b9e0949 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
@@ -146,16 +146,16 @@ public class FromCompiler {
      * @return the column resolver
      * @throws SQLException
      * @throws SQLFeatureNotSupportedException
-     *             if unsupported constructs appear in the FROM clause. Currently only a single table name is supported.
+     *             if unsupported constructs appear in the FROM clause
      * @throws TableNotFoundException
      *             if table name not found in schema
      */
     public static ColumnResolver getResolverForQuery(SelectStatement statement, PhoenixConnection connection)
     		throws SQLException {
     	List<TableNode> fromNodes = statement.getFrom();
-        if (!statement.isJoin())
-            return new SingleTableColumnResolver(connection, (NamedTableNode)fromNodes.get(0), true);
-
+        if (!statement.isJoin() && fromNodes.get(0) instanceof NamedTableNode)
+            return new SingleTableColumnResolver(connection, (NamedTableNode) fromNodes.get(0), true);
+        
         MultiTableColumnResolver visitor = new MultiTableColumnResolver(connection);
         for (TableNode node : fromNodes) {
             node.accept(visitor);
@@ -406,12 +406,15 @@ public class FromCompiler {
                     
                     alias = SchemaUtil.normalizeIdentifier(node.getAlias());
                 }
-                if (alias != null) {
-                    PColumnImpl column = new PColumnImpl(PNameFactory.newName(alias), 
-                            PNameFactory.newName(QueryConstants.DEFAULT_COLUMN_FAMILY), 
-                            null, 0, 0, true, position++, SortOrder.ASC, null, null, false);
-                    columns.add(column);
+                if (alias == null) {
+                    // Use position as column name for anonymous columns, which can be 
+                    // referenced by an outer wild-card select.
+                    alias = String.valueOf(position);
                 }
+                PColumnImpl column = new PColumnImpl(PNameFactory.newName(alias), 
+                        PNameFactory.newName(QueryConstants.DEFAULT_COLUMN_FAMILY), 
+                        null, 0, 0, true, position++, SortOrder.ASC, null, null, false);
+                columns.add(column);
             }
             PTable t = PTableImpl.makePTable(null, PName.EMPTY_NAME, PName.EMPTY_NAME, 
                     PTableType.SUBQUERY, null, MetaDataProtocol.MIN_TABLE_TIMESTAMP, PTable.INITIAL_SEQ_NUM, 

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/43c78877/phoenix-core/src/main/java/org/apache/phoenix/compile/IndexStatementRewriter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/IndexStatementRewriter.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/IndexStatementRewriter.java
index 858c7ca..68a1218 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/IndexStatementRewriter.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/IndexStatementRewriter.java
@@ -73,11 +73,6 @@ public class IndexStatementRewriter extends ParseNodeRewriter {
     public static SelectStatement translate(SelectStatement statement, ColumnResolver dataResolver, Map<TableRef, TableRef> multiTableRewriteMap) throws SQLException {
         return rewrite(statement, new IndexStatementRewriter(dataResolver, multiTableRewriteMap));
     }
-    
-    @Override
-    protected boolean visitDerivedTableNode() {
-        return false;
-    }
 
     @Override
     public ParseNode visit(ColumnParseNode node) throws SQLException {

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/43c78877/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 0293ee0..c494194 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
@@ -66,7 +66,6 @@ import org.apache.phoenix.parse.OrParseNode;
 import org.apache.phoenix.parse.OrderByNode;
 import org.apache.phoenix.parse.ParseNode;
 import org.apache.phoenix.parse.ParseNodeFactory;
-import org.apache.phoenix.parse.ParseNodeRewriter;
 import org.apache.phoenix.parse.SelectStatement;
 import org.apache.phoenix.parse.StatelessTraverseAllParseNodeVisitor;
 import org.apache.phoenix.parse.TableName;
@@ -102,23 +101,25 @@ public class JoinCompiler {
         GENERAL,
     }
     
-    private final SelectStatement statement;
+    private final PhoenixStatement statement;
+    private final SelectStatement select;
     private final ColumnResolver origResolver;
     private final boolean useStarJoin;
     private final Map<ColumnRef, ColumnRefType> columnRefs;
     
     
-    private JoinCompiler(SelectStatement statement, ColumnResolver resolver) {
+    private JoinCompiler(PhoenixStatement statement, SelectStatement select, ColumnResolver resolver) {
         this.statement = statement;
+        this.select = select;
         this.origResolver = resolver;
-        this.useStarJoin = !statement.getHint().hasHint(Hint.NO_STAR_JOIN);
+        this.useStarJoin = !select.getHint().hasHint(Hint.NO_STAR_JOIN);
         this.columnRefs = new HashMap<ColumnRef, ColumnRefType>();
     }
     
-    public static JoinTable compile(SelectStatement statement, ColumnResolver resolver) throws SQLException {
-        JoinCompiler compiler = new JoinCompiler(statement, resolver);
+    public static JoinTable compile(PhoenixStatement statement, SelectStatement select, ColumnResolver resolver) throws SQLException {
+        JoinCompiler compiler = new JoinCompiler(statement, select, resolver);
         
-        List<TableNode> from = statement.getFrom();
+        List<TableNode> from = select.getFrom();
         if (from.size() > 1) {
             throw new SQLFeatureNotSupportedException("Cross join not supported.");
         }
@@ -126,8 +127,8 @@ public class JoinCompiler {
         JoinTableConstructor constructor = compiler.new JoinTableConstructor();
         Pair<Table, List<JoinSpec>> res = from.get(0).accept(constructor);
         JoinTable joinTable = res.getSecond() == null ? compiler.new JoinTable(res.getFirst()) : compiler.new JoinTable(res.getFirst(), res.getSecond());
-        if (statement.getWhere() != null) {
-            joinTable.addFilter(statement.getWhere());
+        if (select.getWhere() != null) {
+            joinTable.addFilter(select.getWhere());
         }
         
         ColumnParseNodeVisitor generalRefVisitor = new ColumnParseNodeVisitor(resolver);
@@ -136,19 +137,19 @@ public class JoinCompiler {
         
         joinTable.pushDownColumnRefVisitors(generalRefVisitor, joinLocalRefVisitor, prefilterRefVisitor);
 
-        for (AliasedNode node : statement.getSelect()) {
+        for (AliasedNode node : select.getSelect()) {
             node.getNode().accept(generalRefVisitor);
         }
-        if (statement.getGroupBy() != null) {
-            for (ParseNode node : statement.getGroupBy()) {
+        if (select.getGroupBy() != null) {
+            for (ParseNode node : select.getGroupBy()) {
                 node.accept(generalRefVisitor);
             }
         }
-        if (statement.getHaving() != null) {
-            statement.getHaving().accept(generalRefVisitor);
+        if (select.getHaving() != null) {
+            select.getHaving().accept(generalRefVisitor);
         }
-        if (statement.getOrderBy() != null) {
-            for (OrderByNode node : statement.getOrderBy()) {
+        if (select.getOrderBy() != null) {
+            for (OrderByNode node : select.getOrderBy()) {
                 node.getNode().accept(generalRefVisitor);
             }
         }
@@ -180,7 +181,7 @@ public class JoinCompiler {
         @Override
         public Pair<Table, List<JoinSpec>> visit(BindTableNode boundTableNode) throws SQLException {
             TableRef tableRef = resolveTable(boundTableNode.getAlias(), boundTableNode.getName());
-            List<AliasedNode> selectNodes = extractFromSelect(statement.getSelect(), tableRef, origResolver);
+            List<AliasedNode> selectNodes = extractFromSelect(select.getSelect(), tableRef, origResolver);
             Table table = new Table(boundTableNode, Collections.<ColumnDef>emptyList(), selectNodes, tableRef);
             return new Pair<Table, List<JoinSpec>>(table, null);
         }
@@ -203,7 +204,7 @@ public class JoinCompiler {
         public Pair<Table, List<JoinSpec>> visit(NamedTableNode namedTableNode)
                 throws SQLException {
             TableRef tableRef = resolveTable(namedTableNode.getAlias(), namedTableNode.getName());
-            List<AliasedNode> selectNodes = extractFromSelect(statement.getSelect(), tableRef, origResolver);
+            List<AliasedNode> selectNodes = extractFromSelect(select.getSelect(), tableRef, origResolver);
             Table table = new Table(namedTableNode, namedTableNode.getDynamicColumns(), selectNodes, tableRef);
             return new Pair<Table, List<JoinSpec>>(table, null);
         }
@@ -212,7 +213,7 @@ public class JoinCompiler {
         public Pair<Table, List<JoinSpec>> visit(DerivedTableNode subselectNode)
                 throws SQLException {
             TableRef tableRef = resolveTable(subselectNode.getAlias(), null);
-            List<AliasedNode> selectNodes = extractFromSelect(statement.getSelect(), tableRef, origResolver);
+            List<AliasedNode> selectNodes = extractFromSelect(select.getSelect(), tableRef, origResolver);
             Table table = new Table(subselectNode, selectNodes, tableRef);
             return new Pair<Table, List<JoinSpec>>(table, null);
         }
@@ -281,7 +282,7 @@ public class JoinCompiler {
         }
         
         public SelectStatement getStatement() {
-            return statement;
+            return select;
         }
         
         public ColumnResolver getOriginalResolver() {
@@ -392,7 +393,7 @@ public class JoinCompiler {
             if (asSubquery)
                 return query;
             
-            return NODE_FACTORY.select(query.getFrom(), statement.getHint(), statement.isDistinct(), statement.getSelect(), query.getWhere(), statement.getGroupBy(), statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(), statement.isAggregate());            
+            return NODE_FACTORY.select(query.getFrom(), select.getHint(), select.isDistinct(), select.getSelect(), query.getWhere(), select.getGroupBy(), select.getHaving(), select.getOrderBy(), select.getLimit(), select.getBindCount(), select.isAggregate());            
         }
         
         public boolean hasPostReference() {
@@ -594,10 +595,10 @@ public class JoinCompiler {
         }
         
         private Table(DerivedTableNode tableNode, 
-                List<AliasedNode> selectNodes, TableRef tableRef) {
+                List<AliasedNode> selectNodes, TableRef tableRef) throws SQLException {
             this.tableNode = tableNode;
             this.dynamicColumns = Collections.<ColumnDef>emptyList();
-            this.subselect = tableNode.getSelect();
+            this.subselect = SubselectRewriter.flatten(tableNode.getSelect(), statement.getConnection());
             this.tableRef = tableRef;
             this.selectNodes = selectNodes;
             this.preFilters = Collections.<ParseNode>emptyList();
@@ -647,10 +648,10 @@ public class JoinCompiler {
         
         public SelectStatement getAsSubquery() throws SQLException {
             if (isSubselect())
-                return SubqueryColumnAliasRewriter.applyPostFilters(subselect, postFilters, tableNode.getAlias());
+                return SubselectRewriter.applyPostFilters(subselect, postFilters, tableNode.getAlias());
             
             List<TableNode> from = Collections.<TableNode>singletonList(tableNode);
-            return NODE_FACTORY.select(from, statement.getHint(), false, selectNodes, getPreFiltersCombined(), null, null, null, null, 0, false);
+            return NODE_FACTORY.select(from, select.getHint(), false, selectNodes, getPreFiltersCombined(), null, null, null, null, 0, false);
         }
         
         public boolean isFlat() {
@@ -1024,68 +1025,11 @@ public class JoinCompiler {
         }
     }
     
-    private static class SubqueryColumnAliasRewriter extends ParseNodeRewriter {
-        List<AliasedNode> effectiveSelectNodes = new ArrayList<AliasedNode>();
-        Map<String, ParseNode> aliasMap = new HashMap<String, ParseNode>();
-        
-        public static SelectStatement applyPostFilters(SelectStatement statement, List<ParseNode> postFilters, String subqueryAlias) throws SQLException {
-            if (postFilters.isEmpty())
-                return statement;
-            
-            SubqueryColumnAliasRewriter rewriter = new SubqueryColumnAliasRewriter(statement.getSelect(), subqueryAlias);
-            List<ParseNode> postFiltersRewrite = new ArrayList<ParseNode>(postFilters.size());
-            for (ParseNode node : postFilters) {
-                postFiltersRewrite.add(node.accept(rewriter));
-            }
-            
-            if (statement.getGroupBy().isEmpty()) {
-                ParseNode where = statement.getWhere();
-                if (where != null) {
-                    postFiltersRewrite.add(where);
-                }
-                return NODE_FACTORY.select(statement.getFrom(), statement.getHint(), statement.isDistinct(), rewriter.effectiveSelectNodes, combine(postFiltersRewrite), statement.getGroupBy(), statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(), statement.isAggregate());
-            }
-            
-            ParseNode having = statement.getHaving();
-            if (having != null) {
-                postFiltersRewrite.add(having);
-            }
-            return NODE_FACTORY.select(statement.getFrom(), statement.getHint(), statement.isDistinct(), rewriter.effectiveSelectNodes, statement.getWhere(), statement.getGroupBy(), combine(postFiltersRewrite), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(), statement.isAggregate());
-        }
-        
-        private SubqueryColumnAliasRewriter(List<AliasedNode> aliasedNodes, String subqueryAlias) {
-            for (AliasedNode aliasedNode : aliasedNodes) {
-                String alias = aliasedNode.getAlias();
-                ParseNode node = aliasedNode.getNode();
-                if (alias == null) {
-                    alias = SchemaUtil.normalizeIdentifier(node.getAlias());
-                }
-                if (alias != null) {
-                    effectiveSelectNodes.add(aliasedNode);
-                    aliasMap.put(SchemaUtil.getColumnName(subqueryAlias, alias), node);
-                }
-            }
-        }
-        
-        
-        @Override
-        public ParseNode visit(ColumnParseNode node) throws SQLException {
-            if (node.getTableName() != null) {
-                ParseNode aliasedNode = aliasMap.get(node.getFullName());
-                if (aliasedNode != null) {
-                    return aliasedNode;
-                }
-            }
-            return node;
-        }        
-    }
-    
     private static String PROJECTED_TABLE_SCHEMA = ".";
     // for creation of new statements
     private static ParseNodeFactory NODE_FACTORY = new ParseNodeFactory();
     
     private static boolean isFlat(SelectStatement select) {
-        // TODO flatten single nested query in normalization
         return !select.isJoin() 
                 && !select.isAggregate() 
                 && !select.isDistinct() 
@@ -1134,8 +1078,7 @@ public class JoinCompiler {
         return ret;
     }
     
-    public static SelectStatement optimize(StatementContext context, SelectStatement select, PhoenixStatement statement) throws SQLException {
-        final ColumnResolver resolver = context.getResolver();
+    public static SelectStatement optimize(PhoenixStatement statement, SelectStatement select, final ColumnResolver resolver) throws SQLException {
         TableRef groupByTableRef = null;
         TableRef orderByTableRef = null;
         if (select.getGroupBy() != null && !select.getGroupBy().isEmpty()) {
@@ -1157,7 +1100,7 @@ public class JoinCompiler {
                 orderByTableRef = set.iterator().next();
             }
         }
-        JoinTable join = compile(select, context.getResolver());
+        JoinTable join = compile(statement, select, resolver);
         if (groupByTableRef != null || orderByTableRef != null) {
             QueryCompiler compiler = new QueryCompiler(statement, select, resolver);
             List<Object> binds = statement.getParameters();
@@ -1181,7 +1124,7 @@ public class JoinCompiler {
             List<ParseNode> groupBy = tableRef.equals(groupByTableRef) ? select.getGroupBy() : null;
             List<OrderByNode> orderBy = tableRef.equals(orderByTableRef) ? select.getOrderBy() : null;
             SelectStatement stmt = getSubqueryForOptimizedPlan(select.getHint(), table.getDynamicColumns(), tableRef, join.getColumnRefs(), table.getPreFiltersCombined(), groupBy, orderBy, table.isWildCardSelect());
-            QueryPlan plan = context.getConnection().getQueryServices().getOptimizer().optimize(statement, stmt);
+            QueryPlan plan = statement.getConnection().getQueryServices().getOptimizer().optimize(statement, stmt);
             if (!plan.getTableRef().equals(tableRef)) {
                 replacement.put(tableRef, plan.getTableRef());            
             }            

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/43c78877/phoenix-core/src/main/java/org/apache/phoenix/compile/LimitCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/LimitCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/LimitCompiler.java
index b114fba..4f31107 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/LimitCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/LimitCompiler.java
@@ -98,6 +98,10 @@ public class LimitCompiler {
     
         @Override
         public Void visit(BindParseNode node) throws SQLException {
+            // This is for static evaluation in SubselectRewriter.
+            if (context == null)
+                return null;
+                        
             Object value = context.getBindManager().getBindValue(node);
             context.getBindManager().addParamMetaData(node, LIMIT_DATUM);
             // Resolve the bind value, create a LiteralParseNode, and call the visit method for it.

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/43c78877/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 c1ea4ca..8b5cd93 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
@@ -54,6 +54,7 @@ import org.apache.phoenix.schema.AmbiguousColumnException;
 import org.apache.phoenix.schema.ColumnNotFoundException;
 import org.apache.phoenix.schema.PDatum;
 import org.apache.phoenix.schema.PTable;
+import org.apache.phoenix.schema.PTableType;
 import org.apache.phoenix.schema.TableRef;
 import org.apache.phoenix.util.ScanUtil;
 
@@ -118,12 +119,12 @@ public class QueryCompiler {
         List<Object> binds = statement.getParameters();
         StatementContext context = new StatementContext(statement, resolver, scan);
         if (select.isJoin()) {
-            select = JoinCompiler.optimize(context, select, statement);
+            select = JoinCompiler.optimize(statement, select, resolver);
             if (this.select != select) {
                 ColumnResolver resolver = FromCompiler.getResolverForQuery(select, statement.getConnection());
                 context = new StatementContext(statement, resolver, scan);
             }
-            JoinTable joinTable = JoinCompiler.compile(select, context.getResolver());
+            JoinTable joinTable = JoinCompiler.compile(statement, select, context.getResolver());
             return compileJoinQuery(context, binds, joinTable, false);
         } else {
             return compileSingleQuery(context, select, binds, parallelIteratorFactory);
@@ -281,6 +282,7 @@ public class QueryCompiler {
     
     protected QueryPlan compileSubquery(SelectStatement subquery) throws SQLException {
         ColumnResolver resolver = FromCompiler.getResolverForQuery(subquery, this.statement.getConnection());
+        subquery = StatementNormalizer.normalize(subquery, resolver);
         QueryPlan plan = new QueryCompiler(this.statement, subquery, resolver).compile();
         return statement.getConnection().getQueryServices().getOptimizer().optimize(statement, plan);
     }
@@ -290,6 +292,11 @@ public class QueryCompiler {
         ColumnResolver resolver = context.getResolver();
         TableRef tableRef = context.getCurrentTable();
         PTable table = tableRef.getTable();
+        
+        // TODO PHOENIX-944. See DerivedTableIT for a list of unsupported cases.
+        if (table.getType() == PTableType.SUBQUERY)
+            throw new SQLFeatureNotSupportedException("Complex nested queries not supported.");
+        
         ParseNode viewWhere = null;
         if (table.getViewStatement() != null) {
             viewWhere = new SQLParser(table.getViewStatement()).parseQuery().getWhere();

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/43c78877/phoenix-core/src/main/java/org/apache/phoenix/compile/SubselectRewriter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/SubselectRewriter.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/SubselectRewriter.java
new file mode 100644
index 0000000..a3d9ebb
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/SubselectRewriter.java
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.phoenix.compile;
+
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.phoenix.jdbc.PhoenixConnection;
+import org.apache.phoenix.parse.AliasedNode;
+import org.apache.phoenix.parse.ColumnParseNode;
+import org.apache.phoenix.parse.DerivedTableNode;
+import org.apache.phoenix.parse.HintNode;
+import org.apache.phoenix.parse.LimitNode;
+import org.apache.phoenix.parse.OrderByNode;
+import org.apache.phoenix.parse.ParseNode;
+import org.apache.phoenix.parse.ParseNodeRewriter;
+import org.apache.phoenix.parse.SelectStatement;
+import org.apache.phoenix.parse.TableNode;
+import org.apache.phoenix.parse.TableWildcardParseNode;
+import org.apache.phoenix.parse.WildcardParseNode;
+import org.apache.phoenix.util.SchemaUtil;
+
+import com.google.common.collect.Lists;
+
+public class SubselectRewriter extends ParseNodeRewriter {
+    private final String tableAlias;
+    private final Map<String, ParseNode> aliasMap;
+    
+    public static SelectStatement applyPostFilters(SelectStatement statement, List<ParseNode> postFilters, String subqueryAlias) throws SQLException {
+        if (postFilters.isEmpty())
+            return statement;
+        
+        // TODO Handle post-filters in the below two cases from JoinCompiler:
+        // 1) select ... from A join (select id, b from T limit 10) as B on A.id = B.id where B.b = 'b'
+        // 2) select ... from A join (select count(*) c from T) as B on A.a = B.c where B.c > 10
+        if (statement.getLimit() != null || (statement.isAggregate() && statement.getGroupBy().isEmpty()))
+            throw new SQLFeatureNotSupportedException();
+        
+        return new SubselectRewriter(null, statement.getSelect(), subqueryAlias).applyPostFilters(statement, postFilters);
+    }
+    
+    public static SelectStatement flatten(SelectStatement select, PhoenixConnection connection) throws SQLException {
+        List<TableNode> from = select.getFrom();
+        while (from.size() == 1 && from.get(0) instanceof DerivedTableNode) {
+            DerivedTableNode derivedTable = (DerivedTableNode) from.get(0);
+            SelectStatement subselect = derivedTable.getSelect();
+            ColumnResolver resolver = FromCompiler.getResolverForQuery(subselect, connection);
+            SubselectRewriter rewriter = new SubselectRewriter(resolver, subselect.getSelect(), derivedTable.getAlias());
+            SelectStatement ret = rewriter.flatten(select, subselect);
+            if (ret == select)
+                break;
+            
+            select = ret;
+            from = select.getFrom();
+        }
+        
+        return select;
+    }
+    
+    private SubselectRewriter(ColumnResolver resolver, List<AliasedNode> aliasedNodes, String tableAlias) {
+        super(resolver, aliasedNodes.size());
+        this.tableAlias = tableAlias;
+        this.aliasMap = new HashMap<String, ParseNode>();
+        for (AliasedNode aliasedNode : aliasedNodes) {
+            String alias = aliasedNode.getAlias();
+            ParseNode node = aliasedNode.getNode();
+            if (alias == null) {
+                alias = SchemaUtil.normalizeIdentifier(node.getAlias());
+            }
+            if (alias != null) {
+                aliasMap.put(SchemaUtil.getColumnName(tableAlias, alias), node);
+            }
+        }
+    }
+    
+    private SelectStatement flatten(SelectStatement select, SelectStatement subselect) throws SQLException {
+        // Replace aliases in sub-select first.
+        subselect = ParseNodeRewriter.rewrite(subselect, this);
+        
+        ParseNode whereRewrite = subselect.getWhere();
+        List<ParseNode> groupByRewrite = subselect.getGroupBy();
+        ParseNode havingRewrite = subselect.getHaving();
+        List<OrderByNode> orderByRewrite = subselect.getOrderBy();
+        LimitNode limitRewrite = subselect.getLimit();
+        HintNode hintRewrite = subselect.getHint();
+        boolean isDistinctRewrite = subselect.isDistinct();
+        boolean isAggregateRewrite = subselect.isAggregate();
+        
+        ParseNode where = select.getWhere();
+        if (where != null) {
+            if (subselect.getLimit() != null || (subselect.isAggregate() && subselect.getGroupBy().isEmpty())) {
+                return select;
+            }
+            ParseNode postFilter = where.accept(this);
+            if (subselect.getGroupBy().isEmpty()) {
+                whereRewrite = whereRewrite == null ? postFilter : NODE_FACTORY.and(Arrays.<ParseNode>asList(whereRewrite, postFilter));
+            } else {
+                havingRewrite = havingRewrite == null ? postFilter : NODE_FACTORY.and(Arrays.<ParseNode>asList(havingRewrite, postFilter));
+            }
+        }
+        
+        List<ParseNode> groupBy = select.getGroupBy();
+        if (!groupBy.isEmpty()) {
+            if (subselect.getLimit() != null || subselect.isAggregate() || subselect.isDistinct()) {
+                return select;
+            }
+            groupByRewrite = Lists.<ParseNode>newArrayListWithExpectedSize(groupBy.size());
+            for (ParseNode node : groupBy) {
+                groupByRewrite.add(node.accept(this));
+            }
+            if (select.getHaving() != null) {
+                havingRewrite = select.getHaving().accept(this);
+            }
+        }
+        
+        List<AliasedNode> selectNodes = select.getSelect();
+        List<AliasedNode> selectNodesRewrite = Lists.newArrayListWithExpectedSize(selectNodes.size());
+        for (AliasedNode aliasedNode : selectNodes) {
+            ParseNode node = aliasedNode.getNode();
+            if (node instanceof WildcardParseNode 
+                    || (node instanceof TableWildcardParseNode 
+                            && ((TableWildcardParseNode) node).getTableName().equals(tableAlias))) {
+                for (AliasedNode aNode : subselect.getSelect()) {
+                    String alias = aNode.getAlias();
+                    String aliasRewrite = alias == null ? null : SchemaUtil.getColumnName(tableAlias, alias);
+                    selectNodesRewrite.add(NODE_FACTORY.aliasedNode(aliasRewrite, aNode.getNode()));
+                }                
+            } else {
+                selectNodesRewrite.add(NODE_FACTORY.aliasedNode(aliasedNode.getAlias(), node.accept(this)));
+            }
+        }
+        
+        List<OrderByNode> orderBy = select.getOrderBy();
+        if (!orderBy.isEmpty()) {
+            if (subselect.getLimit() != null) {
+                return select;
+            }
+            orderByRewrite = Lists.newArrayListWithExpectedSize(orderBy.size());
+            for (OrderByNode orderByNode : orderBy) {
+                ParseNode node = orderByNode.getNode();
+                orderByRewrite.add(NODE_FACTORY.orderBy(node.accept(this), orderByNode.isNullsLast(), orderByNode.isAscending()));
+            }
+        }
+        
+        LimitNode limit = select.getLimit();
+        if (limit != null) {
+            if (limitRewrite == null) {
+                limitRewrite = limit;
+            } else {
+                Integer limitValue = LimitCompiler.compile(null, select);
+                Integer limitValueSubselect = LimitCompiler.compile(null, subselect);
+                if (limitValue != null && limitValueSubselect != null) {
+                    limitRewrite = limitValue < limitValueSubselect ? limit : limitRewrite;
+                } else {
+                    return select;
+                }
+            }
+        }
+        
+        HintNode hint = select.getHint();
+        if (hint != null) {
+            hintRewrite = hintRewrite == null ? hint : HintNode.combine(hint, hintRewrite);
+        }
+        
+        if (select.isDistinct()) {
+            if (subselect.getLimit() != null || subselect.isAggregate() || subselect.isDistinct()) {
+                return select;
+            }
+            isDistinctRewrite = true;
+        }
+        
+        if (select.isAggregate()) {
+            if (subselect.getLimit() != null || subselect.isAggregate() || subselect.isDistinct()) {
+                return select;
+            }
+            isAggregateRewrite = true;
+        }
+        
+        return NODE_FACTORY.select(subselect.getFrom(), hintRewrite, isDistinctRewrite, selectNodesRewrite, whereRewrite, groupByRewrite, havingRewrite, orderByRewrite, limitRewrite, select.getBindCount(), isAggregateRewrite);
+    }
+    
+    private SelectStatement applyPostFilters(SelectStatement statement, List<ParseNode> postFilters) throws SQLException {
+        List<ParseNode> postFiltersRewrite = Lists.<ParseNode>newArrayListWithExpectedSize(postFilters.size());
+        for (ParseNode node : postFilters) {
+            postFiltersRewrite.add(node.accept(this));
+        }
+        
+        if (statement.getGroupBy().isEmpty()) {
+            ParseNode where = statement.getWhere();
+            if (where != null) {
+                postFiltersRewrite.add(where);
+            }
+            return NODE_FACTORY.select(statement.getFrom(), statement.getHint(), statement.isDistinct(), statement.getSelect(), combine(postFiltersRewrite), statement.getGroupBy(), statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(), statement.isAggregate());
+        }
+        
+        ParseNode having = statement.getHaving();
+        if (having != null) {
+            postFiltersRewrite.add(having);
+        }
+        return NODE_FACTORY.select(statement.getFrom(), statement.getHint(), statement.isDistinct(), statement.getSelect(), statement.getWhere(), statement.getGroupBy(), combine(postFiltersRewrite), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(), statement.isAggregate());
+    }
+    
+    @Override
+    public ParseNode visit(ColumnParseNode node) throws SQLException {
+        if (node.getTableName() == null)
+            return super.visit(node);
+        
+        ParseNode aliasedNode = aliasMap.get(node.getFullName());
+        if (aliasedNode != null) {
+            return aliasedNode;
+        }
+        return node;
+    }        
+    
+    private static ParseNode combine(List<ParseNode> nodes) {
+        if (nodes.isEmpty())
+            return null;
+        
+        if (nodes.size() == 1)
+            return nodes.get(0);
+        
+        return NODE_FACTORY.and(nodes);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/43c78877/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java
index 78867d1..6855827 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java
@@ -352,6 +352,7 @@ public class UpsertCompiler {
         if (valueNodes == null) {
             SelectStatement select = upsert.getSelect();
             assert(select != null);
+            select = SubselectRewriter.flatten(select, connection);
             ColumnResolver selectResolver = FromCompiler.getResolverForQuery(select, connection);
             select = StatementNormalizer.normalize(select, selectResolver);
             select = prependTenantAndViewConstants(table, select, tenantId, addViewColumnsToBe);

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/43c78877/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 ff1c953..74eaecf 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
@@ -43,6 +43,7 @@ import org.apache.phoenix.compile.DropSequenceCompiler;
 import org.apache.phoenix.compile.ExplainPlan;
 import org.apache.phoenix.compile.ExpressionProjector;
 import org.apache.phoenix.compile.FromCompiler;
+import org.apache.phoenix.compile.SubselectRewriter;
 import org.apache.phoenix.compile.GroupByCompiler.GroupBy;
 import org.apache.phoenix.compile.MutationPlan;
 import org.apache.phoenix.compile.OrderByCompiler.OrderBy;
@@ -259,8 +260,9 @@ public class PhoenixStatement implements Statement, SQLCloseable, org.apache.pho
         @SuppressWarnings("unchecked")
         @Override
         public QueryPlan compilePlan(PhoenixStatement stmt) throws SQLException {
-            ColumnResolver resolver = FromCompiler.getResolverForQuery(this, stmt.getConnection());
-            SelectStatement select = StatementNormalizer.normalize(this, resolver);
+            SelectStatement select = SubselectRewriter.flatten(this, stmt.getConnection());
+            ColumnResolver resolver = FromCompiler.getResolverForQuery(select, stmt.getConnection());
+            select = StatementNormalizer.normalize(select, resolver);
             return new QueryCompiler(stmt, select, resolver).compile();
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/43c78877/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java
index ea373b0..0d2ede9 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java
@@ -106,6 +106,12 @@ public class HintNode {
         return new HintNode(hints);
     }
     
+    public static HintNode combine(HintNode hintNode, HintNode override) {
+        Map<Hint,String> hints = new HashMap<Hint,String>(hintNode.hints);
+        hints.putAll(override.hints);
+        return new HintNode(hints);
+    }
+    
     private HintNode() {
         hints = new HashMap<Hint,String>();
     }

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/43c78877/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeRewriter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeRewriter.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeRewriter.java
index 19d0570..bff5834 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeRewriter.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeRewriter.java
@@ -204,10 +204,6 @@ public class ParseNodeRewriter extends TraverseAllParseNodeVisitor<ParseNode> {
         this.nodeCount = 0;
     }
     
-    protected boolean visitDerivedTableNode() {
-        return true;
-    }
-    
     private static interface CompoundNodeFactory {
         ParseNode createNode(List<ParseNode> children);
     }
@@ -532,15 +528,7 @@ public class ParseNodeRewriter extends TraverseAllParseNodeVisitor<ParseNode> {
 
         @Override
         public TableNode visit(DerivedTableNode subselectNode) throws SQLException {
-            if (!parseNodeRewriter.visitDerivedTableNode())
-                return subselectNode;
-            
-            SelectStatement select = subselectNode.getSelect();
-            SelectStatement normSelect = rewrite(select, parseNodeRewriter);
-            if (select == normSelect)
-                return subselectNode;
-            
-            return NODE_FACTORY.derivedTable(subselectNode.getAlias(), normSelect);
+            return subselectNode;
         }
 	    
 	}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/43c78877/phoenix-core/src/test/java/org/apache/phoenix/compile/JoinQueryCompilerTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/JoinQueryCompilerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/JoinQueryCompilerTest.java
index b64fe56..5a44331 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/compile/JoinQueryCompilerTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/JoinQueryCompilerTest.java
@@ -33,7 +33,6 @@ import java.sql.DriverManager;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 
-import org.apache.hadoop.hbase.client.Scan;
 import org.apache.phoenix.compile.JoinCompiler.JoinTable;
 import org.apache.phoenix.jdbc.PhoenixConnection;
 import org.apache.phoenix.jdbc.PhoenixStatement;
@@ -129,13 +128,12 @@ public class JoinQueryCompilerTest extends BaseConnectionlessQueryTest {
     }
     
     private static JoinTable getJoinTable(String query, PhoenixConnection connection) throws SQLException {
-        Scan scan = new Scan();
         SQLParser parser = new SQLParser(query);
-        SelectStatement select = parser.parseQuery();
+        SelectStatement select = SubselectRewriter.flatten(parser.parseQuery(), connection);
         ColumnResolver resolver = FromCompiler.getResolverForQuery(select, connection);
         select = StatementNormalizer.normalize(select, resolver);
-        StatementContext context = new StatementContext(new PhoenixStatement(connection), resolver, scan);
-        return JoinCompiler.compile(select, context.getResolver());        
+        PhoenixStatement stmt = connection.createStatement().unwrap(PhoenixStatement.class);
+        return JoinCompiler.compile(stmt, select, resolver);        
     }
 }
 


[2/2] git commit: Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/incubator-phoenix

Posted by ma...@apache.org.
Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/incubator-phoenix


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

Branch: refs/heads/master
Commit: 76908006c24edc78e3cca5fcd82cbebf1d34eaf2
Parents: 43c7887 db481c5
Author: maryannxue <ma...@apache.org>
Authored: Tue Apr 22 19:32:25 2014 -0400
Committer: maryannxue <ma...@apache.org>
Committed: Tue Apr 22 19:32:25 2014 -0400

----------------------------------------------------------------------
 .../apache/phoenix/end2end/CreateTableIT.java   | 222 ++++++++++++++++++-
 .../RoundFloorCeilFunctionsEnd2EndIT.java       | 144 ++++++++++--
 .../function/RoundDecimalExpression.java        |   2 +-
 .../apache/phoenix/schema/MetaDataClient.java   |   6 +
 4 files changed, 348 insertions(+), 26 deletions(-)
----------------------------------------------------------------------