Repository: phoenix Updated Branches: refs/heads/4.0 39c64815c -> e67de4368
PHOENIX-945 Support correlated subqueries in comparison without ANY/SOME/ALL Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/e67de436 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/e67de436 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/e67de436 Branch: refs/heads/4.0 Commit: e67de4368c10ab0ad25825877ba1e7a61ea530c7 Parents: 39c6481 Author: maryannxue <[email protected]> Authored: Tue Oct 7 23:02:05 2014 -0400 Committer: maryannxue <[email protected]> Committed: Tue Oct 7 23:02:05 2014 -0400 ---------------------------------------------------------------------- .../org/apache/phoenix/end2end/SubqueryIT.java | 98 ++++++++++++++++++++ .../phoenix/compile/ExpressionCompiler.java | 7 +- .../phoenix/compile/StatementNormalizer.java | 15 +-- .../phoenix/compile/SubqueryRewriter.java | 70 ++++++++++++-- .../apache/phoenix/parse/ParseNodeFactory.java | 24 +++++ 5 files changed, 188 insertions(+), 26 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/e67de436/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryIT.java index 3aecd29..58d92f3 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryIT.java @@ -19,6 +19,7 @@ package org.apache.phoenix.end2end; import static org.apache.phoenix.util.TestUtil.JOIN_COITEM_TABLE_DISPLAY_NAME; import static org.apache.phoenix.util.TestUtil.JOIN_COITEM_TABLE_FULL_NAME; +import static org.apache.phoenix.util.TestUtil.JOIN_CUSTOMER_TABLE_DISPLAY_NAME; import static org.apache.phoenix.util.TestUtil.JOIN_CUSTOMER_TABLE_FULL_NAME; import static org.apache.phoenix.util.TestUtil.JOIN_ITEM_TABLE_DISPLAY_NAME; import static org.apache.phoenix.util.TestUtil.JOIN_ITEM_TABLE_FULL_NAME; @@ -31,12 +32,14 @@ import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.sql.Connection; import java.sql.Date; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.sql.SQLException; import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.Collection; @@ -154,6 +157,21 @@ public class SubqueryIT extends BaseHBaseManagedTimeIT { " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + " SERVER AGGREGATE INTO DISTINCT ROWS BY [item_id]\n" + " CLIENT MERGE SORT", + + "CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_CUSTOMER_TABLE_DISPLAY_NAME + "\n" + + " SKIP-SCAN-JOIN TABLE 0\n" + + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ITEM_TABLE_DISPLAY_NAME + "\n" + + " SERVER AGGREGATE INTO DISTINCT ROWS BY \\[O.customer_id\\]\n" + + " CLIENT MERGE SORT\n" + + " PARALLEL INNER-JOIN TABLE 0\n" + + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + + " PARALLEL LEFT-JOIN TABLE 1\\(DELAYED EVALUATION\\)\n" + + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + + " SERVER AGGREGATE INTO DISTINCT ROWS BY \\[item_id\\]\n" + + " CLIENT MERGE SORT\n" + + " DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF \\(O.item_id\\)\n" + + " AFTER-JOIN SERVER FILTER BY \\(I.NAME = 'T2' OR O.QUANTITY > \\$\\d+.\\$\\d+\\)\n" + + " DYNAMIC SERVER FILTER BY customer_id IN \\(\\$\\d+.\\$\\d+\\)" }}); testCases.add(new String[][] { { @@ -207,6 +225,20 @@ public class SubqueryIT extends BaseHBaseManagedTimeIT { " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + " SERVER AGGREGATE INTO DISTINCT ROWS BY [item_id]\n" + " CLIENT MERGE SORT", + + "CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SCHEMA + ".idx_customer\n" + + " PARALLEL SEMI-JOIN TABLE 0 \\(SKIP MERGE\\)\n" + + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SCHEMA + ".idx_item\n" + + " SERVER FILTER BY FIRST KEY ONLY\n" + + " SERVER AGGREGATE INTO DISTINCT ROWS BY \\[O.customer_id\\]\n" + + " CLIENT MERGE SORT\n" + + " PARALLEL INNER-JOIN TABLE 0\n" + + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + + " PARALLEL LEFT-JOIN TABLE 1\\(DELAYED EVALUATION\\)\n" + + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + + " SERVER AGGREGATE INTO DISTINCT ROWS BY \\[item_id\\]\n" + + " CLIENT MERGE SORT\n" + + " AFTER-JOIN SERVER FILTER BY \\(I.0:NAME = 'T2' OR O.QUANTITY > \\$\\d+.\\$\\d+\\)" }}); testCases.add(new String[][] { { @@ -266,6 +298,23 @@ public class SubqueryIT extends BaseHBaseManagedTimeIT { " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + " SERVER AGGREGATE INTO DISTINCT ROWS BY [item_id]\n" + " CLIENT MERGE SORT", + + "CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + MetaDataUtil.LOCAL_INDEX_TABLE_PREFIX + JOIN_CUSTOMER_TABLE_DISPLAY_NAME + " \\[-32768\\]\n" + + "CLIENT MERGE SORT\n" + + " PARALLEL SEMI-JOIN TABLE 0 \\(SKIP MERGE\\)\n" + + " CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + MetaDataUtil.LOCAL_INDEX_TABLE_PREFIX + JOIN_ITEM_TABLE_DISPLAY_NAME + " \\[-32768\\]\n" + + " SERVER FILTER BY FIRST KEY ONLY\n" + + " SERVER AGGREGATE INTO DISTINCT ROWS BY \\[O.customer_id\\]\n" + + " CLIENT MERGE SORT\n" + + " PARALLEL INNER-JOIN TABLE 0\n" + + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + + " PARALLEL LEFT-JOIN TABLE 1\\(DELAYED EVALUATION\\)\n" + + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + + " SERVER AGGREGATE INTO DISTINCT ROWS BY \\[item_id\\]\n" + + " CLIENT MERGE SORT\n" + + " DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF \\(O.item_id\\)\n" + + " AFTER-JOIN SERVER FILTER BY \\(I.0:NAME = 'T2' OR O.QUANTITY > \\$\\d+.\\$\\d+\\)\n" + + " DYNAMIC SERVER FILTER BY customer_id IN \\(\\$\\d+.\\$\\d+\\)" }}); return testCases; } @@ -650,6 +699,14 @@ public class SubqueryIT extends BaseHBaseManagedTimeIT { assertEquals(rs.getString(4), "T1"); assertFalse(rs.next()); + + query = "SELECT \"item_id\", name FROM " + JOIN_ITEM_TABLE_FULL_NAME + " WHERE \"item_id\" < (SELECT \"item_id\" FROM " + JOIN_ORDER_TABLE_FULL_NAME + ")"; + statement = conn.prepareStatement(query); + try { + rs = statement.executeQuery(); + fail("Should have got Exception."); + } catch (SQLException e) { + } } finally { conn.close(); } @@ -805,6 +862,47 @@ public class SubqueryIT extends BaseHBaseManagedTimeIT { conn.close(); } } + + @Test + public void testComparisonSubquery() throws Exception { + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + String query = "SELECT \"order_id\", name FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o JOIN " + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" WHERE quantity = (SELECT max(quantity) FROM " + JOIN_ORDER_TABLE_FULL_NAME + " q WHERE o.\"item_id\" = q.\"item_id\")"; + PreparedStatement statement = conn.prepareStatement(query); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000001"); + assertEquals(rs.getString(2), "T1"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000003"); + assertEquals(rs.getString(2), "T2"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000004"); + assertEquals(rs.getString(2), "T6"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000005"); + assertEquals(rs.getString(2), "T3"); + + assertFalse(rs.next()); + + query = "SELECT name from " + JOIN_CUSTOMER_TABLE_FULL_NAME + " WHERE \"customer_id\" IN (SELECT \"customer_id\" FROM " + JOIN_ITEM_TABLE_FULL_NAME + " i JOIN " + JOIN_ORDER_TABLE_FULL_NAME + " o ON o.\"item_id\" = i.\"item_id\" WHERE i.name = 'T2' OR quantity > (SELECT avg(quantity) FROM " + JOIN_ORDER_TABLE_FULL_NAME + " q WHERE o.\"item_id\" = q.\"item_id\"))"; + statement = conn.prepareStatement(query); + rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "C2"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "C4"); + + assertFalse(rs.next()); + + rs = conn.createStatement().executeQuery("EXPLAIN " + query); + String plan = QueryUtil.getExplainPlan(rs); + assertTrue("\"" + plan + "\" does not match \"" + plans[4] + "\"", Pattern.matches(plans[4], plan)); + } finally { + conn.close(); + } + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/e67de436/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java index a01c147..1f1313c 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java @@ -55,6 +55,7 @@ import org.apache.phoenix.expression.LongAddExpression; import org.apache.phoenix.expression.LongDivideExpression; import org.apache.phoenix.expression.LongMultiplyExpression; import org.apache.phoenix.expression.LongSubtractExpression; +import org.apache.phoenix.expression.ModulusExpression; import org.apache.phoenix.expression.NotExpression; import org.apache.phoenix.expression.OrExpression; import org.apache.phoenix.expression.RowKeyColumnExpression; @@ -65,7 +66,6 @@ import org.apache.phoenix.expression.TimestampSubtractExpression; import org.apache.phoenix.expression.function.ArrayAllComparisonExpression; import org.apache.phoenix.expression.function.ArrayAnyComparisonExpression; import org.apache.phoenix.expression.function.InlineArrayElemRefExpression; -import org.apache.phoenix.expression.ModulusExpression; import org.apache.phoenix.parse.AddParseNode; import org.apache.phoenix.parse.AndParseNode; import org.apache.phoenix.parse.ArithmeticParseNode; @@ -82,11 +82,10 @@ import org.apache.phoenix.parse.DivideParseNode; import org.apache.phoenix.parse.ExistsParseNode; import org.apache.phoenix.parse.FunctionParseNode; import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunctionInfo; -import org.apache.phoenix.parse.LikeParseNode.LikeType; import org.apache.phoenix.parse.InListParseNode; -import org.apache.phoenix.parse.InParseNode; import org.apache.phoenix.parse.IsNullParseNode; import org.apache.phoenix.parse.LikeParseNode; +import org.apache.phoenix.parse.LikeParseNode.LikeType; import org.apache.phoenix.parse.LiteralParseNode; import org.apache.phoenix.parse.ModulusParseNode; import org.apache.phoenix.parse.MultiplyParseNode; @@ -120,8 +119,6 @@ import org.apache.phoenix.util.ExpressionUtil; import org.apache.phoenix.util.IndexUtil; import org.apache.phoenix.util.SchemaUtil; -import com.google.common.collect.Lists; - public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expression> { private boolean isAggregate; http://git-wip-us.apache.org/repos/asf/phoenix/blob/e67de436/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementNormalizer.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementNormalizer.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementNormalizer.java index acab605..803f554 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementNormalizer.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementNormalizer.java @@ -30,18 +30,17 @@ import org.apache.phoenix.parse.ComparisonParseNode; import org.apache.phoenix.parse.DerivedTableNode; import org.apache.phoenix.parse.FamilyWildcardParseNode; import org.apache.phoenix.parse.JoinTableNode; +import org.apache.phoenix.parse.JoinTableNode.JoinType; import org.apache.phoenix.parse.LessThanOrEqualParseNode; import org.apache.phoenix.parse.NamedTableNode; import org.apache.phoenix.parse.ParseNode; import org.apache.phoenix.parse.ParseNodeRewriter; import org.apache.phoenix.parse.SelectStatement; -import org.apache.phoenix.parse.SubqueryParseNode; import org.apache.phoenix.parse.TableName; import org.apache.phoenix.parse.TableNode; import org.apache.phoenix.parse.TableNodeVisitor; import org.apache.phoenix.parse.TableWildcardParseNode; import org.apache.phoenix.parse.WildcardParseNode; -import org.apache.phoenix.parse.JoinTableNode.JoinType; import org.apache.phoenix.util.SchemaUtil; import com.google.common.collect.Lists; @@ -154,18 +153,6 @@ public class StatementNormalizer extends ParseNodeRewriter { nodes = normNodes; node = NODE_FACTORY.comparison(node.getInvertFilterOp(), nodes.get(0), nodes.get(1)); } - // Add limit 2 to direct comparison with sub-query without ANY/SOME/ALL modifiers. - ParseNode rhs = nodes.get(1); - if (rhs instanceof SubqueryParseNode) { - SelectStatement subquery = ((SubqueryParseNode) rhs).getSelectNode(); - subquery = NODE_FACTORY.select(subquery, NODE_FACTORY.limit(NODE_FACTORY.literal(2))); - rhs = NODE_FACTORY.subquery(subquery, true); - List<ParseNode> normNodes = Lists.newArrayListWithExpectedSize(2); - normNodes.add(nodes.get(0)); - normNodes.add(rhs); - nodes = normNodes; - node = NODE_FACTORY.comparison(node.getFilterOp(), nodes.get(0), nodes.get(1)); - } return super.visitLeave(node, nodes); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/e67de436/phoenix-core/src/main/java/org/apache/phoenix/compile/SubqueryRewriter.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/SubqueryRewriter.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/SubqueryRewriter.java index 42d060f..6428155 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/SubqueryRewriter.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/SubqueryRewriter.java @@ -79,7 +79,7 @@ public class SubqueryRewriter extends ParseNodeRewriter { if (normWhere == where) return select; - return NODE_FACTORY.select(Collections.singletonList(rewriter.tableNode), select.getHint(), select.isDistinct(), select.getSelect(), normWhere, select.getGroupBy(), select.getHaving(), select.getOrderBy(), select.getLimit(), select.getBindCount(), select.isAggregate(), select.hasSequence()); + return NODE_FACTORY.select(select, Collections.singletonList(rewriter.tableNode), normWhere); } protected SubqueryRewriter(SelectStatement select, ColumnResolver resolver, PhoenixConnection connection) { @@ -133,9 +133,7 @@ public class SubqueryRewriter extends ParseNodeRewriter { SelectStatement subquery = subqueryNode.getSelectNode(); String rhsTableAlias = ParseNodeFactory.createTempAlias(); List<AliasedNode> selectNodes = fixAliasedNodes(subquery.getSelect()); - subquery = NODE_FACTORY.select(subquery.getFrom(), subquery.getHint(), true, - selectNodes, subquery.getWhere(), subquery.getGroupBy(), subquery.getHaving(), subquery.getOrderBy(), - subquery.getLimit(), subquery.getBindCount(), subquery.isAggregate(), subquery.hasSequence()); + subquery = NODE_FACTORY.select(subquery, true, selectNodes); ParseNode onNode = getJoinConditionNode(l.get(0), selectNodes, rhsTableAlias); TableNode rhsTable = NODE_FACTORY.derivedTable(rhsTableAlias, subquery); JoinType joinType = topNode == node ? (node.isNegate() ? JoinType.Anti : JoinType.Semi) : JoinType.Left; @@ -168,9 +166,7 @@ public class SubqueryRewriter extends ParseNodeRewriter { selectNodes.add(NODE_FACTORY.aliasedNode(ParseNodeFactory.createTempAlias(), LiteralParseNode.ONE)); selectNodes.addAll(additionalSelectNodes); - subquery = NODE_FACTORY.select(subquery.getFrom(), subquery.getHint(), true, - selectNodes, where, subquery.getGroupBy(), subquery.getHaving(), subquery.getOrderBy(), - subquery.getLimit(), subquery.getBindCount(), subquery.isAggregate(), subquery.hasSequence()); + subquery = NODE_FACTORY.select(subquery, true, selectNodes, where); ParseNode onNode = conditionExtractor.getJoinCondition(); TableNode rhsTable = NODE_FACTORY.derivedTable(rhsTableAlias, subquery); JoinType joinType = topNode == node ? (node.isNegate() ? JoinType.Anti : JoinType.Semi) : JoinType.Left; @@ -183,6 +179,66 @@ public class SubqueryRewriter extends ParseNodeRewriter { return ret; } + + @Override + public ParseNode visitLeave(ComparisonParseNode node, List<ParseNode> l) throws SQLException { + ParseNode secondChild = l.get(1); + if (!(secondChild instanceof SubqueryParseNode)) { + return super.visitLeave(node, l); + } + + SubqueryParseNode subqueryNode = (SubqueryParseNode) secondChild; + SelectStatement subquery = subqueryNode.getSelectNode(); + String rhsTableAlias = ParseNodeFactory.createTempAlias(); + JoinConditionExtractor conditionExtractor = new JoinConditionExtractor(subquery, resolver, connection, rhsTableAlias); + ParseNode where = subquery.getWhere() == null ? null : subquery.getWhere().accept(conditionExtractor); + if (where == subquery.getWhere()) { // non-correlated comparison subquery, add LIMIT 2, expectSingleRow = true + subquery = NODE_FACTORY.select(subquery, NODE_FACTORY.limit(NODE_FACTORY.literal(2))); + subqueryNode = NODE_FACTORY.subquery(subquery, true); + l = Lists.newArrayList(l.get(0), subqueryNode); + node = NODE_FACTORY.comparison(node.getFilterOp(), l.get(0), l.get(1)); + return super.visitLeave(node, l); + } + + if (!subquery.isAggregate() || !subquery.getGroupBy().isEmpty()) { + //TODO add runtime singleton check or add a "singleton" aggregate funtion + throw new SQLFeatureNotSupportedException("Do not support non-aggregate or groupby subquery in comparison."); + } + + ParseNode rhsNode = null; + List<AliasedNode> aliasedNodes = subquery.getSelect(); + if (aliasedNodes.size() == 1) { + rhsNode = aliasedNodes.get(0).getNode(); + } else { + List<ParseNode> nodes = Lists.<ParseNode> newArrayListWithExpectedSize(aliasedNodes.size()); + for (AliasedNode aliasedNode : aliasedNodes) { + nodes.add(aliasedNode.getNode()); + } + rhsNode = NODE_FACTORY.rowValueConstructor(nodes); + } + + List<AliasedNode> additionalSelectNodes = conditionExtractor.getAdditionalSelectNodes(); + List<AliasedNode> selectNodes = Lists.newArrayListWithExpectedSize(additionalSelectNodes.size() + 1); + selectNodes.add(NODE_FACTORY.aliasedNode(ParseNodeFactory.createTempAlias(), rhsNode)); + selectNodes.addAll(additionalSelectNodes); + List<ParseNode> groupbyNodes = Lists.newArrayListWithExpectedSize(additionalSelectNodes.size()); + for (AliasedNode aliasedNode : additionalSelectNodes) { + groupbyNodes.add(aliasedNode.getNode()); + } + + subquery = NODE_FACTORY.select(subquery, selectNodes, where, groupbyNodes, true); + ParseNode onNode = conditionExtractor.getJoinCondition(); + TableNode rhsTable = NODE_FACTORY.derivedTable(rhsTableAlias, subquery); + JoinType joinType = topNode == node ? JoinType.Inner : JoinType.Left; + ParseNode ret = NODE_FACTORY.comparison(node.getFilterOp(), l.get(0), NODE_FACTORY.column(NODE_FACTORY.table(null, rhsTableAlias), selectNodes.get(0).getAlias(), null)); + tableNode = NODE_FACTORY.join(joinType, tableNode, rhsTable, onNode); + + if (topNode == node) { + topNode = null; + } + + return ret; + } private List<AliasedNode> fixAliasedNodes(List<AliasedNode> nodes) { List<AliasedNode> normNodes = Lists.<AliasedNode> newArrayListWithExpectedSize(nodes.size() + 1); http://git-wip-us.apache.org/repos/asf/phoenix/blob/e67de436/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java index 2b9f914..951098e 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java @@ -611,6 +611,30 @@ public class ParseNodeFactory { statement.hasSequence()); } + public SelectStatement select(SelectStatement statement, List<? extends TableNode> tables, ParseNode where) { + return select(tables, statement.getHint(), statement.isDistinct(), statement.getSelect(), where, statement.getGroupBy(), + statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(), statement.isAggregate(), + statement.hasSequence()); + } + + public SelectStatement select(SelectStatement statement, boolean isDistinct, List<AliasedNode> select) { + return select(statement.getFrom(), statement.getHint(), isDistinct, select, statement.getWhere(), statement.getGroupBy(), + statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(), statement.isAggregate(), + statement.hasSequence()); + } + + public SelectStatement select(SelectStatement statement, boolean isDistinct, List<AliasedNode> select, ParseNode where) { + return select(statement.getFrom(), statement.getHint(), isDistinct, select, where, statement.getGroupBy(), + statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(), statement.isAggregate(), + statement.hasSequence()); + } + + public SelectStatement select(SelectStatement statement, List<AliasedNode> select, ParseNode where, List<ParseNode> groupBy, boolean isAggregate) { + return select(statement.getFrom(), statement.getHint(), statement.isDistinct(), select, where, groupBy, + statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(), isAggregate, + statement.hasSequence()); + } + public SelectStatement select(SelectStatement statement, HintNode hint) { return hint == null || hint.isEmpty() ? statement : select(statement.getFrom(), hint, statement.isDistinct(), statement.getSelect(), statement.getWhere(), statement.getGroupBy(), statement.getHaving(), statement.getOrderBy(), statement.getLimit(),
