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/06/10 22:47:23 UTC

[1/4] phoenix git commit: Adjust cost of Project

Repository: phoenix
Updated Branches:
  refs/heads/calcite 53dab808a -> f2d95da77


Adjust cost of Project


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

Branch: refs/heads/calcite
Commit: cedc1c502b177824a476622294d8699f5637e327
Parents: 53dab80
Author: maryannxue <we...@intel.com>
Authored: Tue Jun 2 15:14:43 2015 -0400
Committer: maryannxue <we...@intel.com>
Committed: Tue Jun 2 15:14:43 2015 -0400

----------------------------------------------------------------------
 .../org/apache/phoenix/calcite/CalciteTest.java |  4 ++--
 .../apache/phoenix/calcite/PhoenixSchema.java   |  3 +++
 .../calcite/metadata/PhoenixRelMdRowCount.java  |  7 +-----
 .../calcite/rel/PhoenixAbstractProject.java     | 12 ++++++++++
 .../phoenix/calcite/rel/PhoenixClientJoin.java  | 24 ++++++++++++--------
 .../phoenix/calcite/rel/PhoenixServerJoin.java  | 21 +++++++++--------
 6 files changed, 44 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/cedc1c50/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 acb02f3..89006ed 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
@@ -623,8 +623,8 @@ public class CalciteTest extends BaseClientManagedTimeIT {
         
         start().sql("SELECT item.\"item_id\", item.name, supp.\"supplier_id\", supp.name FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp ON item.\"supplier_id\" = supp.\"supplier_id\" limit 3")
                 .explainIs("PhoenixToEnumerableConverter\n" +
-                           "  PhoenixClientProject(item_id=[$0], NAME=[$1], supplier_id=[$3], NAME0=[$4])\n" +
-                           "    PhoenixLimit(fetch=[3])\n" +
+                           "  PhoenixLimit(fetch=[3])\n" +
+                           "    PhoenixServerProject(item_id=[$0], NAME=[$1], supplier_id=[$3], NAME0=[$4])\n" +
                            "      PhoenixServerJoin(condition=[=($2, $3)], joinType=[inner])\n" +
                            "        PhoenixServerProject(item_id=[$0], NAME=[$1], supplier_id=[$5])\n" +
                            "          PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n" +

http://git-wip-us.apache.org/repos/asf/phoenix/blob/cedc1c50/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixSchema.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixSchema.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixSchema.java
index 589f61d..5fb407b 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixSchema.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/PhoenixSchema.java
@@ -82,11 +82,14 @@ public class PhoenixSchema implements Schema {
             properties.setProperty(entry.getKey(), String.valueOf(entry.getValue()));
         }
         try {
+            Class.forName("org.apache.phoenix.jdbc.PhoenixDriver");
             final Connection connection =
                 DriverManager.getConnection(url, properties);
             final PhoenixConnection phoenixConnection =
                 connection.unwrap(PhoenixConnection.class);
             return new PhoenixSchema(null, phoenixConnection);
+        } catch (ClassNotFoundException e) {
+            throw new RuntimeException(e);
         } catch (SQLException e) {
             throw new RuntimeException(e);
         }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/cedc1c50/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 a9b5274..23108b2 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
@@ -7,7 +7,6 @@ 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;
 
 public class PhoenixRelMdRowCount {
@@ -34,11 +33,7 @@ public class PhoenixRelMdRowCount {
         }
     }
     
-    public Double getRowCount(PhoenixAbstractSort rel) {
-        return rel.getRows();
-      }
-    
     public Double getRowCount(PhoenixLimit rel) {
         return rel.getRows();
-      }
+    }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/cedc1c50/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractProject.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractProject.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractProject.java
index 9950605..893dcd1 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractProject.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractProject.java
@@ -3,9 +3,12 @@ package org.apache.phoenix.calcite.rel;
 import java.util.List;
 
 import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptCost;
+import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Project;
+import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexNode;
 import org.apache.phoenix.calcite.CalciteUtils;
@@ -25,6 +28,15 @@ abstract public class PhoenixAbstractProject extends Project implements PhoenixR
         super(cluster, traits, input, projects, rowType);
         assert getConvention() == PhoenixRel.CONVENTION;
     }
+
+    @Override
+    public RelOptCost computeSelfCost(RelOptPlanner planner) {
+        // This is to minimize the weight of cost of Project so that it
+        // does not affect more important decisions like join algorithms.
+        double rowCount = RelMetadataQuery.getRowCount(getInput());
+        double rows = 2 * rowCount / (rowCount + 1);
+        return planner.getCostFactory().makeCost(rows, 0, 0);
+    }
     
     protected TupleProjector project(Implementor implementor) {        
         List<Expression> exprs = Lists.newArrayList();

http://git-wip-us.apache.org/repos/asf/phoenix/blob/cedc1c50/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 2acd11f..7bc0b5e 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
@@ -13,8 +13,8 @@ import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelFieldCollation;
-import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelFieldCollation.Direction;
+import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.JoinInfo;
 import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
@@ -26,11 +26,11 @@ import org.apache.phoenix.calcite.metadata.PhoenixRelMdCollation;
 import org.apache.phoenix.compile.ColumnResolver;
 import org.apache.phoenix.compile.FromCompiler;
 import org.apache.phoenix.compile.JoinCompiler;
+import org.apache.phoenix.compile.OrderByCompiler.OrderBy;
 import org.apache.phoenix.compile.QueryPlan;
 import org.apache.phoenix.compile.RowProjector;
 import org.apache.phoenix.compile.SequenceManager;
 import org.apache.phoenix.compile.StatementContext;
-import org.apache.phoenix.compile.OrderByCompiler.OrderBy;
 import org.apache.phoenix.execute.ClientScanPlan;
 import org.apache.phoenix.execute.SortMergeJoinPlan;
 import org.apache.phoenix.expression.Expression;
@@ -102,16 +102,20 @@ public class PhoenixClientJoin extends PhoenixAbstractJoin {
 
     @Override
     public RelOptCost computeSelfCost(RelOptPlanner planner) {
-        double rowCount = RelMetadataQuery.getRowCount(this);
-        
-        for (RelNode input : getInputs()) {
-            double inputRowCount = RelMetadataQuery.getRowCount(input);
-            if (Double.isInfinite(inputRowCount)) {
-                rowCount = inputRowCount;
+        double rowCount = RelMetadataQuery.getRowCount(this);        
+
+        double leftRowCount = RelMetadataQuery.getRowCount(getLeft());
+        if (Double.isInfinite(leftRowCount)) {
+            rowCount = leftRowCount;
+        } else {
+            rowCount += leftRowCount;
+            double rightRowCount = RelMetadataQuery.getRowCount(getRight());
+            if (Double.isInfinite(rightRowCount)) {
+                rowCount = rightRowCount;
             } else {
-                rowCount += inputRowCount;
+                rowCount += rightRowCount;
             }
-        }
+        }            
         RelOptCost cost = planner.getCostFactory().makeCost(rowCount, 0, 0);
 
         return cost.multiplyBy(PHOENIX_FACTOR);

http://git-wip-us.apache.org/repos/asf/phoenix/blob/cedc1c50/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 f73527a..32ec08b 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
@@ -74,17 +74,20 @@ public class PhoenixServerJoin extends PhoenixAbstractJoin {
         //TODO return infinite cost if RHS size exceeds memory limit.
         
         double rowCount = RelMetadataQuery.getRowCount(this);
-        
-        for (RelNode input : getInputs()) {
-            double inputRowCount = RelMetadataQuery.getRowCount(input);
-            if (Double.isInfinite(inputRowCount)) {
-                rowCount = inputRowCount;
-            } else if (input == getLeft()) {
-                rowCount += inputRowCount;
+
+        double leftRowCount = RelMetadataQuery.getRowCount(getLeft());
+        if (Double.isInfinite(leftRowCount)) {
+            rowCount = leftRowCount;
+        } else {
+            rowCount += leftRowCount;
+            double rightRowCount = RelMetadataQuery.getRowCount(getRight());
+            if (Double.isInfinite(rightRowCount)) {
+                rowCount = rightRowCount;
             } else {
-                rowCount += Util.nLogN(inputRowCount);
+                rowCount += Util.nLogN(rightRowCount);
             }
-        }
+        }            
+        
         RelOptCost cost = planner.getCostFactory().makeCost(rowCount, 0, 0);
 
         return cost.multiplyBy(SERVER_FACTOR).multiplyBy(PHOENIX_FACTOR);


[4/4] phoenix git commit: Add server/client conventions for PhoenixRel and use ConvertRules to apply Phoenix server/client operators

Posted by ma...@apache.org.
Add server/client conventions for PhoenixRel and use ConvertRules to apply Phoenix server/client operators


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

Branch: refs/heads/calcite
Commit: f2d95da77205384df21bfe277693602afddf276a
Parents: c1396ec
Author: maryannxue <we...@intel.com>
Authored: Wed Jun 10 16:46:57 2015 -0400
Committer: maryannxue <we...@intel.com>
Committed: Wed Jun 10 16:46:57 2015 -0400

----------------------------------------------------------------------
 .../org/apache/phoenix/calcite/rel/PhoenixClientAggregate.java     | 2 --
 .../java/org/apache/phoenix/calcite/rel/PhoenixClientProject.java  | 2 --
 .../java/org/apache/phoenix/calcite/rel/PhoenixClientSort.java     | 1 -
 .../org/apache/phoenix/calcite/rel/PhoenixCompactClientSort.java   | 1 -
 .../main/java/org/apache/phoenix/calcite/rel/PhoenixFilter.java    | 1 -
 .../src/main/java/org/apache/phoenix/calcite/rel/PhoenixLimit.java | 2 --
 .../org/apache/phoenix/calcite/rel/PhoenixPostJoinProject.java     | 2 --
 .../org/apache/phoenix/calcite/rel/PhoenixServerAggregate.java     | 2 --
 .../java/org/apache/phoenix/calcite/rel/PhoenixServerProject.java  | 2 --
 .../java/org/apache/phoenix/calcite/rel/PhoenixServerSort.java     | 1 -
 10 files changed, 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/f2d95da7/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientAggregate.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientAggregate.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientAggregate.java
index db3de2c..7e9ff90 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientAggregate.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientAggregate.java
@@ -55,8 +55,6 @@ public class PhoenixClientAggregate extends PhoenixAbstractAggregate {
 
     @Override
     public QueryPlan implement(Implementor implementor) {
-        assert getConvention() == getInput().getConvention();
-        
         QueryPlan plan = implementor.visitInput(0, (PhoenixRel) getInput());
         
         TableRef tableRef = implementor.getTableRef();

http://git-wip-us.apache.org/repos/asf/phoenix/blob/f2d95da7/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientProject.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientProject.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientProject.java
index ecdbc3b..4cbf4d0 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientProject.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientProject.java
@@ -53,8 +53,6 @@ public class PhoenixClientProject extends PhoenixAbstractProject {
 
     @Override
     public QueryPlan implement(Implementor implementor) {
-        assert getConvention() == getInput().getConvention();
-        
         QueryPlan plan = implementor.visitInput(0, (PhoenixRel) getInput());        
         TupleProjector tupleProjector = project(implementor);
         

http://git-wip-us.apache.org/repos/asf/phoenix/blob/f2d95da7/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientSort.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientSort.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientSort.java
index 052f078..ab9dfd2 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientSort.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientSort.java
@@ -50,7 +50,6 @@ public class PhoenixClientSort extends PhoenixAbstractSort {
 
     @Override
     public QueryPlan implement(Implementor implementor) {
-        assert getConvention() == getInput().getConvention();
         if (this.offset != null)
             throw new UnsupportedOperationException();
             

http://git-wip-us.apache.org/repos/asf/phoenix/blob/f2d95da7/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixCompactClientSort.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixCompactClientSort.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixCompactClientSort.java
index 39d7d08..81b5608 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixCompactClientSort.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixCompactClientSort.java
@@ -45,7 +45,6 @@ public class PhoenixCompactClientSort extends PhoenixAbstractSort {
 
     @Override
     public QueryPlan implement(Implementor implementor) {
-        assert getConvention() == getInput().getConvention();
         if (this.offset != null)
             throw new UnsupportedOperationException();
             

http://git-wip-us.apache.org/repos/asf/phoenix/blob/f2d95da7/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixFilter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixFilter.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixFilter.java
index d958fe7..7583750 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixFilter.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixFilter.java
@@ -53,7 +53,6 @@ public class PhoenixFilter extends Filter implements PhoenixRel {
     }
 
     public QueryPlan implement(Implementor implementor) {
-        assert getConvention() == getInput().getConvention();
         QueryPlan plan = implementor.visitInput(0, (PhoenixRel) getInput());
         Expression expr = CalciteUtils.toExpression(condition, implementor);
         return new ClientScanPlan(plan.getContext(), plan.getStatement(), plan.getTableRef(),

http://git-wip-us.apache.org/repos/asf/phoenix/blob/f2d95da7/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixLimit.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixLimit.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixLimit.java
index 52482c1..b66ecbd 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixLimit.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixLimit.java
@@ -86,8 +86,6 @@ public class PhoenixLimit extends SingleRel implements PhoenixRel {
 
     @Override
     public QueryPlan implement(Implementor implementor) {
-        assert getConvention() == getInput().getConvention();
-        
         QueryPlan plan = implementor.visitInput(0, (PhoenixRel) getInput());
         // TODO only wrap with ClientScanPlan 
         // if (plan.getLimit() != null);

http://git-wip-us.apache.org/repos/asf/phoenix/blob/f2d95da7/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixPostJoinProject.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixPostJoinProject.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixPostJoinProject.java
index daa2978..0559ba6 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixPostJoinProject.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixPostJoinProject.java
@@ -54,8 +54,6 @@ public class PhoenixPostJoinProject extends PhoenixAbstractProject {
 
     @Override
     public QueryPlan implement(Implementor implementor) {
-        assert getConvention() == getInput().getConvention();
-        
         implementor.pushContext(new ImplementorContext(implementor.getCurrentContext().isRetainPKColumns(), false));
         QueryPlan plan = implementor.visitInput(0, (PhoenixRel) getInput());
         implementor.popContext();

http://git-wip-us.apache.org/repos/asf/phoenix/blob/f2d95da7/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerAggregate.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerAggregate.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerAggregate.java
index 776ec0d..4231f03 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerAggregate.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerAggregate.java
@@ -50,8 +50,6 @@ public class PhoenixServerAggregate extends PhoenixAbstractAggregate {
 
     @Override
     public QueryPlan implement(Implementor implementor) {
-        assert getConvention() == getInput().getConvention();
-        
         QueryPlan plan = implementor.visitInput(0, (PhoenixRel) getInput());
         assert (plan instanceof ScanPlan 
                     || plan instanceof HashJoinPlan)

http://git-wip-us.apache.org/repos/asf/phoenix/blob/f2d95da7/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerProject.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerProject.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerProject.java
index a5d9039..802211a 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerProject.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerProject.java
@@ -54,8 +54,6 @@ public class PhoenixServerProject extends PhoenixAbstractProject {
 
     @Override
     public QueryPlan implement(Implementor implementor) {
-        assert getConvention() == getInput().getConvention();
-        
         implementor.pushContext(new ImplementorContext(implementor.getCurrentContext().isRetainPKColumns(), false));
         QueryPlan plan = implementor.visitInput(0, (PhoenixRel) getInput());
         implementor.popContext();

http://git-wip-us.apache.org/repos/asf/phoenix/blob/f2d95da7/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerSort.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerSort.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerSort.java
index a57dd8d..dea751f 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerSort.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerSort.java
@@ -45,7 +45,6 @@ public class PhoenixServerSort extends PhoenixAbstractSort {
 
     @Override
     public QueryPlan implement(Implementor implementor) {
-        assert getConvention() == getInput().getConvention();
         if (this.offset != null)
             throw new UnsupportedOperationException();
             


[2/4] phoenix git commit: Add server/client conventions for PhoenixRel and use ConvertRules to apply Phoenix server/client operators

Posted by ma...@apache.org.
http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixConverterRules.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixConverterRules.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixConverterRules.java
index 7748709..dee433c 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixConverterRules.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixConverterRules.java
@@ -1,19 +1,27 @@
 package org.apache.phoenix.calcite.rules;
 
 import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
 import java.util.logging.Logger;
 
 import org.apache.calcite.adapter.enumerable.EnumerableConvention;
 import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelTrait;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollations;
+import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.RelFieldCollation.Direction;
 import org.apache.calcite.rel.convert.ConverterRule;
 import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.core.Aggregate.Group;
 import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.rel.core.Filter;
 import org.apache.calcite.rel.core.Join;
+import org.apache.calcite.rel.core.JoinInfo;
+import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.core.Union;
@@ -28,17 +36,24 @@ import org.apache.calcite.util.trace.CalciteTrace;
 import org.apache.phoenix.calcite.CalciteUtils;
 import org.apache.phoenix.calcite.rel.PhoenixAbstractAggregate;
 import org.apache.phoenix.calcite.rel.PhoenixClientAggregate;
+import org.apache.phoenix.calcite.rel.PhoenixClientJoin;
 import org.apache.phoenix.calcite.rel.PhoenixClientProject;
 import org.apache.phoenix.calcite.rel.PhoenixClientSort;
 import org.apache.phoenix.calcite.rel.PhoenixFilter;
-import org.apache.phoenix.calcite.rel.PhoenixJoin;
 import org.apache.phoenix.calcite.rel.PhoenixLimit;
+import org.apache.phoenix.calcite.rel.PhoenixPostJoinProject;
 import org.apache.phoenix.calcite.rel.PhoenixRel;
+import org.apache.phoenix.calcite.rel.PhoenixServerAggregate;
+import org.apache.phoenix.calcite.rel.PhoenixServerJoin;
+import org.apache.phoenix.calcite.rel.PhoenixServerProject;
+import org.apache.phoenix.calcite.rel.PhoenixServerSort;
+import org.apache.phoenix.calcite.rel.PhoenixToClientConverter;
 import org.apache.phoenix.calcite.rel.PhoenixToEnumerableConverter;
 import org.apache.phoenix.calcite.rel.PhoenixUnion;
 
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
+import com.google.common.collect.Lists;
 
 /**
  * Rules and relational operators for
@@ -52,13 +67,22 @@ public class PhoenixConverterRules {
 
     public static final RelOptRule[] RULES = {
         PhoenixToEnumerableConverterRule.INSTANCE,
-        PhoenixSortRule.INSTANCE,
+        PhoenixServerToClientConverterRule.INSTANCE,
+        PhoenixProjectableToClientConverterRule.INSTANCE,
+        PhoenixClientSortRule.INSTANCE,
+        PhoenixServerSortRule.SERVER,
+        PhoenixServerSortRule.PROJECTABLE,
         PhoenixLimitRule.INSTANCE,
         PhoenixFilterRule.INSTANCE,
-        PhoenixProjectRule.INSTANCE,
-        PhoenixAggregateRule.INSTANCE,
+        PhoenixClientProjectRule.INSTANCE,
+        PhoenixServerProjectRule.INSTANCE,
+        PhoenixPostJoinProjectRule.INSTANCE,
+        PhoenixClientAggregateRule.INSTANCE,
+        PhoenixServerAggregateRule.SERVER,
+        PhoenixServerAggregateRule.PROJECTABLE,
         PhoenixUnionRule.INSTANCE,
-        PhoenixJoinRule.INSTANCE,
+        PhoenixClientJoinRule.INSTANCE,
+        PhoenixServerJoinRule.INSTANCE,
     };
 
     /** Base class for planner rules that convert a relational expression to
@@ -89,36 +113,82 @@ public class PhoenixConverterRules {
      * Rule to convert a {@link org.apache.calcite.rel.core.Sort} to a
      * {@link PhoenixClientSort}.
      */
-    private static class PhoenixSortRule extends PhoenixConverterRule {
-        private static Predicate<LogicalSort> IS_CONVERTIBLE = new Predicate<LogicalSort>() {
+    private static class PhoenixClientSortRule extends PhoenixConverterRule {
+        
+        private static Predicate<Sort> IS_CONVERTIBLE = new Predicate<Sort>() {
             @Override
-            public boolean apply(LogicalSort input) {
+            public boolean apply(Sort input) {
                 return isConvertible(input);
             }            
         };
-        private static Predicate<LogicalSort> SORT_ONLY = new Predicate<LogicalSort>() {
+        
+        private static Predicate<Sort> SORT_ONLY = new Predicate<Sort>() {
             @Override
-            public boolean apply(LogicalSort input) {
+            public boolean apply(Sort input) {
                 return !input.getCollation().getFieldCollations().isEmpty()
                         && input.offset == null
                         && input.fetch == null;
             }            
         };
         
-        public static final PhoenixSortRule INSTANCE = new PhoenixSortRule();
+        public static final PhoenixClientSortRule INSTANCE = new PhoenixClientSortRule();
 
-        private PhoenixSortRule() {
-            super(LogicalSort.class, 
+        private PhoenixClientSortRule() {
+            super(Sort.class, 
                     Predicates.and(Arrays.asList(SORT_ONLY, IS_CONVERTIBLE)), 
-                    Convention.NONE, PhoenixRel.CONVENTION, "PhoenixSortRule");
+                    Convention.NONE, PhoenixRel.CLIENT_CONVENTION, "PhoenixClientSortRule");
         }
 
         public RelNode convert(RelNode rel) {
-            final LogicalSort sort = (LogicalSort) rel;
+            final Sort sort = (Sort) rel;
             return PhoenixClientSort.create(
                 convert(
                         sort.getInput(), 
-                        sort.getInput().getTraitSet().replace(out)),
+                        sort.getInput().getTraitSet().replace(PhoenixRel.CLIENT_CONVENTION)),
+                sort.getCollation());
+        }
+    }
+
+    /**
+     * Rule to convert a {@link org.apache.calcite.rel.core.Sort} to a
+     * {@link PhoenixServerSort}.
+     */
+    private static class PhoenixServerSortRule extends PhoenixConverterRule {
+        
+        private static Predicate<Sort> IS_CONVERTIBLE = new Predicate<Sort>() {
+            @Override
+            public boolean apply(Sort input) {
+                return isConvertible(input);
+            }            
+        };
+        
+        private static Predicate<Sort> SORT_ONLY = new Predicate<Sort>() {
+            @Override
+            public boolean apply(Sort input) {
+                return !input.getCollation().getFieldCollations().isEmpty()
+                        && input.offset == null
+                        && input.fetch == null;
+            }            
+        };
+        
+        public static final PhoenixServerSortRule SERVER = new PhoenixServerSortRule(PhoenixRel.SERVER_CONVENTION);
+        public static final PhoenixServerSortRule PROJECTABLE = new PhoenixServerSortRule(PhoenixRel.PROJECTABLE_CONVENTION);
+
+        private final Convention inputConvention;
+
+        private PhoenixServerSortRule(Convention inputConvention) {
+            super(Sort.class, 
+                    Predicates.and(Arrays.asList(SORT_ONLY, IS_CONVERTIBLE)), 
+                    Convention.NONE, PhoenixRel.CLIENT_CONVENTION, "PhoenixServerSortRule:" + inputConvention.getName());
+            this.inputConvention = inputConvention;
+        }
+
+        public RelNode convert(RelNode rel) {
+            final Sort sort = (Sort) rel;
+            return PhoenixServerSort.create(
+                convert(
+                        sort.getInput(), 
+                        sort.getInput().getTraitSet().replace(inputConvention)),
                 sort.getCollation());
         }
     }
@@ -128,15 +198,15 @@ public class PhoenixConverterRules {
      * {@link PhoenixLimit}.
      */
     private static class PhoenixLimitRule extends PhoenixConverterRule {
-        private static Predicate<LogicalSort> IS_CONVERTIBLE = new Predicate<LogicalSort>() {
+        private static Predicate<Sort> IS_CONVERTIBLE = new Predicate<Sort>() {
             @Override
-            public boolean apply(LogicalSort input) {
+            public boolean apply(Sort input) {
                 return isConvertible(input);
             }            
         };
-        private static Predicate<LogicalSort> OFFSET_OR_FETCH = new Predicate<LogicalSort>() {
+        private static Predicate<Sort> OFFSET_OR_FETCH = new Predicate<Sort>() {
             @Override
-            public boolean apply(LogicalSort input) {
+            public boolean apply(Sort input) {
                 return input.offset != null 
                         || input.fetch != null;
             }            
@@ -145,21 +215,25 @@ public class PhoenixConverterRules {
         public static final PhoenixLimitRule INSTANCE = new PhoenixLimitRule();
 
         private PhoenixLimitRule() {
-            super(LogicalSort.class, 
+            super(Sort.class, 
                     Predicates.and(Arrays.asList(OFFSET_OR_FETCH, IS_CONVERTIBLE)), 
-                    Convention.NONE, PhoenixRel.CONVENTION, "PhoenixLimitRule");
+                    Convention.NONE, PhoenixRel.CLIENT_CONVENTION, "PhoenixLimitRule");
         }
 
         public RelNode convert(RelNode rel) {
-            final LogicalSort sort = (LogicalSort) rel;
-            RelNode input = convert(
-                    sort.getInput(), 
-                    sort.getInput().getTraitSet().replace(out));
+            final Sort sort = (Sort) rel;
+            RelNode input = sort.getInput();
             if (!sort.getCollation().getFieldCollations().isEmpty()) {
-                input = PhoenixClientSort.create(input, sort.getCollation());
+                input = sort.copy(
+                            sort.getTraitSet(), 
+                            sort.getInput(), 
+                            sort.getCollation(), 
+                            null, null);
             }
             return PhoenixLimit.create(
-                input,
+                convert(
+                        input, 
+                        input.getTraitSet().replace(out)),
                 sort.offset, 
                 sort.fetch);
         }
@@ -181,7 +255,7 @@ public class PhoenixConverterRules {
 
         private PhoenixFilterRule() {
             super(LogicalFilter.class, IS_CONVERTIBLE, Convention.NONE, 
-                    PhoenixRel.CONVENTION, "PhoenixFilterRule");
+                    PhoenixRel.CLIENT_CONVENTION, "PhoenixFilterRule");
         }
 
         public RelNode convert(RelNode rel) {
@@ -198,7 +272,8 @@ public class PhoenixConverterRules {
      * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalProject}
      * to a {@link PhoenixClientProject}.
      */
-    private static class PhoenixProjectRule extends PhoenixConverterRule {
+    private static class PhoenixClientProjectRule extends PhoenixConverterRule {
+        
         private static Predicate<LogicalProject> IS_CONVERTIBLE = new Predicate<LogicalProject>() {
             @Override
             public boolean apply(LogicalProject input) {
@@ -206,11 +281,11 @@ public class PhoenixConverterRules {
             }            
         };
         
-        private static final PhoenixProjectRule INSTANCE = new PhoenixProjectRule();
+        private static final PhoenixClientProjectRule INSTANCE = new PhoenixClientProjectRule();
 
-        private PhoenixProjectRule() {
+        private PhoenixClientProjectRule() {
             super(LogicalProject.class, IS_CONVERTIBLE, Convention.NONE, 
-                    PhoenixRel.CONVENTION, "PhoenixProjectRule");
+                    PhoenixRel.CLIENT_CONVENTION, "PhoenixClientProjectRule");
         }
 
         public RelNode convert(RelNode rel) {
@@ -218,7 +293,69 @@ public class PhoenixConverterRules {
             return PhoenixClientProject.create(
                 convert(
                         project.getInput(), 
-                        project.getInput().getTraitSet().replace(out)), 
+                        project.getInput().getTraitSet().replace(PhoenixRel.CLIENT_CONVENTION)), 
+                project.getProjects(),
+                project.getRowType());
+        }
+    }
+
+    /**
+     * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalProject}
+     * to a {@link PhoenixServerProject}.
+     */
+    private static class PhoenixServerProjectRule extends PhoenixConverterRule {
+        
+        private static Predicate<LogicalProject> IS_CONVERTIBLE = new Predicate<LogicalProject>() {
+            @Override
+            public boolean apply(LogicalProject input) {
+                return isConvertible(input);
+            }            
+        };
+        
+        private static final PhoenixServerProjectRule INSTANCE = new PhoenixServerProjectRule();
+
+        private PhoenixServerProjectRule() {
+            super(LogicalProject.class, IS_CONVERTIBLE, Convention.NONE, 
+                    PhoenixRel.SERVER_CONVENTION, "PhoenixServerProjectRule");
+        }
+
+        public RelNode convert(RelNode rel) {
+            final LogicalProject project = (LogicalProject) rel;
+            return PhoenixServerProject.create(
+                convert(
+                        project.getInput(), 
+                        project.getInput().getTraitSet().replace(PhoenixRel.SERVER_CONVENTION)), 
+                project.getProjects(),
+                project.getRowType());
+        }
+    }
+
+    /**
+     * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalProject}
+     * to a {@link PhoenixPostJoinProject}.
+     */
+    private static class PhoenixPostJoinProjectRule extends PhoenixConverterRule {
+        
+        private static Predicate<LogicalProject> IS_CONVERTIBLE = new Predicate<LogicalProject>() {
+            @Override
+            public boolean apply(LogicalProject input) {
+                return isConvertible(input);
+            }            
+        };
+        
+        private static final PhoenixPostJoinProjectRule INSTANCE = new PhoenixPostJoinProjectRule();
+
+        private PhoenixPostJoinProjectRule() {
+            super(LogicalProject.class, IS_CONVERTIBLE, Convention.NONE, 
+                    PhoenixRel.PROJECTABLE_CONVENTION, "PhoenixPostJoinProjectRule");
+        }
+
+        public RelNode convert(RelNode rel) {
+            final LogicalProject project = (LogicalProject) rel;
+            return PhoenixPostJoinProject.create(
+                convert(
+                        project.getInput(), 
+                        project.getInput().getTraitSet().replace(PhoenixRel.PROJECTABLE_CONVENTION)), 
                 project.getProjects(),
                 project.getRowType());
         }
@@ -228,7 +365,8 @@ public class PhoenixConverterRules {
      * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalAggregate}
      * to an {@link PhoenixClientAggregate}.
      */
-    private static class PhoenixAggregateRule extends PhoenixConverterRule {
+    private static class PhoenixClientAggregateRule extends PhoenixConverterRule {
+        
         private static Predicate<LogicalAggregate> IS_CONVERTIBLE = new Predicate<LogicalAggregate>() {
             @Override
             public boolean apply(LogicalAggregate input) {
@@ -236,11 +374,11 @@ public class PhoenixConverterRules {
             }            
         };
         
-        public static final RelOptRule INSTANCE = new PhoenixAggregateRule();
+        public static final RelOptRule INSTANCE = new PhoenixClientAggregateRule();
 
-        private PhoenixAggregateRule() {
+        private PhoenixClientAggregateRule() {
             super(LogicalAggregate.class, IS_CONVERTIBLE, Convention.NONE, 
-                    PhoenixRel.CONVENTION, "PhoenixAggregateRule");
+                    PhoenixRel.CLIENT_CONVENTION, "PhoenixClientAggregateRule");
         }
 
         public RelNode convert(RelNode rel) {
@@ -248,7 +386,44 @@ public class PhoenixConverterRules {
             return PhoenixClientAggregate.create(
                     convert(
                             agg.getInput(), 
-                            agg.getInput().getTraitSet().replace(out)),
+                            agg.getInput().getTraitSet().replace(PhoenixRel.CLIENT_CONVENTION)),
+                    agg.indicator,
+                    agg.getGroupSet(),
+                    agg.getGroupSets(),
+                    agg.getAggCallList());
+        }
+    }
+
+    /**
+     * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalAggregate}
+     * to an {@link PhoenixServerAggregate}.
+     */
+    private static class PhoenixServerAggregateRule extends PhoenixConverterRule {
+        
+        private static Predicate<LogicalAggregate> IS_CONVERTIBLE = new Predicate<LogicalAggregate>() {
+            @Override
+            public boolean apply(LogicalAggregate input) {
+                return isConvertible(input);
+            }            
+        };
+        
+        public static final RelOptRule SERVER = new PhoenixServerAggregateRule(PhoenixRel.SERVER_CONVENTION);
+        public static final RelOptRule PROJECTABLE = new PhoenixServerAggregateRule(PhoenixRel.PROJECTABLE_CONVENTION);
+        
+        private final Convention inputConvention;
+
+        private PhoenixServerAggregateRule(Convention inputConvention) {
+            super(LogicalAggregate.class, IS_CONVERTIBLE, Convention.NONE, 
+                    PhoenixRel.CLIENT_CONVENTION, "PhoenixServerAggregateRule:" + inputConvention.getName());
+            this.inputConvention = inputConvention;
+        }
+
+        public RelNode convert(RelNode rel) {
+            final LogicalAggregate agg = (LogicalAggregate) rel;
+            return PhoenixServerAggregate.create(
+                    convert(
+                            agg.getInput(), 
+                            agg.getInput().getTraitSet().replace(inputConvention)),
                     agg.indicator,
                     agg.getGroupSet(),
                     agg.getGroupSets(),
@@ -272,7 +447,7 @@ public class PhoenixConverterRules {
 
         private PhoenixUnionRule() {
             super(LogicalUnion.class, IS_CONVERTIBLE, Convention.NONE, 
-                    PhoenixRel.CONVENTION, "PhoenixUnionRule");
+                    PhoenixRel.CLIENT_CONVENTION, "PhoenixUnionRule");
         }
 
         public RelNode convert(RelNode rel) {
@@ -285,34 +460,107 @@ public class PhoenixConverterRules {
 
     /**
      * Rule to convert a {@link org.apache.calcite.rel.core.Join} to a
-     * {@link PhoenixJoin}.
+     * {@link PhoenixClientJoin}.
      */
-    private static class PhoenixJoinRule extends PhoenixConverterRule {
+    private static class PhoenixClientJoinRule extends PhoenixConverterRule {
+        
         private static Predicate<LogicalJoin> IS_CONVERTIBLE = new Predicate<LogicalJoin>() {
             @Override
             public boolean apply(LogicalJoin input) {
                 return isConvertible(input);
             }            
         };
-        public static final PhoenixJoinRule INSTANCE = new PhoenixJoinRule();
 
-        private PhoenixJoinRule() {
-            super(LogicalJoin.class, IS_CONVERTIBLE, Convention.NONE, 
-                    PhoenixRel.CONVENTION, "PhoenixJoinRule");
+        private static final Predicate<LogicalJoin> NO_RIGHT_JOIN = new Predicate<LogicalJoin>() {
+            @Override
+            public boolean apply(LogicalJoin input) {
+                return input.getJoinType() != JoinRelType.RIGHT;
+            }
+        };
+        
+        public static final PhoenixClientJoinRule INSTANCE = new PhoenixClientJoinRule();
+
+        private PhoenixClientJoinRule() {
+            super(LogicalJoin.class, Predicates.and(Arrays.asList(IS_CONVERTIBLE, NO_RIGHT_JOIN)), Convention.NONE, 
+                    PhoenixRel.CLIENT_CONVENTION, "PhoenixClientJoinRule");
         }
 
         public RelNode convert(RelNode rel) {
             final LogicalJoin join = (LogicalJoin) rel;
-            return PhoenixJoin.create(
+            RelNode left = join.getLeft();
+            RelNode right = join.getRight();
+            
+            JoinInfo joinInfo = JoinInfo.of(join.getLeft(), join.getRight(), join.getCondition());
+            if (!joinInfo.leftKeys.isEmpty()) {
+                List<RelFieldCollation> leftFieldCollations = Lists.newArrayList();
+                for (Iterator<Integer> iter = joinInfo.leftKeys.iterator(); iter.hasNext();) {
+                    leftFieldCollations.add(new RelFieldCollation(iter.next(), Direction.ASCENDING));
+                }
+                RelCollation leftCollation = RelCollations.of(leftFieldCollations);
+                left = LogicalSort.create(left, leftCollation, null, null);
+                
+                List<RelFieldCollation> rightFieldCollations = Lists.newArrayList();
+                for (Iterator<Integer> iter = joinInfo.rightKeys.iterator(); iter.hasNext();) {
+                    rightFieldCollations.add(new RelFieldCollation(iter.next(), Direction.ASCENDING));
+                }
+                RelCollation rightCollation = RelCollations.of(rightFieldCollations);
+                right = LogicalSort.create(right, rightCollation, null, null);
+            }
+            
+            return PhoenixClientJoin.create(
+                    convert(
+                            left, 
+                            left.getTraitSet().replace(PhoenixRel.CLIENT_CONVENTION)),
+                    convert(
+                            right, 
+                            right.getTraitSet().replace(PhoenixRel.CLIENT_CONVENTION)),
+                    join.getCondition(),
+                    join.getJoinType(),
+                    join.getVariablesStopped(),
+                    false);
+        }
+    }
+
+    /**
+     * Rule to convert a {@link org.apache.calcite.rel.core.Join} to a
+     * {@link PhoenixServerJoin}.
+     */
+    private static class PhoenixServerJoinRule extends PhoenixConverterRule {
+        
+        private static Predicate<LogicalJoin> IS_CONVERTIBLE = new Predicate<LogicalJoin>() {
+            @Override
+            public boolean apply(LogicalJoin input) {
+                return isConvertible(input);
+            }            
+        };
+
+        private static final Predicate<LogicalJoin> NO_RIGHT_OR_FULL_JOIN = new Predicate<LogicalJoin>() {
+            @Override
+            public boolean apply(LogicalJoin input) {
+                return input.getJoinType() != JoinRelType.RIGHT && input.getJoinType() != JoinRelType.FULL;
+            }
+        };
+        
+        public static final PhoenixServerJoinRule INSTANCE = new PhoenixServerJoinRule();
+
+        private PhoenixServerJoinRule() {
+            super(LogicalJoin.class, Predicates.and(Arrays.asList(IS_CONVERTIBLE, NO_RIGHT_OR_FULL_JOIN)), Convention.NONE, 
+                    PhoenixRel.PROJECTABLE_CONVENTION, "PhoenixServerJoinRule");
+        }
+
+        public RelNode convert(RelNode rel) {
+            final LogicalJoin join = (LogicalJoin) rel;
+            return PhoenixServerJoin.create(
                     convert(
                             join.getLeft(), 
-                            join.getLeft().getTraitSet().replace(out)),
+                            join.getLeft().getTraitSet().replace(PhoenixRel.SERVER_CONVENTION)),
                     convert(
                             join.getRight(), 
-                            join.getRight().getTraitSet().replace(out)),
+                            join.getRight().getTraitSet().replace(PhoenixRel.CLIENT_CONVENTION)),
                     join.getCondition(),
                     join.getJoinType(),
-                    join.getVariablesStopped());
+                    join.getVariablesStopped(),
+                    false);
         }
     }
 
@@ -461,6 +709,44 @@ public class PhoenixConverterRules {
 
     /**
      * Rule to convert a relational expression from
+     * {@link org.apache.phoenix.calcite.rel.PhoenixRel#SERVER_CONVENTION} to
+     * {@link org.apache.phoenix.calcite.rel.PhoenixRel#CLIENT_CONVENTION}.
+     */
+    public static class PhoenixServerToClientConverterRule extends ConverterRule {
+        public static final ConverterRule INSTANCE =
+            new PhoenixServerToClientConverterRule();
+
+        private PhoenixServerToClientConverterRule() {
+            super(RelNode.class, PhoenixRel.SERVER_CONVENTION, PhoenixRel.CLIENT_CONVENTION,
+                "PhoenixServerToClientConverterRule");
+        }
+
+        @Override public RelNode convert(RelNode rel) {
+            return PhoenixToClientConverter.create(rel);
+        }
+    }
+
+    /**
+     * Rule to convert a relational expression from
+     * {@link org.apache.phoenix.calcite.rel.PhoenixRel#PROJECTABLE_CONVENTION} to
+     * {@link org.apache.phoenix.calcite.rel.PhoenixRel#CLIENT_CONVENTION}.
+     */
+    public static class PhoenixProjectableToClientConverterRule extends ConverterRule {
+        public static final ConverterRule INSTANCE =
+            new PhoenixProjectableToClientConverterRule();
+
+        private PhoenixProjectableToClientConverterRule() {
+            super(RelNode.class, PhoenixRel.PROJECTABLE_CONVENTION, PhoenixRel.CLIENT_CONVENTION,
+                "PhoenixProjectableToClientConverterRule");
+        }
+
+        @Override public RelNode convert(RelNode rel) {
+            return PhoenixToClientConverter.create(rel);
+        }
+    }
+
+    /**
+     * Rule to convert a relational expression from
      * {@link org.apache.phoenix.calcite.rel.PhoenixRel#CONVENTION} to
      * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention}.
      */
@@ -469,7 +755,7 @@ public class PhoenixConverterRules {
             new PhoenixToEnumerableConverterRule();
 
         private PhoenixToEnumerableConverterRule() {
-            super(RelNode.class, PhoenixRel.CONVENTION, EnumerableConvention.INSTANCE,
+            super(RelNode.class, PhoenixRel.CLIENT_CONVENTION, EnumerableConvention.INSTANCE,
                 "PhoenixToEnumerableConverterRule");
         }
 

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixFilterScanMergeRule.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixFilterScanMergeRule.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixFilterScanMergeRule.java
index 87335ef..d717a1e 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixFilterScanMergeRule.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixFilterScanMergeRule.java
@@ -4,7 +4,7 @@ import com.google.common.base.Predicate;
 
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.phoenix.calcite.rel.PhoenixFilter;
+import org.apache.calcite.rel.core.Filter;
 import org.apache.phoenix.calcite.rel.PhoenixTableScan;
 
 public class PhoenixFilterScanMergeRule extends RelOptRule {
@@ -22,13 +22,13 @@ public class PhoenixFilterScanMergeRule extends RelOptRule {
 
     private PhoenixFilterScanMergeRule() {
         super(
-            operand(PhoenixFilter.class,
+            operand(Filter.class,
                 operand(PhoenixTableScan.class, null, NO_FILTER, any())));
     }
 
     @Override
     public void onMatch(RelOptRuleCall call) {
-        PhoenixFilter filter = call.rel(0);
+        Filter filter = call.rel(0);
         PhoenixTableScan scan = call.rel(1);
         assert scan.filter == null : "predicate should have ensured no filter";
         call.transformTo(PhoenixTableScan.create(scan.getCluster(),

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixServerAggregateRule.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixServerAggregateRule.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixServerAggregateRule.java
deleted file mode 100644
index 90ebce7..0000000
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixServerAggregateRule.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.apache.phoenix.calcite.rules;
-
-import org.apache.calcite.plan.RelOptRule;
-import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.phoenix.calcite.rel.PhoenixClientAggregate;
-import org.apache.phoenix.calcite.rel.PhoenixRel;
-import org.apache.phoenix.calcite.rel.PhoenixServerAggregate;
-import org.apache.phoenix.calcite.rel.PhoenixServerJoin;
-import org.apache.phoenix.calcite.rel.PhoenixServerProject;
-import org.apache.phoenix.calcite.rel.PhoenixTableScan;
-
-public class PhoenixServerAggregateRule extends RelOptRule {
-    
-    public static final PhoenixServerAggregateRule AGGREGATE_SCAN = 
-            new PhoenixServerAggregateRule("PhoenixServerAggregateRule:aggregate_scan", PhoenixTableScan.class);
-    
-    public static final PhoenixServerAggregateRule AGGREGATE_SERVERJOIN = 
-            new PhoenixServerAggregateRule("PhoenixServerAggregateRule:aggregate_serverjoin", PhoenixServerJoin.class);
-    
-    public static final PhoenixServerAggregateRule AGGREGATE_SERVERPROJECT = 
-            new PhoenixServerAggregateRule("PhoenixServerAggregateRule:aggregate_serverproject", PhoenixServerProject.class);
-
-    public PhoenixServerAggregateRule(String description, Class<? extends PhoenixRel> clazz) {
-        super(
-            operand(PhoenixClientAggregate.class,
-                    operand(clazz, any())),
-            description);
-    }
-
-    @Override
-    public void onMatch(RelOptRuleCall call) {
-        PhoenixClientAggregate aggregate = call.rel(0);
-        PhoenixRel input = call.rel(1);
-        call.transformTo(PhoenixServerAggregate.create(input, aggregate.indicator, 
-                aggregate.getGroupSet(), aggregate.getGroupSets(), 
-                aggregate.getAggCallList()));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/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
deleted file mode 100644
index cf19389..0000000
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixServerJoinRule.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package org.apache.phoenix.calcite.rules;
-
-import org.apache.calcite.plan.RelOptRule;
-import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.plan.RelOptRuleOperand;
-import org.apache.calcite.rel.core.JoinRelType;
-import org.apache.phoenix.calcite.rel.PhoenixJoin;
-import org.apache.phoenix.calcite.rel.PhoenixRel;
-import org.apache.phoenix.calcite.rel.PhoenixServerJoin;
-import org.apache.phoenix.calcite.rel.PhoenixServerProject;
-import org.apache.phoenix.calcite.rel.PhoenixTableScan;
-
-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_JOIN =
-        new Predicate<PhoenixJoin>() {
-            @Override
-            public boolean apply(PhoenixJoin phoenixJoin) {
-                return phoenixJoin.getJoinType() != JoinRelType.RIGHT
-                        && phoenixJoin.getJoinType() != JoinRelType.FULL;
-            }
-        };
-   
-    public static final PhoenixServerJoinRule JOIN_SCAN =
-            new PhoenixServerJoinRule("PhoenixServerJoinRule:join_scan", 
-                    operand(PhoenixTableScan.class, any()));
-    
-    public static final PhoenixServerJoinRule JOIN_SERVERPROJECT_SCAN =
-            new PhoenixServerJoinRule("PhoenixServerJoinRule:join_serverproject_scan", 
-                    operand(PhoenixServerProject.class, 
-                            operand(PhoenixTableScan.class, any())));
-
-    public PhoenixServerJoinRule(String description, RelOptRuleOperand left) {
-        super(
-            operand(PhoenixJoin.class, null, NO_RIGHT_OR_FULL_JOIN,
-                    left, 
-                    operand(PhoenixRel.class, any())),
-            description);
-    }
-
-    @Override
-    public void onMatch(RelOptRuleCall call) {
-        PhoenixJoin join = call.rel(0);
-        PhoenixRel left = call.rel(1);
-        PhoenixRel right = call.rel(call.getRelList().size() - 1);
-        call.transformTo(PhoenixServerJoin.create(
-                left, right, join.getCondition(), 
-                join.getJoinType(), join.getVariablesStopped(), false));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixServerProjectRule.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixServerProjectRule.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixServerProjectRule.java
deleted file mode 100644
index 662acd3..0000000
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixServerProjectRule.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.apache.phoenix.calcite.rules;
-
-import org.apache.calcite.plan.RelOptRule;
-import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.phoenix.calcite.rel.PhoenixClientProject;
-import org.apache.phoenix.calcite.rel.PhoenixRel;
-import org.apache.phoenix.calcite.rel.PhoenixServerJoin;
-import org.apache.phoenix.calcite.rel.PhoenixServerProject;
-import org.apache.phoenix.calcite.rel.PhoenixTableScan;
-
-public class PhoenixServerProjectRule extends RelOptRule {
-    
-    public static final PhoenixServerProjectRule PROJECT_SCAN = 
-            new PhoenixServerProjectRule("PhoenixServerProjectRule:project_scan", PhoenixTableScan.class);
-    
-    public static final PhoenixServerProjectRule PROJECT_SERVERJOIN = 
-            new PhoenixServerProjectRule("PhoenixServerProjectRule:project_serverjoin", PhoenixServerJoin.class);
-
-    public PhoenixServerProjectRule(String description, Class<? extends PhoenixRel> clazz) {
-        super(
-            operand(PhoenixClientProject.class,
-                    operand(clazz, any())),
-            description);
-    }
-
-    @Override
-    public void onMatch(RelOptRuleCall call) {
-        PhoenixClientProject project = call.rel(0);
-        PhoenixRel input = call.rel(1);
-        call.transformTo(PhoenixServerProject.create(
-                input, project.getProjects(), project.getRowType()));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixServerSortRule.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixServerSortRule.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixServerSortRule.java
deleted file mode 100644
index 21959eb..0000000
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixServerSortRule.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.apache.phoenix.calcite.rules;
-
-import org.apache.calcite.plan.RelOptRule;
-import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.phoenix.calcite.rel.PhoenixClientSort;
-import org.apache.phoenix.calcite.rel.PhoenixRel;
-import org.apache.phoenix.calcite.rel.PhoenixServerJoin;
-import org.apache.phoenix.calcite.rel.PhoenixServerProject;
-import org.apache.phoenix.calcite.rel.PhoenixServerSort;
-import org.apache.phoenix.calcite.rel.PhoenixTableScan;
-
-public class PhoenixServerSortRule extends RelOptRule {
-    
-    public static final PhoenixServerSortRule SORT_SCAN = 
-            new PhoenixServerSortRule("PhoenixServerSortRule:sort_scan", PhoenixTableScan.class);
-    
-    public static final PhoenixServerSortRule SORT_SERVERJOIN = 
-            new PhoenixServerSortRule("PhoenixServerSortRule:sort_serverjoin", PhoenixServerJoin.class);
-    
-    public static final PhoenixServerSortRule SORT_SERVERPROJECT = 
-            new PhoenixServerSortRule("PhoenixServerSortRule:sort_serverproject", PhoenixServerProject.class);
-
-    public PhoenixServerSortRule(String description, Class<? extends PhoenixRel> clazz) {
-        super(
-            operand(PhoenixClientSort.class,
-                    operand(clazz, any())),
-            description);
-    }
-
-    @Override
-    public void onMatch(RelOptRuleCall call) {
-        PhoenixClientSort sort = call.rel(0);
-        PhoenixRel input = call.rel(1);
-        call.transformTo(PhoenixServerSort.create(
-                input, sort.getCollation()));
-    }
-
-}


[3/4] phoenix git commit: Add server/client conventions for PhoenixRel and use ConvertRules to apply Phoenix server/client operators

Posted by ma...@apache.org.
Add server/client conventions for PhoenixRel and use ConvertRules to apply Phoenix server/client operators


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

Branch: refs/heads/calcite
Commit: c1396ecfff867d059cb0eb424188ffbfdbfd54f0
Parents: cedc1c5
Author: maryannxue <we...@intel.com>
Authored: Wed Jun 10 16:29:15 2015 -0400
Committer: maryannxue <we...@intel.com>
Committed: Wed Jun 10 16:29:15 2015 -0400

----------------------------------------------------------------------
 .../org/apache/phoenix/calcite/CalciteTest.java | 268 ++++++++-----
 .../calcite/jdbc/PhoenixPrepareImpl.java        |  18 +-
 .../calcite/metadata/PhoenixRelMdCollation.java |   4 -
 .../calcite/rel/PhoenixAbstractAggregate.java   |   1 -
 .../calcite/rel/PhoenixAbstractJoin.java        |   3 +-
 .../calcite/rel/PhoenixAbstractProject.java     |   1 -
 .../calcite/rel/PhoenixAbstractSort.java        |   1 -
 .../calcite/rel/PhoenixClientAggregate.java     |   2 +-
 .../phoenix/calcite/rel/PhoenixClientJoin.java  |  42 +-
 .../calcite/rel/PhoenixClientProject.java       |   2 +-
 .../phoenix/calcite/rel/PhoenixClientSort.java  |   2 +-
 .../calcite/rel/PhoenixCompactClientSort.java   |   2 +-
 .../phoenix/calcite/rel/PhoenixFilter.java      |   3 +-
 .../apache/phoenix/calcite/rel/PhoenixJoin.java |  49 ---
 .../phoenix/calcite/rel/PhoenixLimit.java       |   3 +-
 .../calcite/rel/PhoenixPostJoinProject.java     |  70 ++++
 .../apache/phoenix/calcite/rel/PhoenixRel.java  |   6 +-
 .../calcite/rel/PhoenixServerAggregate.java     |   2 +-
 .../phoenix/calcite/rel/PhoenixServerJoin.java  |  10 +-
 .../calcite/rel/PhoenixServerProject.java       |   9 +-
 .../phoenix/calcite/rel/PhoenixServerSort.java  |   2 +-
 .../phoenix/calcite/rel/PhoenixTableScan.java   |   2 +-
 .../calcite/rel/PhoenixToClientConverter.java   |  45 +++
 .../phoenix/calcite/rel/PhoenixUnion.java       |   3 +-
 .../phoenix/calcite/rel/PhoenixValues.java      |   3 +-
 .../calcite/rules/PhoenixClientJoinRule.java    |  40 --
 .../calcite/rules/PhoenixConverterRules.java    | 388 ++++++++++++++++---
 .../rules/PhoenixFilterScanMergeRule.java       |   6 +-
 .../rules/PhoenixServerAggregateRule.java       |  39 --
 .../calcite/rules/PhoenixServerJoinRule.java    |  54 ---
 .../calcite/rules/PhoenixServerProjectRule.java |  34 --
 .../calcite/rules/PhoenixServerSortRule.java    |  38 --
 32 files changed, 653 insertions(+), 499 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/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 89006ed..dca783d 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
@@ -238,7 +238,8 @@ public class CalciteTest extends BaseClientManagedTimeIT {
     @Test public void testTableScan() throws Exception {
         start().sql("select * from aTable where a_string = 'a'")
                 .explainIs("PhoenixToEnumerableConverter\n" +
-                           "  PhoenixTableScan(table=[[phoenix, ATABLE]], filter=[=($2, 'a')])\n")
+                           "  PhoenixToClientConverter\n" +
+                           "    PhoenixTableScan(table=[[phoenix, ATABLE]], filter=[=($2, 'a')])\n")
                 .resultIs(new Object[][] {
                           {"00D300000000XHP", "00A123122312312", "a"}, 
                           {"00D300000000XHP", "00A223122312312", "a"}, 
@@ -250,8 +251,9 @@ public class CalciteTest extends BaseClientManagedTimeIT {
     @Test public void testProject() throws Exception {
         start().sql("select entity_id, a_string, organization_id from aTable where a_string = 'a'")
                 .explainIs("PhoenixToEnumerableConverter\n" +
-                           "  PhoenixServerProject(ENTITY_ID=[$1], A_STRING=[$2], ORGANIZATION_ID=[$0])\n" +
-                           "    PhoenixTableScan(table=[[phoenix, ATABLE]], filter=[=($2, 'a')])\n")
+                           "  PhoenixToClientConverter\n" +
+                           "    PhoenixServerProject(ENTITY_ID=[$1], A_STRING=[$2], ORGANIZATION_ID=[$0])\n" +
+                           "      PhoenixTableScan(table=[[phoenix, ATABLE]], filter=[=($2, 'a')])\n")
                 .resultIs(new Object[][] {
                           {"00A123122312312", "a", "00D300000000XHP"}, 
                           {"00A223122312312", "a", "00D300000000XHP"}, 
@@ -263,12 +265,14 @@ public class CalciteTest extends BaseClientManagedTimeIT {
     @Test public void testJoin() throws Exception {
         start().sql("select t1.entity_id, t2.a_string, t1.organization_id from aTable t1 join aTable t2 on t1.entity_id = t2.entity_id and t1.organization_id = t2.organization_id where t1.a_string = 'a'") 
                 .explainIs("PhoenixToEnumerableConverter\n" +
-                           "  PhoenixServerProject(ENTITY_ID=[$4], A_STRING=[$2], ORGANIZATION_ID=[$3])\n" +
-                           "    PhoenixServerJoin(condition=[AND(=($1, $4), =($0, $3))], joinType=[inner])\n" +
-                           "      PhoenixServerProject(ORGANIZATION_ID=[$0], ENTITY_ID=[$1], A_STRING=[$2])\n" +
-                           "        PhoenixTableScan(table=[[phoenix, ATABLE]])\n" +
-                           "      PhoenixServerProject(ORGANIZATION_ID=[$0], ENTITY_ID=[$1], A_STRING=[$2])\n" +
-                           "        PhoenixTableScan(table=[[phoenix, ATABLE]], filter=[=($2, 'a')])\n")
+                           "  PhoenixToClientConverter\n" +
+                           "    PhoenixPostJoinProject(ENTITY_ID=[$4], A_STRING=[$2], ORGANIZATION_ID=[$3])\n" +
+                           "      PhoenixServerJoin(condition=[AND(=($4, $1), =($3, $0))], joinType=[inner])\n" +
+                           "        PhoenixServerProject(ORGANIZATION_ID=[$0], ENTITY_ID=[$1], A_STRING=[$2])\n" +
+                           "          PhoenixTableScan(table=[[phoenix, ATABLE]])\n" +
+                           "        PhoenixToClientConverter\n" +
+                           "          PhoenixServerProject(ORGANIZATION_ID=[$0], ENTITY_ID=[$1], A_STRING=[$2])\n" +
+                           "            PhoenixTableScan(table=[[phoenix, ATABLE]], filter=[=($2, 'a')])\n")
                 .resultIs(new Object[][] {
                           {"00A123122312312", "a", "00D300000000XHP"}, 
                           {"00A223122312312", "a", "00D300000000XHP"}, 
@@ -278,12 +282,14 @@ public class CalciteTest extends BaseClientManagedTimeIT {
         
         start().sql("SELECT item.\"item_id\", item.name, supp.\"supplier_id\", supp.name FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp ON item.\"supplier_id\" = supp.\"supplier_id\"")
                 .explainIs("PhoenixToEnumerableConverter\n" +
-                           "  PhoenixServerProject(item_id=[$0], NAME=[$1], supplier_id=[$3], NAME0=[$4])\n" +
-                           "    PhoenixServerJoin(condition=[=($2, $3)], joinType=[inner])\n" +
-                           "      PhoenixServerProject(item_id=[$0], NAME=[$1], supplier_id=[$5])\n" +
-                           "        PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n" +
-                           "      PhoenixServerProject(supplier_id=[$0], NAME=[$1])\n" +
-                           "        PhoenixTableScan(table=[[phoenix, Join, SupplierTable]])\n")
+                           "  PhoenixToClientConverter\n" +
+                           "    PhoenixPostJoinProject(item_id=[$0], NAME=[$1], supplier_id=[$3], NAME0=[$4])\n" +
+                           "      PhoenixServerJoin(condition=[=($2, $3)], joinType=[inner])\n" +
+                           "        PhoenixServerProject(item_id=[$0], NAME=[$1], supplier_id=[$5])\n" +
+                           "          PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n" +
+                           "        PhoenixToClientConverter\n" +
+                           "          PhoenixServerProject(supplier_id=[$0], NAME=[$1])\n" +
+                           "            PhoenixTableScan(table=[[phoenix, Join, SupplierTable]])\n")
                 .resultIs(new Object[][] {
                           {"0000000001", "T1", "0000000001", "S1"}, 
                           {"0000000002", "T2", "0000000001", "S1"}, 
@@ -295,11 +301,13 @@ public class CalciteTest extends BaseClientManagedTimeIT {
         
         start().sql("SELECT * FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp ON item.\"supplier_id\" = supp.\"supplier_id\" AND supp.name = 'S5'")
                 .explainIs("PhoenixToEnumerableConverter\n" +
-                           "  PhoenixServerProject(item_id=[$0], NAME=[$1], PRICE=[$2], DISCOUNT1=[$3], DISCOUNT2=[$4], supplier_id=[$5], DESCRIPTION=[$6], supplier_id0=[$7], NAME0=[$8], PHONE=[$9], ADDRESS=[$10], LOC_ID=[$11])\n" +
-                           "    PhoenixServerJoin(condition=[=($5, $7)], joinType=[inner])\n" +
-                           "      PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n" +
-                           "      PhoenixServerProject(supplier_id=[$0], NAME=[$1], PHONE=[$2], ADDRESS=[$3], LOC_ID=[$4], $f5=[CAST($1):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL])\n" +
-                           "        PhoenixTableScan(table=[[phoenix, Join, SupplierTable]], filter=[=(CAST($1):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL, 'S5')])\n")
+                           "  PhoenixToClientConverter\n" +
+                           "    PhoenixPostJoinProject(item_id=[$0], NAME=[$1], PRICE=[$2], DISCOUNT1=[$3], DISCOUNT2=[$4], supplier_id=[$5], DESCRIPTION=[$6], supplier_id0=[$7], NAME0=[$8], PHONE=[$9], ADDRESS=[$10], LOC_ID=[$11])\n" +
+                           "      PhoenixServerJoin(condition=[=($5, $7)], joinType=[inner])\n" +
+                           "        PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n" +
+                           "        PhoenixToClientConverter\n" +
+                           "          PhoenixServerProject(supplier_id=[$0], NAME=[$1], PHONE=[$2], ADDRESS=[$3], LOC_ID=[$4], $f5=[CAST($1):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL])\n" +
+                           "            PhoenixTableScan(table=[[phoenix, Join, SupplierTable]], filter=[=(CAST($1):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL, 'S5')])\n")
                 .resultIs(new Object[][] {
                           {"0000000005", "T5", 500, 8, 15, "0000000005", "Item T5", "0000000005", "S5", "888-888-5555", "505 YYY Street", "10005"}})
                 .close();
@@ -314,8 +322,9 @@ public class CalciteTest extends BaseClientManagedTimeIT {
                            "        PhoenixServerSort(sort0=[$2], dir0=[ASC])\n" +
                            "          PhoenixServerProject(item_id=[$0], NAME=[$1], supplier_id=[$5])\n" +
                            "            PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n" +
-                           "        PhoenixServerProject(supplier_id=[$0], NAME=[$1])\n" +
-                           "          PhoenixTableScan(table=[[phoenix, Join, SupplierTable]])\n")
+                           "        PhoenixToClientConverter\n" +
+                           "          PhoenixServerProject(supplier_id=[$0], NAME=[$1])\n" +
+                           "            PhoenixTableScan(table=[[phoenix, Join, SupplierTable]])\n")
                 .resultIs(new Object[][] {
                         {null, null, "0000000003", "S3"},
                         {null, null, "0000000004", "S4"},
@@ -326,19 +335,44 @@ public class CalciteTest extends BaseClientManagedTimeIT {
                         {"0000000005", "T5", "0000000005", "S5"},
                         {"0000000006", "T6", "0000000006", "S6"},
                         {"invalid001", "INVALID-1", null, null}})
-                .close();        
+                .close();
+        
+        start().sql("select t1.entity_id, t2.a_string, t1.organization_id from aTable t1 join aTable t2 on t1.organization_id = t2.organization_id and t1.entity_id = t2.entity_id") 
+                .explainIs("PhoenixToEnumerableConverter\n" +
+                           "  PhoenixClientProject(ENTITY_ID=[$1], A_STRING=[$4], ORGANIZATION_ID=[$0])\n" +
+                           "    PhoenixClientJoin(condition=[AND(=($0, $2), =($1, $3))], joinType=[inner])\n" +
+                           "      PhoenixToClientConverter\n" +
+                           "        PhoenixServerProject(ORGANIZATION_ID=[$0], ENTITY_ID=[$1])\n" +
+                           "          PhoenixTableScan(table=[[phoenix, ATABLE]])\n" +
+                           "      PhoenixToClientConverter\n" +
+                           "        PhoenixServerProject(ORGANIZATION_ID=[$0], ENTITY_ID=[$1], A_STRING=[$2])\n" +
+                           "          PhoenixTableScan(table=[[phoenix, ATABLE]])\n")
+                .resultIs(new Object[][] {
+                          {"00A123122312312", "a", "00D300000000XHP"}, 
+                          {"00A223122312312", "a", "00D300000000XHP"}, 
+                          {"00A323122312312", "a", "00D300000000XHP"}, 
+                          {"00A423122312312", "a", "00D300000000XHP"}, 
+                          {"00B523122312312", "b", "00D300000000XHP"}, 
+                          {"00B623122312312", "b", "00D300000000XHP"}, 
+                          {"00B723122312312", "b", "00D300000000XHP"}, 
+                          {"00B823122312312", "b", "00D300000000XHP"}, 
+                          {"00C923122312312", "c", "00D300000000XHP"}})
+                .close();
     }
     
     @Test public void testMultiJoin() throws Exception {
         start().sql("select t1.entity_id, t2.a_string, t3.organization_id from aTable t1 join aTable t2 on t1.entity_id = t2.entity_id and t1.organization_id = t2.organization_id join atable t3 on t1.entity_id = t3.entity_id and t1.organization_id = t3.organization_id where t1.a_string = 'a'") 
                 .explainIs("PhoenixToEnumerableConverter\n" +
-                           "  PhoenixServerProject(ENTITY_ID=[$19], A_STRING=[$2], ORGANIZATION_ID=[$36])\n" +
-                           "    PhoenixServerJoin(condition=[AND(=($1, $19), =($0, $18))], joinType=[inner])\n" +
-                           "      PhoenixTableScan(table=[[phoenix, ATABLE]])\n" +
-                           "      PhoenixServerProject(ORGANIZATION_ID=[$18], ENTITY_ID=[$19], A_STRING=[$20], B_STRING=[$21], A_INTEGER=[$22], A_DATE=[$23], A_TIME=[$24], A_TIMESTAMP=[$25], X_DECIMAL=[$26], X_LONG=[$27], X_INTEGER=[$28], Y_INTEGER=[$29], A_BYTE=[$30], A_SHORT=[$31], A_FLOAT=[$32], A_DOUBLE=[$33], A_UNSIGNED_FLOAT=[$34], A_UNSIGNED_DOUBLE=[$35], ORGANIZATION_ID0=[$0], ENTITY_ID0=[$1], A_STRING0=[$2], B_STRING0=[$3], A_INTEGER0=[$4], A_DATE0=[$5], A_TIME0=[$6], A_TIMESTAMP0=[$7], X_DECIMAL0=[$8], X_LONG0=[$9], X_INTEGER0=[$10], Y_INTEGER0=[$11], A_BYTE0=[$12], A_SHORT0=[$13], A_FLOAT0=[$14], A_DOUBLE0=[$15], A_UNSIGNED_FLOAT0=[$16], A_UNSIGNED_DOUBLE0=[$17])\n" +
-                           "        PhoenixServerJoin(condition=[AND(=($1, $19), =($0, $18))], joinType=[inner])\n" +
-                           "          PhoenixTableScan(table=[[phoenix, ATABLE]])\n" +
-                           "          PhoenixTableScan(table=[[phoenix, ATABLE]], filter=[=($2, 'a')])\n")
+                           "  PhoenixToClientConverter\n" +
+                           "    PhoenixPostJoinProject(ENTITY_ID=[$19], A_STRING=[$38], ORGANIZATION_ID=[$0])\n" +
+                           "      PhoenixServerJoin(condition=[AND(=($19, $1), =($18, $0))], joinType=[inner])\n" +
+                           "        PhoenixTableScan(table=[[phoenix, ATABLE]])\n" +
+                           "        PhoenixToClientConverter\n" +
+                           "          PhoenixPostJoinProject(ORGANIZATION_ID=[$18], ENTITY_ID=[$19], A_STRING=[$20], B_STRING=[$21], A_INTEGER=[$22], A_DATE=[$23], A_TIME=[$24], A_TIMESTAMP=[$25], X_DECIMAL=[$26], X_LONG=[$27], X_INTEGER=[$28], Y_INTEGER=[$29], A_BYTE=[$30], A_SHORT=[$31], A_FLOAT=[$32], A_DOUBLE=[$33], A_UNSIGNED_FLOAT=[$34], A_UNSIGNED_DOUBLE=[$35], ORGANIZATION_ID0=[$0], ENTITY_ID0=[$1], A_STRING0=[$2], B_STRING0=[$3], A_INTEGER0=[$4], A_DATE0=[$5], A_TIME0=[$6], A_TIMESTAMP0=[$7], X_DECIMAL0=[$8], X_LONG0=[$9], X_INTEGER0=[$10], Y_INTEGER0=[$11], A_BYTE0=[$12], A_SHORT0=[$13], A_FLOAT0=[$14], A_DOUBLE0=[$15], A_UNSIGNED_FLOAT0=[$16], A_UNSIGNED_DOUBLE0=[$17])\n" +
+                           "            PhoenixServerJoin(condition=[AND(=($19, $1), =($18, $0))], joinType=[inner])\n" +
+                           "              PhoenixTableScan(table=[[phoenix, ATABLE]])\n" +
+                           "              PhoenixToClientConverter\n" +
+                           "                PhoenixTableScan(table=[[phoenix, ATABLE]], filter=[=($2, 'a')])\n")
                 .resultIs(new Object[][] {
                           {"00A123122312312", "a", "00D300000000XHP"}, 
                           {"00A223122312312", "a", "00D300000000XHP"}, 
@@ -348,12 +382,15 @@ public class CalciteTest extends BaseClientManagedTimeIT {
         
         start().sql("select t1.entity_id, t2.a_string, t3.organization_id from aTable t1 join aTable t2 on t1.entity_id = t2.entity_id and t1.organization_id = t2.organization_id join atable t3 on t1.entity_id = t3.entity_id and t1.organization_id = t3.organization_id") 
                 .explainIs("PhoenixToEnumerableConverter\n" +
-                           "  PhoenixServerProject(ENTITY_ID=[$19], A_STRING=[$38], ORGANIZATION_ID=[$0])\n" +
-                           "    PhoenixServerJoin(condition=[AND(=($19, $1), =($18, $0))], joinType=[inner])\n" +
-                           "      PhoenixTableScan(table=[[phoenix, ATABLE]])\n" +
-                           "      PhoenixServerJoin(condition=[AND(=($1, $19), =($0, $18))], joinType=[inner])\n" +
+                           "  PhoenixToClientConverter\n" +
+                           "    PhoenixPostJoinProject(ENTITY_ID=[$19], A_STRING=[$2], ORGANIZATION_ID=[$36])\n" +
+                           "      PhoenixServerJoin(condition=[AND(=($19, $1), =($18, $0))], joinType=[inner])\n" +
                            "        PhoenixTableScan(table=[[phoenix, ATABLE]])\n" +
-                           "        PhoenixTableScan(table=[[phoenix, ATABLE]])\n")
+                           "        PhoenixToClientConverter\n" +
+                           "          PhoenixServerJoin(condition=[AND(=($1, $19), =($0, $18))], joinType=[inner])\n" +
+                           "            PhoenixTableScan(table=[[phoenix, ATABLE]])\n" +
+                           "            PhoenixToClientConverter\n" +
+                           "              PhoenixTableScan(table=[[phoenix, ATABLE]])\n")
                 .resultIs(new Object[][] {
                           {"00A123122312312", "a", "00D300000000XHP"}, 
                           {"00A223122312312", "a", "00D300000000XHP"}, 
@@ -394,12 +431,13 @@ public class CalciteTest extends BaseClientManagedTimeIT {
         start().sql("select s.name, count(\"item_id\") from " + JOIN_SUPPLIER_TABLE_FULL_NAME + " s join " + JOIN_ITEM_TABLE_FULL_NAME + " i on s.\"supplier_id\" = i.\"supplier_id\" group by s.name")
                 .explainIs("PhoenixToEnumerableConverter\n" +
                            "  PhoenixServerAggregate(group=[{0}], EXPR$1=[COUNT()])\n" +
-                           "    PhoenixServerProject(NAME=[$2])\n" +
+                           "    PhoenixPostJoinProject(NAME=[$2])\n" +
                            "      PhoenixServerJoin(condition=[=($1, $0)], joinType=[inner])\n" +
                            "        PhoenixServerProject(supplier_id=[$5])\n" +
                            "          PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n" +
-                           "        PhoenixServerProject(supplier_id=[$0], NAME=[$1])\n" +
-                           "          PhoenixTableScan(table=[[phoenix, Join, SupplierTable]])\n")
+                           "        PhoenixToClientConverter\n" +
+                           "          PhoenixServerProject(supplier_id=[$0], NAME=[$1])\n" +
+                           "            PhoenixTableScan(table=[[phoenix, Join, SupplierTable]])\n")
                 .resultIs(new Object[][] {
                           {"S1", 2L},
                           {"S2", 2L},
@@ -441,8 +479,9 @@ public class CalciteTest extends BaseClientManagedTimeIT {
         
         start().sql("select organization_id, entity_id, a_string from aTable order by organization_id, entity_id")
                 .explainIs("PhoenixToEnumerableConverter\n" +
-                           "  PhoenixServerProject(ORGANIZATION_ID=[$0], ENTITY_ID=[$1], A_STRING=[$2])\n" +
-                           "    PhoenixTableScan(table=[[phoenix, ATABLE]])\n")
+                           "  PhoenixToClientConverter\n" +
+                           "    PhoenixServerProject(ORGANIZATION_ID=[$0], ENTITY_ID=[$1], A_STRING=[$2])\n" +
+                           "      PhoenixTableScan(table=[[phoenix, ATABLE]])\n")
                 .resultIs(new Object[][] {
                           {"00D300000000XHP", "00A123122312312", "a"}, 
                           {"00D300000000XHP", "00A223122312312", "a"}, 
@@ -472,12 +511,13 @@ public class CalciteTest extends BaseClientManagedTimeIT {
                 .explainIs("PhoenixToEnumerableConverter\n" +
                            "  PhoenixCompactClientSort(sort0=[$1], sort1=[$0], dir0=[ASC], dir1=[DESC])\n" +
                            "    PhoenixServerAggregate(group=[{0}], EXPR$1=[COUNT()])\n" +
-                           "      PhoenixServerProject(NAME=[$2])\n" +
+                           "      PhoenixPostJoinProject(NAME=[$2])\n" +
                            "        PhoenixServerJoin(condition=[=($1, $0)], joinType=[inner])\n" +
                            "          PhoenixServerProject(supplier_id=[$5])\n" +
                            "            PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n" +
-                           "          PhoenixServerProject(supplier_id=[$0], NAME=[$1])\n" +
-                           "            PhoenixTableScan(table=[[phoenix, Join, SupplierTable]])\n")
+                           "          PhoenixToClientConverter\n" +
+                           "            PhoenixServerProject(supplier_id=[$0], NAME=[$1])\n" +
+                           "              PhoenixTableScan(table=[[phoenix, Join, SupplierTable]])\n")
                 .resultIs(new Object[][] {
                           {"S6", 1L},
                           {"S5", 1L},
@@ -488,12 +528,13 @@ public class CalciteTest extends BaseClientManagedTimeIT {
         start().sql("SELECT item.\"item_id\", item.name, supp.\"supplier_id\", supp.name FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp ON item.\"supplier_id\" = supp.\"supplier_id\" order by item.name desc")
                 .explainIs("PhoenixToEnumerableConverter\n" +
                            "  PhoenixServerSort(sort0=[$1], dir0=[DESC])\n" +
-                           "    PhoenixServerProject(item_id=[$0], NAME=[$1], supplier_id=[$3], NAME0=[$4])\n" +
+                           "    PhoenixPostJoinProject(item_id=[$0], NAME=[$1], supplier_id=[$3], NAME0=[$4])\n" +
                            "      PhoenixServerJoin(condition=[=($2, $3)], joinType=[inner])\n" +
                            "        PhoenixServerProject(item_id=[$0], NAME=[$1], supplier_id=[$5])\n" +
                            "          PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n" +
-                           "        PhoenixServerProject(supplier_id=[$0], NAME=[$1])\n" +
-                           "          PhoenixTableScan(table=[[phoenix, Join, SupplierTable]])\n")
+                           "        PhoenixToClientConverter\n" +
+                           "          PhoenixServerProject(supplier_id=[$0], NAME=[$1])\n" +
+                           "            PhoenixTableScan(table=[[phoenix, Join, SupplierTable]])\n")
                 .resultIs(new Object[][] {
                           {"0000000006", "T6", "0000000006", "S6"}, 
                           {"0000000005", "T5", "0000000005", "S5"}, 
@@ -522,8 +563,9 @@ public class CalciteTest extends BaseClientManagedTimeIT {
         start().sql("select organization_id, entity_id, a_string from aTable order by organization_id, entity_id limit 5")
                 .explainIs("PhoenixToEnumerableConverter\n" +
                            "  PhoenixLimit(fetch=[5])\n" +
-                           "    PhoenixServerProject(ORGANIZATION_ID=[$0], ENTITY_ID=[$1], A_STRING=[$2])\n" +
-                           "      PhoenixTableScan(table=[[phoenix, ATABLE]], statelessFetch=[5])\n")
+                           "    PhoenixToClientConverter\n" +
+                           "      PhoenixServerProject(ORGANIZATION_ID=[$0], ENTITY_ID=[$1], A_STRING=[$2])\n" +
+                           "        PhoenixTableScan(table=[[phoenix, ATABLE]])\n")
                 .resultIs(new Object[][] {
                           {"00D300000000XHP", "00A123122312312", "a"}, 
                           {"00D300000000XHP", "00A223122312312", "a"}, 
@@ -550,12 +592,13 @@ public class CalciteTest extends BaseClientManagedTimeIT {
                            "  PhoenixLimit(fetch=[3])\n" +
                            "    PhoenixCompactClientSort(sort0=[$1], sort1=[$0], dir0=[ASC], dir1=[DESC])\n" +
                            "      PhoenixServerAggregate(group=[{0}], EXPR$1=[COUNT()])\n" +
-                           "        PhoenixServerProject(NAME=[$2])\n" +
+                           "        PhoenixPostJoinProject(NAME=[$2])\n" +
                            "          PhoenixServerJoin(condition=[=($1, $0)], joinType=[inner])\n" +
                            "            PhoenixServerProject(supplier_id=[$5])\n" +
                            "              PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n" +
-                           "            PhoenixServerProject(supplier_id=[$0], NAME=[$1])\n" +
-                           "              PhoenixTableScan(table=[[phoenix, Join, SupplierTable]])\n")
+                           "            PhoenixToClientConverter\n" +
+                           "              PhoenixServerProject(supplier_id=[$0], NAME=[$1])\n" +
+                           "                PhoenixTableScan(table=[[phoenix, Join, SupplierTable]])\n")
                 .resultIs(new Object[][] {
                           {"S6", 1L},
                           {"S5", 1L},
@@ -566,12 +609,13 @@ public class CalciteTest extends BaseClientManagedTimeIT {
                 .explainIs("PhoenixToEnumerableConverter\n" +
                            "  PhoenixLimit(fetch=[3])\n" +
                            "    PhoenixServerSort(sort0=[$1], dir0=[DESC])\n" +
-                           "      PhoenixServerProject(item_id=[$0], NAME=[$1], supplier_id=[$3], NAME0=[$4])\n" +
+                           "      PhoenixPostJoinProject(item_id=[$0], NAME=[$1], supplier_id=[$3], NAME0=[$4])\n" +
                            "        PhoenixServerJoin(condition=[=($2, $3)], joinType=[inner])\n" +
                            "          PhoenixServerProject(item_id=[$0], NAME=[$1], supplier_id=[$5])\n" +
                            "            PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n" +
-                           "          PhoenixServerProject(supplier_id=[$0], NAME=[$1])\n" +
-                           "            PhoenixTableScan(table=[[phoenix, Join, SupplierTable]])\n")
+                           "          PhoenixToClientConverter\n" +
+                           "            PhoenixServerProject(supplier_id=[$0], NAME=[$1])\n" +
+                           "              PhoenixTableScan(table=[[phoenix, Join, SupplierTable]])\n")
                 .resultIs(new Object[][] {
                           {"0000000006", "T6", "0000000006", "S6"}, 
                           {"0000000005", "T5", "0000000005", "S5"}, 
@@ -583,8 +627,9 @@ public class CalciteTest extends BaseClientManagedTimeIT {
         start().sql("select organization_id, entity_id, a_string from aTable limit 5")
                 .explainIs("PhoenixToEnumerableConverter\n" +
                            "  PhoenixLimit(fetch=[5])\n" +
-                           "    PhoenixServerProject(ORGANIZATION_ID=[$0], ENTITY_ID=[$1], A_STRING=[$2])\n" +
-                           "      PhoenixTableScan(table=[[phoenix, ATABLE]], statelessFetch=[5])\n")
+                           "    PhoenixToClientConverter\n" +
+                           "      PhoenixServerProject(ORGANIZATION_ID=[$0], ENTITY_ID=[$1], A_STRING=[$2])\n" +
+                           "        PhoenixTableScan(table=[[phoenix, ATABLE]])\n")
                 .resultIs(new Object[][] {
                           {"00D300000000XHP", "00A123122312312", "a"}, 
                           {"00D300000000XHP", "00A223122312312", "a"}, 
@@ -609,12 +654,13 @@ public class CalciteTest extends BaseClientManagedTimeIT {
                 .explainIs("PhoenixToEnumerableConverter\n" +
                            "  PhoenixLimit(fetch=[3])\n" +
                            "    PhoenixServerAggregate(group=[{0}], EXPR$1=[COUNT()])\n" +
-                           "      PhoenixServerProject(NAME=[$2])\n" +
+                           "      PhoenixPostJoinProject(NAME=[$2])\n" +
                            "        PhoenixServerJoin(condition=[=($1, $0)], joinType=[inner])\n" +
                            "          PhoenixServerProject(supplier_id=[$5])\n" +
                            "            PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n" +
-                           "          PhoenixServerProject(supplier_id=[$0], NAME=[$1])\n" +
-                           "            PhoenixTableScan(table=[[phoenix, Join, SupplierTable]])\n")
+                           "          PhoenixToClientConverter\n" +
+                           "            PhoenixServerProject(supplier_id=[$0], NAME=[$1])\n" +
+                           "              PhoenixTableScan(table=[[phoenix, Join, SupplierTable]])\n")
                 .resultIs(new Object[][] {
                           {"S1", 2L},
                           {"S2", 2L},
@@ -624,12 +670,14 @@ public class CalciteTest extends BaseClientManagedTimeIT {
         start().sql("SELECT item.\"item_id\", item.name, supp.\"supplier_id\", supp.name FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp ON item.\"supplier_id\" = supp.\"supplier_id\" limit 3")
                 .explainIs("PhoenixToEnumerableConverter\n" +
                            "  PhoenixLimit(fetch=[3])\n" +
-                           "    PhoenixServerProject(item_id=[$0], NAME=[$1], supplier_id=[$3], NAME0=[$4])\n" +
-                           "      PhoenixServerJoin(condition=[=($2, $3)], joinType=[inner])\n" +
-                           "        PhoenixServerProject(item_id=[$0], NAME=[$1], supplier_id=[$5])\n" +
-                           "          PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n" +
-                           "        PhoenixServerProject(supplier_id=[$0], NAME=[$1])\n" +
-                           "          PhoenixTableScan(table=[[phoenix, Join, SupplierTable]])\n")
+                           "    PhoenixToClientConverter\n" +
+                           "      PhoenixPostJoinProject(item_id=[$0], NAME=[$1], supplier_id=[$3], NAME0=[$4])\n" +
+                           "        PhoenixServerJoin(condition=[=($2, $3)], joinType=[inner])\n" +
+                           "          PhoenixServerProject(item_id=[$0], NAME=[$1], supplier_id=[$5])\n" +
+                           "            PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n" +
+                           "          PhoenixToClientConverter\n" +
+                           "            PhoenixServerProject(supplier_id=[$0], NAME=[$1])\n" +
+                           "              PhoenixTableScan(table=[[phoenix, Join, SupplierTable]])\n")
                 .resultIs(new Object[][] {
                           {"0000000001", "T1", "0000000001", "S1"}, 
                           {"0000000002", "T2", "0000000001", "S1"}, 
@@ -640,16 +688,17 @@ public class CalciteTest extends BaseClientManagedTimeIT {
     @Test public void testSubquery() {
         start().sql("SELECT \"order_id\", quantity FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o WHERE quantity = (SELECT max(quantity) FROM " + JOIN_ORDER_TABLE_FULL_NAME + " q WHERE o.\"item_id\" = q.\"item_id\")")
                .explainIs("PhoenixToEnumerableConverter\n" +
-                          "  PhoenixServerProject(order_id=[$0], QUANTITY=[$4])\n" +
-                          "    PhoenixServerJoin(condition=[AND(=($2, $7), =($4, $8))], joinType=[inner])\n" +
-                          "      PhoenixTableScan(table=[[phoenix, Join, OrderTable]])\n" +
-                          "      PhoenixServerAggregate(group=[{0}], EXPR$0=[MAX($1)])\n" +
-                          "        PhoenixServerProject(item_id0=[$7], QUANTITY=[$4])\n" +
-                          "          PhoenixServerJoin(condition=[=($7, $2)], joinType=[inner])\n" +
-                          "            PhoenixTableScan(table=[[phoenix, Join, OrderTable]])\n" +
-                          "            PhoenixServerAggregate(group=[{0}])\n" +
-                          "              PhoenixServerProject(item_id=[$2])\n" +
-                          "                PhoenixTableScan(table=[[phoenix, Join, OrderTable]])\n")
+                          "  PhoenixToClientConverter\n" +
+                          "    PhoenixPostJoinProject(order_id=[$0], QUANTITY=[$4])\n" +
+                          "      PhoenixServerJoin(condition=[AND(=($2, $7), =($4, $8))], joinType=[inner])\n" +
+                          "        PhoenixTableScan(table=[[phoenix, Join, OrderTable]])\n" +
+                          "        PhoenixServerAggregate(group=[{0}], EXPR$0=[MAX($1)])\n" +
+                          "          PhoenixPostJoinProject(item_id0=[$7], QUANTITY=[$4])\n" +
+                          "            PhoenixServerJoin(condition=[=($7, $2)], joinType=[inner])\n" +
+                          "              PhoenixTableScan(table=[[phoenix, Join, OrderTable]])\n" +
+                          "              PhoenixServerAggregate(group=[{0}])\n" +
+                          "                PhoenixServerProject(item_id=[$2])\n" +
+                          "                  PhoenixTableScan(table=[[phoenix, Join, OrderTable]])\n")
                .resultIs(new Object[][]{
                          {"000000000000001", 1000},
                          {"000000000000003", 3000},
@@ -663,16 +712,17 @@ public class CalciteTest extends BaseClientManagedTimeIT {
             + "from " + JOIN_ORDER_TABLE_FULL_NAME + " o where o.\"item_id\" = i.\"item_id\")\n"
             + "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], isSingleValueRhs=[true])\n" +
-                       "      PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n" +
-                       "      PhoenixServerAggregate(group=[{0}], SQ=[MAX($1)])\n" +
-                       "        PhoenixServerProject(item_id0=[$7], QUANTITY=[$4])\n" +
-                       "          PhoenixServerJoin(condition=[=($2, $7)], joinType=[inner])\n" +
-                       "            PhoenixTableScan(table=[[phoenix, Join, OrderTable]])\n" +
-                       "            PhoenixServerAggregate(group=[{0}])\n" +
-                       "              PhoenixServerProject(item_id=[$0])\n" +
-                       "                PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n")
+                       "  PhoenixToClientConverter\n" +
+                       "    PhoenixPostJoinProject(item_id=[$0], NAME=[$1], EXPR$2=[$8])\n" +
+                       "      PhoenixServerJoin(condition=[=($0, $7)], joinType=[left], isSingleValueRhs=[true])\n" +
+                       "        PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n" +
+                       "        PhoenixServerAggregate(group=[{0}], SQ=[MAX($1)])\n" +
+                       "          PhoenixPostJoinProject(item_id0=[$7], QUANTITY=[$4])\n" +
+                       "            PhoenixServerJoin(condition=[=($2, $7)], joinType=[inner])\n" +
+                       "              PhoenixTableScan(table=[[phoenix, Join, OrderTable]])\n" +
+                       "              PhoenixServerAggregate(group=[{0}])\n" +
+                       "                PhoenixServerProject(item_id=[$0])\n" +
+                       "                  PhoenixTableScan(table=[[phoenix, Join, ItemTable]])\n")
             .resultIs(new Object[][] {
                     new Object[] {"0000000001", "T1", 1000}, 
                     new Object[] {"0000000002", "T2", 3000}, 
@@ -681,27 +731,29 @@ public class CalciteTest extends BaseClientManagedTimeIT {
                     new Object[] {"0000000005", "T5", null}, 
                     new Object[] {"0000000006", "T6", 4000}, 
                     new Object[] {"invalid001", "INVALID-1", null}})
-            .close();;
-            start().sql("select \"item_id\", name, (select quantity sq \n"
+            .close();
+        
+        start().sql("select \"item_id\", name, (select quantity sq \n"
                     + "from " + JOIN_ORDER_TABLE_FULL_NAME + " o where o.\"item_id\" = i.\"item_id\")\n"
                     + "from " + JOIN_ITEM_TABLE_FULL_NAME + " i where \"item_id\" < '0000000006'")
-                    .explainIs("PhoenixToEnumerableConverter\n" +
-                               "  PhoenixServerProject(item_id=[$0], NAME=[$1], EXPR$2=[$8])\n" +
-                               "    PhoenixServerJoin(condition=[=($0, $7)], joinType=[left], isSingleValueRhs=[true])\n" +
-                               "      PhoenixTableScan(table=[[phoenix, Join, ItemTable]], filter=[<($0, '0000000006')])\n" +
-                               "      PhoenixServerProject(item_id0=[$7], SQ=[$4])\n" +
-                               "        PhoenixServerJoin(condition=[=($2, $7)], joinType=[inner])\n" +
-                               "          PhoenixTableScan(table=[[phoenix, Join, OrderTable]])\n" +
-                               "          PhoenixServerAggregate(group=[{0}])\n" +
-                               "            PhoenixServerProject(item_id=[$0])\n" +
-                               "              PhoenixTableScan(table=[[phoenix, Join, ItemTable]], filter=[<($0, '0000000006')])\n")
-                    .resultIs(new Object[][] {
-                            new Object[] {"0000000001", "T1", 1000}, 
-                            new Object[] {"0000000002", "T2", 3000}, 
-                            new Object[] {"0000000003", "T3", 5000}, 
-                            new Object[] {"0000000004", "T4", null}, 
-                            new Object[] {"0000000005", "T5", null}})
-                    .close();;
+               .explainIs("PhoenixToEnumerableConverter\n" +
+                          "  PhoenixToClientConverter\n" +
+                          "    PhoenixPostJoinProject(item_id=[$0], NAME=[$1], EXPR$2=[$8])\n" +
+                          "      PhoenixServerJoin(condition=[=($0, $7)], joinType=[left], isSingleValueRhs=[true])\n" +
+                          "        PhoenixTableScan(table=[[phoenix, Join, ItemTable]], filter=[<($0, '0000000006')])\n" +
+                          "        PhoenixPostJoinProject(item_id0=[$7], SQ=[$4])\n" +
+                          "          PhoenixServerJoin(condition=[=($2, $7)], joinType=[inner])\n" +
+                          "            PhoenixTableScan(table=[[phoenix, Join, OrderTable]])\n" +
+                          "            PhoenixServerAggregate(group=[{0}])\n" +
+                          "              PhoenixServerProject(item_id=[$0])\n" +
+                          "                PhoenixTableScan(table=[[phoenix, Join, ItemTable]], filter=[<($0, '0000000006')])\n")
+               .resultIs(new Object[][] {
+                         new Object[] {"0000000001", "T1", 1000}, 
+                         new Object[] {"0000000002", "T2", 3000}, 
+                         new Object[] {"0000000003", "T3", 5000}, 
+                         new Object[] {"0000000004", "T4", null}, 
+                         new Object[] {"0000000005", "T5", null}})
+               .close();;
     }
     
     @Test public void testConnectJoinHsqldb() {
@@ -717,7 +769,8 @@ public class CalciteTest extends BaseClientManagedTimeIT {
             .explainIs("EnumerableCalc(expr#0..8=[{inputs}], THE_YEAR=[$t6], Q=[$t4], EXPR$2=[$t8])\n" +
                        "  EnumerableJoin(condition=[=($6, $7)], joinType=[left])\n" +
                        "    PhoenixToEnumerableConverter\n" +
-                       "      PhoenixTableScan(table=[[phoenix, Join, OrderTable]])\n" +
+                       "      PhoenixToClientConverter\n" +
+                       "        PhoenixTableScan(table=[[phoenix, Join, OrderTable]])\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" +
@@ -745,8 +798,9 @@ public class CalciteTest extends BaseClientManagedTimeIT {
             }
         };
         start.sql("select * from aTable")
-            .explainIs("PhoenixToEnumerableConverter\n"
-                + "  PhoenixTableScan(table=[[HR, ATABLE]])\n")
+            .explainIs("PhoenixToEnumerableConverter\n" +
+                       "  PhoenixToClientConverter\n" +
+                       "    PhoenixTableScan(table=[[HR, ATABLE]])\n")
             // .resultIs("Xx")
             .close();
     }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/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 e4c0821..20e1943 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
@@ -6,15 +6,11 @@ import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.prepare.CalcitePrepareImpl;
 import org.apache.phoenix.calcite.rules.PhoenixAddScanLimitRule;
-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.PhoenixInnerSortRemoveRule;
 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;
 
 public class PhoenixPrepareImpl extends CalcitePrepareImpl {
 
@@ -35,19 +31,9 @@ public class PhoenixPrepareImpl extends CalcitePrepareImpl {
         planner.addRule(PhoenixFilterScanMergeRule.INSTANCE);
         planner.addRule(PhoenixAddScanLimitRule.LIMIT_SCAN);
         planner.addRule(PhoenixAddScanLimitRule.LIMIT_SERVERPROJECT_SCAN);
-        planner.addRule(PhoenixServerProjectRule.PROJECT_SCAN);
-        planner.addRule(PhoenixServerProjectRule.PROJECT_SERVERJOIN);
-        planner.addRule(PhoenixServerJoinRule.JOIN_SCAN);
-        planner.addRule(PhoenixServerJoinRule.JOIN_SERVERPROJECT_SCAN);
-        planner.addRule(PhoenixServerAggregateRule.AGGREGATE_SCAN);
-        planner.addRule(PhoenixServerAggregateRule.AGGREGATE_SERVERJOIN);
-        planner.addRule(PhoenixServerAggregateRule.AGGREGATE_SERVERPROJECT);
-        planner.addRule(PhoenixServerSortRule.SORT_SCAN);
-        planner.addRule(PhoenixServerSortRule.SORT_SERVERJOIN);
-        planner.addRule(PhoenixServerSortRule.SORT_SERVERPROJECT);
         planner.addRule(PhoenixCompactClientSortRule.SORT_SERVERAGGREGATE);
-        planner.addRule(PhoenixClientJoinRule.INSTANCE);
         planner.addRule(PhoenixJoinSingleValueAggregateMergeRule.INSTANCE);
+        planner.addRule(PhoenixInnerSortRemoveRule.INSTANCE);
 
         return planner;
     }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/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 e3d46b7..53c273b 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
@@ -50,8 +50,6 @@ public class PhoenixRelMdCollation {
 
         final ImmutableList<RelCollation> leftCollations =
                 RelMetadataQuery.collations(left);
-        assert RelCollations.contains(leftCollations, leftKeys)
-        : "cannot merge join: left input is not sorted on left keys";
         for (RelCollation collation : leftCollations) {
             if (!collation.getFieldCollations().isEmpty()) {
                 builder.add(collation);
@@ -60,8 +58,6 @@ public class PhoenixRelMdCollation {
         
         final ImmutableList<RelCollation> rightCollations =
                 RelMetadataQuery.collations(right);
-        assert RelCollations.contains(rightCollations, rightKeys)
-        : "cannot merge join: right input is not sorted on right keys";
         final int leftFieldCount = left.getRowType().getFieldCount();
         for (RelCollation collation : rightCollations) {
             if (!collation.getFieldCollations().isEmpty()) {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/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 7d36494..b807011 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
@@ -55,7 +55,6 @@ abstract public class PhoenixAbstractAggregate extends Aggregate implements Phoe
     
     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;
 
         for (AggregateCall aggCall : aggCalls) {
             if (aggCall.isDistinct()) {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/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 01f3536..829c401 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
@@ -27,10 +27,9 @@ abstract public class PhoenixAbstractJoin extends Join implements PhoenixRel {
     public final boolean isSingleValueRhs;
 
     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);
+        super(cluster, traits, left, right, condition, joinType, variablesStopped);
         this.joinInfo = JoinInfo.of(left, right, condition);
         this.isSingleValueRhs = isSingleValueRhs;
-        assert getConvention() == PhoenixRel.CONVENTION;
     }
     
     abstract public PhoenixAbstractJoin copy(RelTraitSet traits, RexNode condition, RelNode left,

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractProject.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractProject.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractProject.java
index 893dcd1..3c16563 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractProject.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractProject.java
@@ -26,7 +26,6 @@ import com.google.common.collect.Lists;
 abstract public class PhoenixAbstractProject extends Project implements PhoenixRel {
     protected PhoenixAbstractProject(RelOptCluster cluster, RelTraitSet traits, RelNode input, List<? extends RexNode> projects, RelDataType rowType) {
         super(cluster, traits, input, projects, rowType);
-        assert getConvention() == PhoenixRel.CONVENTION;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractSort.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractSort.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractSort.java
index 5a43269..c2ac235 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractSort.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixAbstractSort.java
@@ -29,7 +29,6 @@ abstract public class PhoenixAbstractSort extends Sort implements PhoenixRel {
     
     protected PhoenixAbstractSort(RelOptCluster cluster, RelTraitSet traits, RelNode child, RelCollation collation) {
         super(cluster, traits, child, collation, null, null);
-        assert getConvention() == PhoenixRel.CONVENTION;
         assert !getCollation().getFieldCollations().isEmpty();
     }
     

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientAggregate.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientAggregate.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientAggregate.java
index 360c9b8..db3de2c 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientAggregate.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientAggregate.java
@@ -29,7 +29,7 @@ public class PhoenixClientAggregate extends PhoenixAbstractAggregate {
             ImmutableBitSet groupSet, List<ImmutableBitSet> groupSets, 
             List<AggregateCall> aggCalls) {
         RelOptCluster cluster = input.getCluster();
-        RelTraitSet traits = cluster.traitSetOf(PhoenixRel.CONVENTION);
+        RelTraitSet traits = cluster.traitSetOf(PhoenixRel.CLIENT_CONVENTION);
         return new PhoenixClientAggregate(cluster, traits, input, indicator, 
                 groupSet, groupSets, aggCalls);
     }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/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 7bc0b5e..d664843 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
@@ -1,7 +1,6 @@
 package org.apache.phoenix.calcite.rel;
 
 import java.sql.SQLException;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
@@ -12,14 +11,11 @@ import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelCollations;
-import org.apache.calcite.rel.RelFieldCollation;
-import org.apache.calcite.rel.RelFieldCollation.Direction;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.JoinInfo;
 import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.util.ImmutableIntList;
 import org.apache.hadoop.hbase.client.Scan;
 import org.apache.phoenix.calcite.CalciteUtils;
 import org.apache.phoenix.calcite.metadata.PhoenixRelMdCollation;
@@ -44,40 +40,20 @@ import com.google.common.collect.Lists;
 
 public class PhoenixClientJoin extends PhoenixAbstractJoin {
     
-    public static PhoenixClientJoin create(RelNode left, RelNode right, 
+    public static PhoenixClientJoin create(final RelNode left, final RelNode right, 
             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);
-        final RelNode sortedRight = sortInput(right, joinInfo.rightKeys);
         final RelTraitSet traits =
-                cluster.traitSet().replace(PhoenixRel.CONVENTION)
+                cluster.traitSet().replace(PhoenixRel.CLIENT_CONVENTION)
                 .replaceIfs(RelCollationTraitDef.INSTANCE,
                         new Supplier<List<RelCollation>>() {
                     public List<RelCollation> get() {
-                        return PhoenixRelMdCollation.mergeJoin(sortedLeft, sortedRight, joinInfo.leftKeys, joinInfo.rightKeys);
+                        return PhoenixRelMdCollation.mergeJoin(left, right, joinInfo.leftKeys, joinInfo.rightKeys);
                     }
                 });
-        return new PhoenixClientJoin(cluster, traits, sortedLeft, sortedRight, condition, joinType, variablesStopped, isSingleValueRhs);
-    }
-    
-    private static RelNode sortInput(RelNode input, ImmutableIntList sortKeys) {
-        if (sortKeys.isEmpty()) {
-            return input;
-        }
-        
-        List<RelFieldCollation> fieldCollations = Lists.newArrayList();
-        for (Iterator<Integer> iter = sortKeys.iterator(); iter.hasNext();) {
-            fieldCollations.add(new RelFieldCollation(iter.next(), Direction.ASCENDING));
-        }
-        RelCollation collation = RelCollations.of(fieldCollations);
-        List<RelCollation> collations = input.getTraitSet().getTraits(RelCollationTraitDef.INSTANCE);
-        if (collations.contains(collation)) {
-            return input;
-        }
-        
-        return PhoenixClientSort.create(input, collation);
+        return new PhoenixClientJoin(cluster, traits, left, right, condition, joinType, variablesStopped, isSingleValueRhs);
     }
 
     private PhoenixClientJoin(RelOptCluster cluster, RelTraitSet traits,
@@ -102,6 +78,11 @@ public class PhoenixClientJoin extends PhoenixAbstractJoin {
 
     @Override
     public RelOptCost computeSelfCost(RelOptPlanner planner) {
+        if (joinType == JoinRelType.RIGHT
+                || (!joinInfo.leftKeys.isEmpty() && !RelCollations.contains(RelMetadataQuery.collations(getLeft()), joinInfo.leftKeys))
+                || (!joinInfo.rightKeys.isEmpty() && !RelCollations.contains(RelMetadataQuery.collations(getRight()), joinInfo.rightKeys)))
+            return planner.getCostFactory().makeInfiniteCost();
+        
         double rowCount = RelMetadataQuery.getRowCount(this);        
 
         double leftRowCount = RelMetadataQuery.getRowCount(getLeft());
@@ -118,14 +99,11 @@ public class PhoenixClientJoin extends PhoenixAbstractJoin {
         }            
         RelOptCost cost = planner.getCostFactory().makeCost(rowCount, 0, 0);
 
-        return cost.multiplyBy(PHOENIX_FACTOR);
+        return cost.multiplyBy(SERVER_FACTOR).multiplyBy(PHOENIX_FACTOR);
     }
 
     @Override
     public QueryPlan implement(Implementor implementor) {
-        assert getLeft().getConvention() == PhoenixRel.CONVENTION;
-        assert getRight().getConvention() == PhoenixRel.CONVENTION;
-        
         List<Expression> leftExprs = Lists.<Expression> newArrayList();
         List<Expression> rightExprs = Lists.<Expression> newArrayList();
 

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientProject.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientProject.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientProject.java
index 593fba7..ecdbc3b 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientProject.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientProject.java
@@ -24,7 +24,7 @@ public class PhoenixClientProject extends PhoenixAbstractProject {
             final List<? extends RexNode> projects, RelDataType rowType) {
         RelOptCluster cluster = input.getCluster();
         final RelTraitSet traits =
-                cluster.traitSet().replace(PhoenixRel.CONVENTION)
+                cluster.traitSet().replace(PhoenixRel.CLIENT_CONVENTION)
                 .replaceIfs(RelCollationTraitDef.INSTANCE,
                         new Supplier<List<RelCollation>>() {
                     public List<RelCollation> get() {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientSort.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientSort.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientSort.java
index bee20e4..052f078 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientSort.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixClientSort.java
@@ -27,7 +27,7 @@ public class PhoenixClientSort extends PhoenixAbstractSort {
         RelOptCluster cluster = input.getCluster();
         collation = RelCollationTraitDef.INSTANCE.canonize(collation);
         RelTraitSet traits =
-            input.getTraitSet().replace(PhoenixRel.CONVENTION).replace(collation);
+            input.getTraitSet().replace(PhoenixRel.CLIENT_CONVENTION).replace(collation);
         return new PhoenixClientSort(cluster, traits, input, collation);
     }
 

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixCompactClientSort.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixCompactClientSort.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixCompactClientSort.java
index 863cd22..39d7d08 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixCompactClientSort.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixCompactClientSort.java
@@ -21,7 +21,7 @@ public class PhoenixCompactClientSort extends PhoenixAbstractSort {
         RelOptCluster cluster = input.getCluster();
         collation = RelCollationTraitDef.INSTANCE.canonize(collation);
         RelTraitSet traits =
-            input.getTraitSet().replace(PhoenixRel.CONVENTION).replace(collation);
+            input.getTraitSet().replace(PhoenixRel.CLIENT_CONVENTION).replace(collation);
         return new PhoenixCompactClientSort(cluster, traits, input, collation);
     }
 

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixFilter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixFilter.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixFilter.java
index f54744d..d958fe7 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixFilter.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixFilter.java
@@ -29,7 +29,7 @@ public class PhoenixFilter extends Filter implements PhoenixRel {
     public static PhoenixFilter create(final RelNode input, final RexNode condition) {
         RelOptCluster cluster = input.getCluster();
         final RelTraitSet traits =
-                cluster.traitSet().replace(PhoenixRel.CONVENTION)
+                cluster.traitSet().replace(PhoenixRel.CLIENT_CONVENTION)
                 .replaceIfs(RelCollationTraitDef.INSTANCE,
                         new Supplier<List<RelCollation>>() {
                     public List<RelCollation> get() {
@@ -41,7 +41,6 @@ public class PhoenixFilter extends Filter implements PhoenixRel {
     
     private PhoenixFilter(RelOptCluster cluster, RelTraitSet traits, RelNode input, RexNode condition) {
         super(cluster, traits, input, condition);
-        assert getConvention() == PhoenixRel.CONVENTION;
     }
 
     public PhoenixFilter copy(RelTraitSet traitSet, RelNode input, RexNode condition) {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixJoin.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixJoin.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixJoin.java
deleted file mode 100644
index ff8ef29..0000000
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixJoin.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package org.apache.phoenix.calcite.rel;
-
-import java.util.Set;
-
-import org.apache.calcite.plan.RelOptCluster;
-import org.apache.calcite.plan.RelOptCost;
-import org.apache.calcite.plan.RelOptPlanner;
-import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.core.Join;
-import org.apache.calcite.rel.core.JoinRelType;
-import org.apache.calcite.rex.RexNode;
-import org.apache.phoenix.compile.QueryPlan;
-
-import com.google.common.collect.ImmutableSet;
-
-public class PhoenixJoin extends Join implements PhoenixRel {
-    
-    public static PhoenixJoin create(RelNode left, RelNode right, 
-            RexNode condition, JoinRelType joinType, Set<String> variablesStopped) {
-        RelOptCluster cluster = left.getCluster();
-        RelTraitSet traits = cluster.traitSetOf(PhoenixRel.CONVENTION);
-        return new PhoenixJoin(cluster, traits, left, right, condition, joinType, variablesStopped);
-    }
-
-    private PhoenixJoin(RelOptCluster cluster, RelTraitSet traits, RelNode left,
-            RelNode right, RexNode condition, JoinRelType joinType,
-            Set<String> variablesStopped) {
-        super(cluster, traits, left, right, condition, joinType,
-                variablesStopped);
-    }
-
-    @Override
-    public Join copy(RelTraitSet traits, RexNode condition, RelNode left,
-            RelNode right, JoinRelType joinRelType, boolean semiJoinDone) {
-        return create(left, right, condition, joinRelType, ImmutableSet.<String>of());
-    }
-
-    @Override
-    public RelOptCost computeSelfCost(RelOptPlanner planner) {
-        return planner.getCostFactory().makeCost(Double.POSITIVE_INFINITY, 0, 0);
-    }
-
-    @Override
-    public QueryPlan implement(Implementor implementor) {
-        throw new UnsupportedOperationException();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixLimit.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixLimit.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixLimit.java
index d09c3c6..52482c1 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixLimit.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixLimit.java
@@ -30,7 +30,7 @@ public class PhoenixLimit extends SingleRel implements PhoenixRel {
     public static PhoenixLimit create(final RelNode input, RexNode offset, RexNode fetch) {
         RelOptCluster cluster = input.getCluster();
         final RelTraitSet traits =
-                cluster.traitSet().replace(PhoenixRel.CONVENTION)
+                cluster.traitSet().replace(PhoenixRel.CLIENT_CONVENTION)
                 .replaceIfs(RelCollationTraitDef.INSTANCE,
                         new Supplier<List<RelCollation>>() {
                     public List<RelCollation> get() {
@@ -46,7 +46,6 @@ public class PhoenixLimit extends SingleRel implements PhoenixRel {
         this.fetch = fetch;
         Object value = fetch == null ? null : CalciteUtils.evaluateStatelessExpression(fetch);
         this.statelessFetch = value == null ? null : ((Number) value).intValue();        
-        assert getConvention() == PhoenixRel.CONVENTION;
     }
     
     @Override

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixPostJoinProject.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixPostJoinProject.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixPostJoinProject.java
new file mode 100644
index 0000000..daa2978
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixPostJoinProject.java
@@ -0,0 +1,70 @@
+package org.apache.phoenix.calcite.rel;
+
+import java.util.List;
+
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptCost;
+import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollationTraitDef;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.metadata.RelMdCollation;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexNode;
+import org.apache.phoenix.compile.QueryPlan;
+import org.apache.phoenix.execute.HashJoinPlan;
+import org.apache.phoenix.execute.TupleProjector;
+
+import com.google.common.base.Supplier;
+
+public class PhoenixPostJoinProject extends PhoenixAbstractProject {
+    
+    public static PhoenixPostJoinProject create(final RelNode input, 
+            final List<? extends RexNode> projects, RelDataType rowType) {
+        RelOptCluster cluster = input.getCluster();
+        final RelTraitSet traits =
+                cluster.traitSet().replace(PhoenixRel.PROJECTABLE_CONVENTION)
+                .replaceIfs(RelCollationTraitDef.INSTANCE,
+                        new Supplier<List<RelCollation>>() {
+                    public List<RelCollation> get() {
+                        return RelMdCollation.project(input, projects);
+                    }
+                });
+        return new PhoenixPostJoinProject(cluster, traits, input, projects, rowType);
+    }
+
+    private PhoenixPostJoinProject(RelOptCluster cluster, RelTraitSet traits,
+            RelNode input, List<? extends RexNode> projects, RelDataType rowType) {
+        super(cluster, traits, input, projects, rowType);
+    }
+
+    @Override
+    public PhoenixPostJoinProject copy(RelTraitSet traits, RelNode input,
+            List<RexNode> projects, RelDataType rowType) {
+        return create(input, projects, rowType);
+    }
+
+    @Override
+    public RelOptCost computeSelfCost(RelOptPlanner planner) {
+        return super.computeSelfCost(planner)
+                .multiplyBy(SERVER_FACTOR)
+                .multiplyBy(PHOENIX_FACTOR);
+    }
+
+    @Override
+    public QueryPlan implement(Implementor implementor) {
+        assert getConvention() == getInput().getConvention();
+        
+        implementor.pushContext(new ImplementorContext(implementor.getCurrentContext().isRetainPKColumns(), false));
+        QueryPlan plan = implementor.visitInput(0, (PhoenixRel) getInput());
+        implementor.popContext();
+        assert (plan instanceof HashJoinPlan
+                && !TupleProjector.hasProjector(plan.getContext().getScan(), false));
+        
+        TupleProjector tupleProjector = super.project(implementor);
+        TupleProjector.serializeProjectorIntoScan(plan.getContext().getScan(), tupleProjector, false);
+        return plan;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixRel.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixRel.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixRel.java
index d19f0b4..82afedc 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixRel.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixRel.java
@@ -21,8 +21,10 @@ import org.apache.phoenix.schema.TableRef;
  * over streams of {@link org.apache.phoenix.schema.tuple.Tuple}s.</p>
  */
 public interface PhoenixRel extends RelNode {
-  /** Calling convention for relational operations that occur in Phoenix. */
-  Convention CONVENTION = new Convention.Impl("PHOENIX", PhoenixRel.class);
+  /** Calling conventions for relational operations that occur in Phoenix. */
+  Convention SERVER_CONVENTION = new Convention.Impl("PHOENIX_SERVER", PhoenixRel.class);
+  Convention PROJECTABLE_CONVENTION = new Convention.Impl("PHOENIX_PROJECTABLE", PhoenixRel.class);
+  Convention CLIENT_CONVENTION = new Convention.Impl("PHOENIX_CLIENT", PhoenixRel.class);
   
   /** Metadata Provider for PhoenixRel */
   RelMetadataProvider METADATA_PROVIDER = new PhoenixRelMetadataProvider();

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerAggregate.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerAggregate.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerAggregate.java
index 0eb2808..776ec0d 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerAggregate.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerAggregate.java
@@ -25,7 +25,7 @@ public class PhoenixServerAggregate extends PhoenixAbstractAggregate {
             ImmutableBitSet groupSet, List<ImmutableBitSet> groupSets, 
             List<AggregateCall> aggCalls) {
         RelOptCluster cluster = input.getCluster();
-        RelTraitSet traits = cluster.traitSetOf(PhoenixRel.CONVENTION);
+        RelTraitSet traits = cluster.traitSetOf(PhoenixRel.CLIENT_CONVENTION);
         return new PhoenixServerAggregate(cluster, traits, input, indicator, 
                 groupSet, groupSets, aggCalls);
     }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/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 32ec08b..ef0abd3 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
@@ -38,7 +38,7 @@ public class PhoenixServerJoin extends PhoenixAbstractJoin {
             Set<String> variablesStopped, boolean isSingleValueRhs) {
         RelOptCluster cluster = left.getCluster();
         final RelTraitSet traits =
-                cluster.traitSet().replace(PhoenixRel.CONVENTION)
+                cluster.traitSet().replace(PhoenixRel.PROJECTABLE_CONVENTION)
                 .replaceIfs(RelCollationTraitDef.INSTANCE,
                         new Supplier<List<RelCollation>>() {
                     public List<RelCollation> get() {
@@ -54,7 +54,6 @@ public class PhoenixServerJoin extends PhoenixAbstractJoin {
             boolean isSingleValueRhs) {
         super(cluster, traits, left, right, condition, joinType,
                 variablesStopped, isSingleValueRhs);
-        assert joinType != JoinRelType.FULL && joinType != JoinRelType.RIGHT;
     }
 
     @Override
@@ -73,6 +72,10 @@ public class PhoenixServerJoin extends PhoenixAbstractJoin {
     public RelOptCost computeSelfCost(RelOptPlanner planner) {
         //TODO return infinite cost if RHS size exceeds memory limit.
         
+        if (joinType == JoinRelType.FULL || joinType == JoinRelType.RIGHT
+                || getLeft().getConvention() != PhoenixRel.SERVER_CONVENTION)
+            return planner.getCostFactory().makeInfiniteCost();
+        
         double rowCount = RelMetadataQuery.getRowCount(this);
 
         double leftRowCount = RelMetadataQuery.getRowCount(getLeft());
@@ -95,9 +98,6 @@ public class PhoenixServerJoin extends PhoenixAbstractJoin {
     
     @Override
     public QueryPlan implement(Implementor implementor) {
-        assert getLeft().getConvention() == PhoenixRel.CONVENTION;
-        assert getRight().getConvention() == PhoenixRel.CONVENTION;
-        
         List<Expression> leftExprs = Lists.<Expression> newArrayList();
         List<Expression> rightExprs = Lists.<Expression> newArrayList();
 

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerProject.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerProject.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerProject.java
index 2f201fc..a5d9039 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerProject.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerProject.java
@@ -13,7 +13,6 @@ import org.apache.calcite.rel.metadata.RelMdCollation;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexNode;
 import org.apache.phoenix.compile.QueryPlan;
-import org.apache.phoenix.execute.HashJoinPlan;
 import org.apache.phoenix.execute.ScanPlan;
 import org.apache.phoenix.execute.TupleProjector;
 
@@ -25,7 +24,7 @@ public class PhoenixServerProject extends PhoenixAbstractProject {
             final List<? extends RexNode> projects, RelDataType rowType) {
         RelOptCluster cluster = input.getCluster();
         final RelTraitSet traits =
-                cluster.traitSet().replace(PhoenixRel.CONVENTION)
+                cluster.traitSet().replace(PhoenixRel.SERVER_CONVENTION)
                 .replaceIfs(RelCollationTraitDef.INSTANCE,
                         new Supplier<List<RelCollation>>() {
                     public List<RelCollation> get() {
@@ -60,11 +59,11 @@ public class PhoenixServerProject extends PhoenixAbstractProject {
         implementor.pushContext(new ImplementorContext(implementor.getCurrentContext().isRetainPKColumns(), false));
         QueryPlan plan = implementor.visitInput(0, (PhoenixRel) getInput());
         implementor.popContext();
-        assert (plan instanceof ScanPlan || plan instanceof HashJoinPlan) 
-                && !TupleProjector.hasProjector(plan.getContext().getScan(), plan instanceof ScanPlan);
+        assert (plan instanceof ScanPlan
+                && !TupleProjector.hasProjector(plan.getContext().getScan(), true));
         
         TupleProjector tupleProjector = super.project(implementor);
-        TupleProjector.serializeProjectorIntoScan(plan.getContext().getScan(), tupleProjector, plan instanceof ScanPlan);
+        TupleProjector.serializeProjectorIntoScan(plan.getContext().getScan(), tupleProjector, true);
         return plan;
     }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerSort.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerSort.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerSort.java
index 4f40182..a57dd8d 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerSort.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixServerSort.java
@@ -21,7 +21,7 @@ public class PhoenixServerSort extends PhoenixAbstractSort {
         RelOptCluster cluster = input.getCluster();
         collation = RelCollationTraitDef.INSTANCE.canonize(collation);
         RelTraitSet traits =
-            input.getTraitSet().replace(PhoenixRel.CONVENTION).replace(collation);
+            input.getTraitSet().replace(PhoenixRel.CLIENT_CONVENTION).replace(collation);
         return new PhoenixServerSort(cluster, traits, input, collation);
     }
 

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixTableScan.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixTableScan.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixTableScan.java
index 51cca21..d646a99 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixTableScan.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixTableScan.java
@@ -60,7 +60,7 @@ public class PhoenixTableScan extends TableScan implements PhoenixRel {
     public static PhoenixTableScan create(RelOptCluster cluster, final RelOptTable table, 
             RexNode filter, Integer statelessFetch) {
         final RelTraitSet traits =
-                cluster.traitSetOf(PhoenixRel.CONVENTION)
+                cluster.traitSetOf(PhoenixRel.SERVER_CONVENTION)
                 .replaceIfs(RelCollationTraitDef.INSTANCE,
                         new Supplier<List<RelCollation>>() {
                     public List<RelCollation> get() {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixToClientConverter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixToClientConverter.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixToClientConverter.java
new file mode 100644
index 0000000..f395787
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixToClientConverter.java
@@ -0,0 +1,45 @@
+package org.apache.phoenix.calcite.rel;
+
+import java.util.List;
+
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptCost;
+import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.SingleRel;
+import org.apache.phoenix.compile.QueryPlan;
+
+public class PhoenixToClientConverter extends SingleRel implements
+        PhoenixRel {
+    
+    public static PhoenixToClientConverter create(RelNode input) {
+        return new PhoenixToClientConverter(
+                input.getCluster(), 
+                input.getTraitSet().replace(PhoenixRel.CLIENT_CONVENTION), 
+                input);
+    }
+
+    private PhoenixToClientConverter(RelOptCluster cluster,
+            RelTraitSet traits, RelNode input) {
+        super(cluster, traits, input);
+    }
+    
+    @Override
+    public PhoenixToClientConverter copy(
+            RelTraitSet traitSet,
+            List<RelNode> newInputs) {
+        return create(sole(newInputs));
+    }
+
+    @Override 
+    public RelOptCost computeSelfCost(RelOptPlanner planner) {
+        return planner.getCostFactory().makeCost(0, 0, 0);
+    }
+    
+    @Override
+    public QueryPlan implement(Implementor implementor) {
+        return implementor.visitInput(0, (PhoenixRel) getInput());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixUnion.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixUnion.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixUnion.java
index b961679..9a19a95 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixUnion.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixUnion.java
@@ -17,13 +17,12 @@ public class PhoenixUnion extends Union implements PhoenixRel {
     
     public static PhoenixUnion create(List<RelNode> inputs, boolean all) {
         RelOptCluster cluster = inputs.get(0).getCluster();
-        RelTraitSet traits = cluster.traitSetOf(PhoenixRel.CONVENTION);
+        RelTraitSet traits = cluster.traitSetOf(PhoenixRel.CLIENT_CONVENTION);
         return new PhoenixUnion(cluster, traits, inputs, all);
     }
     
     private PhoenixUnion(RelOptCluster cluster, RelTraitSet traits, List<RelNode> inputs, boolean all) {
         super(cluster, traits, inputs, all);
-        assert getConvention() == PhoenixRel.CONVENTION;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixValues.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixValues.java b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixValues.java
index 52cd5a4..c982a28 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixValues.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixValues.java
@@ -19,13 +19,12 @@ import com.google.common.collect.ImmutableList;
 public class PhoenixValues extends Values implements PhoenixRel {
     
     public static PhoenixValues create(RelOptCluster cluster, RelDataType rowType, ImmutableList<ImmutableList<RexLiteral>> tuples) {
-        RelTraitSet traits = cluster.traitSetOf(PhoenixRel.CONVENTION);
+        RelTraitSet traits = cluster.traitSetOf(PhoenixRel.CLIENT_CONVENTION);
         return new PhoenixValues(cluster, rowType, tuples, traits);
     }
     
     private PhoenixValues(RelOptCluster cluster, RelDataType rowType, ImmutableList<ImmutableList<RexLiteral>> tuples, RelTraitSet traits) {
         super(cluster, rowType, tuples, traits);
-        assert getConvention() == PhoenixRel.CONVENTION;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/phoenix/blob/c1396ecf/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
deleted file mode 100644
index 86f0f08..0000000
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rules/PhoenixClientJoinRule.java
+++ /dev/null
@@ -1,40 +0,0 @@
-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, null, NO_RIGHT_JOIN, any()), "PhoenixClientJoinRule");
-    }
-
-    @Override
-    public void onMatch(RelOptRuleCall call) {
-        PhoenixJoin join = call.rel(0);
-        RelNode left = join.getLeft();
-        RelNode right = join.getRight();
-
-        call.transformTo(PhoenixClientJoin.create(
-                left, right, join.getCondition(), 
-                join.getJoinType(), join.getVariablesStopped(), false));
-    }
-
-}