You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by li...@apache.org on 2015/07/11 01:27:32 UTC

[46/50] [abbrv] incubator-kylin git commit: KYLIN-881 Upgrade to Calcite 1.3.0

KYLIN-881 Upgrade to Calcite 1.3.0


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

Branch: refs/heads/0.7
Commit: f2b92061444f48fa016c3bc6a4dfff9331e63b41
Parents: 88baae9
Author: Li, Yang <ya...@ebay.com>
Authored: Tue Jul 7 16:07:23 2015 +0800
Committer: Li, Yang <ya...@ebay.com>
Committed: Tue Jul 7 16:07:23 2015 +0800

----------------------------------------------------------------------
 .../adapter/enumerable/EnumerableJoin.java      |  26 +-
 .../apache/calcite/runtime/SqlFunctions.java    | 119 +++-
 .../calcite/sql2rel/SqlToRelConverter.java      | 660 ++++++++++---------
 .../java/org/apache/kylin/jdbc/KylinClient.java |   2 +-
 .../org/apache/kylin/jdbc/KylinJdbcFactory.java |   5 +-
 .../java/org/apache/kylin/jdbc/KylinMeta.java   |  38 +-
 .../kylin/jdbc/KylinPreparedStatement.java      |  50 +-
 .../org/apache/kylin/jdbc/KylinResultSet.java   |   9 +-
 pom.xml                                         |   2 +-
 .../query/enumerator/LookupTableEnumerator.java |   2 +
 .../kylin/query/optrule/OLAPFilterRule.java     |   4 +-
 .../kylin/query/optrule/OLAPLimitRule.java      |   5 +-
 .../kylin/query/optrule/OLAPProjectRule.java    |   6 +-
 .../kylin/query/relnode/OLAPFilterRel.java      |   4 +-
 .../kylin/query/relnode/OLAPProjectRel.java     |  12 +-
 .../kylin/query/relnode/OLAPTableScan.java      |   6 +-
 16 files changed, 584 insertions(+), 366 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/f2b92061/atopcalcite/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java
----------------------------------------------------------------------
diff --git a/atopcalcite/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java b/atopcalcite/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java
index 918b4bf..2b2ca8d 100644
--- a/atopcalcite/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java
+++ b/atopcalcite/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java
@@ -1,6 +1,6 @@
 /*
  * OVERRIDE POINT:
- * - constructor was private instead of public 
+ * - constructor was private instead of protected 
  */
 
 /*
@@ -31,10 +31,10 @@ import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.InvalidRelException;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelNodes;
+import org.apache.calcite.rel.core.EquiJoin;
 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.rel.rules.EquiJoin;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.util.BuiltInMethod;
 import org.apache.calcite.util.ImmutableIntList;
@@ -47,7 +47,10 @@ import java.util.Set;
 /** Implementation of {@link org.apache.calcite.rel.core.Join} in
  * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}. */
 public class EnumerableJoin extends EquiJoin implements EnumerableRel {
-  public EnumerableJoin( // OVERRIDE POINT, the constructor was private
+  /** Creates an EnumerableJoin.
+   *
+   * <p>Use {@link #create} unless you know what you're doing. */
+  public EnumerableJoin(
       RelOptCluster cluster,
       RelTraitSet traits,
       RelNode left,
@@ -70,6 +73,23 @@ public class EnumerableJoin extends EquiJoin implements EnumerableRel {
         variablesStopped);
   }
 
+  /** Creates an EnumerableJoin. */
+  public static EnumerableJoin create(
+      RelNode left,
+      RelNode right,
+      RexNode condition,
+      ImmutableIntList leftKeys,
+      ImmutableIntList rightKeys,
+      JoinRelType joinType,
+      Set<String> variablesStopped)
+      throws InvalidRelException {
+    final RelOptCluster cluster = left.getCluster();
+    final RelTraitSet traitSet =
+        cluster.traitSetOf(EnumerableConvention.INSTANCE);
+    return new EnumerableJoin(cluster, traitSet, left, right, condition,
+        leftKeys, rightKeys, joinType, variablesStopped);
+  }
+
   @Override public EnumerableJoin copy(RelTraitSet traitSet, RexNode condition,
       RelNode left, RelNode right, JoinRelType joinType,
       boolean semiJoinDone) {

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/f2b92061/atopcalcite/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
----------------------------------------------------------------------
diff --git a/atopcalcite/src/main/java/org/apache/calcite/runtime/SqlFunctions.java b/atopcalcite/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
index 3b1a2e0..80b9fdd 100644
--- a/atopcalcite/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/atopcalcite/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -549,7 +549,6 @@ public class SqlFunctions {
 
   /** SQL <code>/</code> operator applied to BigDecimal values. */
   public static BigDecimal divide(BigDecimal b0, BigDecimal b1) {
-    // OVERRIDE POINT
     return (b0 == null || b1 == null) ? null : b0.divide(b1, MathContext.DECIMAL64);
   }
 
@@ -693,6 +692,124 @@ public class SqlFunctions {
     return bigDecimals[1];
   }
 
+  // FLOOR
+
+  public static double floor(double b0) {
+    return Math.floor(b0);
+  }
+
+  public static float floor(float b0) {
+    return (float) Math.floor(b0);
+  }
+
+  public static BigDecimal floor(BigDecimal b0) {
+    return b0.setScale(0, BigDecimal.ROUND_FLOOR);
+  }
+
+  /** SQL <code>FLOOR</code> operator applied to byte values. */
+  public static byte floor(byte b0, byte b1) {
+    return (byte) floor((int) b0, (int) b1);
+  }
+
+  /** SQL <code>FLOOR</code> operator applied to short values. */
+  public static short floor(short b0, short b1) {
+    return (short) floor((int) b0, (int) b1);
+  }
+
+  /** SQL <code>FLOOR</code> operator applied to int values. */
+  public static int floor(int b0, int b1) {
+    int r = b0 % b1;
+    if (r < 0) {
+      r += b1;
+    }
+    return b0 - r;
+  }
+
+  /** SQL <code>FLOOR</code> operator applied to long values. */
+  public static long floor(long b0, long b1) {
+    long r = b0 % b1;
+    if (r < 0) {
+      r += b1;
+    }
+    return b0 - r;
+  }
+
+  // temporary
+  public static BigDecimal floor(BigDecimal b0, int b1) {
+    return floor(b0, BigDecimal.valueOf(b1));
+  }
+
+  // temporary
+  public static int floor(int b0, BigDecimal b1) {
+    return floor(b0, b1.intValue());
+  }
+
+  public static BigDecimal floor(BigDecimal b0, BigDecimal b1) {
+    final BigDecimal[] bigDecimals = b0.divideAndRemainder(b1);
+    BigDecimal r = bigDecimals[1];
+    if (r.signum() < 0) {
+      r = r.add(b1);
+    }
+    return b0.subtract(r);
+  }
+
+  // CEIL
+
+  public static double ceil(double b0) {
+    return Math.ceil(b0);
+  }
+
+  public static float ceil(float b0) {
+    return (float) Math.ceil(b0);
+  }
+
+  public static BigDecimal ceil(BigDecimal b0) {
+    return b0.setScale(0, BigDecimal.ROUND_CEILING);
+  }
+
+  /** SQL <code>CEIL</code> operator applied to byte values. */
+  public static byte ceil(byte b0, byte b1) {
+    return floor((byte) (b0 + b1 - 1), b1);
+  }
+
+  /** SQL <code>CEIL</code> operator applied to short values. */
+  public static short ceil(short b0, short b1) {
+    return floor((short) (b0 + b1 - 1), b1);
+  }
+
+  /** SQL <code>CEIL</code> operator applied to int values. */
+  public static int ceil(int b0, int b1) {
+    int r = b0 % b1;
+    if (r > 0) {
+      r -= b1;
+    }
+    return b0 - r;
+  }
+
+  /** SQL <code>CEIL</code> operator applied to long values. */
+  public static long ceil(long b0, long b1) {
+    return floor(b0 + b1 - 1, b1);
+  }
+
+  // temporary
+  public static BigDecimal ceil(BigDecimal b0, int b1) {
+    return ceil(b0, BigDecimal.valueOf(b1));
+  }
+
+  // temporary
+  public static int ceil(int b0, BigDecimal b1) {
+    return ceil(b0, b1.intValue());
+  }
+
+  public static BigDecimal ceil(BigDecimal b0, BigDecimal b1) {
+    final BigDecimal[] bigDecimals = b0.divideAndRemainder(b1);
+    BigDecimal r = bigDecimals[1];
+    if (r.signum() > 0) {
+      r = r.subtract(b1);
+    }
+    return b0.subtract(r);
+  }
+
   // ABS
 
   /** SQL <code>ABS</code> operator applied to byte values. */

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/f2b92061/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index 2508629..c643f94 100644
--- a/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -27,14 +27,13 @@ import org.apache.calcite.linq4j.Ord;
 import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptPlanner;
-import org.apache.calcite.plan.RelOptQuery;
 import org.apache.calcite.plan.RelOptSamplingParameters;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.prepare.Prepare;
 import org.apache.calcite.prepare.RelOptTableImpl;
 import org.apache.calcite.rel.RelCollation;
-import org.apache.calcite.rel.RelCollationImpl;
+import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelShuttle;
@@ -47,7 +46,6 @@ 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.Sample;
-import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.core.Uncollect;
 import org.apache.calcite.rel.logical.LogicalAggregate;
 import org.apache.calcite.rel.logical.LogicalCorrelate;
@@ -55,12 +53,14 @@ import org.apache.calcite.rel.logical.LogicalIntersect;
 import org.apache.calcite.rel.logical.LogicalJoin;
 import org.apache.calcite.rel.logical.LogicalMinus;
 import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.rel.logical.LogicalSort;
 import org.apache.calcite.rel.logical.LogicalTableFunctionScan;
 import org.apache.calcite.rel.logical.LogicalTableModify;
 import org.apache.calcite.rel.logical.LogicalTableScan;
 import org.apache.calcite.rel.logical.LogicalUnion;
 import org.apache.calcite.rel.logical.LogicalValues;
 import org.apache.calcite.rel.metadata.RelColumnMapping;
+import org.apache.calcite.rel.stream.LogicalDelta;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeField;
@@ -80,6 +80,8 @@ import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.rex.RexVisitorImpl;
 import org.apache.calcite.rex.RexWindowBound;
 import org.apache.calcite.schema.ModifiableTable;
+import org.apache.calcite.schema.ModifiableView;
+import org.apache.calcite.schema.Table;
 import org.apache.calcite.schema.TranslatableTable;
 import org.apache.calcite.sql.JoinConditionType;
 import org.apache.calcite.sql.JoinType;
@@ -101,6 +103,7 @@ import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlMerge;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlNodeList;
+import org.apache.calcite.sql.SqlNumericLiteral;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlOperatorTable;
 import org.apache.calcite.sql.SqlSampleSpec;
@@ -109,6 +112,7 @@ import org.apache.calcite.sql.SqlSelectKeyword;
 import org.apache.calcite.sql.SqlSetOperator;
 import org.apache.calcite.sql.SqlUpdate;
 import org.apache.calcite.sql.SqlUtil;
+import org.apache.calcite.sql.SqlValuesOperator;
 import org.apache.calcite.sql.SqlWindow;
 import org.apache.calcite.sql.SqlWith;
 import org.apache.calcite.sql.SqlWithItem;
@@ -146,9 +150,9 @@ import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 import org.apache.calcite.util.mapping.Mappings;
 import org.apache.calcite.util.trace.CalciteTrace;
-import org.apache.calcite.sql.SqlNumericLiteral;
 
 import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
@@ -189,12 +193,6 @@ public class SqlToRelConverter {
   protected static final Logger SQL2REL_LOGGER =
       CalciteTrace.getSqlToRelTracer();
 
-  private static final Function<SubQuery, SqlNode> FN =
-      new Function<SubQuery, SqlNode>() {
-        public SqlNode apply(SubQuery input) {
-          return input.node;
-        }
-      };
   private static final BigDecimal TWO = BigDecimal.valueOf(2L);
 
   //~ Instance fields --------------------------------------------------------
@@ -205,9 +203,8 @@ public class SqlToRelConverter {
   protected final RelOptCluster cluster;
   private DefaultValueFactory defaultValueFactory;
   private SubqueryConverter subqueryConverter;
-  protected final List<RelNode> leaves = new ArrayList<RelNode>();
-  private final List<SqlDynamicParam> dynamicParamSqlNodes =
-      new ArrayList<SqlDynamicParam>();
+  protected final List<RelNode> leaves = new ArrayList<>();
+  private final List<SqlDynamicParam> dynamicParamSqlNodes = new ArrayList<>();
   private final SqlOperatorTable opTab;
   private boolean shouldConvertTableAccess;
   protected final RelDataTypeFactory typeFactory;
@@ -222,7 +219,7 @@ public class SqlToRelConverter {
    * Fields used in name resolution for correlated subqueries.
    */
   private final Map<String, DeferredLookup> mapCorrelToDeferred =
-      new HashMap<String, DeferredLookup>();
+      new HashMap<>();
   private int nextCorrel = 0;
 
   private static final String CORREL_PREFIX = "$cor";
@@ -231,7 +228,7 @@ public class SqlToRelConverter {
    * Stack of names of datasets requested by the <code>
    * TABLE(SAMPLE(&lt;datasetName&gt;, &lt;query&gt;))</code> construct.
    */
-  private final Stack<String> datasetStack = new Stack<String>();
+  private final Stack<String> datasetStack = new Stack<>();
 
   /**
    * Mapping of non-correlated subqueries that have been converted to their
@@ -239,7 +236,7 @@ public class SqlToRelConverter {
    * already been evaluated.
    */
   private final Map<SqlNode, RexNode> mapConvertedNonCorrSubqs =
-      new HashMap<SqlNode, RexNode>();
+      new HashMap<>();
 
   public final RelOptTable.ViewExpander viewExpander;
 
@@ -254,6 +251,7 @@ public class SqlToRelConverter {
    * @param rexBuilder      Rex builder
    * @param convertletTable Expression converter
    */
+  @Deprecated // will be removed before 2.0
   public SqlToRelConverter(
       RelOptTable.ViewExpander viewExpander,
       SqlValidator validator,
@@ -261,6 +259,17 @@ public class SqlToRelConverter {
       RelOptPlanner planner,
       RexBuilder rexBuilder,
       SqlRexConvertletTable convertletTable) {
+    this(viewExpander, validator, catalogReader,
+        RelOptCluster.create(planner, rexBuilder), convertletTable);
+  }
+
+  /* Creates a converter. */
+  public SqlToRelConverter(
+      RelOptTable.ViewExpander viewExpander,
+      SqlValidator validator,
+      Prepare.CatalogReader catalogReader,
+      RelOptCluster cluster,
+      SqlRexConvertletTable convertletTable) {
     this.viewExpander = viewExpander;
     this.opTab =
         (validator
@@ -270,10 +279,9 @@ public class SqlToRelConverter {
     this.catalogReader = catalogReader;
     this.defaultValueFactory = new NullDefaultValueFactory();
     this.subqueryConverter = new NoOpSubqueryConverter();
-    this.rexBuilder = rexBuilder;
+    this.rexBuilder = cluster.getRexBuilder();
     this.typeFactory = rexBuilder.getTypeFactory();
-    RelOptQuery query = new RelOptQuery(planner);
-    this.cluster = query.createCluster(typeFactory, rexBuilder);
+    this.cluster = Preconditions.checkNotNull(cluster);
     this.shouldConvertTableAccess = true;
     this.exprConverter =
         new SqlNodeToRexConverterImpl(convertletTable);
@@ -532,6 +540,9 @@ public class SqlToRelConverter {
     }
 
     RelNode result = convertQueryRecursive(query, top, null);
+    if (top && isStream(query)) {
+      result = new LogicalDelta(cluster, result.getTraitSet(), result);
+    }
     checkConvertedType(query, result);
 
     boolean dumpPlan = SQL2REL_LOGGER.isLoggable(Level.FINE);
@@ -547,6 +558,11 @@ public class SqlToRelConverter {
     return result;
   }
 
+  private static boolean isStream(SqlNode query) {
+    return query instanceof SqlSelect
+        && ((SqlSelect) query).isKeywordPresent(SqlSelectKeyword.STREAM);
+  }
+
   protected boolean checkConvertedRowType(
       SqlNode query,
       RelDataType convertedRowType) {
@@ -554,11 +570,7 @@ public class SqlToRelConverter {
     validatedRowType = uniquifyFields(validatedRowType);
 
     return RelOptUtil.equal(
-        "validated row type",
-        validatedRowType,
-        "converted row type",
-        convertedRowType,
-        false);
+        "validated row type", validatedRowType, "converted row type", convertedRowType, false);
   }
 
   protected RelDataType uniquifyFields(RelDataType rowType) {
@@ -600,9 +612,8 @@ public class SqlToRelConverter {
         bb,
         select.getWhere());
 
-    List<SqlNode> orderExprList = new ArrayList<SqlNode>();
-    List<RelFieldCollation> collationList =
-        new ArrayList<RelFieldCollation>();
+    final List<SqlNode> orderExprList = new ArrayList<>();
+    final List<RelFieldCollation> collationList = new ArrayList<>();
     gatherOrderExprs(
         bb,
         select,
@@ -610,7 +621,7 @@ public class SqlToRelConverter {
         orderExprList,
         collationList);
     final RelCollation collation =
-        cluster.traitSetOf().canonize(RelCollationImpl.of(collationList));
+        cluster.traitSet().canonize(RelCollations.of(collationList));
 
     if (validator.isAggregate(select)) {
       convertAgg(
@@ -656,7 +667,7 @@ public class SqlToRelConverter {
     if (checkForDupExprs && (rel instanceof LogicalProject)) {
       LogicalProject project = (LogicalProject) rel;
       final List<RexNode> projectExprs = project.getProjects();
-      List<Integer> origins = new ArrayList<Integer>();
+      final List<Integer> origins = new ArrayList<>();
       int dupCount = 0;
       for (int i = 0; i < projectExprs.size(); i++) {
         int x = findExpr(projectExprs.get(i), projectExprs, i);
@@ -682,13 +693,8 @@ public class SqlToRelConverter {
         }
       }
       rel =
-          new LogicalProject(
-              cluster,
-              rel,
-              Pair.left(newProjects),
-              Pair.right(newProjects),
-              LogicalProject.Flags.BOXED);
-
+          LogicalProject.create(rel, Pair.left(newProjects),
+              Pair.right(newProjects));
       bb.root = rel;
       distinctify(bb, false);
       rel = bb.root;
@@ -707,13 +713,8 @@ public class SqlToRelConverter {
       }
 
       rel =
-          new LogicalProject(
-              cluster,
-              rel,
-              Pair.left(undoProjects),
-              Pair.right(undoProjects),
-              LogicalProject.Flags.BOXED);
-
+          LogicalProject.create(rel, Pair.left(undoProjects),
+              Pair.right(undoProjects));
       bb.setRoot(
           rel,
           false);
@@ -772,11 +773,7 @@ public class SqlToRelConverter {
 
     // Create a sorter using the previously constructed collations.
     bb.setRoot(
-        new Sort(
-            cluster,
-            cluster.traitSetOf(Convention.NONE, collation),
-            bb.root,
-            collation,
+        LogicalSort.create(bb.root, collation,
             offset == null ? null : convertExpression(offset),
             fetch == null ? null : convertExpression(fetch)),
         false);
@@ -784,7 +781,7 @@ public class SqlToRelConverter {
     // If extra expressions were added to the project list for sorting,
     // add another project to remove them.
     if (orderExprList.size() > 0) {
-      List<RexNode> exprs = new ArrayList<RexNode>();
+      final List<RexNode> exprs = new ArrayList<>();
       final RelDataType rowType = bb.root.getRowType();
       final int fieldCount =
           rowType.getFieldCount() - orderExprList.size();
@@ -794,12 +791,11 @@ public class SqlToRelConverter {
       bb.setRoot(
           new LogicalProject(
               cluster,
-              cluster.traitSetOf(RelCollationImpl.PRESERVE),
+              cluster.traitSetOf(RelCollations.PRESERVE),
               bb.root,
               exprs,
               cluster.getTypeFactory().createStructType(
-                  rowType.getFieldList().subList(0, fieldCount)),
-              Project.Flags.BOXED),
+                  rowType.getFieldList().subList(0, fieldCount))),
           false);
     }
   }
@@ -1045,16 +1041,17 @@ public class SqlToRelConverter {
         final int keyCount = leftKeys.size();
         final List<Integer> args = ImmutableIntList.range(0, keyCount);
         LogicalAggregate aggregate =
-            new LogicalAggregate(cluster, seek, false, ImmutableBitSet.of(),
-                null,
+            LogicalAggregate.create(seek, false, ImmutableBitSet.of(), null,
                 ImmutableList.of(
-                    new AggregateCall(SqlStdOperatorTable.COUNT, false,
-                        ImmutableList.<Integer>of(), longType, null),
-                    new AggregateCall(SqlStdOperatorTable.COUNT, false,
-                        args, longType, null)));
+                    AggregateCall.create(SqlStdOperatorTable.COUNT, false,
+                        ImmutableList.<Integer>of(), -1, longType, null),
+                    AggregateCall.create(SqlStdOperatorTable.COUNT, false,
+                        args, -1, longType, null)));
         LogicalJoin join =
-            new LogicalJoin(cluster, bb.root, aggregate,
-                rexBuilder.makeLiteral(true), JoinRelType.INNER,
+            LogicalJoin.create(bb.root,
+                aggregate,
+                rexBuilder.makeLiteral(true),
+                JoinRelType.INNER,
                 ImmutableSet.<String>of());
         bb.setRoot(join, false);
       }
@@ -1169,7 +1166,7 @@ public class SqlToRelConverter {
       //   on e.deptno = dt.deptno
       final Join join = (Join) root;
       final Project left = (Project) join.getLeft();
-      final RelNode leftLeft = ((Join) left.getInput(0)).getLeft();
+      final RelNode leftLeft = ((Join) left.getInput()).getLeft();
       final int leftLeftCount = leftLeft.getRowType().getFieldCount();
       final RelDataType nullableBooleanType =
           typeFactory.createTypeWithNullability(
@@ -1286,12 +1283,31 @@ public class SqlToRelConverter {
         SqlNode selectExpr = selectList.get(0);
         if (selectExpr instanceof SqlCall) {
           SqlCall selectExprCall = (SqlCall) selectExpr;
-          if (selectExprCall.getOperator()
-              instanceof SqlAggFunction) {
+          if (Util.isSingleValue(selectExprCall)) {
+            return plan;
+          }
+        }
+
+        // If there is a limit with 0 or 1,
+        // it is ensured to produce a single value
+        if (select.getFetch() != null
+            && select.getFetch() instanceof SqlNumericLiteral) {
+          SqlNumericLiteral limitNum = (SqlNumericLiteral) select.getFetch();
+          if (((BigDecimal) limitNum.getValue()).intValue() < 2) {
             return plan;
           }
         }
       }
+    } else if (query instanceof SqlCall) {
+      // If the query is (values ...),
+      // it is necessary to look into the operands to determine
+      // whether SingleValueAgg is necessary
+      SqlCall exprCall = (SqlCall) query;
+      if (exprCall.getOperator()
+          instanceof SqlValuesOperator
+              && Util.isSingleValue(exprCall)) {
+        return plan;
+      }
     }
 
     // If not, project SingleValueAgg
@@ -1313,7 +1329,7 @@ public class SqlToRelConverter {
       final List<RexNode> leftKeys,
       SqlNodeList valuesList,
       boolean isNotIn) {
-    List<RexNode> comparisons = new ArrayList<RexNode>();
+    final List<RexNode> comparisons = new ArrayList<>();
     for (SqlNode rightVals : valuesList) {
       RexNode rexComparison;
       if (leftKeys.size() == 1) {
@@ -1321,7 +1337,8 @@ public class SqlToRelConverter {
             rexBuilder.makeCall(
                 SqlStdOperatorTable.EQUALS,
                 leftKeys.get(0),
-                bb.convertExpression(rightVals));
+                rexBuilder.ensureType(leftKeys.get(0).getType(),
+                    bb.convertExpression(rightVals), true));
       } else {
         assert rightVals instanceof SqlCall;
         final SqlBasicCall call = (SqlBasicCall) rightVals;
@@ -1335,7 +1352,9 @@ public class SqlToRelConverter {
                     new Function<Pair<RexNode, SqlNode>, RexNode>() {
                       public RexNode apply(Pair<RexNode, SqlNode> pair) {
                         return rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
-                            pair.left, bb.convertExpression(pair.right));
+                            pair.left,
+                            rexBuilder.ensureType(pair.left.getType(),
+                                bb.convertExpression(pair.right), true));
                       }
                     }),
                 false);
@@ -1368,8 +1387,8 @@ public class SqlToRelConverter {
    * @return threshold, default 20
    */
   protected int getInSubqueryThreshold() {
-    // OVERRIDE POINT
-    return Integer.MAX_VALUE; // was 20
+    /* OVERRIDE POINT */
+    return Integer.MAX_VALUE;
   }
 
   /**
@@ -1451,7 +1470,7 @@ public class SqlToRelConverter {
               null);
     }
 
-    List<RelNode> unionInputs = new ArrayList<RelNode>();
+    final List<RelNode> unionInputs = new ArrayList<>();
     for (SqlNode node : rows) {
       SqlBasicCall call;
       if (isRowConstructor(node)) {
@@ -1503,10 +1522,7 @@ public class SqlToRelConverter {
       unionInputs.add(convertRowConstructor(bb, call));
     }
     LogicalValues values =
-        new LogicalValues(
-            cluster,
-            rowType,
-            tupleList.build());
+        LogicalValues.create(cluster, rowType, tupleList.build());
     RelNode resultRel;
     if (unionInputs.isEmpty()) {
       resultRel = values;
@@ -1514,12 +1530,7 @@ public class SqlToRelConverter {
       if (!values.getTuples().isEmpty()) {
         unionInputs.add(values);
       }
-      LogicalUnion union =
-          new LogicalUnion(
-              cluster,
-              unionInputs,
-              true);
-      resultRel = union;
+      resultRel = LogicalUnion.create(unionInputs, true);
     }
     leaves.add(resultRel);
     return resultRel;
@@ -1710,8 +1721,7 @@ public class SqlToRelConverter {
   public RexNode convertExpression(
       SqlNode node,
       Map<String, RexNode> nameToNodeMap) {
-    final Map<String, RelDataType> nameToTypeMap =
-        new HashMap<String, RelDataType>();
+    final Map<String, RelDataType> nameToTypeMap = new HashMap<>();
     for (Map.Entry<String, RexNode> entry : nameToNodeMap.entrySet()) {
       nameToTypeMap.put(entry.getKey(), entry.getValue().getType());
     }
@@ -1878,7 +1888,7 @@ public class SqlToRelConverter {
       if (shouldConvertTableAccess) {
         tableRel = toRel(table);
       } else {
-        tableRel = new LogicalTableScan(cluster, table);
+        tableRel = LogicalTableScan.create(cluster, table);
       }
       bb.setRoot(tableRel, true);
       if (usedDataset[0]) {
@@ -2020,7 +2030,7 @@ public class SqlToRelConverter {
     Set<RelColumnMapping> columnMappings =
         getColumnMappings(operator);
     LogicalTableFunctionScan callRel =
-        new LogicalTableFunctionScan(
+        LogicalTableFunctionScan.create(
             cluster,
             inputs,
             rexCall,
@@ -2161,12 +2171,8 @@ public class SqlToRelConverter {
                   ImmutableSet.copyOf(Util.skip(correlNames)));
           rightRel = rightRel.accept(dedup);
         }
-        LogicalCorrelate corr = new LogicalCorrelate(
-            rightRel.getCluster(),
-            leftRel,
-            rightRel,
-            new CorrelationId(correlNames.get(0)),
-            requiredColumns.build(),
+        LogicalCorrelate corr = LogicalCorrelate.create(leftRel, rightRel,
+            new CorrelationId(correlNames.get(0)), requiredColumns.build(),
             SemiJoinType.of(joinType));
         if (!joinCond.isAlwaysTrue()) {
           return RelOptUtil.createFilter(corr, joinCond);
@@ -2175,8 +2181,8 @@ public class SqlToRelConverter {
       }
     }
 
-    final List<RexNode> extraLeftExprs = new ArrayList<RexNode>();
-    final List<RexNode> extraRightExprs = new ArrayList<RexNode>();
+    final List<RexNode> extraLeftExprs = new ArrayList<>();
+    final List<RexNode> extraRightExprs = new ArrayList<>();
     final int leftCount = leftRel.getRowType().getFieldCount();
     final int rightCount = rightRel.getRowType().getFieldCount();
     if (!containsGet(joinCond)) {
@@ -2200,8 +2206,7 @@ public class SqlToRelConverter {
                     new RexInputRef(index, field.getType()),
                     field.getName());
               } else {
-                return Pair.<RexNode, String>of(
-                    extraLeftExprs.get(index - leftCount), null);
+                return Pair.of(extraLeftExprs.get(index - leftCount), null);
               }
             }
           },
@@ -2248,7 +2253,7 @@ public class SqlToRelConverter {
                   + rightCount + extraRightExprs.size(),
               0, 0, leftCount,
               leftCount, leftCount + extraLeftExprs.size(), rightCount);
-      return RelOptUtil.project(join, mapping);
+      return RelOptUtil.createProject(join, mapping);
     }
     return join;
   }
@@ -2287,8 +2292,8 @@ public class SqlToRelConverter {
     case AND:
     case OR:
     case EQUALS:
-      RexCall call = (RexCall) node;
-      List<RexNode> list = new ArrayList<RexNode>();
+      final RexCall call = (RexCall) node;
+      final List<RexNode> list = new ArrayList<>();
       List<RexNode> operands = Lists.newArrayList(call.getOperands());
       for (int i = 0; i < operands.size(); i++) {
         RexNode operand = operands.get(i);
@@ -2439,8 +2444,8 @@ public class SqlToRelConverter {
       bb.setRoot(ImmutableList.of(leftRel, rightRel));
       return bb.convertExpression(condition);
     case USING:
-      SqlNodeList list = (SqlNodeList) condition;
-      List<String> nameList = new ArrayList<String>();
+      final SqlNodeList list = (SqlNodeList) condition;
+      final List<String> nameList = new ArrayList<>();
       for (SqlNode columnName : list) {
         final SqlIdentifier id = (SqlIdentifier) columnName;
         String name = id.getSimple();
@@ -2547,17 +2552,16 @@ public class SqlToRelConverter {
       SqlNodeList groupList,
       SqlNode having,
       List<SqlNode> orderExprList) {
-    SqlNodeList aggList = new SqlNodeList(SqlParserPos.ZERO);
-
-    for (SqlNode selectNode : selectList) {
-      if (validator.isAggregate(selectNode)) {
-        aggList.add(selectNode);
-      }
+    // Find aggregate functions in SELECT and HAVING clause
+    final AggregateFinder aggregateFinder = new AggregateFinder();
+    selectList.accept(aggregateFinder);
+    if (having != null) {
+      having.accept(aggregateFinder);
     }
 
     // first replace the subqueries inside the aggregates
     // because they will provide input rows to the aggregates.
-    replaceSubqueries(bb, aggList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
+    replaceSubqueries(bb, aggregateFinder.list, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
 
     // If group-by clause is missing, pretend that it has zero elements.
     if (groupList == null) {
@@ -2704,6 +2708,7 @@ public class SqlToRelConverter {
       // (yet) appear in the validator type.
       final SelectScope selectScope =
           SqlValidatorUtil.getEnclosingSelectScope(bb.scope);
+      assert selectScope != null;
       final SqlValidatorNamespace selectNamespace =
           validator.getNamespace(selectScope.getNode());
       final List<String> names =
@@ -2769,13 +2774,8 @@ public class SqlToRelConverter {
   protected RelNode createAggregate(Blackboard bb, boolean indicator,
       ImmutableBitSet groupSet, ImmutableList<ImmutableBitSet> groupSets,
       List<AggregateCall> aggCalls) {
-    return new LogicalAggregate(
-        cluster,
-        bb.root,
-        indicator,
-        groupSet,
-        groupSets,
-        aggCalls);
+    return LogicalAggregate.create(
+        bb.root, indicator, groupSet, groupSets, aggCalls);
   }
 
   public RexDynamicParam convertDynamicParam(
@@ -2917,8 +2917,8 @@ public class SqlToRelConverter {
    * @return Whether to trim unused fields
    */
   public boolean isTrimUnusedFields() {
-    // OVERRIDE POINT
-    return false; // was `trimUnusedFields`
+    /* OVERRIDE POINT */
+    return false;
   }
 
   /**
@@ -2974,18 +2974,12 @@ public class SqlToRelConverter {
     }
     switch (call.getKind()) {
     case UNION:
-      return new LogicalUnion(
-          cluster,
-          ImmutableList.of(left, right),
-          all);
+      return LogicalUnion.create(ImmutableList.of(left, right), all);
 
     case INTERSECT:
       // TODO:  all
       if (!all) {
-        return new LogicalIntersect(
-            cluster,
-            ImmutableList.of(left, right),
-            all);
+        return LogicalIntersect.create(ImmutableList.of(left, right), all);
       } else {
         throw Util.newInternal(
             "set operator INTERSECT ALL not suported");
@@ -2994,10 +2988,7 @@ public class SqlToRelConverter {
     case EXCEPT:
       // TODO:  all
       if (!all) {
-        return new LogicalMinus(
-            cluster,
-            ImmutableList.of(left, right),
-            all);
+        return LogicalMinus.create(ImmutableList.of(left, right), all);
       } else {
         throw Util.newInternal(
             "set operator EXCEPT ALL not suported");
@@ -3016,31 +3007,86 @@ public class SqlToRelConverter {
     assert targetRowType != null;
     RelNode sourceRel =
         convertQueryRecursive(
-            call.getSource(),
-            false,
-            targetRowType);
+            call.getSource(), false, targetRowType);
     RelNode massagedRel = convertColumnList(call, sourceRel);
 
+    return createModify(targetTable, massagedRel);
+  }
+
+  /** Creates a relational expression to modify a table or modifiable view. */
+  private RelNode createModify(RelOptTable targetTable, RelNode source) {
     final ModifiableTable modifiableTable =
         targetTable.unwrap(ModifiableTable.class);
     if (modifiableTable != null) {
-      return modifiableTable.toModificationRel(
-          cluster,
-          targetTable,
-          catalogReader,
-          massagedRel,
-          LogicalTableModify.Operation.INSERT,
-          null,
+      return modifiableTable.toModificationRel(cluster, targetTable,
+          catalogReader, source, LogicalTableModify.Operation.INSERT, null,
           false);
     }
-    return new LogicalTableModify(
-        cluster,
-        targetTable,
-        catalogReader,
-        massagedRel,
-        LogicalTableModify.Operation.INSERT,
-        null,
-        false);
+    final ModifiableView modifiableView =
+        targetTable.unwrap(ModifiableView.class);
+    if (modifiableView != null) {
+      final Table delegateTable = modifiableView.getTable();
+      final RelDataType delegateRowType = delegateTable.getRowType(typeFactory);
+      final RelOptTable delegateRelOptTable =
+          RelOptTableImpl.create(null, delegateRowType, delegateTable,
+              modifiableView.getTablePath());
+      final RelNode newSource =
+          createSource(targetTable, source, modifiableView, delegateRowType);
+      return createModify(delegateRelOptTable, newSource);
+    }
+    return LogicalTableModify.create(targetTable, catalogReader, source,
+        LogicalTableModify.Operation.INSERT, null, false);
+  }
+
+  /** Wraps a relational expression in the projects and filters implied by
+   * a {@link ModifiableView}.
+   *
+   * <p>The input relational expression is suitable for inserting into the view,
+   * and the returned relational expression is suitable for inserting into its
+   * delegate table.
+   *
+   * <p>In principle, the delegate table of a view might be another modifiable
+   * view, and if so, the process can be repeated. */
+  private RelNode createSource(RelOptTable targetTable, RelNode source,
+      ModifiableView modifiableView, RelDataType delegateRowType) {
+    final ImmutableIntList mapping = modifiableView.getColumnMapping();
+    assert mapping.size() == targetTable.getRowType().getFieldCount();
+
+    // For columns represented in the mapping, the expression is just a field
+    // reference.
+    final Map<Integer, RexNode> projectMap = new HashMap<>();
+    final List<RexNode> filters = new ArrayList<>();
+    for (int i = 0; i < mapping.size(); i++) {
+      int target = mapping.get(i);
+      if (target >= 0) {
+        projectMap.put(target, RexInputRef.of(i, source.getRowType()));
+      }
+    }
+
+    // For columns that are not in the mapping, and have a constraint of the
+    // form "column = value", the expression is the literal "value".
+    //
+    // If a column has multiple constraints, the extra ones will become a
+    // filter.
+    final RexNode constraint =
+        modifiableView.getConstraint(rexBuilder, delegateRowType);
+    RelOptUtil.inferViewPredicates(projectMap, filters, constraint);
+    final List<Pair<RexNode, String>> projects = new ArrayList<>();
+    for (RelDataTypeField field : delegateRowType.getFieldList()) {
+      RexNode node = projectMap.get(field.getIndex());
+      if (node == null) {
+        node = rexBuilder.makeNullLiteral(field.getType().getSqlTypeName());
+      }
+      projects.add(
+          Pair.of(rexBuilder.ensureType(field.getType(), node, false),
+              field.getName()));
+    }
+
+    source = RelOptUtil.createProject(source, projects, true);
+    if (filters.size() > 0) {
+      source = RelOptUtil.createFilter(source, filters);
+    }
+    return source;
   }
 
   private RelOptTable.ToRelContext createToRelContext() {
@@ -3088,8 +3134,8 @@ public class SqlToRelConverter {
     RelDataType sourceRowType = sourceRel.getRowType();
     final RexNode sourceRef =
         rexBuilder.makeRangeReference(sourceRowType, 0, false);
-    final List<String> targetColumnNames = new ArrayList<String>();
-    final List<RexNode> columnExprs = new ArrayList<RexNode>();
+    final List<String> targetColumnNames = new ArrayList<>();
+    final List<RexNode> columnExprs = new ArrayList<>();
     collectInsertTargets(call, sourceRef, targetColumnNames, columnExprs);
 
     final RelOptTable targetTable = getTargetTable(call);
@@ -3097,10 +3143,10 @@ public class SqlToRelConverter {
     final List<RelDataTypeField> targetFields =
         targetRowType.getFieldList();
     final List<RexNode> sourceExps =
-        new ArrayList<RexNode>(
+        new ArrayList<>(
             Collections.<RexNode>nCopies(targetFields.size(), null));
     final List<String> fieldNames =
-        new ArrayList<String>(
+        new ArrayList<>(
             Collections.<String>nCopies(targetFields.size(), null));
 
     // Walk the name list and place the associated value in the
@@ -3181,21 +3227,15 @@ public class SqlToRelConverter {
   private RelNode convertDelete(SqlDelete call) {
     RelOptTable targetTable = getTargetTable(call);
     RelNode sourceRel = convertSelect(call.getSourceSelect());
-    return new LogicalTableModify(
-        cluster,
-        targetTable,
-        catalogReader,
-        sourceRel,
-        LogicalTableModify.Operation.DELETE,
-        null,
-        false);
+    return LogicalTableModify.create(targetTable, catalogReader, sourceRel,
+        LogicalTableModify.Operation.DELETE, null, false);
   }
 
   private RelNode convertUpdate(SqlUpdate call) {
     RelOptTable targetTable = getTargetTable(call);
 
     // convert update column list from SqlIdentifier to String
-    List<String> targetColumnNameList = new ArrayList<String>();
+    final List<String> targetColumnNameList = new ArrayList<>();
     for (SqlNode node : call.getTargetColumnList()) {
       SqlIdentifier id = (SqlIdentifier) node;
       String name = id.getSimple();
@@ -3204,21 +3244,15 @@ public class SqlToRelConverter {
 
     RelNode sourceRel = convertSelect(call.getSourceSelect());
 
-    return new LogicalTableModify(
-        cluster,
-        targetTable,
-        catalogReader,
-        sourceRel,
-        LogicalTableModify.Operation.UPDATE,
-        targetColumnNameList,
-        false);
+    return LogicalTableModify.create(targetTable, catalogReader, sourceRel,
+        LogicalTableModify.Operation.UPDATE, targetColumnNameList, false);
   }
 
   private RelNode convertMerge(SqlMerge call) {
     RelOptTable targetTable = getTargetTable(call);
 
     // convert update column list from SqlIdentifier to String
-    List<String> targetColumnNameList = new ArrayList<String>();
+    final List<String> targetColumnNameList = new ArrayList<>();
     SqlUpdate updateCall = call.getUpdateCall();
     if (updateCall != null) {
       for (SqlNode targetColumn : updateCall.getTargetColumnList()) {
@@ -3267,7 +3301,7 @@ public class SqlToRelConverter {
 
     LogicalJoin join = (LogicalJoin) mergeSourceRel.getInput(0);
     int nSourceFields = join.getLeft().getRowType().getFieldCount();
-    List<RexNode> projects = new ArrayList<RexNode>();
+    final List<RexNode> projects = new ArrayList<>();
     for (int level1Idx = 0; level1Idx < nLevel1Exprs; level1Idx++) {
       if ((level2InsertExprs != null)
           && (level1InsertExprs.get(level1Idx) instanceof RexInputRef)) {
@@ -3287,14 +3321,8 @@ public class SqlToRelConverter {
     RelNode massagedRel =
         RelOptUtil.createProject(join, projects, null, true);
 
-    return new LogicalTableModify(
-        cluster,
-        targetTable,
-        catalogReader,
-        massagedRel,
-        LogicalTableModify.Operation.MERGE,
-        targetColumnNameList,
-        false);
+    return LogicalTableModify.create(targetTable, catalogReader, massagedRel,
+        LogicalTableModify.Operation.MERGE, targetColumnNameList, false);
   }
 
   /**
@@ -3399,8 +3427,8 @@ public class SqlToRelConverter {
       Blackboard bb) {
     // NOTE: Wael 2/04/05: this implementation is not the most efficient in
     // terms of planning since it generates XOs that can be reduced.
-    List<Object> joinList = new ArrayList<Object>();
-    List<SqlNode> lastList = new ArrayList<SqlNode>();
+    final List<Object> joinList = new ArrayList<>();
+    List<SqlNode> lastList = new ArrayList<>();
     for (int i = 0; i < operands.size(); i++) {
       SqlNode operand = operands.get(i);
       if (!(operand instanceof SqlCall)) {
@@ -3447,7 +3475,7 @@ public class SqlToRelConverter {
       if (lastList.size() > 0) {
         joinList.add(lastList);
       }
-      lastList = new ArrayList<SqlNode>();
+      lastList = new ArrayList<>();
       Collect collect =
           new Collect(
               cluster,
@@ -3465,8 +3493,8 @@ public class SqlToRelConverter {
       Object o = joinList.get(i);
       if (o instanceof List) {
         List<SqlNode> projectList = (List<SqlNode>) o;
-        final List<RexNode> selectList = new ArrayList<RexNode>();
-        final List<String> fieldNameList = new ArrayList<String>();
+        final List<RexNode> selectList = new ArrayList<>();
+        final List<String> fieldNameList = new ArrayList<>();
         for (int j = 0; j < projectList.size(); j++) {
           SqlNode operand = projectList.get(j);
           selectList.add(bb.convertExpression(operand));
@@ -3524,12 +3552,7 @@ public class SqlToRelConverter {
       RexNode condition,
       JoinRelType joinType,
       Set<String> variablesStopped) {
-    return new LogicalJoin(
-        cluster,
-        left,
-        right,
-        condition,
-        joinType,
+    return LogicalJoin.create(left, right, condition, joinType,
         variablesStopped);
   }
 
@@ -3542,14 +3565,13 @@ public class SqlToRelConverter {
 
     replaceSubqueries(bb, selectList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
 
-    List<String> fieldNames = new ArrayList<String>();
-    List<RexNode> exprs = new ArrayList<RexNode>();
-    Collection<String> aliases = new TreeSet<String>();
+    List<String> fieldNames = new ArrayList<>();
+    final List<RexNode> exprs = new ArrayList<>();
+    final Collection<String> aliases = new TreeSet<>();
 
     // Project any system fields. (Must be done before regular select items,
     // because offsets may be affected.)
-    final List<SqlMonotonicity> columnMonotonicityList =
-        new ArrayList<SqlMonotonicity>();
+    final List<SqlMonotonicity> columnMonotonicityList = new ArrayList<>();
     extraSelectItems(
         bb,
         select,
@@ -3675,14 +3697,13 @@ public class SqlToRelConverter {
       return;
     }
 
-    List<RelNode> unionRels = new ArrayList<RelNode>();
+    final List<RelNode> unionRels = new ArrayList<>();
     for (SqlNode rowConstructor1 : values.getOperandList()) {
       SqlCall rowConstructor = (SqlCall) rowConstructor1;
       Blackboard tmpBb = createBlackboard(bb.scope, null);
       replaceSubqueries(tmpBb, rowConstructor,
           RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
-      List<Pair<RexNode, String>> exps =
-          new ArrayList<Pair<RexNode, String>>();
+      final List<Pair<RexNode, String>> exps = new ArrayList<>();
       for (Ord<SqlNode> operand : Ord.zip(rowConstructor.getOperandList())) {
         exps.add(
             Pair.of(
@@ -3709,10 +3730,7 @@ public class SqlToRelConverter {
           true);
     } else {
       bb.setRoot(
-          new LogicalUnion(
-              cluster,
-              unionRels,
-              true),
+          LogicalUnion.create(unionRels, true),
           true);
     }
 
@@ -3746,7 +3764,7 @@ public class SqlToRelConverter {
     public RelNode root;
     private List<RelNode> inputs;
     private final Map<String, RexNode> mapCorrelateVariableToRexNode =
-        new HashMap<String, RexNode>();
+        new HashMap<>();
 
     List<RelNode> cursors;
 
@@ -3756,9 +3774,6 @@ public class SqlToRelConverter {
      */
     private final Set<SubQuery> subqueryList = Sets.newLinkedHashSet();
 
-    private final Map<SqlNode, SubQuery> subqueryMap =
-        Util.asIndexMap(subqueryList, FN);
-
     private boolean subqueryNeedsOuterJoin;
 
     /**
@@ -3778,14 +3793,12 @@ public class SqlToRelConverter {
      * "right" to the subquery.
      */
     private final Map<RelNode, Map<Integer, Integer>>
-    mapRootRelToFieldProjection =
-        new HashMap<RelNode, Map<Integer, Integer>>();
+    mapRootRelToFieldProjection = new HashMap<>();
 
     private final List<SqlMonotonicity> columnMonotonicities =
-        new ArrayList<SqlMonotonicity>();
+        new ArrayList<>();
 
-    private final List<RelDataTypeField> systemFieldList =
-        new ArrayList<RelDataTypeField>();
+    private final List<RelDataTypeField> systemFieldList = new ArrayList<>();
 
     /**
      * Creates a Blackboard.
@@ -3802,7 +3815,7 @@ public class SqlToRelConverter {
         Map<String, RexNode> nameToNodeMap) {
       this.scope = scope;
       this.nameToNodeMap = nameToNodeMap;
-      this.cursors = new ArrayList<RelNode>();
+      this.cursors = new ArrayList<>();
       subqueryNeedsOuterJoin = false;
     }
 
@@ -4078,9 +4091,24 @@ public class SqlToRelConverter {
     }
 
     void registerSubquery(SqlNode node, RelOptUtil.Logic logic) {
+      for (SubQuery subQuery : subqueryList) {
+        if (node.equalsDeep(subQuery.node, false)) {
+          return;
+        }
+      }
       subqueryList.add(new SubQuery(node, logic));
     }
 
+    SubQuery getSubquery(SqlNode expr) {
+      for (SubQuery subQuery : subqueryList) {
+        if (expr.equalsDeep(subQuery.node, false)) {
+          return subQuery;
+        }
+      }
+
+      return null;
+    }
+
     ImmutableList<RelNode> retrieveCursors() {
       try {
         return ImmutableList.copyOf(cursors);
@@ -4113,26 +4141,28 @@ public class SqlToRelConverter {
         return rex;
       }
 
-      boolean needTruthTest;
-
       // Sub-queries and OVER expressions are not like ordinary
       // expressions.
       final SqlKind kind = expr.getKind();
       final SubQuery subQuery;
       switch (kind) {
       case CURSOR:
+      case IN:
+        subQuery = getSubquery(expr);
+
+        assert subQuery != null;
+        rex = subQuery.expr;
+        assert rex != null : "rex != null";
+        return rex;
+
       case SELECT:
       case EXISTS:
       case SCALAR_QUERY:
-        subQuery = subqueryMap.get(expr);
+        subQuery = getSubquery(expr);
         assert subQuery != null;
         rex = subQuery.expr;
         assert rex != null : "rex != null";
 
-        if (kind == SqlKind.CURSOR) {
-          // cursor reference is pre-baked
-          return rex;
-        }
         if (((kind == SqlKind.SCALAR_QUERY)
             || (kind == SqlKind.EXISTS))
             && isConvertedSubq(rex)) {
@@ -4141,11 +4171,8 @@ public class SqlToRelConverter {
           return rex;
         }
 
-        RexNode fieldAccess;
-        needTruthTest = false;
-
         // The indicator column is the last field of the subquery.
-        fieldAccess =
+        RexNode fieldAccess =
             rexBuilder.makeFieldAccess(
                 rex,
                 rex.getType().getFieldCount() - 1);
@@ -4153,13 +4180,8 @@ public class SqlToRelConverter {
         // The indicator column will be nullable if it comes from
         // the null-generating side of the join. For EXISTS, add an
         // "IS TRUE" check so that the result is "BOOLEAN NOT NULL".
-        if (fieldAccess.getType().isNullable()) {
-          if (kind == SqlKind.EXISTS) {
-            needTruthTest = true;
-          }
-        }
-
-        if (needTruthTest) {
+        if (fieldAccess.getType().isNullable()
+            && kind == SqlKind.EXISTS) {
           fieldAccess =
               rexBuilder.makeCall(
                   SqlStdOperatorTable.IS_NOT_NULL,
@@ -4167,12 +4189,6 @@ public class SqlToRelConverter {
         }
         return fieldAccess;
 
-      case IN:
-        subQuery = subqueryMap.get(expr);
-        assert subQuery != null;
-        assert subQuery.expr != null : "expr != null";
-        return subQuery.expr;
-
       case OVER:
         return convertOver(this, expr);
 
@@ -4246,7 +4262,7 @@ public class SqlToRelConverter {
 
     // implement SqlRexContext
     public RexRangeRef getSubqueryExpr(SqlCall call) {
-      final SubQuery subQuery = subqueryMap.get(call);
+      final SubQuery subQuery = getSubquery(call);
       assert subQuery != null;
       return (RexRangeRef) subQuery.expr;
     }
@@ -4284,7 +4300,7 @@ public class SqlToRelConverter {
     public RexNode visit(SqlCall call) {
       if (agg != null) {
         final SqlOperator op = call.getOperator();
-        if (op.isAggregator()) {
+        if (op.isAggregator() || op.getKind() == SqlKind.FILTER) {
           return agg.lookupAggregates(call);
         }
       }
@@ -4537,81 +4553,97 @@ public class SqlToRelConverter {
     }
 
     public Void visit(SqlCall call) {
-      if (call.getOperator().isAggregator()) {
-        assert bb.agg == this;
-        List<Integer> args = new ArrayList<Integer>();
-        List<RelDataType> argTypes =
-            call.getOperator() instanceof SqlCountAggFunction
-            ? new ArrayList<RelDataType>(call.getOperandList().size())
-            : null;
-        try {
-          // switch out of agg mode
-          bb.agg = null;
-          for (SqlNode operand : call.getOperandList()) {
-            RexNode convertedExpr;
-
-            // special case for COUNT(*):  delete the *
-            if (operand instanceof SqlIdentifier) {
-              SqlIdentifier id = (SqlIdentifier) operand;
-              if (id.isStar() || isSimpleCount(call)) { // OVERRIDE POINT, was just `id.isStar()`
-                assert call.operandCount() == 1;
-                assert args.isEmpty();
-                break;
-              }
-            }
-            convertedExpr = bb.convertExpression(operand);
-            assert convertedExpr != null;
-            if (argTypes != null) {
-              argTypes.add(convertedExpr.getType());
-            }
-            args.add(lookupOrCreateGroupExpr(convertedExpr));
-          }
-        } finally {
-          // switch back into agg mode
-          bb.agg = this;
-        }
-
-        final SqlAggFunction aggFunction =
-            (SqlAggFunction) call.getOperator();
-        RelDataType type = validator.deriveType(bb.scope, call);
-        boolean distinct = false;
-        SqlLiteral quantifier = call.getFunctionQuantifier();
-        if ((null != quantifier)
-            && (quantifier.getValue() == SqlSelectKeyword.DISTINCT)) {
-          distinct = true;
-        }
-        final AggregateCall aggCall =
-            new AggregateCall(
-                aggFunction,
-                distinct,
-                args,
-                type,
-                nameMap.get(call.toString()));
-        RexNode rex =
-            rexBuilder.addAggCall(
-                aggCall,
-                groupExprs.size(),
-                aggregatingSelectScope.indicator,
-                aggCalls,
-                aggCallMapping,
-                argTypes);
-        aggMapping.put(call, rex);
-      } else if (call instanceof SqlSelect) {
+      switch (call.getKind()) {
+      case FILTER:
+        translateAgg((SqlCall) call.operand(0), call.operand(1), call);
+        return null;
+      case SELECT:
         // rchen 2006-10-17:
         // for now do not detect aggregates in subqueries.
         return null;
-      } else {
+      }
+      if (call.getOperator().isAggregator()) {
+        translateAgg(call, null, call);
+        return null;
+      }
+      for (SqlNode operand : call.getOperandList()) {
+        // Operands are occasionally null, e.g. switched CASE arg 0.
+        if (operand != null) {
+          operand.accept(this);
+        }
+      }
+      return null;
+    }
+
+    private void translateAgg(SqlCall call, SqlNode filter, SqlCall outerCall) {
+      assert bb.agg == this;
+      final List<Integer> args = new ArrayList<>();
+      int filterArg = -1;
+      final List<RelDataType> argTypes =
+          call.getOperator() instanceof SqlCountAggFunction
+              ? new ArrayList<RelDataType>(call.getOperandList().size())
+              : null;
+      try {
+        // switch out of agg mode
+        bb.agg = null;
         for (SqlNode operand : call.getOperandList()) {
-          // Operands are occasionally null, e.g. switched CASE arg 0.
-          if (operand != null) {
-            operand.accept(this);
+
+          // special case for COUNT(*):  delete the *
+          if (operand instanceof SqlIdentifier) {
+            SqlIdentifier id = (SqlIdentifier) operand;
+            if (id.isStar() || isSimpleCount(call)) { /* OVERRIDE POINT */
+              assert call.operandCount() == 1;
+              assert args.isEmpty();
+              break;
+            }
+          }
+          RexNode convertedExpr = bb.convertExpression(operand);
+          assert convertedExpr != null;
+          if (argTypes != null) {
+            argTypes.add(convertedExpr.getType());
           }
+          args.add(lookupOrCreateGroupExpr(convertedExpr));
         }
+
+        if (filter != null) {
+          RexNode convertedExpr = bb.convertExpression(filter);
+          assert convertedExpr != null;
+          filterArg = lookupOrCreateGroupExpr(convertedExpr);
+        }
+      } finally {
+        // switch back into agg mode
+        bb.agg = this;
       }
-      return null;
+
+      final SqlAggFunction aggFunction =
+          (SqlAggFunction) call.getOperator();
+      RelDataType type = validator.deriveType(bb.scope, call);
+      boolean distinct = false;
+      SqlLiteral quantifier = call.getFunctionQuantifier();
+      if ((null != quantifier)
+          && (quantifier.getValue() == SqlSelectKeyword.DISTINCT)) {
+        distinct = true;
+      }
+      final AggregateCall aggCall =
+          AggregateCall.create(
+              aggFunction,
+              distinct,
+              args,
+              filterArg,
+              type,
+              nameMap.get(outerCall.toString()));
+      RexNode rex =
+          rexBuilder.addAggCall(
+              aggCall,
+              groupExprs.size(),
+              aggregatingSelectScope.indicator,
+              aggCalls,
+              aggCallMapping,
+              argTypes);
+      aggMapping.put(outerCall, rex);
     }
 
-    // OVERRIDE POINT
+    /* OVERRIDE POINT */
     private boolean isSimpleCount(SqlCall call) {
         if (call.getOperator().isName("COUNT") && call.operandCount() == 1) {
             final SqlNode parm = call.operand(0);
@@ -4622,7 +4654,7 @@ public class SqlToRelConverter {
         }
         return false;
     }
-
+    
     private int lookupOrCreateGroupExpr(RexNode expr) {
       for (int i = 0; i < convertedInputExprs.size(); i++) {
         RexNode convertedInputExpr = convertedInputExprs.get(i);
@@ -4741,7 +4773,7 @@ public class SqlToRelConverter {
    */
   private static class LookupContext {
     private final List<Pair<RelNode, Integer>> relOffsetList =
-        new ArrayList<Pair<RelNode, Integer>>();
+        new ArrayList<>();
 
     /**
      * Creates a LookupContext with multiple input relational expressions.
@@ -4848,7 +4880,7 @@ public class SqlToRelConverter {
         // Replace original expression with CAST of not one
         // of the supported types
         if (histogramType != type) {
-          exprs = new ArrayList<RexNode>(exprs);
+          exprs = new ArrayList<>(exprs);
           exprs.set(
               0,
               reinterpretCast
@@ -4973,6 +5005,28 @@ public class SqlToRelConverter {
       this.logic = logic;
     }
   }
+
+  /**
+   * Visitor that collects all aggregate functions in a {@link SqlNode} tree.
+   */
+  private static class AggregateFinder extends SqlBasicVisitor<Void> {
+    final SqlNodeList list = new SqlNodeList(SqlParserPos.ZERO);
+
+    @Override public Void visit(SqlCall call) {
+      if (call.getOperator().isAggregator()) {
+        list.add(call);
+        return null;
+      }
+
+      // Don't traverse into sub-queries, even if they contain aggregate
+      // functions.
+      if (call instanceof SqlSelect) {
+        return null;
+      }
+
+      return call.getOperator().acceptCall(this, call);
+    }
+  }
 }
 
 // End SqlToRelConverter.java

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/f2b92061/jdbc/src/main/java/org/apache/kylin/jdbc/KylinClient.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc/KylinClient.java b/jdbc/src/main/java/org/apache/kylin/jdbc/KylinClient.java
index 4b73ad6..3d0007e 100644
--- a/jdbc/src/main/java/org/apache/kylin/jdbc/KylinClient.java
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc/KylinClient.java
@@ -259,7 +259,7 @@ public class KylinClient implements IRemoteClient {
 
             for (int i = 0; i < result.length; i++) {
                 ColumnMetaData meta = metas.get(i);
-                row[i] = wrapObject(result[i], meta.type.type);
+                row[i] = wrapObject(result[i], meta.type.id);
             }
 
             data.add(row);

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/f2b92061/jdbc/src/main/java/org/apache/kylin/jdbc/KylinJdbcFactory.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc/KylinJdbcFactory.java b/jdbc/src/main/java/org/apache/kylin/jdbc/KylinJdbcFactory.java
index 030dbbb..f1a4939 100644
--- a/jdbc/src/main/java/org/apache/kylin/jdbc/KylinJdbcFactory.java
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc/KylinJdbcFactory.java
@@ -30,6 +30,7 @@ import org.apache.calcite.avatica.AvaticaPreparedStatement;
 import org.apache.calcite.avatica.AvaticaResultSet;
 import org.apache.calcite.avatica.AvaticaResultSetMetaData;
 import org.apache.calcite.avatica.AvaticaStatement;
+import org.apache.calcite.avatica.Meta.Frame;
 import org.apache.calcite.avatica.Meta.Signature;
 import org.apache.calcite.avatica.Meta.StatementHandle;
 import org.apache.calcite.avatica.UnregisteredDriver;
@@ -92,9 +93,9 @@ public class KylinJdbcFactory implements AvaticaFactory {
     }
 
     @Override
-    public AvaticaResultSet newResultSet(AvaticaStatement statement, Signature signature, TimeZone timeZone, Iterable<Object> iterable) throws SQLException {
+    public AvaticaResultSet newResultSet(AvaticaStatement statement, Signature signature, TimeZone timeZone, Frame firstFrame) throws SQLException {
         AvaticaResultSetMetaData resultSetMetaData = new AvaticaResultSetMetaData(statement, null, signature);
-        return new KylinResultSet(statement, signature, resultSetMetaData, timeZone, iterable);
+        return new KylinResultSet(statement, signature, resultSetMetaData, timeZone, firstFrame);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/f2b92061/jdbc/src/main/java/org/apache/kylin/jdbc/KylinMeta.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc/KylinMeta.java b/jdbc/src/main/java/org/apache/kylin/jdbc/KylinMeta.java
index 821fba5..433262f 100644
--- a/jdbc/src/main/java/org/apache/kylin/jdbc/KylinMeta.java
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc/KylinMeta.java
@@ -31,6 +31,8 @@ import org.apache.calcite.avatica.AvaticaUtils;
 import org.apache.calcite.avatica.ColumnMetaData;
 import org.apache.calcite.avatica.MetaImpl;
 
+import com.google.common.collect.ImmutableList;
+
 /**
  * Implementation of Avatica interface
  */
@@ -48,26 +50,34 @@ public class KylinMeta extends MetaImpl {
 
     // insert/update/delete go this path, ignorable for Kylin
     @Override
-    public Signature prepare(StatementHandle h, String sql, int maxRowCount) {
-        return connection().mockPreparedSignature(sql);
+    public StatementHandle prepare(ConnectionHandle ch, String sql, int maxRowCount) {
+        StatementHandle result = super.createStatement(ch);
+        result.signature = connection().mockPreparedSignature(sql);
+        return result;
     }
 
     // mimic from CalciteMetaImpl, real execution happens via callback in KylinResultSet.execute()
     @Override
-    public MetaResultSet prepareAndExecute(StatementHandle h, String sql, int maxRowCount, PrepareCallback callback) {
-        final Signature signature;
+    public ExecuteResult prepareAndExecute(ConnectionHandle ch, String sql, int maxRowCount, PrepareCallback callback) {
+        final StatementHandle sh;
         try {
             synchronized (callback.getMonitor()) {
                 callback.clear();
-                signature = prepare(h, sql, maxRowCount);
-                callback.assign(signature, null);
+                sh = prepare(ch, sql, maxRowCount);
+                callback.assign(sh.signature, null, -1);
             }
             callback.execute();
-            return new MetaResultSet(h.id, false, signature, null);
+            final MetaResultSet metaResultSet = MetaResultSet.create(ch.id, sh.id, false, sh.signature, null);
+            return new ExecuteResult(ImmutableList.of(metaResultSet));
         } catch (SQLException e) {
             throw new RuntimeException(e);
         }
     }
+    
+    @Override
+    public void closeStatement(StatementHandle h) {
+        // nothing to do
+    }
 
     private KMetaProject getMetaProject() {
         try {
@@ -164,9 +174,10 @@ public class KylinMeta extends MetaImpl {
 
         CursorFactory cursorFactory = CursorFactory.record(clazz, fields, fieldNames);
         Signature signature = new Signature(columns, "", null, Collections.<String, Object> emptyMap(), cursorFactory);
-        StatementHandle statementHandle = this.createStatement(null);
+        StatementHandle sh = this.createStatement(connection().handle);
+        Frame frame = new Frame(0, true, iterable);
 
-        return new MetaResultSet(statementHandle.id, true, signature, iterable);
+        return MetaResultSet.create(connection().id, sh.id, true, signature, frame);
     }
 
     // ============================================================================
@@ -177,7 +188,7 @@ public class KylinMeta extends MetaImpl {
 
     public static List<? extends NamedWithChildren> searchByPatterns(NamedWithChildren parent, Pat... patterns) {
         assert patterns != null && patterns.length > 0;
-        
+
         List<? extends NamedWithChildren> children = findChildren(parent, patterns[0]);
         if (patterns.length == 1) {
             return children;
@@ -268,12 +279,12 @@ public class KylinMeta extends MetaImpl {
         public List<KMetaTable> getTables(String catalog, Pat schemaPattern, Pat tableNamePattern, List<String> typeList) {
             return (List<KMetaTable>) searchByPatterns(this, Pat.of(catalog), schemaPattern, tableNamePattern);
         }
-        
+
         @SuppressWarnings("unchecked")
         public List<KMetaColumn> getColumns(String catalog, Pat schemaPattern, Pat tableNamePattern, Pat columnNamePattern) {
             return (List<KMetaColumn>) searchByPatterns(this, Pat.of(catalog), schemaPattern, tableNamePattern, columnNamePattern);
         }
-        
+
         @Override
         public String getName() {
             return projectName;
@@ -293,7 +304,7 @@ public class KylinMeta extends MetaImpl {
             this.tableCat = tableCatalog;
             this.schemas = schemas;
         }
-        
+
         @Override
         public String getName() {
             return tableCat;
@@ -344,4 +355,5 @@ public class KylinMeta extends MetaImpl {
             return Collections.<NamedWithChildren> emptyList();
         }
     }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/f2b92061/jdbc/src/main/java/org/apache/kylin/jdbc/KylinPreparedStatement.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc/KylinPreparedStatement.java b/jdbc/src/main/java/org/apache/kylin/jdbc/KylinPreparedStatement.java
index 21cb162..b14865b 100644
--- a/jdbc/src/main/java/org/apache/kylin/jdbc/KylinPreparedStatement.java
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc/KylinPreparedStatement.java
@@ -6,7 +6,7 @@ import java.sql.NClob;
 import java.sql.RowId;
 import java.sql.SQLException;
 import java.sql.SQLXML;
-import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.calcite.avatica.AvaticaConnection;
@@ -19,82 +19,86 @@ public class KylinPreparedStatement extends AvaticaPreparedStatement {
     protected KylinPreparedStatement(AvaticaConnection connection, StatementHandle h, Signature signature, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
         super(connection, h, signature, resultSetType, resultSetConcurrency, resultSetHoldability);
     }
-    
-    protected List<Object> getParameterValues() {
-        return Arrays.asList(slots);
+
+    protected List<Object> getParameterValues2() {
+        List<Object> values = new ArrayList<>(slots.length);
+        for (int i = 0; i < slots.length; i++) {
+            values.add(slots[i].value);
+        }
+        return values;
     }
-    
+
     // ============================================================================
 
     public void setRowId(int parameterIndex, RowId x) throws SQLException {
-        getParameter(parameterIndex).setRowId(slots, parameterIndex, x);
+        getSite(parameterIndex).setRowId(x);
     }
 
     public void setNString(int parameterIndex, String value) throws SQLException {
-        getParameter(parameterIndex).setNString(slots, parameterIndex, value);
+        getSite(parameterIndex).setNString(value);
     }
 
     public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException {
-        getParameter(parameterIndex).setNCharacterStream(slots, parameterIndex, value, length);
+        getSite(parameterIndex).setNCharacterStream(value, length);
     }
 
     public void setNClob(int parameterIndex, NClob value) throws SQLException {
-        getParameter(parameterIndex).setNClob(slots, parameterIndex, value);
+        getSite(parameterIndex).setNClob(value);
     }
 
     public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {
-        getParameter(parameterIndex).setClob(slots, parameterIndex, reader, length);
+        getSite(parameterIndex).setClob(reader, length);
     }
 
     public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException {
-        getParameter(parameterIndex).setBlob(slots, parameterIndex, inputStream, length);
+        getSite(parameterIndex).setBlob(inputStream, length);
     }
 
     public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {
-        getParameter(parameterIndex).setNClob(slots, parameterIndex, reader, length);
+        getSite(parameterIndex).setNClob(reader, length);
     }
 
     public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException {
-        getParameter(parameterIndex).setSQLXML(slots, parameterIndex, xmlObject);
+        getSite(parameterIndex).setSQLXML(xmlObject);
     }
 
     public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
-        getParameter(parameterIndex).setAsciiStream(slots, parameterIndex, x, length);
+        getSite(parameterIndex).setAsciiStream(x, length);
     }
 
     public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
-        getParameter(parameterIndex).setBinaryStream(slots, parameterIndex, x, length);
+        getSite(parameterIndex).setBinaryStream(x, length);
     }
 
     public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
-        getParameter(parameterIndex).setCharacterStream(slots, parameterIndex, reader, length);
+        getSite(parameterIndex).setCharacterStream(reader, length);
     }
 
     public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {
-        getParameter(parameterIndex).setAsciiStream(slots, parameterIndex, x);
+        getSite(parameterIndex).setAsciiStream(x);
     }
 
     public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
-        getParameter(parameterIndex).setBinaryStream(slots, parameterIndex, x);
+        getSite(parameterIndex).setBinaryStream(x);
     }
 
     public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
-        getParameter(parameterIndex).setCharacterStream(slots, parameterIndex, reader);
+        getSite(parameterIndex).setCharacterStream(reader);
     }
 
     public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
-        getParameter(parameterIndex).setNCharacterStream(slots, parameterIndex, value);
+        getSite(parameterIndex).setNCharacterStream(value);
     }
 
     public void setClob(int parameterIndex, Reader reader) throws SQLException {
-        getParameter(parameterIndex).setClob(slots, parameterIndex, reader);
+        getSite(parameterIndex).setClob(reader);
     }
 
     public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {
-        getParameter(parameterIndex).setBlob(slots, parameterIndex, inputStream);
+        getSite(parameterIndex).setBlob(inputStream);
     }
 
     public void setNClob(int parameterIndex, Reader reader) throws SQLException {
-        getParameter(parameterIndex).setNClob(slots, parameterIndex, reader);
+        getSite(parameterIndex).setNClob(reader);
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/f2b92061/jdbc/src/main/java/org/apache/kylin/jdbc/KylinResultSet.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc/KylinResultSet.java b/jdbc/src/main/java/org/apache/kylin/jdbc/KylinResultSet.java
index 1229d10..3320415 100644
--- a/jdbc/src/main/java/org/apache/kylin/jdbc/KylinResultSet.java
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc/KylinResultSet.java
@@ -27,21 +27,22 @@ import java.util.TimeZone;
 import org.apache.calcite.avatica.AvaticaParameter;
 import org.apache.calcite.avatica.AvaticaResultSet;
 import org.apache.calcite.avatica.AvaticaStatement;
+import org.apache.calcite.avatica.Meta.Frame;
 import org.apache.calcite.avatica.Meta.Signature;
 import org.apache.calcite.avatica.MetaImpl;
 import org.apache.kylin.jdbc.IRemoteClient.QueryResult;
 
 public class KylinResultSet extends AvaticaResultSet {
 
-    public KylinResultSet(AvaticaStatement statement, Signature signature, ResultSetMetaData resultSetMetaData, TimeZone timeZone, Iterable<Object> iterable) {
-        super(statement, signature, resultSetMetaData, timeZone, iterable);
+    public KylinResultSet(AvaticaStatement statement, Signature signature, ResultSetMetaData resultSetMetaData, TimeZone timeZone, Frame firstFrame) {
+        super(statement, signature, resultSetMetaData, timeZone, firstFrame);
     }
 
     @Override
     protected AvaticaResultSet execute() throws SQLException {
         
         // skip execution if result is already there (case of meta data lookup)
-        if (this.iterable != null) {
+        if (this.firstFrame != null) {
             return super.execute();
         }
         
@@ -49,7 +50,7 @@ public class KylinResultSet extends AvaticaResultSet {
         List<AvaticaParameter> params = signature.parameters;
         List<Object> paramValues = null;
         if (params != null && params.size() > 0) {
-            paramValues = ((KylinPreparedStatement) statement).getParameterValues();
+            paramValues = ((KylinPreparedStatement) statement).getParameterValues2();
         }
         
         IRemoteClient client = ((KylinConnection) statement.connection).getRemoteClient();

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/f2b92061/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index c0a4be2..ed598fb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -84,7 +84,7 @@
         <spring.framework.version>3.1.2.RELEASE</spring.framework.version>
 
         <!-- Calcite Version -->
-        <calcite.version>1.0.0-incubating</calcite.version>
+        <calcite.version>1.3.0-incubating</calcite.version>
 
         <!-- Metrics Codahale Version -->
         <metrics.version>3.0.1</metrics.version>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/f2b92061/query/src/main/java/org/apache/kylin/query/enumerator/LookupTableEnumerator.java
----------------------------------------------------------------------
diff --git a/query/src/main/java/org/apache/kylin/query/enumerator/LookupTableEnumerator.java b/query/src/main/java/org/apache/kylin/query/enumerator/LookupTableEnumerator.java
index 733e8fe..c538080 100644
--- a/query/src/main/java/org/apache/kylin/query/enumerator/LookupTableEnumerator.java
+++ b/query/src/main/java/org/apache/kylin/query/enumerator/LookupTableEnumerator.java
@@ -46,7 +46,9 @@ public class LookupTableEnumerator implements Enumerator<Object[]> {
     private final Object[] current;
     private Iterator<String[]> iterator;
 
+    @SuppressWarnings("unused")
     private final static Logger logger = LoggerFactory.getLogger(LookupTableEnumerator.class);
+    
     public LookupTableEnumerator(OLAPContext olapContext) {
 
         //TODO: assuming LookupTableEnumerator is handled by a cube

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/f2b92061/query/src/main/java/org/apache/kylin/query/optrule/OLAPFilterRule.java
----------------------------------------------------------------------
diff --git a/query/src/main/java/org/apache/kylin/query/optrule/OLAPFilterRule.java b/query/src/main/java/org/apache/kylin/query/optrule/OLAPFilterRule.java
index 4c34f4e..3dcbbd7 100644
--- a/query/src/main/java/org/apache/kylin/query/optrule/OLAPFilterRule.java
+++ b/query/src/main/java/org/apache/kylin/query/optrule/OLAPFilterRule.java
@@ -39,7 +39,9 @@ public class OLAPFilterRule extends RelOptRule {
     public void onMatch(RelOptRuleCall call) {
         LogicalFilter filter = call.rel(0);
 
-        RelTraitSet traitSet = filter.getTraitSet().replace(OLAPRel.CONVENTION);
+        RelTraitSet origTraitSet = filter.getTraitSet();
+        RelTraitSet traitSet = origTraitSet.replace(OLAPRel.CONVENTION).simplify();
+        
         OLAPFilterRel olapFilter = new OLAPFilterRel(filter.getCluster(), traitSet, convert(filter.getInput(), traitSet), filter.getCondition());
         call.transformTo(olapFilter);
     }

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/f2b92061/query/src/main/java/org/apache/kylin/query/optrule/OLAPLimitRule.java
----------------------------------------------------------------------
diff --git a/query/src/main/java/org/apache/kylin/query/optrule/OLAPLimitRule.java b/query/src/main/java/org/apache/kylin/query/optrule/OLAPLimitRule.java
index cde934e..5eb1ff8 100644
--- a/query/src/main/java/org/apache/kylin/query/optrule/OLAPLimitRule.java
+++ b/query/src/main/java/org/apache/kylin/query/optrule/OLAPLimitRule.java
@@ -42,7 +42,10 @@ public class OLAPLimitRule extends RelOptRule {
         if (sort.offset == null && sort.fetch == null) {
             return;
         }
-        final RelTraitSet traitSet = sort.getTraitSet().replace(OLAPRel.CONVENTION);
+        
+        RelTraitSet origTraitSet = sort.getTraitSet();
+        RelTraitSet traitSet = origTraitSet.replace(OLAPRel.CONVENTION).simplify();
+
         RelNode input = sort.getInput();
         if (!sort.getCollation().getFieldCollations().isEmpty()) {
             // Create a sort with the same sort key, but no offset or fetch.

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/f2b92061/query/src/main/java/org/apache/kylin/query/optrule/OLAPProjectRule.java
----------------------------------------------------------------------
diff --git a/query/src/main/java/org/apache/kylin/query/optrule/OLAPProjectRule.java b/query/src/main/java/org/apache/kylin/query/optrule/OLAPProjectRule.java
index 4867162..bee992b 100644
--- a/query/src/main/java/org/apache/kylin/query/optrule/OLAPProjectRule.java
+++ b/query/src/main/java/org/apache/kylin/query/optrule/OLAPProjectRule.java
@@ -39,9 +39,11 @@ public class OLAPProjectRule extends RelOptRule {
     public void onMatch(RelOptRuleCall call) {
         LogicalProject project = call.rel(0);
 
-        RelTraitSet traitSet = project.getTraitSet().replace(OLAPRel.CONVENTION);
+        RelTraitSet origTraitSet = project.getTraitSet();
+        RelTraitSet traitSet = origTraitSet.replace(OLAPRel.CONVENTION).simplify();
+
         OLAPProjectRel olapProj = new OLAPProjectRel(project.getCluster(), traitSet, //
-                convert(project.getInput(), traitSet), project.getProjects(), project.getRowType(), project.getFlags());
+                convert(project.getInput(), traitSet), project.getProjects(), project.getRowType());
         call.transformTo(olapProj);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/f2b92061/query/src/main/java/org/apache/kylin/query/relnode/OLAPFilterRel.java
----------------------------------------------------------------------
diff --git a/query/src/main/java/org/apache/kylin/query/relnode/OLAPFilterRel.java b/query/src/main/java/org/apache/kylin/query/relnode/OLAPFilterRel.java
index 48c1075..cf985b7 100644
--- a/query/src/main/java/org/apache/kylin/query/relnode/OLAPFilterRel.java
+++ b/query/src/main/java/org/apache/kylin/query/relnode/OLAPFilterRel.java
@@ -33,7 +33,6 @@ import org.apache.calcite.plan.RelOptCost;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelTrait;
 import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Filter;
 import org.apache.calcite.rel.type.RelDataType;
@@ -62,7 +61,6 @@ import org.apache.kylin.metadata.filter.TupleFilter.FilterOperatorEnum;
 import org.apache.kylin.metadata.model.TblColRef;
 
 import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Sets;
 
 /**
@@ -307,7 +305,7 @@ public class OLAPFilterRel extends Filter implements OLAPRel {
         RexProgram program = programBuilder.getProgram();
 
         return new EnumerableCalc(getCluster(), getCluster().traitSetOf(EnumerableConvention.INSTANCE), //
-                sole(inputs), program, ImmutableList.<RelCollation> of());
+                sole(inputs), program);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/f2b92061/query/src/main/java/org/apache/kylin/query/relnode/OLAPProjectRel.java
----------------------------------------------------------------------
diff --git a/query/src/main/java/org/apache/kylin/query/relnode/OLAPProjectRel.java b/query/src/main/java/org/apache/kylin/query/relnode/OLAPProjectRel.java
index 8f80962..cda2cbc 100644
--- a/query/src/main/java/org/apache/kylin/query/relnode/OLAPProjectRel.java
+++ b/query/src/main/java/org/apache/kylin/query/relnode/OLAPProjectRel.java
@@ -33,7 +33,6 @@ import org.apache.calcite.plan.RelOptCost;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelTrait;
 import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.type.RelDataType;
@@ -53,7 +52,6 @@ import org.apache.kylin.metadata.model.TblColRef;
 import org.apache.kylin.metadata.model.TblColRef.InnerDataTypeEnum;
 
 import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
 
 /**
  */
@@ -67,8 +65,8 @@ public class OLAPProjectRel extends Project implements OLAPRel {
     private boolean afterJoin;
     private boolean afterAggregate;
 
-    public OLAPProjectRel(RelOptCluster cluster, RelTraitSet traitSet, RelNode child, List<RexNode> exps, RelDataType rowType, int flags) {
-        super(cluster, traitSet, child, exps, rowType, flags);
+    public OLAPProjectRel(RelOptCluster cluster, RelTraitSet traitSet, RelNode child, List<RexNode> exps, RelDataType rowType) {
+        super(cluster, traitSet, child, exps, rowType);
         Preconditions.checkArgument(getConvention() == OLAPRel.CONVENTION);
         Preconditions.checkArgument(child.getConvention() == OLAPRel.CONVENTION);
         this.rewriteProjects = exps;
@@ -94,7 +92,7 @@ public class OLAPProjectRel extends Project implements OLAPRel {
 
     @Override
     public Project copy(RelTraitSet traitSet, RelNode child, List<RexNode> exps, RelDataType rowType) {
-        return new OLAPProjectRel(getCluster(), traitSet, child, exps, rowType, this.flags);
+        return new OLAPProjectRel(getCluster(), traitSet, child, exps, rowType);
     }
 
     @Override
@@ -214,13 +212,13 @@ public class OLAPProjectRel extends Project implements OLAPRel {
             RelNode inputOfFilter = inputs.get(0).getInput(0);
             RexProgram program = RexProgram.create(inputOfFilter.getRowType(), this.rewriteProjects, filter.getCondition(), this.rowType, getCluster().getRexBuilder());
             return new EnumerableCalc(getCluster(), getCluster().traitSetOf(EnumerableConvention.INSTANCE), //
-                    inputOfFilter, program, ImmutableList.<RelCollation> of());
+                    inputOfFilter, program);
         } else {
             // keep project for table scan
             EnumerableRel input = sole(inputs);
             RexProgram program = RexProgram.create(input.getRowType(), this.rewriteProjects, null, this.rowType, getCluster().getRexBuilder());
             return new EnumerableCalc(getCluster(), getCluster().traitSetOf(EnumerableConvention.INSTANCE), //
-                    input, program, ImmutableList.<RelCollation> of());
+                    input, program);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/f2b92061/query/src/main/java/org/apache/kylin/query/relnode/OLAPTableScan.java
----------------------------------------------------------------------
diff --git a/query/src/main/java/org/apache/kylin/query/relnode/OLAPTableScan.java b/query/src/main/java/org/apache/kylin/query/relnode/OLAPTableScan.java
index fc1fdf5..1f2edf9 100644
--- a/query/src/main/java/org/apache/kylin/query/relnode/OLAPTableScan.java
+++ b/query/src/main/java/org/apache/kylin/query/relnode/OLAPTableScan.java
@@ -41,6 +41,8 @@ import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelWriter;
 import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.rules.AggregateExpandDistinctAggregatesRule;
+import org.apache.calcite.rel.rules.AggregateJoinTransposeRule;
+import org.apache.calcite.rel.rules.AggregateProjectMergeRule;
 import org.apache.calcite.rel.rules.FilterJoinRule;
 import org.apache.calcite.rel.rules.FilterProjectTransposeRule;
 import org.apache.calcite.rel.rules.JoinCommuteRule;
@@ -130,7 +132,9 @@ public class OLAPTableScan extends TableScan implements OLAPRel, EnumerableRel {
         planner.removeRule(JoinPushThroughJoinRule.LEFT);
         planner.removeRule(JoinPushThroughJoinRule.RIGHT);
 
-        // for columns in having clause will enable table scan filter rule cause kylin does not depend on MPP
+        // keep tree structure like filter -> aggregation -> project -> join/table scan, implementOLAP() rely on this tree pattern
+        planner.removeRule(AggregateJoinTransposeRule.INSTANCE);
+        planner.removeRule(AggregateProjectMergeRule.INSTANCE);
         planner.removeRule(FilterProjectTransposeRule.INSTANCE);
         // distinct count will be split into a separated query that is joined with the left query
         planner.removeRule(AggregateExpandDistinctAggregatesRule.INSTANCE);