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 2015/04/30 00:47:48 UTC

phoenix git commit: Add PhoenixJoinSingleValueAggregateMergeRule

Repository: phoenix
Updated Branches:
  refs/heads/calcite ff4c733e3 -> 5cf992ef6


Add PhoenixJoinSingleValueAggregateMergeRule


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

Branch: refs/heads/calcite
Commit: 5cf992ef6e4c62afff7c700a27d239e07bcae998
Parents: ff4c733
Author: maryannxue <we...@intel.com>
Authored: Wed Apr 29 18:47:35 2015 -0400
Committer: maryannxue <we...@intel.com>
Committed: Wed Apr 29 18:47:35 2015 -0400

----------------------------------------------------------------------
 .../org/apache/phoenix/calcite/CalciteTest.java | 21 ++++----
 .../apache/phoenix/calcite/PhoenixTable.java    |  1 -
 .../calcite/jdbc/PhoenixPrepareImpl.java        |  4 +-
 .../calcite/metadata/PhoenixRelMdCollation.java | 23 +-------
 .../calcite/metadata/PhoenixRelMdRowCount.java  | 23 ++++++++
 .../calcite/rel/PhoenixAbstractAggregate.java   | 20 +++++++
 .../calcite/rel/PhoenixAbstractJoin.java        | 16 +++++-
 .../phoenix/calcite/rel/PhoenixClientJoin.java  | 20 ++++---
 .../phoenix/calcite/rel/PhoenixServerJoin.java  | 22 +++++---
 .../calcite/rules/PhoenixClientJoinRule.java    | 16 +++++-
 ...hoenixJoinSingleValueAggregateMergeRule.java | 51 ++++++++++++++++++
 .../calcite/rules/PhoenixServerJoinRule.java    |  6 +--
 .../PhoenixSingleValueAggregateRemoveRule.java  | 55 --------------------
 13 files changed, 169 insertions(+), 109 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/5cf992ef/phoenix-core/src/it/java/org/apache/phoenix/calcite/CalciteTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/calcite/CalciteTest.java b/phoenix-core/src/it/java/org/apache/phoenix/calcite/CalciteTest.java
index 620a375..6b7065b 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/calcite/CalciteTest.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/calcite/CalciteTest.java
@@ -661,15 +661,16 @@ public class CalciteTest extends BaseClientManagedTimeIT {
                        "  EnumerableJoin(condition=[=($6, $7)], joinType=[left])\n" +
                        "    PhoenixToEnumerableConverter\n" +
                        "      PhoenixTableScan(table=[[phoenix, Join, OrderTable]])\n" +
-                       "    EnumerableAggregate(group=[{0}], CNT=[COUNT()])\n" +
-                       "      EnumerableCalc(expr#0..10=[{inputs}], expr#11=[0], expr#12=[CAST($t5):INTEGER], expr#13=[=($t12, $t0)], THE_YEAR=[$t0], $f0=[$t11], $condition=[$t13])\n" +
-                       "        EnumerableJoin(condition=[true], joinType=[inner])\n" +
-                       "          PhoenixToEnumerableConverter\n" +
-                       "            PhoenixServerAggregate(group=[{0}])\n" +
-                       "              PhoenixServerProject(THE_YEAR=[$6])\n" +
-                       "                PhoenixTableScan(table=[[phoenix, Join, OrderTable]])\n" +
-                       "          JdbcToEnumerableConverter\n" +
-                       "            JdbcTableScan(table=[[foodmart, time_by_day]])\n")
+                       "    EnumerableAggregate(group=[{0}], agg#0=[SINGLE_VALUE($1)])\n" +
+                       "      EnumerableAggregate(group=[{0}], CNT=[COUNT()])\n" +
+                       "        EnumerableCalc(expr#0..10=[{inputs}], expr#11=[0], expr#12=[CAST($t5):INTEGER], expr#13=[=($t12, $t0)], THE_YEAR=[$t0], $f0=[$t11], $condition=[$t13])\n" +
+                       "          EnumerableJoin(condition=[true], joinType=[inner])\n" +
+                       "            PhoenixToEnumerableConverter\n" +
+                       "              PhoenixServerAggregate(group=[{0}])\n" +
+                       "                PhoenixServerProject(THE_YEAR=[$6])\n" +
+                       "                  PhoenixTableScan(table=[[phoenix, Join, OrderTable]])\n" +
+                       "            JdbcToEnumerableConverter\n" +
+                       "              JdbcTableScan(table=[[foodmart, time_by_day]])\n")
             .resultIs(new Object[][] {
                     new Object[] {1997, 1000, 365L}, 
                     new Object[] {1997, 2000, 365L},
@@ -685,7 +686,7 @@ public class CalciteTest extends BaseClientManagedTimeIT {
             + "from " + JOIN_ITEM_TABLE_FULL_NAME + " i")
             .explainIs("PhoenixToEnumerableConverter\n" +
                        "  PhoenixServerProject(item_id=[$0], NAME=[$1], EXPR$2=[$8])\n" +
-                       "    PhoenixServerJoin(condition=[=($0, $7)], joinType=[left])\n" +
+                       "    PhoenixServerJoin(condition=[=($0, $7)], joinType=[left], isSingleValueRhs=[true])\n" +
                        "      PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n" +
                        "      PhoenixServerAggregate(group=[{0}], SQ=[MAX($1)])\n" +
                        "        PhoenixServerProject(item_id0=[$7], QUANTITY=[$4])\n" +

http://git-wip-us.apache.org/repos/asf/phoenix/blob/5cf992ef/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixTable.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixTable.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixTable.java
index a8e16d1..19d05da 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixTable.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixTable.java
@@ -1,7 +1,6 @@
 package org.apache.phoenix.calcite;
 
 import java.util.List;
-import java.util.Map;
 
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptTable;

http://git-wip-us.apache.org/repos/asf/phoenix/blob/5cf992ef/phoenix-core/src/main/java/org/apache/phoenix/calcite/jdbc/PhoenixPrepareImpl.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/jdbc/PhoenixPrepareImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/jdbc/PhoenixPrepareImpl.java
index beaea4b..e4c0821 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/jdbc/PhoenixPrepareImpl.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/jdbc/PhoenixPrepareImpl.java
@@ -10,11 +10,11 @@ import org.apache.phoenix.calcite.rules.PhoenixClientJoinRule;
 import org.apache.phoenix.calcite.rules.PhoenixCompactClientSortRule;
 import org.apache.phoenix.calcite.rules.PhoenixConverterRules;
 import org.apache.phoenix.calcite.rules.PhoenixFilterScanMergeRule;
+import org.apache.phoenix.calcite.rules.PhoenixJoinSingleValueAggregateMergeRule;
 import org.apache.phoenix.calcite.rules.PhoenixServerAggregateRule;
 import org.apache.phoenix.calcite.rules.PhoenixServerJoinRule;
 import org.apache.phoenix.calcite.rules.PhoenixServerProjectRule;
 import org.apache.phoenix.calcite.rules.PhoenixServerSortRule;
-import org.apache.phoenix.calcite.rules.PhoenixSingleValueAggregateRemoveRule;
 
 public class PhoenixPrepareImpl extends CalcitePrepareImpl {
 
@@ -47,7 +47,7 @@ public class PhoenixPrepareImpl extends CalcitePrepareImpl {
         planner.addRule(PhoenixServerSortRule.SORT_SERVERPROJECT);
         planner.addRule(PhoenixCompactClientSortRule.SORT_SERVERAGGREGATE);
         planner.addRule(PhoenixClientJoinRule.INSTANCE);
-        planner.addRule(PhoenixSingleValueAggregateRemoveRule.INSTANCE);
+        planner.addRule(PhoenixJoinSingleValueAggregateMergeRule.INSTANCE);
 
         return planner;
     }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/5cf992ef/phoenix-core/src/main/java/org/apache/phoenix/calcite/metadata/PhoenixRelMdCollation.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/metadata/PhoenixRelMdCollation.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/metadata/PhoenixRelMdCollation.java
index 09e6239..e3d46b7 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/metadata/PhoenixRelMdCollation.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/metadata/PhoenixRelMdCollation.java
@@ -17,7 +17,6 @@ import org.apache.phoenix.calcite.rel.PhoenixLimit;
 import org.apache.phoenix.calcite.rel.PhoenixServerJoin;
 
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
 
 public class PhoenixRelMdCollation {
     public static final RelMetadataProvider SOURCE =
@@ -40,27 +39,9 @@ public class PhoenixRelMdCollation {
     
     /** Helper method to determine a {@link PhoenixServerJoin}'s collation. */
     public static List<RelCollation> hashJoin(RelNode left, RelNode right, JoinRelType joinType) {
-        if (joinType != JoinRelType.FULL)
-            return ImmutableList.of();
-        
         // TODO enable the following code, right now would cause some unexpected behaviors.
-        if (joinType == JoinRelType.RIGHT) {
-            final ImmutableList<RelCollation> rightCollations =
-                    RelMetadataQuery.collations(right);
-            if (rightCollations.isEmpty())
-                return rightCollations;
-
-            List<RelCollation> newCollations = Lists.<RelCollation> newArrayList();
-            final int leftFieldCount = left.getRowType().getFieldCount();
-            for (RelCollation collation : rightCollations) {
-                if (!collation.getFieldCollations().isEmpty()) {
-                    newCollations.add(RelCollations.shift(collation, leftFieldCount));
-                }
-            }
-            return ImmutableList.copyOf(newCollations);
-        }
-
-        return RelMetadataQuery.collations(left);
+        // return RelMetadataQuery.collations(left);
+        return ImmutableList.of();
     }
 
     public static List<RelCollation> mergeJoin(RelNode left, RelNode right,

http://git-wip-us.apache.org/repos/asf/phoenix/blob/5cf992ef/phoenix-core/src/main/java/org/apache/phoenix/calcite/metadata/PhoenixRelMdRowCount.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/metadata/PhoenixRelMdRowCount.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/metadata/PhoenixRelMdRowCount.java
index 797867d..a9b5274 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/metadata/PhoenixRelMdRowCount.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/metadata/PhoenixRelMdRowCount.java
@@ -1,8 +1,12 @@
 package org.apache.phoenix.calcite.metadata;
 
+import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.metadata.ReflectiveRelMetadataProvider;
 import org.apache.calcite.rel.metadata.RelMetadataProvider;
+import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.util.BuiltInMethod;
+import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.phoenix.calcite.rel.PhoenixAbstractAggregate;
 import org.apache.phoenix.calcite.rel.PhoenixAbstractSort;
 import org.apache.phoenix.calcite.rel.PhoenixLimit;
 
@@ -10,6 +14,25 @@ public class PhoenixRelMdRowCount {
     public static final RelMetadataProvider SOURCE =
             ReflectiveRelMetadataProvider.reflectiveSource(
                 BuiltInMethod.ROW_COUNT.method, new PhoenixRelMdRowCount());
+
+    public Double getRowCount(Aggregate rel) {
+        if (PhoenixAbstractAggregate.isSingleValueCheckAggregate(rel)) {
+            return RelMetadataQuery.getRowCount(rel.getInput());
+        }
+        
+        ImmutableBitSet groupKey = rel.getGroupSet();
+        // rowcount is the cardinality of the group by columns
+        Double distinctRowCount =
+                RelMetadataQuery.getDistinctRowCount(
+                        rel.getInput(),
+                        groupKey,
+                        null);
+        if (distinctRowCount == null) {
+            return rel.getRows();
+        } else {
+            return distinctRowCount;
+        }
+    }
     
     public Double getRowCount(PhoenixAbstractSort rel) {
         return rel.getRows();

http://git-wip-us.apache.org/repos/asf/phoenix/blob/5cf992ef/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractAggregate.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractAggregate.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractAggregate.java
index adc9b63..7d36494 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractAggregate.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractAggregate.java
@@ -33,6 +33,26 @@ import com.google.common.collect.Lists;
  */
 abstract public class PhoenixAbstractAggregate extends Aggregate implements PhoenixRel {
     
+    public static boolean isSingleValueCheckAggregate(Aggregate aggregate) {
+        List<Integer> groupSet = aggregate.getGroupSet().asList();
+        int groupCount = groupSet.size();
+        if (groupCount + 1 != aggregate.getInput().getRowType().getFieldCount())
+            return false;
+        
+        for (int i = 0; i < groupCount; i++) {
+            if (groupSet.get(i) != i)
+                return false;
+        }
+        
+        List<AggregateCall> aggCalls = aggregate.getAggCallList();
+        if (aggCalls.size() != 1)
+            return false;
+        
+        AggregateCall call = aggCalls.get(0);
+        return call.getAggregation().getName().equals("SINGLE_VALUE")
+                && call.getArgList().get(0) == groupCount;
+    }
+    
     protected PhoenixAbstractAggregate(RelOptCluster cluster, RelTraitSet traits, RelNode child, boolean indicator, ImmutableBitSet groupSet, List<ImmutableBitSet> groupSets, List<AggregateCall> aggCalls) {
         super(cluster, traits, child, indicator, groupSet, groupSets, aggCalls);
         assert getConvention() == PhoenixRel.CONVENTION;

http://git-wip-us.apache.org/repos/asf/phoenix/blob/5cf992ef/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractJoin.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractJoin.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractJoin.java
index 5e42ab3..39426f4 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractJoin.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractJoin.java
@@ -5,6 +5,7 @@ import java.util.Set;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.RelWriter;
 import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.JoinInfo;
 import org.apache.calcite.rel.core.JoinRelType;
@@ -17,13 +18,24 @@ import org.apache.phoenix.parse.JoinTableNode.JoinType;
  */
 abstract public class PhoenixAbstractJoin extends Join implements PhoenixRel {
     public final JoinInfo joinInfo;
+    public final boolean isSingleValueRhs;
 
-    protected PhoenixAbstractJoin(RelOptCluster cluster, RelTraitSet traits, RelNode left, RelNode right, RexNode condition, JoinRelType joinType, Set<String> variablesStopped) {
+    protected PhoenixAbstractJoin(RelOptCluster cluster, RelTraitSet traits, RelNode left, RelNode right, RexNode condition, JoinRelType joinType, Set<String> variablesStopped, boolean isSingleValueRhs) {
         super( cluster, traits, left, right, condition, joinType, variablesStopped);
-        joinInfo = JoinInfo.of(left, right, condition);
+        this.joinInfo = JoinInfo.of(left, right, condition);
+        this.isSingleValueRhs = isSingleValueRhs;
         assert getConvention() == PhoenixRel.CONVENTION;
     }
     
+    abstract public PhoenixAbstractJoin copy(RelTraitSet traits, RexNode condition, RelNode left,
+            RelNode right, JoinRelType joinRelType, boolean semiJoinDone, boolean isSingleValueRhs);
+
+    @Override
+    public RelWriter explainTerms(RelWriter pw) {
+        return super.explainTerms(pw)
+            .itemIf("isSingleValueRhs", isSingleValueRhs, isSingleValueRhs);
+    }
+    
     protected static JoinType convertJoinType(JoinRelType type) {
         JoinType ret = null;
         switch (type) {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/5cf992ef/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientJoin.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientJoin.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientJoin.java
index b7e917d..decc723 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientJoin.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientJoin.java
@@ -28,7 +28,8 @@ import com.google.common.collect.Lists;
 public class PhoenixClientJoin extends PhoenixAbstractJoin {
     
     public static PhoenixClientJoin create(RelNode left, RelNode right, 
-            RexNode condition, JoinRelType joinType, Set<String> variablesStopped) {
+            RexNode condition, JoinRelType joinType, Set<String> variablesStopped,
+            boolean isSingleValueRhs) {
         RelOptCluster cluster = left.getCluster();
         final JoinInfo joinInfo = JoinInfo.of(left, right, condition);
         final RelNode sortedLeft = sortInput(left, joinInfo.leftKeys);
@@ -41,7 +42,7 @@ public class PhoenixClientJoin extends PhoenixAbstractJoin {
                         return PhoenixRelMdCollation.mergeJoin(sortedLeft, sortedRight, joinInfo.leftKeys, joinInfo.rightKeys);
                     }
                 });
-        return new PhoenixClientJoin(cluster, traits, sortedLeft, sortedRight, condition, joinType, variablesStopped);
+        return new PhoenixClientJoin(cluster, traits, sortedLeft, sortedRight, condition, joinType, variablesStopped, isSingleValueRhs);
     }
     
     private static RelNode sortInput(RelNode input, ImmutableIntList sortKeys) {
@@ -64,15 +65,22 @@ public class PhoenixClientJoin extends PhoenixAbstractJoin {
 
     private PhoenixClientJoin(RelOptCluster cluster, RelTraitSet traits,
             RelNode left, RelNode right, RexNode condition,
-            JoinRelType joinType, Set<String> variablesStopped) {
+            JoinRelType joinType, Set<String> variablesStopped, boolean isSingleValueRhs) {
         super(cluster, traits, left, right, condition, joinType,
-                variablesStopped);
+                variablesStopped, isSingleValueRhs);
+        assert joinType != JoinRelType.RIGHT;
     }
 
     @Override
     public PhoenixClientJoin copy(RelTraitSet traits, RexNode condition, RelNode left,
             RelNode right, JoinRelType joinRelType, boolean semiJoinDone) {
-        return create(left, right, condition, joinRelType, variablesStopped);
+        return copy(traits, condition, left, right, joinRelType, semiJoinDone, isSingleValueRhs);
+    }
+
+    @Override
+    public PhoenixClientJoin copy(RelTraitSet traits, RexNode condition, RelNode left,
+            RelNode right, JoinRelType joinRelType, boolean semiJoinDone, boolean isSingleValueRhs) {
+        return create(left, right, condition, joinRelType, variablesStopped, isSingleValueRhs);
     }
 
     @Override
@@ -80,7 +88,7 @@ public class PhoenixClientJoin extends PhoenixAbstractJoin {
         double rowCount = RelMetadataQuery.getRowCount(this);
         
         for (RelNode input : getInputs()) {
-            double inputRowCount = input.getRows();
+            double inputRowCount = RelMetadataQuery.getRowCount(input);
             if (Double.isInfinite(inputRowCount)) {
                 rowCount = inputRowCount;
             } else {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/5cf992ef/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerJoin.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerJoin.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerJoin.java
index 7a94c0e..57b9ad0 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerJoin.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerJoin.java
@@ -37,7 +37,7 @@ public class PhoenixServerJoin extends PhoenixAbstractJoin {
     
     public static PhoenixServerJoin create(final RelNode left, final RelNode right, 
             RexNode condition, final JoinRelType joinType, 
-            Set<String> variablesStopped) {
+            Set<String> variablesStopped, boolean isSingleValueRhs) {
         RelOptCluster cluster = left.getCluster();
         final RelTraitSet traits =
                 cluster.traitSet().replace(PhoenixRel.CONVENTION)
@@ -47,20 +47,28 @@ public class PhoenixServerJoin extends PhoenixAbstractJoin {
                         return PhoenixRelMdCollation.hashJoin(left, right, joinType);
                     }
                 });
-        return new PhoenixServerJoin(cluster, traits, left, right, condition, joinType, variablesStopped);
+        return new PhoenixServerJoin(cluster, traits, left, right, condition, joinType, variablesStopped, isSingleValueRhs);
     }
 
     private PhoenixServerJoin(RelOptCluster cluster, RelTraitSet traits,
             RelNode left, RelNode right, RexNode condition,
-            JoinRelType joinType, Set<String> variablesStopped) {
+            JoinRelType joinType, Set<String> variablesStopped, 
+            boolean isSingleValueRhs) {
         super(cluster, traits, left, right, condition, joinType,
-                variablesStopped);
+                variablesStopped, isSingleValueRhs);
+        assert joinType != JoinRelType.FULL && joinType != JoinRelType.RIGHT;
     }
 
     @Override
     public PhoenixServerJoin copy(RelTraitSet traits, RexNode condition, RelNode left,
             RelNode right, JoinRelType joinRelType, boolean semiJoinDone) {
-        return create(left, right, condition, joinRelType, variablesStopped);
+        return copy(traits, condition, left, right, joinRelType, semiJoinDone, isSingleValueRhs);
+    }
+
+    @Override
+    public PhoenixServerJoin copy(RelTraitSet traits, RexNode condition, RelNode left,
+            RelNode right, JoinRelType joinRelType, boolean semiJoinDone, boolean isSingleValueRhs) {
+        return create(left, right, condition, joinRelType, variablesStopped, isSingleValueRhs);
     }
 
     @Override
@@ -70,7 +78,7 @@ public class PhoenixServerJoin extends PhoenixAbstractJoin {
         double rowCount = RelMetadataQuery.getRowCount(this);
         
         for (RelNode input : getInputs()) {
-            double inputRowCount = input.getRows();
+            double inputRowCount = RelMetadataQuery.getRowCount(input);
             if (Double.isInfinite(inputRowCount)) {
                 rowCount = inputRowCount;
             } else if (input == getLeft()) {
@@ -135,7 +143,7 @@ public class PhoenixServerJoin extends PhoenixAbstractJoin {
                 new int[] {leftTable.getColumns().size() - leftTable.getPKColumns().size()}, 
                 postFilterExpr, null);
         
-        return HashJoinPlan.create(SelectStatement.SELECT_STAR, leftPlan, hashJoinInfo, new HashJoinPlan.HashSubPlan[] {new HashJoinPlan.HashSubPlan(0, rightPlan, rightExprs, false, null, null)});
+        return HashJoinPlan.create(SelectStatement.SELECT_STAR, leftPlan, hashJoinInfo, new HashJoinPlan.HashSubPlan[] {new HashJoinPlan.HashSubPlan(0, rightPlan, rightExprs, isSingleValueRhs, null, null)});
     }
 
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/5cf992ef/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixClientJoinRule.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixClientJoinRule.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixClientJoinRule.java
index 7b627ba..86f0f08 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixClientJoinRule.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixClientJoinRule.java
@@ -3,15 +3,27 @@ package org.apache.phoenix.calcite.rules;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.phoenix.calcite.rel.PhoenixClientJoin;
 import org.apache.phoenix.calcite.rel.PhoenixJoin;
 
+import com.google.common.base.Predicate;
+
 public class PhoenixClientJoinRule extends RelOptRule {
     
+    /** Predicate that returns true if a join type is not right. */
+    private static final Predicate<PhoenixJoin> NO_RIGHT_JOIN =
+        new Predicate<PhoenixJoin>() {
+            @Override
+            public boolean apply(PhoenixJoin phoenixJoin) {
+                return phoenixJoin.getJoinType() != JoinRelType.RIGHT;
+            }
+        };
+    
     public static PhoenixClientJoinRule INSTANCE = new PhoenixClientJoinRule();
 
     public PhoenixClientJoinRule() {
-        super(operand(PhoenixJoin.class, any()), "PhoenixClientJoinRule");
+        super(operand(PhoenixJoin.class, null, NO_RIGHT_JOIN, any()), "PhoenixClientJoinRule");
     }
 
     @Override
@@ -22,7 +34,7 @@ public class PhoenixClientJoinRule extends RelOptRule {
 
         call.transformTo(PhoenixClientJoin.create(
                 left, right, join.getCondition(), 
-                join.getJoinType(), join.getVariablesStopped()));
+                join.getJoinType(), join.getVariablesStopped(), false));
     }
 
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/5cf992ef/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixJoinSingleValueAggregateMergeRule.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixJoinSingleValueAggregateMergeRule.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixJoinSingleValueAggregateMergeRule.java
new file mode 100644
index 0000000..b5c752b
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixJoinSingleValueAggregateMergeRule.java
@@ -0,0 +1,51 @@
+package org.apache.phoenix.calcite.rules;
+
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.phoenix.calcite.rel.PhoenixAbstractAggregate;
+import org.apache.phoenix.calcite.rel.PhoenixAbstractJoin;
+import org.apache.phoenix.calcite.rel.PhoenixRel;
+
+import com.google.common.base.Predicate;
+
+public class PhoenixJoinSingleValueAggregateMergeRule extends RelOptRule {
+
+    /** Predicate that returns true if the Aggregate is solely SINGLE_VALUE check. */
+    private static final Predicate<PhoenixAbstractAggregate> IS_SINGLE_VALUE_CHECK_AGGREGATE =
+            new Predicate<PhoenixAbstractAggregate>() {
+        @Override
+        public boolean apply(PhoenixAbstractAggregate phoenixAggregate) {
+            return PhoenixAbstractAggregate.isSingleValueCheckAggregate(phoenixAggregate);
+        }
+    };
+    
+    public static PhoenixJoinSingleValueAggregateMergeRule INSTANCE = new PhoenixJoinSingleValueAggregateMergeRule();
+
+    private PhoenixJoinSingleValueAggregateMergeRule() {
+        super(
+            operand(
+                    PhoenixAbstractJoin.class,
+                    operand(
+                            PhoenixRel.class, any()),
+                    operand(
+                            PhoenixAbstractAggregate.class, null, IS_SINGLE_VALUE_CHECK_AGGREGATE, any())), 
+            "PhoenixJoinSingleValueAggregateMergeRule");
+    }
+
+    @Override
+    public void onMatch(RelOptRuleCall call) {
+        PhoenixAbstractJoin join = call.rel(0);
+        PhoenixRel left = call.rel(1);
+        PhoenixAbstractAggregate right = call.rel(2);
+        int groupCount = right.getGroupCount();
+        for (Integer key : join.joinInfo.rightKeys) {
+            if (key >= groupCount) {
+                return;
+            }
+        }
+        
+        call.transformTo(join.copy(join.getTraitSet(), join.getCondition(), 
+                left, right.getInput(), join.getJoinType(), false, true));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/5cf992ef/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixServerJoinRule.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixServerJoinRule.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixServerJoinRule.java
index 45e0f12..cf19389 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixServerJoinRule.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixServerJoinRule.java
@@ -15,7 +15,7 @@ import com.google.common.base.Predicate;
 public class PhoenixServerJoinRule extends RelOptRule {
     
     /** Predicate that returns true if a join type is not right or full. */
-    private static final Predicate<PhoenixJoin> NO_RIGHT_OR_FULL =
+    private static final Predicate<PhoenixJoin> NO_RIGHT_OR_FULL_JOIN =
         new Predicate<PhoenixJoin>() {
             @Override
             public boolean apply(PhoenixJoin phoenixJoin) {
@@ -35,7 +35,7 @@ public class PhoenixServerJoinRule extends RelOptRule {
 
     public PhoenixServerJoinRule(String description, RelOptRuleOperand left) {
         super(
-            operand(PhoenixJoin.class, null, NO_RIGHT_OR_FULL,
+            operand(PhoenixJoin.class, null, NO_RIGHT_OR_FULL_JOIN,
                     left, 
                     operand(PhoenixRel.class, any())),
             description);
@@ -48,7 +48,7 @@ public class PhoenixServerJoinRule extends RelOptRule {
         PhoenixRel right = call.rel(call.getRelList().size() - 1);
         call.transformTo(PhoenixServerJoin.create(
                 left, right, join.getCondition(), 
-                join.getJoinType(), join.getVariablesStopped()));
+                join.getJoinType(), join.getVariablesStopped(), false));
     }
 
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/5cf992ef/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixSingleValueAggregateRemoveRule.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixSingleValueAggregateRemoveRule.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixSingleValueAggregateRemoveRule.java
deleted file mode 100644
index 5ef2f2a..0000000
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixSingleValueAggregateRemoveRule.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package org.apache.phoenix.calcite.rules;
-
-import java.util.List;
-
-import org.apache.calcite.plan.RelOptRule;
-import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.rel.core.AggregateCall;
-import org.apache.phoenix.calcite.rel.PhoenixAbstractAggregate;
-import com.google.common.base.Predicate;
-
-public class PhoenixSingleValueAggregateRemoveRule extends RelOptRule {
-
-    /** Predicate that returns true if SINGLE_VALUE is the only aggregate call in the Aggregate. */
-    private static final Predicate<PhoenixAbstractAggregate> SINGLE_VALUE_FUNC_ONLY =
-            new Predicate<PhoenixAbstractAggregate>() {
-        @Override
-        public boolean apply(PhoenixAbstractAggregate phoenixAggregate) {
-            List<AggregateCall> aggCalls = phoenixAggregate.getAggCallList();
-            return aggCalls.size() == 1 
-                    && aggCalls.get(0).getAggregation().getName().equals("SINGLE_VALUE");
-        }
-    };
-    
-    public static PhoenixSingleValueAggregateRemoveRule INSTANCE = new PhoenixSingleValueAggregateRemoveRule();
-
-    private PhoenixSingleValueAggregateRemoveRule() {
-        super(
-            operand(
-                    PhoenixAbstractAggregate.class, null, SINGLE_VALUE_FUNC_ONLY,
-                    operand(
-                            // TODO check returns single value?
-                            PhoenixAbstractAggregate.class, any())), 
-            "PhoenixSingleValueAggregateRemoveRule");
-    }
-
-    @Override
-    public void onMatch(RelOptRuleCall call) {
-        PhoenixAbstractAggregate aggregate = call.rel(0);
-        PhoenixAbstractAggregate innerAggregate = call.rel(1);
-        int groupCount = aggregate.getGroupCount();
-        int innerGroupCount = innerAggregate.getGroupCount();
-        if (groupCount != innerGroupCount)
-            return;
-        
-        List<Integer> ordinals = aggregate.getGroupSet().asList();
-        for (int i = 0; i < ordinals.size(); i++) {
-            if (ordinals.get(i) != i) {
-                return;
-            }
-        }
-        
-        call.transformTo(innerAggregate);
-    }
-
-}