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/01 02:34:50 UTC
[3/3] git commit: PHOENIX-71 Support sub-joins
PHOENIX-71 Support sub-joins
Project: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/commit/12bd7aed
Tree: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/tree/12bd7aed
Diff: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/diff/12bd7aed
Branch: refs/heads/master
Commit: 12bd7aeddd4e25a754b76c3f05b00730c4304644
Parents: 0849b25
Author: maryannxue <ma...@apache.org>
Authored: Mon Mar 31 20:33:50 2014 -0400
Committer: maryannxue <ma...@apache.org>
Committed: Mon Mar 31 20:33:50 2014 -0400
----------------------------------------------------------------------
.../org/apache/phoenix/end2end/HashJoinIT.java | 258 +++-
phoenix-core/src/main/antlr3/PhoenixSQL.g | 23 +-
.../apache/phoenix/compile/FromCompiler.java | 17 +-
.../apache/phoenix/compile/JoinCompiler.java | 1425 +++++++++---------
.../apache/phoenix/compile/QueryCompiler.java | 99 +-
.../phoenix/compile/StatementNormalizer.java | 42 +-
.../apache/phoenix/optimize/QueryOptimizer.java | 2 +-
.../org/apache/phoenix/parse/BindTableNode.java | 4 +-
.../apache/phoenix/parse/DerivedTableNode.java | 4 +-
.../org/apache/phoenix/parse/JoinPartNode.java | 53 +
.../org/apache/phoenix/parse/JoinTableNode.java | 35 +-
.../apache/phoenix/parse/NamedTableNode.java | 4 +-
.../apache/phoenix/parse/ParseNodeFactory.java | 16 +-
.../apache/phoenix/parse/ParseNodeRewriter.java | 81 +-
.../apache/phoenix/parse/SelectStatement.java | 4 +
.../org/apache/phoenix/parse/TableNode.java | 2 +-
.../apache/phoenix/parse/TableNodeVisitor.java | 10 +-
.../phoenix/compile/JoinQueryCompilerTest.java | 70 +-
18 files changed, 1192 insertions(+), 957 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/12bd7aed/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 248621b..5ccef2c 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
@@ -226,7 +226,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
" BUILD HASH TABLE 1\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SUPPLIER_TABLE_DISPLAY_NAME,
/*
- * testSelfJoin
+ * testSelfJoin()
* SELECT i2.item_id, i1.name FROM joinItemTable i1
* JOIN joinItemTable i2 ON i1.item_id = i2.item_id
* ORDER BY i1.item_id
@@ -237,7 +237,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ITEM_TABLE_DISPLAY_NAME + "\n" +
" SERVER FILTER BY FIRST KEY ONLY",
/*
- * testSelfJoin
+ * testSelfJoin()
* SELECT i1.name, i2.name FROM joinItemTable i1
* JOIN joinItemTable i2 ON i1.item_id = i2.supplier_id
* ORDER BY i1.name, i2.name
@@ -249,12 +249,12 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
" BUILD HASH TABLE 0\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ITEM_TABLE_DISPLAY_NAME,
/*
- * testStarJoin
- * SELECT order_id, c.name, i.name iname, quantity, o.date
- * FROM joinOrderTable o
- * JOIN joinCustomerTable c ON o.customer_id = c.customer_id
- * JOIN joinItemTable i ON o.item_id = i.item_id
- * ORDER BY order_id
+ * testStarJoin()
+ * SELECT order_id, c.name, i.name iname, quantity, o.date
+ * FROM joinOrderTable o
+ * JOIN joinCustomerTable c ON o.customer_id = c.customer_id
+ * JOIN joinItemTable i ON o.item_id = i.item_id
+ * ORDER BY order_id
*/
"CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" +
" PARALLEL EQUI-JOIN 2 HASH TABLES:\n" +
@@ -263,12 +263,12 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
" BUILD HASH TABLE 1\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ITEM_TABLE_DISPLAY_NAME,
/*
- * testStarJoin
- * SELECT (*NO_STAR_JOIN*) order_id, c.name, i.name iname, quantity, o.date
- * FROM joinOrderTable o
- * JOIN joinCustomerTable c ON o.customer_id = c.customer_id
- * JOIN joinItemTable i ON o.item_id = i.item_id
- * ORDER BY order_id
+ * testStarJoin()
+ * SELECT (*NO_STAR_JOIN*) order_id, c.name, i.name iname, quantity, o.date
+ * FROM joinOrderTable o
+ * JOIN joinCustomerTable c ON o.customer_id = c.customer_id
+ * JOIN joinItemTable i ON o.item_id = i.item_id
+ * ORDER BY order_id
*/
"CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ITEM_TABLE_DISPLAY_NAME + "\n" +
" SERVER SORTED BY [O.order_id]\n" +
@@ -279,6 +279,33 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
" PARALLEL EQUI-JOIN 1 HASH TABLES:\n" +
" BUILD HASH TABLE 0\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_CUSTOMER_TABLE_DISPLAY_NAME,
+ /*
+ * testSubJoin()
+ * SELECT * FROM joinCustomerTable c
+ * INNER JOIN (joinOrderTable o
+ * INNER JOIN (joinSupplierTable s
+ * RIGHT JOIN joinItemTable i ON i.supplier_id = s.supplier_id)
+ * ON o.item_id = i.item_id)
+ * ON c.customer_id = o.customer_id
+ * WHERE c.customer_id <= '0000000005'
+ * AND order_id != '000000000000003'
+ * AND i.name != 'T3'
+ * ORDER BY c.customer_id, i.name
+ */
+ "CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_CUSTOMER_TABLE_DISPLAY_NAME + " [*] - ['0000000005']\n" +
+ " SERVER SORTED BY [C.customer_id, I.NAME]\n" +
+ "CLIENT MERGE SORT\n" +
+ " PARALLEL EQUI-JOIN 1 HASH TABLES:\n" +
+ " BUILD HASH TABLE 0\n" +
+ " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" +
+ " SERVER FILTER BY order_id != '000000000000003'\n" +
+ " PARALLEL EQUI-JOIN 1 HASH TABLES:\n" +
+ " BUILD HASH TABLE 0\n" +
+ " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ITEM_TABLE_DISPLAY_NAME + "\n" +
+ " SERVER FILTER BY NAME != 'T3'\n" +
+ " PARALLEL EQUI-JOIN 1 HASH TABLES:\n" +
+ " BUILD HASH TABLE 0\n" +
+ " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SUPPLIER_TABLE_DISPLAY_NAME,
}});
testCases.add(new String[][] {
{
@@ -404,7 +431,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
" BUILD HASH TABLE 1\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SCHEMA + ".idx_supplier",
/*
- * testSelfJoin
+ * testSelfJoin()
* SELECT i2.item_id, i1.name FROM joinItemTable i1
* JOIN joinItemTable i2 ON i1.item_id = i2.item_id
* ORDER BY i1.item_id
@@ -415,7 +442,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SCHEMA + ".idx_item\n" +
" SERVER FILTER BY FIRST KEY ONLY",
/*
- * testSelfJoin
+ * testSelfJoin()
* SELECT i1.name, i2.name FROM joinItemTable i1
* JOIN joinItemTable i2 ON i1.item_id = i2.supplier_id
* ORDER BY i1.name, i2.name
@@ -428,12 +455,12 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
" BUILD HASH TABLE 0\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SCHEMA + ".idx_item",
/*
- * testStarJoin
- * SELECT order_id, c.name, i.name iname, quantity, o.date
- * FROM joinOrderTable o
- * JOIN joinCustomerTable c ON o.customer_id = c.customer_id
- * JOIN joinItemTable i ON o.item_id = i.item_id
- * ORDER BY order_id
+ * testStarJoin()
+ * SELECT order_id, c.name, i.name iname, quantity, o.date
+ * FROM joinOrderTable o
+ * JOIN joinCustomerTable c ON o.customer_id = c.customer_id
+ * JOIN joinItemTable i ON o.item_id = i.item_id
+ * ORDER BY order_id
*/
"CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" +
" PARALLEL EQUI-JOIN 2 HASH TABLES:\n" +
@@ -443,12 +470,12 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SCHEMA + ".idx_item\n" +
" SERVER FILTER BY FIRST KEY ONLY",
/*
- * testStarJoin
- * SELECT (*NO_STAR_JOIN*) order_id, c.name, i.name iname, quantity, o.date
- * FROM joinOrderTable o
- * JOIN joinCustomerTable c ON o.customer_id = c.customer_id
- * JOIN joinItemTable i ON o.item_id = i.item_id
- * ORDER BY order_id
+ * testStarJoin()
+ * SELECT (*NO_STAR_JOIN*) order_id, c.name, i.name iname, quantity, o.date
+ * FROM joinOrderTable o
+ * JOIN joinCustomerTable c ON o.customer_id = c.customer_id
+ * JOIN joinItemTable i ON o.item_id = i.item_id
+ * ORDER BY order_id
*/
"CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SCHEMA + ".idx_item\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
@@ -460,6 +487,33 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
" PARALLEL EQUI-JOIN 1 HASH TABLES:\n" +
" BUILD HASH TABLE 0\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SCHEMA + ".idx_customer",
+ /*
+ * testSubJoin()
+ * SELECT * FROM joinCustomerTable c
+ * INNER JOIN (joinOrderTable o
+ * INNER JOIN (joinSupplierTable s
+ * RIGHT JOIN joinItemTable i ON i.supplier_id = s.supplier_id)
+ * ON o.item_id = i.item_id)
+ * ON c.customer_id = o.customer_id
+ * WHERE c.customer_id <= '0000000005'
+ * AND order_id != '000000000000003'
+ * AND i.name != 'T3'
+ * ORDER BY c.customer_id, i.name
+ */
+ "CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_CUSTOMER_TABLE_DISPLAY_NAME + " [*] - ['0000000005']\n" +
+ " SERVER SORTED BY [C.customer_id, I.0:NAME]\n" +
+ "CLIENT MERGE SORT\n" +
+ " PARALLEL EQUI-JOIN 1 HASH TABLES:\n" +
+ " BUILD HASH TABLE 0\n" +
+ " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" +
+ " SERVER FILTER BY order_id != '000000000000003'\n" +
+ " PARALLEL EQUI-JOIN 1 HASH TABLES:\n" +
+ " BUILD HASH TABLE 0\n" +
+ " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SCHEMA + ".idx_item\n" +
+ " SERVER FILTER BY NAME != 'T3'\n" +
+ " PARALLEL EQUI-JOIN 1 HASH TABLES:\n" +
+ " BUILD HASH TABLE 0\n" +
+ " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SCHEMA + ".idx_supplier",
}});
return testCases;
}
@@ -1309,13 +1363,16 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
@Test
public void testLeftRightJoin() throws Exception {
- String query = "SELECT \"order_id\", i.name, s.name, quantity, date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o LEFT JOIN "
- + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" RIGHT JOIN "
- + JOIN_SUPPLIER_TABLE_FULL_NAME + " s ON i.\"supplier_id\" = s.\"supplier_id\" ORDER BY \"order_id\", s.\"supplier_id\" DESC";
+ String query1 = "SELECT \"order_id\", i.name, s.name, quantity, date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o LEFT JOIN "
+ + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" RIGHT JOIN "
+ + JOIN_SUPPLIER_TABLE_FULL_NAME + " s ON i.\"supplier_id\" = s.\"supplier_id\" ORDER BY \"order_id\", s.\"supplier_id\" DESC";
+ String query2 = "SELECT \"order_id\", i.name, s.name, quantity, date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o LEFT JOIN "
+ + "(" + JOIN_ITEM_TABLE_FULL_NAME + " i RIGHT JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " s ON i.\"supplier_id\" = s.\"supplier_id\")"
+ + " ON o.\"item_id\" = i.\"item_id\" ORDER BY \"order_id\", s.\"supplier_id\" DESC";
Properties props = new Properties(TEST_PROPERTIES);
Connection conn = DriverManager.getConnection(getUrl(), props);
try {
- PreparedStatement statement = conn.prepareStatement(query);
+ PreparedStatement statement = conn.prepareStatement(query1);
ResultSet rs = statement.executeQuery();
assertTrue (rs.next());
assertNull(rs.getString(1));
@@ -1367,21 +1424,9 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
assertNotNull(rs.getDate(5));
assertFalse(rs.next());
- } finally {
- conn.close();
- }
- }
-
- @Test
- public void testMultiLeftJoin() throws Exception {
- String query = "SELECT \"order_id\", i.name, s.name, quantity, date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o LEFT JOIN "
- + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" LEFT JOIN "
- + JOIN_SUPPLIER_TABLE_FULL_NAME + " s ON i.\"supplier_id\" = s.\"supplier_id\"";
- Properties props = new Properties(TEST_PROPERTIES);
- Connection conn = DriverManager.getConnection(getUrl(), props);
- try {
- PreparedStatement statement = conn.prepareStatement(query);
- ResultSet rs = statement.executeQuery();
+
+ statement = conn.prepareStatement(query2);
+ rs = statement.executeQuery();
assertTrue (rs.next());
assertEquals(rs.getString(1), "000000000000001");
assertEquals(rs.getString(2), "T1");
@@ -1420,6 +1465,59 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
}
@Test
+ public void testMultiLeftJoin() throws Exception {
+ String[] queries = {
+ "SELECT \"order_id\", i.name, s.name, quantity, date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o LEFT JOIN "
+ + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" LEFT JOIN "
+ + JOIN_SUPPLIER_TABLE_FULL_NAME + " s ON i.\"supplier_id\" = s.\"supplier_id\"",
+ "SELECT \"order_id\", i.name, s.name, quantity, date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o LEFT JOIN "
+ + "(" + JOIN_ITEM_TABLE_FULL_NAME + " i LEFT JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " s ON i.\"supplier_id\" = s.\"supplier_id\") "
+ + "ON o.\"item_id\" = i.\"item_id\""};
+ Properties props = new Properties(TEST_PROPERTIES);
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ try {
+ for (String query : queries) {
+ PreparedStatement statement = conn.prepareStatement(query);
+ ResultSet rs = statement.executeQuery();
+ assertTrue (rs.next());
+ assertEquals(rs.getString(1), "000000000000001");
+ assertEquals(rs.getString(2), "T1");
+ assertEquals(rs.getString(3), "S1");
+ assertEquals(rs.getInt(4), 1000);
+ assertNotNull(rs.getDate(5));
+ assertTrue (rs.next());
+ assertEquals(rs.getString(1), "000000000000002");
+ assertEquals(rs.getString(2), "T6");
+ assertEquals(rs.getString(3), "S6");
+ assertEquals(rs.getInt(4), 2000);
+ assertNotNull(rs.getDate(5));
+ assertTrue (rs.next());
+ assertEquals(rs.getString(1), "000000000000003");
+ assertEquals(rs.getString(2), "T2");
+ assertEquals(rs.getString(3), "S1");
+ assertEquals(rs.getInt(4), 3000);
+ assertNotNull(rs.getDate(5));
+ assertTrue (rs.next());
+ assertEquals(rs.getString(1), "000000000000004");
+ assertEquals(rs.getString(2), "T6");
+ assertEquals(rs.getString(3), "S6");
+ assertEquals(rs.getInt(4), 4000);
+ assertNotNull(rs.getDate(5));
+ assertTrue (rs.next());
+ assertEquals(rs.getString(1), "000000000000005");
+ assertEquals(rs.getString(2), "T3");
+ assertEquals(rs.getString(3), "S2");
+ assertEquals(rs.getInt(4), 5000);
+ assertNotNull(rs.getDate(5));
+
+ assertFalse(rs.next());
+ }
+ } finally {
+ conn.close();
+ }
+ }
+
+ @Test
public void testMultiRightJoin() throws Exception {
String query = "SELECT \"order_id\", i.name, s.name, quantity, date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o RIGHT JOIN "
+ JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" RIGHT JOIN "
@@ -2306,6 +2404,72 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT {
}
}
+
+ @Test
+ public void testSubJoin() throws Exception {
+ String query1 = "SELECT i.name, count(c.name), min(s.name), max(quantity) FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o LEFT JOIN "
+ + "(" + JOIN_SUPPLIER_TABLE_FULL_NAME + " s RIGHT JOIN " + JOIN_ITEM_TABLE_FULL_NAME + " i ON i.\"supplier_id\" = s.\"supplier_id\")"
+ + " ON o.\"item_id\" = i.\"item_id\" LEFT JOIN "
+ + JOIN_CUSTOMER_TABLE_FULL_NAME + " c ON c.\"customer_id\" = o.\"customer_id\" GROUP BY i.name ORDER BY i.name";
+ String query2 = "SELECT c.name, o.\"order_id\", i.name, s.name FROM " + JOIN_CUSTOMER_TABLE_FULL_NAME + " c INNER JOIN "
+ + "(" + JOIN_ORDER_TABLE_FULL_NAME + " o INNER JOIN "
+ + "(" + JOIN_SUPPLIER_TABLE_FULL_NAME + " s RIGHT JOIN " + JOIN_ITEM_TABLE_FULL_NAME + " i ON i.\"supplier_id\" = s.\"supplier_id\")"
+ + " ON o.\"item_id\" = i.\"item_id\") ON c.\"customer_id\" = o.\"customer_id\""
+ + " WHERE c.\"customer_id\" <= '0000000005' AND \"order_id\" != '000000000000003' AND i.name != 'T3' ORDER BY c.\"customer_id\", i.name";
+ Properties props = new Properties(TEST_PROPERTIES);
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ try {
+ PreparedStatement statement = conn.prepareStatement(query1);
+ ResultSet rs = statement.executeQuery();
+ assertTrue (rs.next());
+ assertEquals(rs.getString(1), "T1");
+ assertEquals(rs.getInt(2), 1);
+ assertEquals(rs.getString(3), "S1");
+ assertEquals(rs.getInt(4), 1000);
+ assertTrue (rs.next());
+ assertEquals(rs.getString(1), "T2");
+ assertEquals(rs.getInt(2), 1);
+ assertEquals(rs.getString(3), "S1");
+ assertEquals(rs.getInt(4), 3000);
+ assertTrue (rs.next());
+ assertEquals(rs.getString(1), "T3");
+ assertEquals(rs.getInt(2), 1);
+ assertEquals(rs.getString(3), "S2");
+ assertEquals(rs.getInt(4), 5000);
+ assertTrue (rs.next());
+ assertEquals(rs.getString(1), "T6");
+ assertEquals(rs.getInt(2), 2);
+ assertEquals(rs.getString(3), "S6");
+ assertEquals(rs.getInt(4), 4000);
+
+ assertFalse(rs.next());
+
+ statement = conn.prepareStatement(query2);
+ rs = statement.executeQuery();
+ assertTrue(rs.next());
+ assertEquals(rs.getString("c.name"), "C3");
+ assertEquals(rs.getString("O.order_id"), "000000000000002");
+ assertEquals(rs.getString("i.name"), "T6");
+ assertEquals(rs.getString("s.name"), "S6");
+ assertTrue(rs.next());
+ assertEquals(rs.getString("c.name"), "C4");
+ assertEquals(rs.getString("O.order_id"), "000000000000001");
+ assertEquals(rs.getString("i.name"), "T1");
+ assertEquals(rs.getString("s.name"), "S1");
+ assertTrue(rs.next());
+ assertEquals(rs.getString("c.name"), "C4");
+ assertEquals(rs.getString("O.order_id"), "000000000000004");
+ assertEquals(rs.getString("i.name"), "T6");
+ assertEquals(rs.getString("s.name"), "S6");
+
+ assertFalse(rs.next());
+
+ rs = conn.createStatement().executeQuery("EXPLAIN " + query2);
+ assertEquals(plans[13], QueryUtil.getExplainPlan(rs));
+ } finally {
+ conn.close();
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/12bd7aed/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 6ccd03e..4f1d107 100644
--- a/phoenix-core/src/main/antlr3/PhoenixSQL.g
+++ b/phoenix-core/src/main/antlr3/PhoenixSQL.g
@@ -629,23 +629,28 @@ parseOrderByField returns [OrderByNode ret]
parseFrom returns [List<TableNode> ret]
@init{ret = new ArrayList<TableNode>(4); }
- : t=table_ref {$ret.add(t);} (s=sub_table_ref { $ret.add(s); })*
- ;
-
-sub_table_ref returns [TableNode ret]
- : COMMA t=table_ref { $ret = t; }
- | t=join_spec { $ret = t; }
+ : t=table_ref {$ret.add(t);} (COMMA s=table_ref { $ret.add(s); })*
;
table_ref returns [TableNode ret]
+ : t=single_table_ref p=join_parts { $ret = factory.table(t, p); }
+ ;
+
+single_table_ref returns [TableNode ret]
: n=bind_name ((AS)? alias=identifier)? { $ret = factory.bindTable(alias, factory.table(null,n)); } // TODO: review
| t=from_table_name ((AS)? alias=identifier)? (LPAREN cdefs=dyn_column_defs RPAREN)? { $ret = factory.namedTable(alias,t,cdefs); }
| LPAREN SELECT s=hinted_select_node RPAREN ((AS)? alias=identifier)? { $ret = factory.derivedTable(alias, s); }
;
-join_spec returns [TableNode ret]
- : j=join_type JOIN t=table_ref ON e=expression { $ret = factory.join(j, e, t); }
- ;
+join_parts returns [List<JoinPartNode> ret]
+@init{ret = new ArrayList<JoinPartNode>(4); }
+ : (p=join_part { $ret.add(p); })*
+ ;
+
+join_part returns [JoinPartNode ret]
+ : j=join_type JOIN r=single_table_ref ON e=expression { $ret = factory.joinPart(j, e, r); }
+ | j=join_type JOIN LPAREN r=table_ref RPAREN ON e=expression { $ret = factory.joinPart(j, e, r); }
+ ;
join_type returns [JoinTableNode.JoinType ret]
: INNER? { $ret = JoinTableNode.JoinType.Inner; }
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/12bd7aed/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 f43ff4f..500ae5f 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,7 +146,7 @@ public class FromCompiler {
public static ColumnResolver getResolverForQuery(SelectStatement statement, PhoenixConnection connection)
throws SQLException {
List<TableNode> fromNodes = statement.getFrom();
- if (fromNodes.size() == 1)
+ if (!statement.isJoin())
return new SingleTableColumnResolver(connection, (NamedTableNode)fromNodes.get(0), true);
MultiTableColumnResolver visitor = new MultiTableColumnResolver(connection);
@@ -337,7 +337,7 @@ public class FromCompiler {
}
// TODO: unused, but should be used for joins - make private once used
- public static class MultiTableColumnResolver extends BaseColumnResolver implements TableNodeVisitor {
+ public static class MultiTableColumnResolver extends BaseColumnResolver implements TableNodeVisitor<Void> {
private final ListMultimap<String, TableRef> tableMap;
private final List<TableRef> tables;
@@ -353,17 +353,19 @@ public class FromCompiler {
}
@Override
- public void visit(BindTableNode boundTableNode) throws SQLException {
+ public Void visit(BindTableNode boundTableNode) throws SQLException {
throw new SQLFeatureNotSupportedException();
}
@Override
- public void visit(JoinTableNode joinNode) throws SQLException {
- joinNode.getTable().accept(this);
+ public Void visit(JoinTableNode joinNode) throws SQLException {
+ joinNode.getLHS().accept(this);
+ joinNode.getRHS().accept(this);
+ return null;
}
@Override
- public void visit(NamedTableNode tableNode) throws SQLException {
+ public Void visit(NamedTableNode tableNode) throws SQLException {
String alias = tableNode.getAlias();
TableRef tableRef = createTableRef(tableNode, true);
PTable theTable = tableRef.getTable();
@@ -378,10 +380,11 @@ public class FromCompiler {
tableMap.put(name, tableRef);
}
tables.add(tableRef);
+ return null;
}
@Override
- public void visit(DerivedTableNode subselectNode) throws SQLException {
+ public Void visit(DerivedTableNode subselectNode) throws SQLException {
throw new SQLFeatureNotSupportedException();
}