PHOENIX-1399 Support cross joins and comma-separated table list
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/91e29c60 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/91e29c60 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/91e29c60 Branch: refs/heads/4.0 Commit: 91e29c60d7433352de9a350b7cfde1c67ef952ac Parents: e137711 Author: maryannxue <maryann...@apache.org> Authored: Sat Nov 1 14:59:52 2014 -0400 Committer: maryannxue <maryann...@apache.org> Committed: Sat Nov 1 14:59:52 2014 -0400 ---------------------------------------------------------------------- .../org/apache/phoenix/end2end/HashJoinIT.java | 70 +++++- phoenix-core/src/main/antlr3/PhoenixSQL.g | 30 +-- .../apache/phoenix/compile/DeleteCompiler.java | 2 +- .../apache/phoenix/compile/FromCompiler.java | 10 +- .../apache/phoenix/compile/JoinCompiler.java | 231 ++++++++++--------- .../apache/phoenix/compile/QueryCompiler.java | 4 +- .../phoenix/compile/StatementNormalizer.java | 12 +- .../phoenix/compile/SubqueryRewriter.java | 6 +- .../phoenix/compile/SubselectRewriter.java | 6 +- .../apache/phoenix/compile/UpsertCompiler.java | 2 +- .../phoenix/exception/SQLExceptionCode.java | 1 + .../apache/phoenix/jdbc/PhoenixStatement.java | 4 +- .../apache/phoenix/optimize/QueryOptimizer.java | 4 +- .../org/apache/phoenix/parse/JoinPartNode.java | 53 ----- .../apache/phoenix/parse/ParseNodeFactory.java | 21 +- .../apache/phoenix/parse/ParseNodeRewriter.java | 25 +- .../apache/phoenix/parse/SelectStatement.java | 18 +- 17 files changed, 239 insertions(+), 260 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/91e29c60/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 3850ac9..5190c18 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 @@ -41,7 +41,6 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; -import java.sql.SQLFeatureNotSupportedException; import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.Collection; @@ -1810,13 +1809,22 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { @Test public void testStarJoin() throws Exception { - String[] query = new String[2]; + String[] query = new String[5]; query[0] = "SELECT \"order_id\", c.name, i.name iname, quantity, o.date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o JOIN " + JOIN_CUSTOMER_TABLE_FULL_NAME + " c ON o.\"customer_id\" = c.\"customer_id\" JOIN " + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" ORDER BY \"order_id\""; - query[1] = "SELECT /*+ NO_STAR_JOIN*/ \"order_id\", c.name, i.name iname, quantity, o.date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o JOIN " + query[1] = "SELECT \"order_id\", c.name, i.name iname, quantity, o.date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o, " + + JOIN_CUSTOMER_TABLE_FULL_NAME + " c, " + + JOIN_ITEM_TABLE_FULL_NAME + " i WHERE o.\"item_id\" = i.\"item_id\" AND o.\"customer_id\" = c.\"customer_id\" ORDER BY \"order_id\""; + query[2] = "SELECT /*+ NO_STAR_JOIN*/ \"order_id\", c.name, i.name iname, quantity, o.date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o JOIN " + JOIN_CUSTOMER_TABLE_FULL_NAME + " c ON o.\"customer_id\" = c.\"customer_id\" JOIN " + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" ORDER BY \"order_id\""; + query[3] = "SELECT /*+ NO_STAR_JOIN*/ \"order_id\", c.name, i.name iname, quantity, o.date FROM (" + JOIN_ORDER_TABLE_FULL_NAME + " o, " + + JOIN_CUSTOMER_TABLE_FULL_NAME + " c), " + + JOIN_ITEM_TABLE_FULL_NAME + " i WHERE o.\"item_id\" = i.\"item_id\" AND o.\"customer_id\" = c.\"customer_id\" ORDER BY \"order_id\""; + query[4] = "SELECT \"order_id\", c.name, i.name iname, quantity, o.date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o, (" + + JOIN_CUSTOMER_TABLE_FULL_NAME + " c, " + + JOIN_ITEM_TABLE_FULL_NAME + " i) WHERE o.\"item_id\" = i.\"item_id\" AND o.\"customer_id\" = c.\"customer_id\" ORDER BY \"order_id\""; Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); Connection conn = DriverManager.getConnection(getUrl(), props); try { @@ -1860,8 +1868,10 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { assertFalse(rs.next()); - rs = conn.createStatement().executeQuery("EXPLAIN " + query[i]); - assertEquals(plans[11 + i], QueryUtil.getExplainPlan(rs)); + if (i < 4) { + rs = conn.createStatement().executeQuery("EXPLAIN " + query[i]); + assertEquals(plans[11 + (i/2)], QueryUtil.getExplainPlan(rs)); + } } } finally { conn.close(); @@ -3828,17 +3838,56 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { } @Test - public void testUnsupportedJoinConditions() throws Exception { - String query = "SELECT * FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp ON (item.\"supplier_id\" || supp.\"supplier_id\") = ''"; + public void testNonEquiJoin() throws Exception { Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); Connection conn = DriverManager.getConnection(getUrl(), props); try { + String query = "SELECT item.name, supp.name FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item, " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp WHERE item.\"supplier_id\" > supp.\"supplier_id\""; PreparedStatement statement = conn.prepareStatement(query); + ResultSet rs = statement.executeQuery(); + assertTrue(rs.next()); + assertEquals(rs.getString(1), "T3"); + assertEquals(rs.getString(2), "S1"); + assertTrue(rs.next()); + assertEquals(rs.getString(1), "T4"); + assertEquals(rs.getString(2), "S1"); + assertTrue(rs.next()); + assertEquals(rs.getString(1), "T5"); + assertEquals(rs.getString(2), "S1"); + assertTrue(rs.next()); + assertEquals(rs.getString(1), "T5"); + assertEquals(rs.getString(2), "S2"); + assertTrue(rs.next()); + assertEquals(rs.getString(1), "T5"); + assertEquals(rs.getString(2), "S3"); + assertTrue(rs.next()); + assertEquals(rs.getString(1), "T5"); + assertEquals(rs.getString(2), "S4"); + assertTrue(rs.next()); + assertEquals(rs.getString(1), "T6"); + assertEquals(rs.getString(2), "S1"); + assertTrue(rs.next()); + assertEquals(rs.getString(1), "T6"); + assertEquals(rs.getString(2), "S2"); + assertTrue(rs.next()); + assertEquals(rs.getString(1), "T6"); + assertEquals(rs.getString(2), "S3"); + assertTrue(rs.next()); + assertEquals(rs.getString(1), "T6"); + assertEquals(rs.getString(2), "S4"); + assertTrue(rs.next()); + assertEquals(rs.getString(1), "T6"); + assertEquals(rs.getString(2), "S5"); + + assertFalse(rs.next()); + + query = "SELECT item.name, supp.name FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp ON item.\"supplier_id\" > supp.\"supplier_id\""; + statement = conn.prepareStatement(query); try { statement.executeQuery(); - fail("Should have got SQLFeatureNotSupportedException."); - } catch (SQLFeatureNotSupportedException e) { - assertEquals("Does not support non-standard or non-equi join conditions.", e.getMessage()); + fail("Should have got SQLException."); + } catch (SQLException e) { + assertEquals(SQLExceptionCode.AMBIGUOUS_JOIN_CONDITION.getErrorCode(), e.getErrorCode()); } } finally { conn.close(); @@ -3847,3 +3896,4 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { } + http://git-wip-us.apache.org/repos/asf/phoenix/blob/91e29c60/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 e2636fb..aa7fdc6 100644 --- a/phoenix-core/src/main/antlr3/PhoenixSQL.g +++ b/phoenix-core/src/main/antlr3/PhoenixSQL.g @@ -647,31 +647,25 @@ parseOrderByField returns [OrderByNode ret] { $ret = factory.orderBy(expr, nullsLast, isAscending); } ; -parseFrom returns [List<TableNode> ret] -@init{ret = new ArrayList<TableNode>(4); } - : t=table_ref {$ret.add(t);} (COMMA s=table_ref { $ret.add(s); })* +parseFrom returns [TableNode ret] + : t=table_list {$ret = t;} + ; + +table_list returns [TableNode ret] + : t=table_ref {$ret = t;} (COMMA s=table_ref { $ret = factory.join(JoinTableNode.JoinType.Inner, ret, s, null, false); })* ; table_ref returns [TableNode ret] - : t=single_table_ref p=join_parts { $ret = factory.table(t, p); } - ; + : l=table_factor { $ret = l; } (j=join_type JOIN r=table_factor ON e=expression { $ret = factory.join(j, ret, r, e, false); })* + ; -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); } +table_factor returns [TableNode ret] + : LPAREN t=table_list RPAREN { $ret = t; } + | n=bind_name ((AS)? alias=identifier)? { $ret = factory.bindTable(alias, factory.table(null,n)); } // TODO: review + | f=from_table_name ((AS)? alias=identifier)? (LPAREN cdefs=dyn_column_defs RPAREN)? { $ret = factory.namedTable(alias,f,cdefs); } | LPAREN SELECT s=hinted_select_node RPAREN ((AS)? alias=identifier)? { $ret = factory.derivedTable(alias, s); } ; -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; } | LEFT OUTER? { $ret = JoinTableNode.JoinType.Left; } http://git-wip-us.apache.org/repos/asf/phoenix/blob/91e29c60/phoenix-core/src/main/java/org/apache/phoenix/compile/DeleteCompiler.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/DeleteCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/DeleteCompiler.java index 1331a2a..6638819 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/DeleteCompiler.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/DeleteCompiler.java @@ -315,7 +315,7 @@ public class DeleteCompiler { aliasedNodes.add(FACTORY.aliasedNode(null, FACTORY.column(null, '"' + column.getName().getString() + '"', null))); } select = FACTORY.select( - Collections.singletonList(delete.getTable()), + delete.getTable(), hint, false, aliasedNodes, delete.getWhere(), Collections.<ParseNode>emptyList(), null, delete.getOrderBy(), delete.getLimit(), http://git-wip-us.apache.org/repos/asf/phoenix/blob/91e29c60/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 1627f45..b9246c9 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 @@ -155,14 +155,12 @@ public class FromCompiler { */ public static ColumnResolver getResolverForQuery(SelectStatement statement, PhoenixConnection connection) throws SQLException { - List<TableNode> fromNodes = statement.getFrom(); - if (!statement.isJoin() && fromNodes.get(0) instanceof NamedTableNode) - return new SingleTableColumnResolver(connection, (NamedTableNode) fromNodes.get(0), true, 1); + TableNode fromNode = statement.getFrom(); + if (fromNode instanceof NamedTableNode) + return new SingleTableColumnResolver(connection, (NamedTableNode) fromNode, true, 1); MultiTableColumnResolver visitor = new MultiTableColumnResolver(connection, 1); - for (TableNode node : fromNodes) { - node.accept(visitor); - } + fromNode.accept(visitor); return visitor; } http://git-wip-us.apache.org/repos/asf/phoenix/blob/91e29c60/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 140146c..b519dc4 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 @@ -28,6 +28,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.ListIterator; import java.util.Map; import java.util.Set; @@ -39,6 +40,7 @@ import org.apache.phoenix.execute.TupleProjector; import org.apache.phoenix.expression.AndExpression; import org.apache.phoenix.expression.CoerceExpression; import org.apache.phoenix.expression.Expression; +import org.apache.phoenix.expression.LiteralExpression; import org.apache.phoenix.expression.function.CountAggregateFunction; import org.apache.phoenix.jdbc.PhoenixStatement; import org.apache.phoenix.parse.AliasedNode; @@ -109,15 +111,9 @@ public class JoinCompiler { } public static JoinTable compile(PhoenixStatement statement, SelectStatement select, ColumnResolver resolver) throws SQLException { - JoinCompiler compiler = new JoinCompiler(statement, select, resolver); - - List<TableNode> from = select.getFrom(); - if (from.size() > 1) { - throw new SQLFeatureNotSupportedException("Cross join not supported."); - } - + JoinCompiler compiler = new JoinCompiler(statement, select, resolver); JoinTableConstructor constructor = compiler.new JoinTableConstructor(); - Pair<Table, List<JoinSpec>> res = from.get(0).accept(constructor); + Pair<Table, List<JoinSpec>> res = select.getFrom().accept(constructor); JoinTable joinTable = res.getSecond() == null ? compiler.new JoinTable(res.getFirst()) : compiler.new JoinTable(res.getFirst(), res.getSecond()); if (select.getWhere() != null) { joinTable.addFilter(select.getWhere()); @@ -218,8 +214,8 @@ public class JoinCompiler { private final List<Table> tables; private final List<TableRef> tableRefs; private final boolean allLeftJoin; - private final boolean hasRightJoin; - private final List<JoinTable> prefilterAcceptedTables; + private final boolean isPrefilterAccepted; + private final List<JoinSpec> prefilterAcceptedTables; private JoinTable(Table table) { this.table = table; @@ -228,8 +224,8 @@ public class JoinCompiler { this.tables = Collections.<Table>singletonList(table); this.tableRefs = Collections.<TableRef>singletonList(table.getTableRef()); this.allLeftJoin = false; - this.hasRightJoin = false; - this.prefilterAcceptedTables = Collections.<JoinTable>emptyList(); + this.isPrefilterAccepted = true; + this.prefilterAcceptedTables = Collections.<JoinSpec>emptyList(); } private JoinTable(Table table, List<JoinSpec> joinSpecs) { @@ -241,10 +237,12 @@ public class JoinCompiler { this.tables.add(table); boolean allLeftJoin = true; int lastRightJoinIndex = -1; + boolean hasFullJoin = false; for (int i = 0; i < joinSpecs.size(); i++) { JoinSpec joinSpec = joinSpecs.get(i); this.tables.addAll(joinSpec.getJoinTable().getTables()); allLeftJoin = allLeftJoin && joinSpec.getType() == JoinType.Left; + hasFullJoin = hasFullJoin || joinSpec.getType() == JoinType.Full; if (joinSpec.getType() == JoinType.Right) { lastRightJoinIndex = i; } @@ -253,12 +251,12 @@ public class JoinCompiler { this.tableRefs.add(t.getTableRef()); } this.allLeftJoin = allLeftJoin; - this.hasRightJoin = lastRightJoinIndex > -1; - this.prefilterAcceptedTables = new ArrayList<JoinTable>(); + this.isPrefilterAccepted = !hasFullJoin && lastRightJoinIndex == -1; + this.prefilterAcceptedTables = new ArrayList<JoinSpec>(); for (int i = lastRightJoinIndex == -1 ? 0 : lastRightJoinIndex; i < joinSpecs.size(); i++) { JoinSpec joinSpec = joinSpecs.get(i); - if (joinSpec.getType() != JoinType.Left && joinSpec.getType() != JoinType.Anti) { - prefilterAcceptedTables.add(joinSpec.getJoinTable()); + if (joinSpec.getType() != JoinType.Left && joinSpec.getType() != JoinType.Anti && joinSpec.getType() != JoinType.Full) { + prefilterAcceptedTables.add(joinSpec); } } } @@ -303,7 +301,7 @@ public class JoinCompiler { WhereNodeVisitor visitor = new WhereNodeVisitor(origResolver, table, postFilters, Collections.<TableRef>singletonList(table.getTableRef()), - hasRightJoin, prefilterAcceptedTables); + isPrefilterAccepted, prefilterAcceptedTables); filter.accept(visitor); } @@ -415,11 +413,11 @@ public class JoinCompiler { if (!postFilters.isEmpty()) return true; - if (!hasRightJoin && table.hasFilters()) + if (isPrefilterAccepted && table.hasFilters()) return true; - for (JoinTable joinTable : prefilterAcceptedTables) { - if (joinTable.hasFilters()) + for (JoinSpec joinSpec : prefilterAcceptedTables) { + if (joinSpec.getJoinTable().hasFilters()) return true; } @@ -433,6 +431,7 @@ public class JoinCompiler { private final JoinTable joinTable; private final boolean singleValueOnly; private Set<TableRef> dependencies; + private OnNodeVisitor onNodeVisitor; private JoinSpec(JoinType type, ParseNode onNode, JoinTable joinTable, boolean singleValueOnly, ColumnResolver resolver) throws SQLException { @@ -441,13 +440,16 @@ public class JoinCompiler { this.joinTable = joinTable; this.singleValueOnly = singleValueOnly; this.dependencies = new HashSet<TableRef>(); - OnNodeVisitor visitor = new OnNodeVisitor(resolver, onConditions, dependencies, joinTable); - onNode.accept(visitor); - if (onConditions.isEmpty()) { - visitor.throwUnsupportedJoinConditionException(); + this.onNodeVisitor = new OnNodeVisitor(resolver, onConditions, dependencies, joinTable); + if (onNode != null) { + onNode.accept(this.onNodeVisitor); } } + public void addOnCondition(ParseNode node) throws SQLException { + node.accept(onNodeVisitor); + } + public JoinType getType() { return type; } @@ -469,6 +471,12 @@ public class JoinCompiler { } public Pair<List<Expression>, List<Expression>> compileJoinConditions(StatementContext context, ColumnResolver leftResolver, ColumnResolver rightResolver) throws SQLException { + if (onConditions.isEmpty()) { + return new Pair<List<Expression>, List<Expression>>( + Collections.<Expression> singletonList(LiteralExpression.newConstant(1)), + Collections.<Expression> singletonList(LiteralExpression.newConstant(1))); + } + ColumnResolver resolver = context.getResolver(); List<Pair<Expression, Expression>> compiled = new ArrayList<Pair<Expression, Expression>>(onConditions.size()); context.setResolver(leftResolver); @@ -679,8 +687,7 @@ public class JoinCompiler { if (isSubselect()) return SubselectRewriter.applyPostFilters(subselect, preFilters, tableNode.getAlias()); - List<TableNode> from = Collections.<TableNode>singletonList(tableNode); - return NODE_FACTORY.select(from, select.getHint(), false, selectNodes, getPreFiltersCombined(), null, null, null, null, 0, false, select.hasSequence()); + return NODE_FACTORY.select(tableNode, select.getHint(), false, selectNodes, getPreFiltersCombined(), null, null, null, null, 0, false, select.hasSequence()); } public boolean hasFilters() { @@ -804,17 +811,17 @@ public class JoinCompiler { private Table table; private List<ParseNode> postFilters; private List<TableRef> selfTableRefs; - private boolean hasRightJoin; - private List<JoinTable> prefilterAcceptedTables; + private boolean isPrefilterAccepted; + private List<JoinSpec> prefilterAcceptedTables; ColumnRefParseNodeVisitor columnRefVisitor; public WhereNodeVisitor(ColumnResolver resolver, Table table, - List<ParseNode> postFilters, List<TableRef> selfTableRefs, boolean hasRightJoin, - List<JoinTable> prefilterAcceptedTables) { + List<ParseNode> postFilters, List<TableRef> selfTableRefs, boolean isPrefilterAccepted, + List<JoinSpec> prefilterAcceptedTables) { this.table = table; this.postFilters = postFilters; this.selfTableRefs = selfTableRefs; - this.hasRightJoin = hasRightJoin; + this.isPrefilterAccepted = isPrefilterAccepted; this.prefilterAcceptedTables = prefilterAcceptedTables; this.columnRefVisitor = new ColumnRefParseNodeVisitor(resolver); } @@ -833,7 +840,7 @@ public class JoinCompiler { switch (type) { case NONE: case SELF_ONLY: - if (!hasRightJoin) { + if (isPrefilterAccepted) { table.addFilter(node); } else { postFilters.add(node); @@ -841,9 +848,9 @@ public class JoinCompiler { break; case FOREIGN_ONLY: JoinTable matched = null; - for (JoinTable joinTable : prefilterAcceptedTables) { - if (columnRefVisitor.getContentType(joinTable.getTableRefs()) == ColumnRefParseNodeVisitor.ColumnRefType.SELF_ONLY) { - matched = joinTable; + for (JoinSpec joinSpec : prefilterAcceptedTables) { + if (columnRefVisitor.getContentType(joinSpec.getJoinTable().getTableRefs()) == ColumnRefParseNodeVisitor.ColumnRefType.SELF_ONLY) { + matched = joinSpec.getJoinTable(); break; } } @@ -879,6 +886,29 @@ public class JoinCompiler { public Void visitLeave(AndParseNode node, List<Void> l) throws SQLException { return null; } + + @Override + public Void visitLeave(ComparisonParseNode node, List<Void> l) + throws SQLException { + if (!(node instanceof EqualParseNode)) + return leaveBooleanNode(node, l); + + ListIterator<JoinSpec> iter = prefilterAcceptedTables.listIterator(prefilterAcceptedTables.size()); + while (iter.hasPrevious()) { + JoinSpec joinSpec = iter.previous(); + if (joinSpec.getType() != JoinType.Inner || joinSpec.isSingleValueOnly()) { + continue; + } + + try { + joinSpec.addOnCondition(node); + return null; + } catch (SQLException e) { + } + } + + return leaveBooleanNode(node, l); + } } private static class OnNodeVisitor extends BooleanParseNodeVisitor<Void> { @@ -894,49 +924,47 @@ public class JoinCompiler { this.joinTable = joinTable; this.columnRefVisitor = new ColumnRefParseNodeVisitor(resolver); } - @Override protected boolean enterBooleanNode(ParseNode node) throws SQLException { return false; } - + @Override protected Void leaveBooleanNode(ParseNode node, List<Void> l) throws SQLException { columnRefVisitor.reset(); node.accept(columnRefVisitor); ColumnRefParseNodeVisitor.ColumnRefType type = columnRefVisitor.getContentType(joinTable.getTableRefs()); - if (type == ColumnRefParseNodeVisitor.ColumnRefType.NONE + if (type == ColumnRefParseNodeVisitor.ColumnRefType.NONE || type == ColumnRefParseNodeVisitor.ColumnRefType.SELF_ONLY) { joinTable.addFilter(node); } else { - throwUnsupportedJoinConditionException(); + throwAmbiguousJoinConditionException(); } return null; } - + @Override protected boolean enterNonBooleanNode(ParseNode node) throws SQLException { return false; } - + @Override protected Void leaveNonBooleanNode(ParseNode node, List<Void> l) throws SQLException { return null; } - + @Override public boolean visitEnter(AndParseNode node) throws SQLException { return true; } - @Override public Void visitLeave(AndParseNode node, List<Void> l) throws SQLException { return null; } - + @Override - public Void visitLeave(ComparisonParseNode node, List<Void> l) + public Void visitLeave(ComparisonParseNode node, List<Void> l) throws SQLException { if (!(node instanceof EqualParseNode)) return leaveBooleanNode(node, l); @@ -951,16 +979,16 @@ public class JoinCompiler { if ((lhsType == ColumnRefParseNodeVisitor.ColumnRefType.SELF_ONLY || lhsType == ColumnRefParseNodeVisitor.ColumnRefType.NONE) && (rhsType == ColumnRefParseNodeVisitor.ColumnRefType.SELF_ONLY || rhsType == ColumnRefParseNodeVisitor.ColumnRefType.NONE)) { joinTable.addFilter(node); - } else if (lhsType == ColumnRefParseNodeVisitor.ColumnRefType.FOREIGN_ONLY + } else if (lhsType == ColumnRefParseNodeVisitor.ColumnRefType.FOREIGN_ONLY && rhsType == ColumnRefParseNodeVisitor.ColumnRefType.SELF_ONLY) { onConditions.add(node); dependencies.addAll(lhsTableRefSet); - } else if (rhsType == ColumnRefParseNodeVisitor.ColumnRefType.FOREIGN_ONLY + } else if (rhsType == ColumnRefParseNodeVisitor.ColumnRefType.FOREIGN_ONLY && lhsType == ColumnRefParseNodeVisitor.ColumnRefType.SELF_ONLY) { onConditions.add(NODE_FACTORY.equal(node.getRHS(), node.getLHS())); dependencies.addAll(rhsTableRefSet); } else { - throwUnsupportedJoinConditionException(); + throwAmbiguousJoinConditionException(); } return null; } @@ -972,10 +1000,9 @@ public class JoinCompiler { * 2) a boolean condition referencing to the self table only. * Otherwise, it can be ambiguous. */ - public void throwUnsupportedJoinConditionException() - throws SQLFeatureNotSupportedException { - throw new SQLFeatureNotSupportedException("Does not support non-standard or non-equi join conditions."); - } + public void throwAmbiguousJoinConditionException() throws SQLException { + throw new SQLExceptionInfo.Builder(SQLExceptionCode.AMBIGUOUS_JOIN_CONDITION).build().buildException(); + } } private static class ColumnRefParseNodeVisitor extends StatelessTraverseAllParseNodeVisitor { @@ -1050,7 +1077,7 @@ public class JoinCompiler { return !select.isJoin() && !select.isAggregate() && !select.isDistinct() - && !(select.getFrom().get(0) instanceof DerivedTableNode) + && !(select.getFrom() instanceof DerivedTableNode) && select.getLimit() == null; } @@ -1168,64 +1195,61 @@ public class JoinCompiler { if (replacement.isEmpty()) return select; - List<TableNode> from = select.getFrom(); - List<TableNode> newFrom = Lists.newArrayListWithExpectedSize(from.size()); - for (TableNode node : from) { - newFrom.add(node.accept(new TableNodeVisitor<TableNode>() { - private TableRef resolveTable(String alias, TableName name) throws SQLException { - if (alias != null) - return resolver.resolveTable(null, alias); + TableNode from = select.getFrom(); + TableNode newFrom = from.accept(new TableNodeVisitor<TableNode>() { + private TableRef resolveTable(String alias, TableName name) throws SQLException { + if (alias != null) + return resolver.resolveTable(null, alias); - return resolver.resolveTable(name.getSchemaName(), name.getTableName()); - } + return resolver.resolveTable(name.getSchemaName(), name.getTableName()); + } - private TableName getReplacedTableName(TableRef tableRef) { - String schemaName = tableRef.getTable().getSchemaName().getString(); - return TableName.create(schemaName.length() == 0 ? null : schemaName, tableRef.getTable().getTableName().getString()); - } + private TableName getReplacedTableName(TableRef tableRef) { + String schemaName = tableRef.getTable().getSchemaName().getString(); + return TableName.create(schemaName.length() == 0 ? null : schemaName, tableRef.getTable().getTableName().getString()); + } - @Override - public TableNode visit(BindTableNode boundTableNode) throws SQLException { - TableRef tableRef = resolveTable(boundTableNode.getAlias(), boundTableNode.getName()); - TableRef replaceRef = replacement.get(tableRef); - if (replaceRef == null) - return boundTableNode; + @Override + public TableNode visit(BindTableNode boundTableNode) throws SQLException { + TableRef tableRef = resolveTable(boundTableNode.getAlias(), boundTableNode.getName()); + TableRef replaceRef = replacement.get(tableRef); + if (replaceRef == null) + return boundTableNode; - String alias = boundTableNode.getAlias(); - return NODE_FACTORY.bindTable(alias == null ? null : '"' + alias + '"', getReplacedTableName(replaceRef)); - } + String alias = boundTableNode.getAlias(); + return NODE_FACTORY.bindTable(alias == null ? null : '"' + alias + '"', getReplacedTableName(replaceRef)); + } - @Override - public TableNode visit(JoinTableNode joinNode) throws SQLException { - TableNode lhs = joinNode.getLHS(); - TableNode rhs = joinNode.getRHS(); - TableNode lhsReplace = lhs.accept(this); - TableNode rhsReplace = rhs.accept(this); - if (lhs == lhsReplace && rhs == rhsReplace) - return joinNode; + @Override + public TableNode visit(JoinTableNode joinNode) throws SQLException { + TableNode lhs = joinNode.getLHS(); + TableNode rhs = joinNode.getRHS(); + TableNode lhsReplace = lhs.accept(this); + TableNode rhsReplace = rhs.accept(this); + if (lhs == lhsReplace && rhs == rhsReplace) + return joinNode; - return NODE_FACTORY.join(joinNode.getType(), lhsReplace, rhsReplace, joinNode.getOnNode(), joinNode.isSingleValueOnly()); - } + return NODE_FACTORY.join(joinNode.getType(), lhsReplace, rhsReplace, joinNode.getOnNode(), joinNode.isSingleValueOnly()); + } - @Override - public TableNode visit(NamedTableNode namedTableNode) - throws SQLException { - TableRef tableRef = resolveTable(namedTableNode.getAlias(), namedTableNode.getName()); - TableRef replaceRef = replacement.get(tableRef); - if (replaceRef == null) - return namedTableNode; + @Override + public TableNode visit(NamedTableNode namedTableNode) + throws SQLException { + TableRef tableRef = resolveTable(namedTableNode.getAlias(), namedTableNode.getName()); + TableRef replaceRef = replacement.get(tableRef); + if (replaceRef == null) + return namedTableNode; - String alias = namedTableNode.getAlias(); - return NODE_FACTORY.namedTable(alias == null ? null : '"' + alias + '"', getReplacedTableName(replaceRef), namedTableNode.getDynamicColumns()); - } + String alias = namedTableNode.getAlias(); + return NODE_FACTORY.namedTable(alias == null ? null : '"' + alias + '"', getReplacedTableName(replaceRef), namedTableNode.getDynamicColumns()); + } - @Override - public TableNode visit(DerivedTableNode subselectNode) - throws SQLException { - return subselectNode; - } - })); - } + @Override + public TableNode visit(DerivedTableNode subselectNode) + throws SQLException { + return subselectNode; + } + }); return IndexStatementRewriter.translate(NODE_FACTORY.select(select, newFrom), resolver, replacement); } @@ -1249,9 +1273,8 @@ public class JoinCompiler { } } String tableAlias = tableRef.getTableAlias(); - List<? extends TableNode> from = Collections.singletonList(NODE_FACTORY.namedTable(tableAlias == null ? null : '"' + tableAlias + '"', tName, dynamicCols)); + TableNode from = NODE_FACTORY.namedTable(tableAlias == null ? null : '"' + tableAlias + '"', tName, dynamicCols); - // TODO: review, as it seems like we're potentially losing if the select statement is an aggregate (i.e. if it's an ungrouped aggregate for example) return NODE_FACTORY.select(from, hintNode, false, selectList, where, groupBy, null, orderBy, null, 0, groupBy != null, hasSequence); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/91e29c60/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 214330c..b9ca813 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 @@ -247,7 +247,7 @@ public class QueryCompiler { JoinSpec lastJoinSpec = joinSpecs.get(joinSpecs.size() - 1); JoinType type = lastJoinSpec.getType(); if (type == JoinType.Full) - throw new SQLFeatureNotSupportedException("Full joins not supported."); + throw new SQLFeatureNotSupportedException(type + " joins not supported."); if (type == JoinType.Right || type == JoinType.Inner) { if (!lastJoinSpec.getJoinTable().getJoinSpecs().isEmpty()) @@ -294,7 +294,7 @@ public class QueryCompiler { if (rhs.getLimit() != null && !rhs.isAggregate() && !rhs.isDistinct() && rhs.getOrderBy().isEmpty()) { limit = LimitCompiler.compile(context, rhs); } - HashJoinInfo joinInfo = new HashJoinInfo(projectedTable.getTable(), joinIds, new List[] {joinExpressions}, new JoinType[] {type == JoinType.Inner ? type : JoinType.Left}, new boolean[] {true}, new PTable[] {lhsProjTable.getTable()}, new int[] {fieldPosition}, postJoinFilterExpression, limit, forceProjection); + HashJoinInfo joinInfo = new HashJoinInfo(projectedTable.getTable(), joinIds, new List[] {joinExpressions}, new JoinType[] {type == JoinType.Right ? JoinType.Left : type}, new boolean[] {true}, new PTable[] {lhsProjTable.getTable()}, new int[] {fieldPosition}, postJoinFilterExpression, limit, forceProjection); Pair<Expression, Expression> keyRangeExpressions = new Pair<Expression, Expression>(null, null); getKeyExpressionCombinations(keyRangeExpressions, context, rhsTableRef, type, joinExpressions, hashExpressions); return HashJoinPlan.create(joinTable.getStatement(), rhsPlan, joinInfo, new HashSubPlan[] {new HashSubPlan(0, lhsPlan, hashExpressions, false, keyRangeExpressions.getFirst(), keyRangeExpressions.getSecond(), lhsJoin.hasFilters())}); http://git-wip-us.apache.org/repos/asf/phoenix/blob/91e29c60/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementNormalizer.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementNormalizer.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementNormalizer.java index 803f554..f6a6f7a 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementNormalizer.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementNormalizer.java @@ -37,7 +37,6 @@ import org.apache.phoenix.parse.ParseNode; import org.apache.phoenix.parse.ParseNodeRewriter; import org.apache.phoenix.parse.SelectStatement; import org.apache.phoenix.parse.TableName; -import org.apache.phoenix.parse.TableNode; import org.apache.phoenix.parse.TableNodeVisitor; import org.apache.phoenix.parse.TableWildcardParseNode; import org.apache.phoenix.parse.WildcardParseNode; @@ -88,13 +87,10 @@ public class StatementNormalizer extends ParseNodeRewriter { if (selectNodes == normSelectNodes) { normSelectNodes = Lists.newArrayList(selectNodes.subList(0, i)); } - for (TableNode tNode : statement.getFrom()) { - TableNameVisitor visitor = new TableNameVisitor(); - List<TableName> tableNames = tNode.accept(visitor); - for (TableName tableName : tableNames) { - TableWildcardParseNode node = NODE_FACTORY.tableWildcard(tableName); - normSelectNodes.add(NODE_FACTORY.aliasedNode(null, node)); - } + List<TableName> tableNames = statement.getFrom().accept(new TableNameVisitor()); + for (TableName tableName : tableNames) { + TableWildcardParseNode node = NODE_FACTORY.tableWildcard(tableName); + normSelectNodes.add(NODE_FACTORY.aliasedNode(null, node)); } } else if (selectNodes != normSelectNodes) { normSelectNodes.add(aliasedNode); http://git-wip-us.apache.org/repos/asf/phoenix/blob/91e29c60/phoenix-core/src/main/java/org/apache/phoenix/compile/SubqueryRewriter.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/SubqueryRewriter.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/SubqueryRewriter.java index 3e470ce..01aca00 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/SubqueryRewriter.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/SubqueryRewriter.java @@ -83,13 +83,13 @@ public class SubqueryRewriter extends ParseNodeRewriter { if (normWhere == where) return select; - return NODE_FACTORY.select(select, Collections.singletonList(rewriter.tableNode), normWhere); + return NODE_FACTORY.select(select, rewriter.tableNode, normWhere); } protected SubqueryRewriter(SelectStatement select, ColumnResolver resolver, PhoenixConnection connection) { this.resolver = resolver; this.connection = connection; - this.tableNode = select.getFrom().get(0); + this.tableNode = select.getFrom(); this.topNode = null; } @@ -339,7 +339,7 @@ public class SubqueryRewriter extends ParseNodeRewriter { groupbyNodes.set(i - 1, aliasedNode.getNode()); } SelectStatement derivedTableStmt = NODE_FACTORY.select(subquery, subquery.isDistinct(), derivedTableSelect, where, derivedTableGroupBy, true); - subquery = NODE_FACTORY.select(Collections.singletonList(NODE_FACTORY.derivedTable(derivedTableAlias, derivedTableStmt)), subquery.getHint(), false, selectNodes, null, groupbyNodes, null, Collections.<OrderByNode> emptyList(), null, subquery.getBindCount(), true, false); + subquery = NODE_FACTORY.select(NODE_FACTORY.derivedTable(derivedTableAlias, derivedTableStmt), subquery.getHint(), false, selectNodes, null, groupbyNodes, null, Collections.<OrderByNode> emptyList(), null, subquery.getBindCount(), true, false); } ParseNode onNode = conditionExtractor.getJoinCondition(); http://git-wip-us.apache.org/repos/asf/phoenix/blob/91e29c60/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 index 35ea900..d229478 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/SubselectRewriter.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/SubselectRewriter.java @@ -59,9 +59,9 @@ public class SubselectRewriter extends ParseNodeRewriter { } 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); + TableNode from = select.getFrom(); + while (from != null && from instanceof DerivedTableNode) { + DerivedTableNode derivedTable = (DerivedTableNode) from; SelectStatement subselect = derivedTable.getSelect(); ColumnResolver resolver = FromCompiler.getResolverForQuery(subselect, connection); SubselectRewriter rewriter = new SubselectRewriter(resolver, subselect.getSelect(), derivedTable.getAlias()); http://git-wip-us.apache.org/repos/asf/phoenix/blob/91e29c60/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 44f62da..0be40b8 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 @@ -381,7 +381,7 @@ public class UpsertCompiler { selectResolver = FromCompiler.getResolverForQuery(transformedSelect, connection); select = StatementNormalizer.normalize(transformedSelect, selectResolver); } - sameTable = select.getFrom().size() == 1 + sameTable = !select.isJoin() && tableRefToBe.equals(selectResolver.getTables().get(0)); tableRefToBe = adjustTimestampToMinOfSameTable(tableRefToBe, selectResolver.getTables()); /* We can run the upsert in a coprocessor if: http://git-wip-us.apache.org/repos/asf/phoenix/blob/91e29c60/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java b/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java index bf13eec..5c6018d 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java @@ -80,6 +80,7 @@ public enum SQLExceptionCode { VALUE_IN_LIST_NOT_CONSTANT(214, "22008", "Values in IN must evaluate to a constant."), SINGLE_ROW_SUBQUERY_RETURNS_MULTIPLE_ROWS(215, "22015", "Single-row sub-query returns more than one row."), SUBQUERY_RETURNS_DIFFERENT_NUMBER_OF_FIELDS(216, "22016", "Sub-query must return the same number of fields as the left-hand-side expression of 'IN'."), + AMBIGUOUS_JOIN_CONDITION(217, "22017", "Amibiguous or non-equi join condition specified. Consider using table list with where clause."), /** * Constraint Violation (errorcode 03, sqlstate 23) http://git-wip-us.apache.org/repos/asf/phoenix/blob/91e29c60/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 f6b7736..c369be8 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 @@ -292,7 +292,7 @@ public class PhoenixStatement implements Statement, SQLCloseable, org.apache.pho } private static class ExecutableSelectStatement extends SelectStatement implements CompilableStatement { - private ExecutableSelectStatement(List<? extends TableNode> from, HintNode hint, boolean isDistinct, List<AliasedNode> select, ParseNode where, + private ExecutableSelectStatement(TableNode from, HintNode hint, boolean isDistinct, List<AliasedNode> select, ParseNode where, List<ParseNode> groupBy, ParseNode having, List<OrderByNode> orderBy, LimitNode limit, int bindCount, boolean isAggregate, boolean hasSequence) { super(from, hint, isDistinct, select, where, groupBy, having, orderBy, limit, bindCount, isAggregate, hasSequence); } @@ -796,7 +796,7 @@ public class PhoenixStatement implements Statement, SQLCloseable, org.apache.pho protected static class ExecutableNodeFactory extends ParseNodeFactory { @Override - public ExecutableSelectStatement select(List<? extends TableNode> from, HintNode hint, boolean isDistinct, List<AliasedNode> select, + public ExecutableSelectStatement select(TableNode from, HintNode hint, boolean isDistinct, List<AliasedNode> select, ParseNode where, List<ParseNode> groupBy, ParseNode having, List<OrderByNode> orderBy, LimitNode limit, int bindCount, boolean isAggregate, boolean hasSequence) { return new ExecutableSelectStatement(from, hint, isDistinct, select, where, groupBy == null ? Collections.<ParseNode>emptyList() : groupBy, http://git-wip-us.apache.org/repos/asf/phoenix/blob/91e29c60/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java b/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java index f027ab3..8f6d026 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java @@ -214,9 +214,9 @@ public class QueryOptimizer { schemaName = schemaName.length() == 0 ? null : '"' + schemaName + '"'; String tableName = '"' + index.getTableName().getString() + '"'; - List<? extends TableNode> tables = Collections.singletonList(FACTORY.namedTable(alias, FACTORY.table(schemaName, tableName))); + TableNode table = FACTORY.namedTable(alias, FACTORY.table(schemaName, tableName)); try { - SelectStatement indexSelect = FACTORY.select(select, tables); + SelectStatement indexSelect = FACTORY.select(select, table); ColumnResolver resolver = FromCompiler.getResolverForQuery(indexSelect, statement.getConnection()); // Check index state of now potentially updated index table to make sure it's active if (PIndexState.ACTIVE.equals(resolver.getTables().get(0).getTable().getIndexState())) { http://git-wip-us.apache.org/repos/asf/phoenix/blob/91e29c60/phoenix-core/src/main/java/org/apache/phoenix/parse/JoinPartNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/JoinPartNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/JoinPartNode.java deleted file mode 100644 index cdbaaea..0000000 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/JoinPartNode.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.parse; - -import org.apache.phoenix.parse.JoinTableNode.JoinType; - -/** - * - * Node representing the partial join clause in the FROM clause of SQL - * - * - * @since 0.1 - */ -class JoinPartNode { - - private final JoinType type; - private final ParseNode onNode; - private final TableNode table; - - JoinPartNode(JoinType type, ParseNode onNode, TableNode table) { - this.type = type; - this.onNode = onNode; - this.table = table; - } - - JoinType getType() { - return type; - } - - ParseNode getOnNode() { - return onNode; - } - - TableNode getTable() { - return table; - } -} - http://git-wip-us.apache.org/repos/asf/phoenix/blob/91e29c60/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java index 6f8339e..cc0b455 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java @@ -415,17 +415,6 @@ public class ParseNodeFactory { return new IsNullParseNode(child, negate); } - public TableNode table(TableNode table, List<JoinPartNode> parts) { - for (JoinPartNode part : parts) { - table = new JoinTableNode(part.getType(), table, part.getTable(), part.getOnNode(), false); - } - return table; - } - - JoinPartNode joinPart(JoinType type, ParseNode onNode, TableNode table) { - return new JoinPartNode(type, onNode, table); - } - public JoinTableNode join(JoinType type, TableNode lhs, TableNode rhs, ParseNode on, boolean singleValueOnly) { return new JoinTableNode(type, lhs, rhs, on, singleValueOnly); } @@ -586,7 +575,7 @@ public class ParseNodeFactory { return new OuterJoinParseNode(node); } - public SelectStatement select(List<? extends TableNode> from, HintNode hint, boolean isDistinct, List<AliasedNode> select, ParseNode where, + public SelectStatement select(TableNode from, HintNode hint, boolean isDistinct, List<AliasedNode> select, ParseNode where, List<ParseNode> groupBy, ParseNode having, List<OrderByNode> orderBy, LimitNode limit, int bindCount, boolean isAggregate, boolean hasSequence) { return new SelectStatement(from, hint, isDistinct, select, where, groupBy == null ? Collections.<ParseNode>emptyList() : groupBy, having, @@ -606,14 +595,14 @@ public class ParseNodeFactory { statement.getOrderBy(), statement.getLimit(), statement.getBindCount(), statement.isAggregate(), statement.hasSequence()); } - public SelectStatement select(SelectStatement statement, List<? extends TableNode> tables) { - return select(tables, statement.getHint(), statement.isDistinct(), statement.getSelect(), statement.getWhere(), statement.getGroupBy(), + public SelectStatement select(SelectStatement statement, TableNode table) { + return select(table, statement.getHint(), statement.isDistinct(), statement.getSelect(), statement.getWhere(), statement.getGroupBy(), statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(), statement.isAggregate(), statement.hasSequence()); } - public SelectStatement select(SelectStatement statement, List<? extends TableNode> tables, ParseNode where) { - return select(tables, statement.getHint(), statement.isDistinct(), statement.getSelect(), where, statement.getGroupBy(), + public SelectStatement select(SelectStatement statement, TableNode table, ParseNode where) { + return select(table, statement.getHint(), statement.isDistinct(), statement.getSelect(), where, statement.getGroupBy(), statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(), statement.isAggregate(), statement.hasSequence()); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/91e29c60/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 338a45b..809480f 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 @@ -57,24 +57,8 @@ public class ParseNodeRewriter extends TraverseAllParseNodeVisitor<ParseNode> { */ public static SelectStatement rewrite(SelectStatement statement, ParseNodeRewriter rewriter) throws SQLException { Map<String,ParseNode> aliasMap = rewriter.getAliasMap(); - List<TableNode> from = statement.getFrom(); - List<TableNode> normFrom = from; - TableNodeRewriter tableNodeRewriter = new TableNodeRewriter(rewriter); - for (int i = 0; i < from.size(); i++) { - TableNode tableNode = from.get(i); - tableNodeRewriter.reset(); - TableNode normTableNode = tableNode.accept(tableNodeRewriter); - if (normTableNode == tableNode) { - if (from != normFrom) { - normFrom.add(tableNode); - } - continue; - } - if (from == normFrom) { - normFrom = Lists.newArrayList(from.subList(0, i)); - } - normFrom.add(normTableNode); - } + TableNode from = statement.getFrom(); + TableNode normFrom = from.accept(new TableNodeRewriter(rewriter)); ParseNode where = statement.getWhere(); ParseNode normWhere = where; if (where != null) { @@ -541,9 +525,6 @@ public class ParseNodeRewriter extends TraverseAllParseNodeVisitor<ParseNode> { this.parseNodeRewriter = parseNodeRewriter; } - public void reset() { - } - @Override public TableNode visit(BindTableNode boundTableNode) throws SQLException { return boundTableNode; @@ -557,7 +538,7 @@ public class ParseNodeRewriter extends TraverseAllParseNodeVisitor<ParseNode> { TableNode normLhsNode = lhsNode.accept(this); TableNode normRhsNode = rhsNode.accept(this); parseNodeRewriter.reset(); - ParseNode normOnNode = onNode.accept(parseNodeRewriter); + ParseNode normOnNode = onNode == null ? null : onNode.accept(parseNodeRewriter); if (lhsNode == normLhsNode && rhsNode == normRhsNode && onNode == normOnNode) return joinNode; http://git-wip-us.apache.org/repos/asf/phoenix/blob/91e29c60/phoenix-core/src/main/java/org/apache/phoenix/parse/SelectStatement.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/SelectStatement.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/SelectStatement.java index e7302dc..961846b 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/SelectStatement.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/SelectStatement.java @@ -36,14 +36,14 @@ import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunctionInfo; public class SelectStatement implements FilterableStatement { public static final SelectStatement SELECT_ONE = new SelectStatement( - Collections.<TableNode>emptyList(), null, false, + null, null, false, Collections.<AliasedNode>singletonList(new AliasedNode(null, LiteralParseNode.ONE)), null, Collections.<ParseNode>emptyList(), null, Collections.<OrderByNode>emptyList(), null, 0, false, false); public static final SelectStatement COUNT_ONE = new SelectStatement( - Collections.<TableNode>emptyList(), null, false, + null, null, false, Collections.<AliasedNode>singletonList( new AliasedNode(null, new AggregateFunctionParseNode( @@ -80,7 +80,7 @@ public class SelectStatement implements FilterableStatement { select.getOrderBy(), select.getLimit(), select.getBindCount(), select.isAggregate(), select.hasSequence()); } - private final List<TableNode> fromTable; + private final TableNode fromTable; private final HintNode hint; private final boolean isDistinct; private final List<AliasedNode> select; @@ -104,10 +104,10 @@ public class SelectStatement implements FilterableStatement { return count; } - protected SelectStatement(List<? extends TableNode> from, HintNode hint, boolean isDistinct, List<AliasedNode> select, + protected SelectStatement(TableNode from, HintNode hint, boolean isDistinct, List<AliasedNode> select, ParseNode where, List<ParseNode> groupBy, ParseNode having, List<OrderByNode> orderBy, LimitNode limit, int bindCount, boolean isAggregate, boolean hasSequence) { - this.fromTable = Collections.unmodifiableList(from); + this.fromTable = from; this.hint = hint == null ? HintNode.EMPTY_HINT_NODE : hint; this.isDistinct = isDistinct; this.select = Collections.unmodifiableList(select); @@ -136,7 +136,7 @@ public class SelectStatement implements FilterableStatement { return bindCount; } - public List<TableNode> getFrom() { + public TableNode getFrom() { return fromTable; } @@ -190,13 +190,13 @@ public class SelectStatement implements FilterableStatement { } public boolean isJoin() { - return fromTable.size() > 1 || (fromTable.size() > 0 && fromTable.get(0) instanceof JoinTableNode); + return fromTable != null && fromTable instanceof JoinTableNode; } public SelectStatement getInnerSelectStatement() { - if (fromTable.size() != 1 || !(fromTable.get(0) instanceof DerivedTableNode)) + if (fromTable == null || !(fromTable instanceof DerivedTableNode)) return null; - return ((DerivedTableNode) fromTable.get(0)).getSelect(); + return ((DerivedTableNode) fromTable).getSelect(); } }