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 2018/03/14 00:13:22 UTC
[5/9] phoenix git commit: PHOENIX-4585 Prune local index regions used
for join queries
PHOENIX-4585 Prune local index regions used for join queries
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/adbce12f
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/adbce12f
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/adbce12f
Branch: refs/heads/4.x-HBase-1.1
Commit: adbce12f90ad3341aa7991bb0445fe1d11cda597
Parents: 6b40a36
Author: maryannxue <ma...@gmail.com>
Authored: Fri Feb 16 11:29:25 2018 -0800
Committer: maryannxue <ma...@gmail.com>
Committed: Tue Mar 13 16:54:27 2018 -0700
----------------------------------------------------------------------
.../apache/phoenix/compile/JoinCompiler.java | 37 ++--
.../apache/phoenix/compile/QueryCompiler.java | 56 +++---
.../phoenix/compile/QueryCompilerTest.java | 187 ++++++++++++++++++-
3 files changed, 237 insertions(+), 43 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/phoenix/blob/adbce12f/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 f5a7e39..4020cf9 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
@@ -1199,7 +1199,8 @@ public class JoinCompiler {
return AndExpression.create(expressions);
}
- public static SelectStatement optimize(PhoenixStatement statement, SelectStatement select, final ColumnResolver resolver) throws SQLException {
+ public static Pair<SelectStatement, Map<TableRef, QueryPlan>> optimize(
+ PhoenixStatement statement, SelectStatement select, final ColumnResolver resolver) throws SQLException {
TableRef groupByTableRef = null;
TableRef orderByTableRef = null;
if (select.getGroupBy() != null && !select.getGroupBy().isEmpty()) {
@@ -1226,7 +1227,7 @@ public class JoinCompiler {
QueryCompiler compiler = new QueryCompiler(statement, select, resolver, false, null);
List<Object> binds = statement.getParameters();
StatementContext ctx = new StatementContext(statement, resolver, new Scan(), new SequenceManager(statement));
- QueryPlan plan = compiler.compileJoinQuery(ctx, binds, join, false, false, null);
+ QueryPlan plan = compiler.compileJoinQuery(ctx, binds, join, false, false, null, Collections.<TableRef, QueryPlan>emptyMap());
TableRef table = plan.getTableRef();
if (groupByTableRef != null && !groupByTableRef.equals(table)) {
groupByTableRef = null;
@@ -1236,7 +1237,8 @@ public class JoinCompiler {
}
}
- final Map<TableRef, TableRef> replacement = new HashMap<TableRef, TableRef>();
+ Map<TableRef, TableRef> replacementMap = null;
+ Map<TableRef, QueryPlan> dataPlanMap = null;
for (Table table : join.getTables()) {
if (table.isSubselect())
@@ -1245,19 +1247,30 @@ public class JoinCompiler {
List<ParseNode> groupBy = tableRef.equals(groupByTableRef) ? select.getGroupBy() : null;
List<OrderByNode> orderBy = tableRef.equals(orderByTableRef) ? select.getOrderBy() : null;
SelectStatement stmt = getSubqueryForOptimizedPlan(select.getHint(), table.getDynamicColumns(), table.getTableSamplingRate(), tableRef, join.getColumnRefs(), table.getPreFiltersCombined(), groupBy, orderBy, table.isWildCardSelect(), select.hasSequence(), select.getUdfParseNodes());
- // TODO: As port of PHOENIX-4585, we need to make sure this plan has a pointer to the data plan
- // when an index is used instead of the data table, and that this method returns that
- // state for downstream processing.
// TODO: It seems inefficient to be recompiling the statement again and again inside of this optimize call
- QueryPlan plan = statement.getConnection().getQueryServices().getOptimizer().optimize(statement, stmt);
- if (!plan.getTableRef().equals(tableRef)) {
- replacement.put(tableRef, plan.getTableRef());
+ QueryPlan dataPlan =
+ new QueryCompiler(
+ statement, stmt,
+ FromCompiler.getResolverForQuery(stmt, statement.getConnection()),
+ false, null)
+ .compile();
+ QueryPlan plan = statement.getConnection().getQueryServices().getOptimizer().optimize(statement, dataPlan);
+ TableRef newTableRef = plan.getTableRef();
+ if (!newTableRef.equals(tableRef)) {
+ if (replacementMap == null) {
+ replacementMap = new HashMap<TableRef, TableRef>();
+ dataPlanMap = new HashMap<TableRef, QueryPlan>();
+ }
+ replacementMap.put(tableRef, newTableRef);
+ dataPlanMap.put(newTableRef, dataPlan);
}
}
- if (replacement.isEmpty())
- return select;
+ if (replacementMap == null)
+ return new Pair<SelectStatement, Map<TableRef, QueryPlan>>(
+ select, Collections.<TableRef, QueryPlan> emptyMap());
+ final Map<TableRef, TableRef> replacement = replacementMap;
TableNode from = select.getFrom();
TableNode newFrom = from.accept(new TableNodeVisitor<TableNode>() {
private TableRef resolveTable(String alias, TableName name) throws SQLException {
@@ -1319,7 +1332,7 @@ public class JoinCompiler {
// replace expressions with corresponding matching columns for functional indexes
indexSelect = ParseNodeRewriter.rewrite(indexSelect, new IndexExpressionParseNodeRewriter(indexTableRef.getTable(), indexTableRef.getTableAlias(), statement.getConnection(), indexSelect.getUdfParseNodes()));
}
- return indexSelect;
+ return new Pair<SelectStatement, Map<TableRef, QueryPlan>>(indexSelect, dataPlanMap);
}
private static SelectStatement getSubqueryForOptimizedPlan(HintNode hintNode, List<ColumnDef> dynamicCols, Double tableSamplingRate, TableRef tableRef, Map<ColumnRef, ColumnRefType> columnRefs, ParseNode where, List<ParseNode> groupBy,
http://git-wip-us.apache.org/repos/asf/phoenix/blob/adbce12f/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 243f03e..729e439 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
@@ -22,9 +22,9 @@ import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Set;
-import org.apache.hadoop.hbase.client.Query;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.util.Pair;
import org.apache.phoenix.compile.GroupByCompiler.GroupBy;
@@ -184,7 +184,7 @@ public class QueryCompiler {
select.hasWildcard() ? null : select.getSelect());
ColumnResolver resolver = FromCompiler.getResolver(tableRef);
StatementContext context = new StatementContext(statement, resolver, scan, sequenceManager);
- QueryPlan plan = compileSingleFlatQuery(context, select, statement.getParameters(), false, false, null, null, false);
+ QueryPlan plan = compileSingleFlatQuery(context, select, statement.getParameters(), false, false, null, null, false, null);
plan = new UnionPlan(context, select, tableRef, plan.getProjector(), plan.getLimit(),
plan.getOffset(), plan.getOrderBy(), GroupBy.EMPTY_GROUP_BY, plans,
context.getBindManager().getParameterMetaData());
@@ -195,15 +195,18 @@ public class QueryCompiler {
List<Object> binds = statement.getParameters();
StatementContext context = new StatementContext(statement, resolver, scan, sequenceManager);
if (select.isJoin()) {
- select = JoinCompiler.optimize(statement, select, resolver);
- if (this.select != select) {
- ColumnResolver resolver = FromCompiler.getResolverForQuery(select, statement.getConnection());
+ Pair<SelectStatement, Map<TableRef, QueryPlan>> optimized =
+ JoinCompiler.optimize(statement, select, resolver);
+ SelectStatement optimizedSelect = optimized.getFirst();
+ if (select != optimizedSelect) {
+ ColumnResolver resolver = FromCompiler.getResolverForQuery(optimizedSelect, statement.getConnection());
context = new StatementContext(statement, resolver, scan, sequenceManager);
}
- JoinTable joinTable = JoinCompiler.compile(statement, select, context.getResolver());
- return compileJoinQuery(context, binds, joinTable, false, false, null);
+ JoinTable joinTable = JoinCompiler.compile(statement, optimizedSelect, context.getResolver());
+ return compileJoinQuery(
+ context, binds, joinTable, false, false, null, optimized.getSecond());
} else {
- return compileSingleQuery(context, select, binds, false, true);
+ return compileSingleQuery(context, select, binds, false, true, dataPlan);
}
}
@@ -216,7 +219,7 @@ public class QueryCompiler {
* 2) Otherwise, return the join plan compiled with the default strategy.
* @see JoinCompiler.JoinTable#getApplicableJoinStrategies()
*/
- protected QueryPlan compileJoinQuery(StatementContext context, List<Object> binds, JoinTable joinTable, boolean asSubquery, boolean projectPKColumns, List<OrderByNode> orderBy) throws SQLException {
+ protected QueryPlan compileJoinQuery(StatementContext context, List<Object> binds, JoinTable joinTable, boolean asSubquery, boolean projectPKColumns, List<OrderByNode> orderBy, Map<TableRef, QueryPlan> dataPlans) throws SQLException {
if (joinTable.getJoinSpecs().isEmpty()) {
Table table = joinTable.getTable();
SelectStatement subquery = table.getAsSubquery(orderBy);
@@ -227,7 +230,8 @@ public class QueryCompiler {
TupleProjector.serializeProjectorIntoScan(context.getScan(), projector);
context.setResolver(FromCompiler.getResolverForProjectedTable(projectedTable, context.getConnection(), subquery.getUdfParseNodes()));
table.projectColumns(context.getScan());
- return compileSingleFlatQuery(context, subquery, binds, asSubquery, !asSubquery, null, projectPKColumns ? projector : null, true);
+ QueryPlan dataPlan = dataPlans.get(table.getTableRef());
+ return compileSingleFlatQuery(context, subquery, binds, asSubquery, !asSubquery, null, projectPKColumns ? projector : null, true, dataPlan);
}
QueryPlan plan = compileSubquery(subquery, false);
PTable projectedTable = table.createProjectedTable(plan.getProjector());
@@ -239,7 +243,7 @@ public class QueryCompiler {
assert strategies.size() > 0;
if (!costBased || strategies.size() == 1) {
return compileJoinQuery(
- strategies.get(0), context, binds, joinTable, asSubquery, projectPKColumns, orderBy);
+ strategies.get(0), context, binds, joinTable, asSubquery, projectPKColumns, orderBy, dataPlans);
}
QueryPlan bestPlan = null;
@@ -248,7 +252,7 @@ public class QueryCompiler {
StatementContext newContext = new StatementContext(
context.getStatement(), context.getResolver(), new Scan(), context.getSequenceManager());
QueryPlan plan = compileJoinQuery(
- strategy, newContext, binds, joinTable, asSubquery, projectPKColumns, orderBy);
+ strategy, newContext, binds, joinTable, asSubquery, projectPKColumns, orderBy, dataPlans);
Cost cost = plan.getCost();
if (bestPlan == null || cost.compareTo(bestCost) < 0) {
bestPlan = plan;
@@ -260,7 +264,7 @@ public class QueryCompiler {
return bestPlan;
}
- protected QueryPlan compileJoinQuery(JoinCompiler.Strategy strategy, StatementContext context, List<Object> binds, JoinTable joinTable, boolean asSubquery, boolean projectPKColumns, List<OrderByNode> orderBy) throws SQLException {
+ protected QueryPlan compileJoinQuery(JoinCompiler.Strategy strategy, StatementContext context, List<Object> binds, JoinTable joinTable, boolean asSubquery, boolean projectPKColumns, List<OrderByNode> orderBy, Map<TableRef, QueryPlan> dataPlans) throws SQLException {
byte[] emptyByteArray = new byte[0];
List<JoinSpec> joinSpecs = joinTable.getJoinSpecs();
switch (strategy) {
@@ -303,7 +307,7 @@ public class QueryCompiler {
JoinSpec joinSpec = joinSpecs.get(i);
Scan subScan = ScanUtil.newScan(originalScan);
subContexts[i] = new StatementContext(statement, context.getResolver(), subScan, new SequenceManager(statement));
- subPlans[i] = compileJoinQuery(subContexts[i], binds, joinSpec.getJoinTable(), true, true, null);
+ subPlans[i] = compileJoinQuery(subContexts[i], binds, joinSpec.getJoinTable(), true, true, null, dataPlans);
boolean hasPostReference = joinSpec.getJoinTable().hasPostReference();
if (hasPostReference) {
tables[i] = subContexts[i].getResolver().getTables().get(0).getTable();
@@ -330,7 +334,8 @@ public class QueryCompiler {
hashPlans[i] = new HashSubPlan(i, subPlans[i], optimized ? null : hashExpressions, joinSpec.isSingleValueOnly(), keyRangeLhsExpression, keyRangeRhsExpression);
}
TupleProjector.serializeProjectorIntoScan(context.getScan(), tupleProjector);
- QueryPlan plan = compileSingleFlatQuery(context, query, binds, asSubquery, !asSubquery && joinTable.isAllLeftJoin(), null, !table.isSubselect() && projectPKColumns ? tupleProjector : null, true);
+ QueryPlan dataPlan = dataPlans.get(tableRef);
+ QueryPlan plan = compileSingleFlatQuery(context, query, binds, asSubquery, !asSubquery && joinTable.isAllLeftJoin(), null, !table.isSubselect() && projectPKColumns ? tupleProjector : null, true, dataPlan);
Expression postJoinFilterExpression = joinTable.compilePostFilterExpression(context, table);
Integer limit = null;
Integer offset = null;
@@ -350,7 +355,7 @@ public class QueryCompiler {
JoinTable lhsJoin = joinTable.getSubJoinTableWithoutPostFilters();
Scan subScan = ScanUtil.newScan(originalScan);
StatementContext lhsCtx = new StatementContext(statement, context.getResolver(), subScan, new SequenceManager(statement));
- QueryPlan lhsPlan = compileJoinQuery(lhsCtx, binds, lhsJoin, true, true, null);
+ QueryPlan lhsPlan = compileJoinQuery(lhsCtx, binds, lhsJoin, true, true, null, dataPlans);
PTable rhsProjTable;
TableRef rhsTableRef;
SelectStatement rhs;
@@ -383,7 +388,8 @@ public class QueryCompiler {
PTable projectedTable = needsMerge ? JoinCompiler.joinProjectedTables(rhsProjTable, lhsTable, type == JoinType.Right ? JoinType.Left : type) : rhsProjTable;
TupleProjector.serializeProjectorIntoScan(context.getScan(), tupleProjector);
context.setResolver(FromCompiler.getResolverForProjectedTable(projectedTable, context.getConnection(), rhs.getUdfParseNodes()));
- QueryPlan rhsPlan = compileSingleFlatQuery(context, rhs, binds, asSubquery, !asSubquery && type == JoinType.Right, null, !rhsTable.isSubselect() && projectPKColumns ? tupleProjector : null, true);
+ QueryPlan dataPlan = dataPlans.get(rhsTableRef);
+ QueryPlan rhsPlan = compileSingleFlatQuery(context, rhs, binds, asSubquery, !asSubquery && type == JoinType.Right, null, !rhsTable.isSubselect() && projectPKColumns ? tupleProjector : null, true, dataPlan);
Expression postJoinFilterExpression = joinTable.compilePostFilterExpression(context, rhsTable);
Integer limit = null;
Integer offset = null;
@@ -420,13 +426,13 @@ public class QueryCompiler {
Scan lhsScan = ScanUtil.newScan(originalScan);
StatementContext lhsCtx = new StatementContext(statement, context.getResolver(), lhsScan, new SequenceManager(statement));
boolean preserveRowkey = !projectPKColumns && type != JoinType.Full;
- QueryPlan lhsPlan = compileJoinQuery(lhsCtx, binds, lhsJoin, true, !preserveRowkey, lhsOrderBy);
+ QueryPlan lhsPlan = compileJoinQuery(lhsCtx, binds, lhsJoin, true, !preserveRowkey, lhsOrderBy, dataPlans);
PTable lhsProjTable = lhsCtx.getResolver().getTables().get(0).getTable();
boolean isInRowKeyOrder = preserveRowkey && lhsPlan.getOrderBy().getOrderByExpressions().isEmpty();
Scan rhsScan = ScanUtil.newScan(originalScan);
StatementContext rhsCtx = new StatementContext(statement, context.getResolver(), rhsScan, new SequenceManager(statement));
- QueryPlan rhsPlan = compileJoinQuery(rhsCtx, binds, rhsJoin, true, true, rhsOrderBy);
+ QueryPlan rhsPlan = compileJoinQuery(rhsCtx, binds, rhsJoin, true, true, rhsOrderBy, dataPlans);
PTable rhsProjTable = rhsCtx.getResolver().getTables().get(0).getTable();
Pair<List<Expression>, List<Expression>> joinConditions = lastJoinSpec.compileJoinConditions(type == JoinType.Right ? rhsCtx : lhsCtx, type == JoinType.Right ? lhsCtx : rhsCtx, strategy);
@@ -453,7 +459,7 @@ public class QueryCompiler {
joinTable.getStatement().getUdfParseNodes())
: NODE_FACTORY.select(joinTable.getStatement(), from, where);
- return compileSingleFlatQuery(context, select, binds, asSubquery, false, innerPlan, null, isInRowKeyOrder);
+ return compileSingleFlatQuery(context, select, binds, asSubquery, false, innerPlan, null, isInRowKeyOrder, null);
}
default:
throw new IllegalArgumentException("Invalid join strategy '" + strategy + "'");
@@ -506,16 +512,16 @@ public class QueryCompiler {
}
int maxRows = this.statement.getMaxRows();
this.statement.setMaxRows(pushDownMaxRows ? maxRows : 0); // overwrite maxRows to avoid its impact on inner queries.
- QueryPlan plan = new QueryCompiler(this.statement, subquery, resolver, false, dataPlan).compile();
+ QueryPlan plan = new QueryCompiler(this.statement, subquery, resolver, false, null).compile();
plan = statement.getConnection().getQueryServices().getOptimizer().optimize(statement, plan);
this.statement.setMaxRows(maxRows); // restore maxRows.
return plan;
}
- protected QueryPlan compileSingleQuery(StatementContext context, SelectStatement select, List<Object> binds, boolean asSubquery, boolean allowPageFilter) throws SQLException{
+ protected QueryPlan compileSingleQuery(StatementContext context, SelectStatement select, List<Object> binds, boolean asSubquery, boolean allowPageFilter, QueryPlan dataPlan) throws SQLException{
SelectStatement innerSelect = select.getInnerSelectStatement();
if (innerSelect == null) {
- return compileSingleFlatQuery(context, select, binds, asSubquery, allowPageFilter, null, null, true);
+ return compileSingleFlatQuery(context, select, binds, asSubquery, allowPageFilter, null, null, true, dataPlan);
}
QueryPlan innerPlan = compileSubquery(innerSelect, false);
@@ -530,10 +536,10 @@ public class QueryCompiler {
context.setCurrentTable(tableRef);
boolean isInRowKeyOrder = innerPlan.getGroupBy() == GroupBy.EMPTY_GROUP_BY && innerPlan.getOrderBy() == OrderBy.EMPTY_ORDER_BY;
- return compileSingleFlatQuery(context, select, binds, asSubquery, allowPageFilter, innerPlan, tupleProjector, isInRowKeyOrder);
+ return compileSingleFlatQuery(context, select, binds, asSubquery, allowPageFilter, innerPlan, tupleProjector, isInRowKeyOrder, null);
}
- protected QueryPlan compileSingleFlatQuery(StatementContext context, SelectStatement select, List<Object> binds, boolean asSubquery, boolean allowPageFilter, QueryPlan innerPlan, TupleProjector innerPlanTupleProjector, boolean isInRowKeyOrder) throws SQLException{
+ protected QueryPlan compileSingleFlatQuery(StatementContext context, SelectStatement select, List<Object> binds, boolean asSubquery, boolean allowPageFilter, QueryPlan innerPlan, TupleProjector innerPlanTupleProjector, boolean isInRowKeyOrder, QueryPlan dataPlan) throws SQLException{
PTable projectedTable = null;
if (this.projectTuples) {
projectedTable = TupleProjectionCompiler.createProjectedTable(select, context);
http://git-wip-us.apache.org/repos/asf/phoenix/blob/adbce12f/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java
index 5112e3d..0d5a0ff 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java
@@ -43,6 +43,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Properties;
+import com.google.common.collect.Lists;
import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.filter.Filter;
@@ -51,12 +52,8 @@ import org.apache.hadoop.hbase.util.Bytes;
import org.apache.phoenix.compile.OrderByCompiler.OrderBy;
import org.apache.phoenix.coprocessor.BaseScannerRegionObserver;
import org.apache.phoenix.exception.SQLExceptionCode;
-import org.apache.phoenix.execute.AggregatePlan;
-import org.apache.phoenix.execute.ClientScanPlan;
-import org.apache.phoenix.execute.HashJoinPlan;
-import org.apache.phoenix.execute.ScanPlan;
-import org.apache.phoenix.execute.SortMergeJoinPlan;
-import org.apache.phoenix.execute.TupleProjectionPlan;
+import org.apache.phoenix.execute.*;
+import org.apache.phoenix.execute.visitor.QueryPlanVisitor;
import org.apache.phoenix.expression.Expression;
import org.apache.phoenix.expression.LiteralExpression;
import org.apache.phoenix.expression.aggregator.Aggregator;
@@ -88,6 +85,7 @@ import org.apache.phoenix.util.PropertiesUtil;
import org.apache.phoenix.util.QueryUtil;
import org.apache.phoenix.util.ScanUtil;
import org.apache.phoenix.util.SchemaUtil;
+import org.junit.Ignore;
import org.junit.Test;
import com.google.common.collect.Lists;
@@ -4554,4 +4552,181 @@ public class QueryCompilerTest extends BaseConnectionlessQueryTest {
}
}
+ @Test
+ public void testLocalIndexPruningInSortMergeJoin() throws SQLException {
+ verifyLocalIndexPruningWithMultipleTables("SELECT /*+ USE_SORT_MERGE_JOIN*/ *\n" +
+ "FROM T1 JOIN T2 ON T1.A = T2.A\n" +
+ "WHERE T1.A = 'B' and T1.C='C' and T2.A IN ('A','G') and T2.B = 'A' and T2.D = 'D'");
+ }
+
+ @Ignore("Blocked by PHOENIX-4614")
+ @Test
+ public void testLocalIndexPruningInLeftOrInnerHashJoin() throws SQLException {
+ verifyLocalIndexPruningWithMultipleTables("SELECT *\n" +
+ "FROM T1 JOIN T2 ON T1.A = T2.A\n" +
+ "WHERE T1.A = 'B' and T1.C='C' and T2.A IN ('A','G') and T2.B = 'A' and T2.D = 'D'");
+ }
+
+ @Ignore("Blocked by PHOENIX-4614")
+ @Test
+ public void testLocalIndexPruningInRightHashJoin() throws SQLException {
+ verifyLocalIndexPruningWithMultipleTables("SELECT *\n" +
+ "FROM (\n" +
+ " SELECT A, B, C, D FROM T2 WHERE T2.A IN ('A','G') and T2.B = 'A' and T2.D = 'D'\n" +
+ ") T2\n" +
+ "RIGHT JOIN T1 ON T2.A = T1.A\n" +
+ "WHERE T1.A = 'B' and T1.C='C'");
+ }
+
+ @Test
+ public void testLocalIndexPruningInUinon() throws SQLException {
+ verifyLocalIndexPruningWithMultipleTables("SELECT A, B, C FROM T1\n" +
+ "WHERE A = 'B' and C='C'\n" +
+ "UNION ALL\n" +
+ "SELECT A, B, C FROM T2\n" +
+ "WHERE A IN ('A','G') and B = 'A' and D = 'D'");
+ }
+
+ private void verifyLocalIndexPruningWithMultipleTables(String query) throws SQLException {
+ Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+ try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
+ conn.createStatement().execute("CREATE TABLE T1 (\n" +
+ " A CHAR(1) NOT NULL,\n" +
+ " B CHAR(1) NOT NULL,\n" +
+ " C CHAR(1) NOT NULL,\n" +
+ " CONSTRAINT PK PRIMARY KEY (\n" +
+ " A,\n" +
+ " B,\n" +
+ " C\n" +
+ " )\n" +
+ ") SPLIT ON ('A','C','E','G','I')");
+ conn.createStatement().execute("CREATE LOCAL INDEX IDX1 ON T1(A,C)");
+ conn.createStatement().execute("CREATE TABLE T2 (\n" +
+ " A CHAR(1) NOT NULL,\n" +
+ " B CHAR(1) NOT NULL,\n" +
+ " C CHAR(1) NOT NULL,\n" +
+ " D CHAR(1) NOT NULL,\n" +
+ " CONSTRAINT PK PRIMARY KEY (\n" +
+ " A,\n" +
+ " B,\n" +
+ " C,\n" +
+ " D\n" +
+ " )\n" +
+ ") SPLIT ON ('A','C','E','G','I')");
+ conn.createStatement().execute("CREATE LOCAL INDEX IDX2 ON T2(A,B,D)");
+ PhoenixStatement statement = conn.createStatement().unwrap(PhoenixStatement.class);
+ QueryPlan plan = statement.optimizeQuery(query);
+ List<QueryPlan> childPlans = plan.accept(new MultipleChildrenExtractor());
+ assertEquals(2, childPlans.size());
+ // Check left child
+ assertEquals("IDX1", childPlans.get(0).getContext().getCurrentTable().getTable().getName().getString());
+ childPlans.get(0).iterator();
+ List<List<Scan>> outerScansL = childPlans.get(0).getScans();
+ assertEquals(1, outerScansL.size());
+ List<Scan> innerScansL = outerScansL.get(0);
+ assertEquals(1, innerScansL.size());
+ Scan scanL = innerScansL.get(0);
+ assertEquals("A", Bytes.toString(scanL.getStartRow()).trim());
+ assertEquals("C", Bytes.toString(scanL.getStopRow()).trim());
+ // Check right child
+ assertEquals("IDX2", childPlans.get(1).getContext().getCurrentTable().getTable().getName().getString());
+ childPlans.get(1).iterator();
+ List<List<Scan>> outerScansR = childPlans.get(1).getScans();
+ assertEquals(2, outerScansR.size());
+ List<Scan> innerScansR1 = outerScansR.get(0);
+ assertEquals(1, innerScansR1.size());
+ Scan scanR1 = innerScansR1.get(0);
+ assertEquals("A", Bytes.toString(scanR1.getStartRow()).trim());
+ assertEquals("C", Bytes.toString(scanR1.getStopRow()).trim());
+ List<Scan> innerScansR2 = outerScansR.get(1);
+ assertEquals(1, innerScansR2.size());
+ Scan scanR2 = innerScansR2.get(0);
+ assertEquals("G", Bytes.toString(scanR2.getStartRow()).trim());
+ assertEquals("I", Bytes.toString(scanR2.getStopRow()).trim());
+ }
+ }
+
+ private static class MultipleChildrenExtractor implements QueryPlanVisitor<List<QueryPlan>> {
+
+ @Override
+ public List<QueryPlan> defaultReturn(QueryPlan plan) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<QueryPlan> visit(AggregatePlan plan) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<QueryPlan> visit(ScanPlan plan) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<QueryPlan> visit(ClientAggregatePlan plan) {
+ return plan.getDelegate().accept(this);
+ }
+
+ @Override
+ public List<QueryPlan> visit(ClientScanPlan plan) {
+ return plan.getDelegate().accept(this);
+ }
+
+ @Override
+ public List<QueryPlan> visit(LiteralResultIterationPlan plan) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<QueryPlan> visit(TupleProjectionPlan plan) {
+ return plan.getDelegate().accept(this);
+ }
+
+ @Override
+ public List<QueryPlan> visit(HashJoinPlan plan) {
+ List<QueryPlan> children = new ArrayList<QueryPlan>(plan.getSubPlans().length + 1);
+ children.add(plan.getDelegate());
+ for (HashJoinPlan.SubPlan subPlan : plan.getSubPlans()) {
+ children.add(subPlan.getInnerPlan());
+ }
+ return children;
+ }
+
+ @Override
+ public List<QueryPlan> visit(SortMergeJoinPlan plan) {
+ return Lists.newArrayList(plan.getLhsPlan(), plan.getRhsPlan());
+ }
+
+ @Override
+ public List<QueryPlan> visit(UnionPlan plan) {
+ return plan.getSubPlans();
+ }
+
+ @Override
+ public List<QueryPlan> visit(UnnestArrayPlan plan) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<QueryPlan> visit(CorrelatePlan plan) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<QueryPlan> visit(CursorFetchPlan plan) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<QueryPlan> visit(ListJarsQueryPlan plan) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<QueryPlan> visit(TraceQueryPlan plan) {
+ return Collections.emptyList();
+ }
+ }
+>>>>>>> 11308c8aa... PHOENIX-4585 Prune local index regions used for join queries
}