You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2016/12/08 06:05:00 UTC

[1/3] calcite git commit: [CALCITE-1530] Create a visitor to traverse linq4j expressions without mutating them, and rename Visitor to Shuttle

Repository: calcite
Updated Branches:
  refs/heads/master 02752fe78 -> e641211fd


http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Shuttle.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Shuttle.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Shuttle.java
new file mode 100644
index 0000000..08aa1ad
--- /dev/null
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Shuttle.java
@@ -0,0 +1,335 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.linq4j.tree;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Extension to {@link Visitor} that returns a mutated tree.
+ */
+public class Shuttle {
+  public Shuttle preVisit(WhileStatement whileStatement) {
+    return this;
+  }
+
+  public Statement visit(WhileStatement whileStatement, Expression condition,
+      Statement body) {
+    return condition == whileStatement.condition
+           && body == whileStatement.body
+        ? whileStatement
+        : Expressions.while_(condition, body);
+  }
+
+  public Shuttle preVisit(ConditionalStatement conditionalStatement) {
+    return this;
+  }
+
+  public Statement visit(ConditionalStatement conditionalStatement,
+      List<Node> list) {
+    return list.equals(conditionalStatement.expressionList)
+        ? conditionalStatement
+        : Expressions.ifThenElse(list);
+  }
+
+  public Shuttle preVisit(BlockStatement blockStatement) {
+    return this;
+  }
+
+  public BlockStatement visit(BlockStatement blockStatement,
+      List<Statement> statements) {
+    return statements.equals(blockStatement.statements)
+        ? blockStatement
+        : Expressions.block(statements);
+  }
+
+  public Shuttle preVisit(GotoStatement gotoStatement) {
+    return this;
+  }
+
+  public Statement visit(GotoStatement gotoStatement, Expression expression) {
+    return expression == gotoStatement.expression
+        ? gotoStatement
+        : Expressions.makeGoto(
+            gotoStatement.kind, gotoStatement.labelTarget,
+            expression);
+  }
+
+  public LabelStatement visit(LabelStatement labelStatement) {
+    return labelStatement;
+  }
+
+  public Shuttle preVisit(ForStatement forStatement) {
+    return this;
+  }
+
+  public ForStatement visit(ForStatement forStatement,
+      List<DeclarationStatement> declarations, Expression condition,
+      Expression post, Statement body) {
+    return declarations.equals(forStatement.declarations)
+        && condition == forStatement.condition
+        && post == forStatement.post
+        && body == forStatement.body
+        ? forStatement
+        : Expressions.for_(declarations, condition, post, body);
+  }
+
+  public Shuttle preVisit(ThrowStatement throwStatement) {
+    return this;
+  }
+
+  public Statement visit(ThrowStatement throwStatement, Expression expression) {
+    return expression == throwStatement.expression
+        ? throwStatement
+        : Expressions.throw_(expression);
+  }
+
+  public Shuttle preVisit(DeclarationStatement declarationStatement) {
+    return this;
+  }
+
+  public DeclarationStatement visit(DeclarationStatement declarationStatement,
+      Expression initializer) {
+    return declarationStatement.initializer == initializer
+        ? declarationStatement
+        : Expressions.declare(
+            declarationStatement.modifiers, declarationStatement.parameter,
+            initializer);
+  }
+
+  public Expression visit(LambdaExpression lambdaExpression) {
+    return lambdaExpression;
+  }
+
+  public Shuttle preVisit(FunctionExpression functionExpression) {
+    return this;
+  }
+
+  public Expression visit(FunctionExpression functionExpression,
+      BlockStatement body) {
+    return functionExpression.body.equals(body)
+        ? functionExpression
+        : Expressions.lambda(body, functionExpression.parameterList);
+  }
+
+  public Shuttle preVisit(BinaryExpression binaryExpression) {
+    return this;
+  }
+
+  public Expression visit(BinaryExpression binaryExpression,
+      Expression expression0, Expression expression1) {
+    return binaryExpression.expression0 == expression0
+           && binaryExpression.expression1 == expression1
+        ? binaryExpression
+        : Expressions.makeBinary(binaryExpression.nodeType, expression0,
+            expression1);
+  }
+
+  public Shuttle preVisit(TernaryExpression ternaryExpression) {
+    return this;
+  }
+
+  public Expression visit(TernaryExpression ternaryExpression,
+      Expression expression0, Expression expression1, Expression expression2) {
+    return ternaryExpression.expression0 == expression0
+           && ternaryExpression.expression1 == expression1
+           && ternaryExpression.expression2 == expression2
+        ? ternaryExpression
+        : Expressions.makeTernary(ternaryExpression.nodeType, expression0,
+            expression1, expression2);
+  }
+
+  public Shuttle preVisit(IndexExpression indexExpression) {
+    return this;
+  }
+
+  public Expression visit(IndexExpression indexExpression, Expression array,
+      List<Expression> indexExpressions) {
+    return indexExpression.array == array
+           && indexExpression.indexExpressions.equals(indexExpressions)
+        ? indexExpression
+        : new IndexExpression(array, indexExpressions);
+  }
+
+  public Shuttle preVisit(UnaryExpression unaryExpression) {
+    return this;
+  }
+
+  public Expression visit(UnaryExpression unaryExpression,
+      Expression expression) {
+    return unaryExpression.expression == expression
+        ? unaryExpression
+        : Expressions.makeUnary(unaryExpression.nodeType, expression,
+            unaryExpression.type, null);
+  }
+
+  public Shuttle preVisit(MethodCallExpression methodCallExpression) {
+    return this;
+  }
+
+  public Expression visit(MethodCallExpression methodCallExpression,
+      Expression targetExpression, List<Expression> expressions) {
+    return methodCallExpression.targetExpression == targetExpression
+           && methodCallExpression.expressions.equals(expressions)
+        ? methodCallExpression
+        : Expressions.call(targetExpression, methodCallExpression.method,
+            expressions);
+  }
+
+  public Expression visit(DefaultExpression defaultExpression) {
+    return defaultExpression;
+  }
+
+  public Expression visit(DynamicExpression dynamicExpression) {
+    return dynamicExpression;
+  }
+
+  public Shuttle preVisit(MemberExpression memberExpression) {
+    return this;
+  }
+
+  public Expression visit(MemberExpression memberExpression,
+      Expression expression) {
+    return memberExpression.expression == expression
+        ? memberExpression
+        : Expressions.field(expression, memberExpression.field);
+  }
+
+  public Expression visit(InvocationExpression invocationExpression) {
+    return invocationExpression;
+  }
+
+  public Shuttle preVisit(NewArrayExpression newArrayExpression) {
+    return this;
+  }
+
+  public Expression visit(NewArrayExpression newArrayExpression, int dimension,
+      Expression bound, List<Expression> expressions) {
+    return Objects.equals(expressions, newArrayExpression.expressions)
+        && Objects.equals(bound, newArrayExpression.bound)
+        ? newArrayExpression
+        : expressions == null
+        ? Expressions.newArrayBounds(
+            Types.getComponentTypeN(newArrayExpression.type), dimension, bound)
+        : Expressions.newArrayInit(
+            Types.getComponentTypeN(newArrayExpression.type),
+            dimension, expressions);
+  }
+
+  public Expression visit(ListInitExpression listInitExpression) {
+    return listInitExpression;
+  }
+
+  public Shuttle preVisit(NewExpression newExpression) {
+    return this;
+  }
+
+  public Expression visit(NewExpression newExpression,
+      List<Expression> arguments, List<MemberDeclaration> memberDeclarations) {
+    return arguments.equals(newExpression.arguments)
+        && Objects.equals(memberDeclarations, newExpression.memberDeclarations)
+        ? newExpression
+        : Expressions.new_(newExpression.type, arguments, memberDeclarations);
+  }
+
+  public Statement visit(SwitchStatement switchStatement) {
+    return switchStatement;
+  }
+
+  public Statement visit(TryStatement tryStatement) {
+    return tryStatement;
+  }
+
+  public Expression visit(MemberInitExpression memberInitExpression) {
+    return memberInitExpression;
+  }
+
+  public Shuttle preVisit(TypeBinaryExpression typeBinaryExpression) {
+    return this;
+  }
+
+  public Expression visit(TypeBinaryExpression typeBinaryExpression,
+      Expression expression) {
+    return typeBinaryExpression.expression == expression
+        ? typeBinaryExpression
+        : new TypeBinaryExpression(expression.getNodeType(), expression,
+            expression.type);
+  }
+
+  public Shuttle preVisit(MethodDeclaration methodDeclaration) {
+    return this;
+  }
+
+  public MemberDeclaration visit(MethodDeclaration methodDeclaration,
+      BlockStatement body) {
+    return body.equals(methodDeclaration.body)
+        ? methodDeclaration
+        : Expressions.methodDecl(methodDeclaration.modifier,
+            methodDeclaration.resultType, methodDeclaration.name,
+            methodDeclaration.parameters, body);
+  }
+
+  public Shuttle preVisit(FieldDeclaration fieldDeclaration) {
+    return this;
+  }
+
+  public MemberDeclaration visit(FieldDeclaration fieldDeclaration,
+      Expression initializer) {
+    return Objects.equals(initializer, fieldDeclaration.initializer)
+        ? fieldDeclaration
+        : Expressions.fieldDecl(fieldDeclaration.modifier,
+            fieldDeclaration.parameter, initializer);
+  }
+
+  public Expression visit(ParameterExpression parameterExpression) {
+    return parameterExpression;
+  }
+
+  public ConstantExpression visit(ConstantExpression constantExpression) {
+    return constantExpression;
+  }
+
+  public Shuttle preVisit(ClassDeclaration classDeclaration) {
+    return this;
+  }
+
+  public ClassDeclaration visit(ClassDeclaration classDeclaration,
+      List<MemberDeclaration> memberDeclarations) {
+    return Objects.equals(memberDeclarations,
+        classDeclaration.memberDeclarations)
+        ? classDeclaration
+        : Expressions.classDecl(classDeclaration.modifier,
+            classDeclaration.name, classDeclaration.extended,
+            classDeclaration.implemented, memberDeclarations);
+  }
+
+  public Shuttle preVisit(ConstructorDeclaration constructorDeclaration) {
+    return this;
+  }
+
+  public MemberDeclaration visit(ConstructorDeclaration constructorDeclaration,
+      BlockStatement body) {
+    return body.equals(constructorDeclaration.body)
+        ? constructorDeclaration
+        : Expressions.constructorDecl(constructorDeclaration.modifier,
+            constructorDeclaration.resultType,
+            constructorDeclaration.parameters,
+            body);
+  }
+}
+
+// End Shuttle.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Statement.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Statement.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Statement.java
index 99e17f9..8c0a225 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Statement.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Statement.java
@@ -34,7 +34,7 @@ public abstract class Statement extends AbstractNode {
 
   // Make return type more specific. A statement can only become a different
   // kind of statement; it can't become an expression.
-  @Override public abstract Statement accept(Visitor visitor);
+  @Override public abstract Statement accept(Shuttle shuttle);
 }
 
 // End Statement.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/SwitchStatement.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/SwitchStatement.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/SwitchStatement.java
index b0fa124..fb787b1 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/SwitchStatement.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/SwitchStatement.java
@@ -25,9 +25,14 @@ public class SwitchStatement extends Statement {
     super(nodeType, Void.TYPE);
   }
 
-  @Override public Statement accept(Visitor visitor) {
+  @Override public Statement accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
+
 }
 
 // End SwitchStatement.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/TernaryExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/TernaryExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/TernaryExpression.java
index 86be802..9bc9ac5 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/TernaryExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/TernaryExpression.java
@@ -38,12 +38,16 @@ public class TernaryExpression extends Expression {
     this.expression2 = expression2;
   }
 
-  @Override public Expression accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
-    Expression expression0 = this.expression0.accept(visitor);
-    Expression expression1 = this.expression1.accept(visitor);
-    Expression expression2 = this.expression2.accept(visitor);
-    return visitor.visit(this, expression0, expression1, expression2);
+  @Override public Expression accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
+    Expression expression0 = this.expression0.accept(shuttle);
+    Expression expression1 = this.expression1.accept(shuttle);
+    Expression expression2 = this.expression2.accept(shuttle);
+    return shuttle.visit(this, expression0, expression1, expression2);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   void accept(ExpressionWriter writer, int lprec, int rprec) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ThrowStatement.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ThrowStatement.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ThrowStatement.java
index b2939a5..221576c 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ThrowStatement.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ThrowStatement.java
@@ -29,10 +29,14 @@ public class ThrowStatement extends Statement {
     this.expression = expression;
   }
 
-  @Override public Statement accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
-    Expression expression = this.expression.accept(visitor);
-    return visitor.visit(this, expression);
+  @Override public Statement accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
+    Expression expression = this.expression.accept(shuttle);
+    return shuttle.visit(this, expression);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override void accept0(ExpressionWriter writer) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/TryStatement.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/TryStatement.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/TryStatement.java
index 0e9d4ca..9313011 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/TryStatement.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/TryStatement.java
@@ -37,7 +37,11 @@ public class TryStatement extends Statement {
     this.fynally = fynally;
   }
 
-  @Override public Statement accept(Visitor visitor) {
+  @Override public Statement accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/TypeBinaryExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/TypeBinaryExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/TypeBinaryExpression.java
index 1890de0..f407db1 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/TypeBinaryExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/TypeBinaryExpression.java
@@ -34,10 +34,14 @@ public class TypeBinaryExpression extends Expression {
     this.type = type;
   }
 
-  @Override public Expression accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
-    Expression expression = this.expression.accept(visitor);
-    return visitor.visit(this, expression);
+  @Override public Expression accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
+    Expression expression = this.expression.accept(shuttle);
+    return shuttle.visit(this, expression);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   void accept(ExpressionWriter writer, int lprec, int rprec) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/UnaryExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/UnaryExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/UnaryExpression.java
index d9bae4d..4dfc9c3 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/UnaryExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/UnaryExpression.java
@@ -31,10 +31,14 @@ public class UnaryExpression extends Expression {
     this.expression = expression;
   }
 
-  @Override public Expression accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
-    Expression expression = this.expression.accept(visitor);
-    return visitor.visit(this, expression);
+  @Override public Expression accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
+    Expression expression = this.expression.accept(shuttle);
+    return shuttle.visit(this, expression);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   void accept(ExpressionWriter writer, int lprec, int rprec) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Visitor.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Visitor.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Visitor.java
index cf50786..50b60d2 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Visitor.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Visitor.java
@@ -16,324 +16,45 @@
  */
 package org.apache.calcite.linq4j.tree;
 
-import java.util.List;
-import java.util.Objects;
-
 /**
  * Node visitor.
+ *
+ * @param <R> Return type
  */
-public class Visitor {
-  public Visitor preVisit(WhileStatement whileStatement) {
-    return this;
-  }
-
-  public Statement visit(WhileStatement whileStatement, Expression condition,
-      Statement body) {
-    return condition == whileStatement.condition
-           && body == whileStatement.body
-        ? whileStatement
-        : Expressions.while_(condition, body);
-  }
-
-  public Visitor preVisit(ConditionalStatement conditionalStatement) {
-    return this;
-  }
-
-  public Statement visit(ConditionalStatement conditionalStatement,
-      List<Node> list) {
-    return list.equals(conditionalStatement.expressionList)
-        ? conditionalStatement
-        : Expressions.ifThenElse(list);
-  }
-
-  public Visitor preVisit(BlockStatement blockStatement) {
-    return this;
-  }
-
-  public BlockStatement visit(BlockStatement blockStatement,
-      List<Statement> statements) {
-    return statements.equals(blockStatement.statements)
-        ? blockStatement
-        : Expressions.block(statements);
-  }
-
-  public Visitor preVisit(GotoStatement gotoStatement) {
-    return this;
-  }
-
-  public Statement visit(GotoStatement gotoStatement, Expression expression) {
-    return expression == gotoStatement.expression
-        ? gotoStatement
-        : Expressions.makeGoto(
-            gotoStatement.kind, gotoStatement.labelTarget,
-            expression);
-  }
-
-  public LabelStatement visit(LabelStatement labelStatement) {
-    return labelStatement;
-  }
-
-  public Visitor preVisit(ForStatement forStatement) {
-    return this;
-  }
-
-  public ForStatement visit(ForStatement forStatement,
-      List<DeclarationStatement> declarations, Expression condition,
-      Expression post, Statement body) {
-    return declarations.equals(forStatement.declarations)
-        && condition == forStatement.condition
-        && post == forStatement.post
-        && body == forStatement.body
-        ? forStatement
-        : Expressions.for_(declarations, condition, post, body);
-  }
-
-  public Visitor preVisit(ThrowStatement throwStatement) {
-    return this;
-  }
-
-  public Statement visit(ThrowStatement throwStatement, Expression expression) {
-    return expression == throwStatement.expression
-        ? throwStatement
-        : Expressions.throw_(expression);
-  }
-
-  public Visitor preVisit(DeclarationStatement declarationStatement) {
-    return this;
-  }
-
-  public DeclarationStatement visit(DeclarationStatement declarationStatement,
-      Expression initializer) {
-    return declarationStatement.initializer == initializer
-        ? declarationStatement
-        : Expressions.declare(
-            declarationStatement.modifiers, declarationStatement.parameter,
-            initializer);
-  }
-
-  public Expression visit(LambdaExpression lambdaExpression) {
-    return lambdaExpression;
-  }
-
-  public Visitor preVisit(FunctionExpression functionExpression) {
-    return this;
-  }
-
-  public Expression visit(FunctionExpression functionExpression,
-      BlockStatement body) {
-    return functionExpression.body.equals(body)
-        ? functionExpression
-        : Expressions.lambda(body, functionExpression.parameterList);
-  }
-
-  public Visitor preVisit(BinaryExpression binaryExpression) {
-    return this;
-  }
-
-  public Expression visit(BinaryExpression binaryExpression,
-      Expression expression0, Expression expression1) {
-    return binaryExpression.expression0 == expression0
-           && binaryExpression.expression1 == expression1
-        ? binaryExpression
-        : Expressions.makeBinary(binaryExpression.nodeType, expression0,
-            expression1);
-  }
-
-  public Visitor preVisit(TernaryExpression ternaryExpression) {
-    return this;
-  }
-
-  public Expression visit(TernaryExpression ternaryExpression,
-      Expression expression0, Expression expression1, Expression expression2) {
-    return ternaryExpression.expression0 == expression0
-           && ternaryExpression.expression1 == expression1
-           && ternaryExpression.expression2 == expression2
-        ? ternaryExpression
-        : Expressions.makeTernary(ternaryExpression.nodeType, expression0,
-            expression1, expression2);
-  }
-
-  public Visitor preVisit(IndexExpression indexExpression) {
-    return this;
-  }
-
-  public Expression visit(IndexExpression indexExpression, Expression array,
-      List<Expression> indexExpressions) {
-    return indexExpression.array == array
-           && indexExpression.indexExpressions.equals(indexExpressions)
-        ? indexExpression
-        : new IndexExpression(array, indexExpressions);
-  }
-
-  public Visitor preVisit(UnaryExpression unaryExpression) {
-    return this;
-  }
-
-  public Expression visit(UnaryExpression unaryExpression,
-      Expression expression) {
-    return unaryExpression.expression == expression
-        ? unaryExpression
-        : Expressions.makeUnary(unaryExpression.nodeType, expression,
-            unaryExpression.type, null);
-  }
-
-  public Visitor preVisit(MethodCallExpression methodCallExpression) {
-    return this;
-  }
-
-  public Expression visit(MethodCallExpression methodCallExpression,
-      Expression targetExpression, List<Expression> expressions) {
-    return methodCallExpression.targetExpression == targetExpression
-           && methodCallExpression.expressions.equals(expressions)
-        ? methodCallExpression
-        : Expressions.call(targetExpression, methodCallExpression.method,
-            expressions);
-  }
-
-  public Expression visit(DefaultExpression defaultExpression) {
-    return defaultExpression;
-  }
-
-  public Expression visit(DynamicExpression dynamicExpression) {
-    return dynamicExpression;
-  }
-
-  public Visitor preVisit(MemberExpression memberExpression) {
-    return this;
-  }
-
-  public Expression visit(MemberExpression memberExpression,
-      Expression expression) {
-    return memberExpression.expression == expression
-        ? memberExpression
-        : Expressions.field(expression, memberExpression.field);
-  }
-
-  public Expression visit(InvocationExpression invocationExpression) {
-    return invocationExpression;
-  }
-
-  static <T> boolean eq(T t0, T t1) {
-    return t0 == t1 || t0 != null && t1 != null && t0.equals(t1);
-  }
-
-  public Visitor preVisit(NewArrayExpression newArrayExpression) {
-    return this;
-  }
-
-  public Expression visit(NewArrayExpression newArrayExpression, int dimension,
-      Expression bound, List<Expression> expressions) {
-    return eq(expressions, newArrayExpression.expressions)
-        && eq(bound, newArrayExpression.bound)
-        ? newArrayExpression
-        : expressions == null
-        ? Expressions.newArrayBounds(
-            Types.getComponentTypeN(newArrayExpression.type), dimension, bound)
-        : Expressions.newArrayInit(
-            Types.getComponentTypeN(newArrayExpression.type),
-            dimension, expressions);
-  }
-
-  public Expression visit(ListInitExpression listInitExpression) {
-    return listInitExpression;
-  }
-
-  public Visitor preVisit(NewExpression newExpression) {
-    return this;
-  }
-
-  public Expression visit(NewExpression newExpression,
-      List<Expression> arguments, List<MemberDeclaration> memberDeclarations) {
-    return arguments.equals(newExpression.arguments)
-        && Objects.equals(memberDeclarations, newExpression.memberDeclarations)
-        ? newExpression
-        : Expressions.new_(newExpression.type, arguments, memberDeclarations);
-  }
-
-  public Statement visit(SwitchStatement switchStatement) {
-    return switchStatement;
-  }
-
-  public Statement visit(TryStatement tryStatement) {
-    return tryStatement;
-  }
-
-  public Expression visit(MemberInitExpression memberInitExpression) {
-    return memberInitExpression;
-  }
-
-  public Visitor preVisit(TypeBinaryExpression typeBinaryExpression) {
-    return this;
-  }
-
-  public Expression visit(TypeBinaryExpression typeBinaryExpression,
-      Expression expression) {
-    return typeBinaryExpression.expression == expression
-        ? typeBinaryExpression
-        : new TypeBinaryExpression(expression.getNodeType(), expression,
-            expression.type);
-  }
-
-  public Visitor preVisit(MethodDeclaration methodDeclaration) {
-    return this;
-  }
-
-  public MemberDeclaration visit(MethodDeclaration methodDeclaration,
-      BlockStatement body) {
-    return body.equals(methodDeclaration.body)
-        ? methodDeclaration
-        : Expressions.methodDecl(methodDeclaration.modifier,
-            methodDeclaration.resultType, methodDeclaration.name,
-            methodDeclaration.parameters, body);
-  }
-
-  public Visitor preVisit(FieldDeclaration fieldDeclaration) {
-    return this;
-  }
-
-  public MemberDeclaration visit(FieldDeclaration fieldDeclaration,
-      Expression initializer) {
-    return eq(initializer, fieldDeclaration.initializer)
-        ? fieldDeclaration
-        : Expressions.fieldDecl(fieldDeclaration.modifier,
-            fieldDeclaration.parameter, initializer);
-  }
-
-  public Expression visit(ParameterExpression parameterExpression) {
-    return parameterExpression;
-  }
-
-  public ConstantExpression visit(ConstantExpression constantExpression) {
-    return constantExpression;
-  }
-
-  public Visitor preVisit(ClassDeclaration classDeclaration) {
-    return this;
-  }
-
-  public ClassDeclaration visit(ClassDeclaration classDeclaration,
-      List<MemberDeclaration> memberDeclarations) {
-    return Objects.equals(memberDeclarations,
-        classDeclaration.memberDeclarations)
-        ? classDeclaration
-        : Expressions.classDecl(classDeclaration.modifier,
-            classDeclaration.name, classDeclaration.extended,
-            classDeclaration.implemented, memberDeclarations);
-  }
-
-  public Visitor preVisit(ConstructorDeclaration constructorDeclaration) {
-    return this;
-  }
-
-  public MemberDeclaration visit(ConstructorDeclaration constructorDeclaration,
-      BlockStatement body) {
-    return body.equals(constructorDeclaration.body)
-        ? constructorDeclaration
-        : Expressions.constructorDecl(constructorDeclaration.modifier,
-            constructorDeclaration.resultType,
-            constructorDeclaration.parameters,
-            body);
-  }
+public interface Visitor<R> {
+  R visit(BinaryExpression binaryExpression);
+  R visit(BlockStatement blockStatement);
+  R visit(ClassDeclaration classDeclaration);
+  R visit(ConditionalExpression conditionalExpression);
+  R visit(ConditionalStatement conditionalStatement);
+  R visit(ConstantExpression constantExpression);
+  R visit(ConstructorDeclaration constructorDeclaration);
+  R visit(DeclarationStatement declarationStatement);
+  R visit(DefaultExpression defaultExpression);
+  R visit(DynamicExpression dynamicExpression);
+  R visit(FieldDeclaration fieldDeclaration);
+  R visit(ForStatement forStatement);
+  R visit(FunctionExpression functionExpression);
+  R visit(GotoStatement gotoStatement);
+  R visit(IndexExpression indexExpression);
+  R visit(InvocationExpression invocationExpression);
+  R visit(LabelStatement labelStatement);
+  R visit(LambdaExpression lambdaExpression);
+  R visit(ListInitExpression listInitExpression);
+  R visit(MemberExpression memberExpression);
+  R visit(MemberInitExpression memberInitExpression);
+  R visit(MethodCallExpression methodCallExpression);
+  R visit(MethodDeclaration methodDeclaration);
+  R visit(NewArrayExpression newArrayExpression);
+  R visit(NewExpression newExpression);
+  R visit(ParameterExpression parameterExpression);
+  R visit(SwitchStatement switchStatement);
+  R visit(TernaryExpression ternaryExpression);
+  R visit(ThrowStatement throwStatement);
+  R visit(TryStatement tryStatement);
+  R visit(TypeBinaryExpression typeBinaryExpression);
+  R visit(UnaryExpression unaryExpression);
+  R visit(WhileStatement whileStatement);
 }
 
 // End Visitor.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/VisitorImpl.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/VisitorImpl.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/VisitorImpl.java
new file mode 100644
index 0000000..2507db9
--- /dev/null
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/VisitorImpl.java
@@ -0,0 +1,206 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.linq4j.tree;
+
+import java.util.List;
+
+/**
+ * Default implementation of {@link Visitor}, which traverses a tree but does
+ * nothing. In a derived class you can override selected methods.
+ *
+ * @param <R> Return type
+ */
+public class VisitorImpl<R> implements Visitor<R> {
+  public VisitorImpl() {
+    super();
+  }
+
+  public R visit(BinaryExpression binaryExpression) {
+    R r0 = binaryExpression.expression0.accept(this);
+    R r1 = binaryExpression.expression1.accept(this);
+    return r1;
+  }
+
+  public R visit(BlockStatement blockStatement) {
+    return Expressions.acceptNodes(blockStatement.statements, this);
+  }
+
+  public R visit(ClassDeclaration classDeclaration) {
+    return Expressions.acceptNodes(classDeclaration.memberDeclarations, this);
+  }
+
+  public R visit(ConditionalExpression conditionalExpression) {
+    return Expressions.acceptNodes(conditionalExpression.expressionList, this);
+  }
+
+  public R visit(ConditionalStatement conditionalStatement) {
+    return Expressions.acceptNodes(conditionalStatement.expressionList, this);
+  }
+
+  public R visit(ConstantExpression constantExpression) {
+    return null;
+  }
+
+  public R visit(ConstructorDeclaration constructorDeclaration) {
+    R r0 = Expressions.acceptNodes(constructorDeclaration.parameters, this);
+    return constructorDeclaration.body.accept(this);
+  }
+
+  public R visit(DeclarationStatement declarationStatement) {
+    R r = declarationStatement.parameter.accept(this);
+    if (declarationStatement.initializer != null) {
+      r = declarationStatement.initializer.accept(this);
+    }
+    return r;
+  }
+
+  public R visit(DefaultExpression defaultExpression) {
+    return null;
+  }
+
+  public R visit(DynamicExpression dynamicExpression) {
+    return null;
+  }
+
+  public R visit(FieldDeclaration fieldDeclaration) {
+    R r0 = fieldDeclaration.parameter.accept(this);
+    return fieldDeclaration.initializer.accept(this);
+  }
+
+  public R visit(ForStatement forStatement) {
+    R r0 = Expressions.acceptNodes(forStatement.declarations, this);
+    R r1 = forStatement.condition.accept(this);
+    R r2 = forStatement.post.accept(this);
+    return forStatement.body.accept(this);
+  }
+
+  public R visit(FunctionExpression functionExpression) {
+    @SuppressWarnings("unchecked") final List<Node> parameterList =
+        functionExpression.parameterList;
+    R r0 = Expressions.acceptNodes(parameterList, this);
+    return functionExpression.body.accept(this);
+  }
+
+  public R visit(GotoStatement gotoStatement) {
+    return gotoStatement.expression.accept(this);
+  }
+
+  public R visit(IndexExpression indexExpression) {
+    R r0 = indexExpression.array.accept(this);
+    return Expressions.acceptNodes(indexExpression.indexExpressions, this);
+  }
+
+  public R visit(InvocationExpression invocationExpression) {
+    return null;
+  }
+
+  public R visit(LabelStatement labelStatement) {
+    return labelStatement.defaultValue.accept(this);
+  }
+
+  public R visit(LambdaExpression lambdaExpression) {
+    return null;
+  }
+
+  public R visit(ListInitExpression listInitExpression) {
+    return null;
+  }
+
+  public R visit(MemberExpression memberExpression) {
+    R r = null;
+    if (memberExpression.expression != null) {
+      r = memberExpression.expression.accept(this);
+    }
+    return r;
+  }
+
+  public R visit(MemberInitExpression memberInitExpression) {
+    return null;
+  }
+
+  public R visit(MethodCallExpression methodCallExpression) {
+    R r = null;
+    if (methodCallExpression.targetExpression != null) {
+      r = methodCallExpression.targetExpression.accept(this);
+    }
+    return Expressions.acceptNodes(methodCallExpression.expressions, this);
+  }
+
+  public R visit(MethodDeclaration methodDeclaration) {
+    R r0 = Expressions.acceptNodes(methodDeclaration.parameters, this);
+    return methodDeclaration.body.accept(this);
+  }
+
+  public R visit(NewArrayExpression newArrayExpression) {
+    R r = null;
+    if (newArrayExpression.bound != null) {
+      r = newArrayExpression.bound.accept(this);
+    }
+    return Expressions.acceptNodes(newArrayExpression.expressions, this);
+  }
+
+  public R visit(NewExpression newExpression) {
+    R r0 = Expressions.acceptNodes(newExpression.arguments, this);
+    return Expressions.acceptNodes(newExpression.memberDeclarations, this);
+  }
+
+  public R visit(ParameterExpression parameterExpression) {
+    return null;
+  }
+
+  public R visit(SwitchStatement switchStatement) {
+    return null;
+  }
+
+  public R visit(TernaryExpression ternaryExpression) {
+    R r0 = ternaryExpression.expression0.accept(this);
+    R r1 = ternaryExpression.expression1.accept(this);
+    return ternaryExpression.expression2.accept(this);
+  }
+
+  public R visit(ThrowStatement throwStatement) {
+    return throwStatement.expression.accept(this);
+  }
+
+  public R visit(TryStatement tryStatement) {
+    R r = tryStatement.body.accept(this);
+    for (CatchBlock catchBlock : tryStatement.catchBlocks) {
+      r = catchBlock.parameter.accept(this);
+      r = catchBlock.body.accept(this);
+    }
+    if (tryStatement.fynally != null) {
+      r = tryStatement.fynally.accept(this);
+    }
+    return r;
+  }
+
+  public R visit(TypeBinaryExpression typeBinaryExpression) {
+    return typeBinaryExpression.expression.accept(this);
+  }
+
+  public R visit(UnaryExpression unaryExpression) {
+    return unaryExpression.expression.accept(this);
+  }
+
+  public R visit(WhileStatement whileStatement) {
+    R r0 = whileStatement.condition.accept(this);
+    return whileStatement.body.accept(this);
+  }
+
+}
+
+// End VisitorImpl.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/WhileStatement.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/WhileStatement.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/WhileStatement.java
index 9253fa7..215097a 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/WhileStatement.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/WhileStatement.java
@@ -33,11 +33,15 @@ public class WhileStatement extends Statement {
     this.body = body;
   }
 
-  @Override public Statement accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
-    final Expression condition1 = condition.accept(visitor);
-    final Statement body1 = body.accept(visitor);
-    return visitor.visit(this, condition1, body1);
+  @Override public Statement accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
+    final Expression condition1 = condition.accept(shuttle);
+    final Statement body1 = body.accept(shuttle);
+    return shuttle.visit(this, condition1, body1);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override void accept0(ExpressionWriter writer) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/test/java/org/apache/calcite/linq4j/test/BlockBuilderTest.java
----------------------------------------------------------------------
diff --git a/linq4j/src/test/java/org/apache/calcite/linq4j/test/BlockBuilderTest.java b/linq4j/src/test/java/org/apache/calcite/linq4j/test/BlockBuilderTest.java
index ce8b03b..86c68c1 100644
--- a/linq4j/src/test/java/org/apache/calcite/linq4j/test/BlockBuilderTest.java
+++ b/linq4j/src/test/java/org/apache/calcite/linq4j/test/BlockBuilderTest.java
@@ -21,8 +21,8 @@ import org.apache.calcite.linq4j.tree.BlockBuilder;
 import org.apache.calcite.linq4j.tree.Expression;
 import org.apache.calcite.linq4j.tree.ExpressionType;
 import org.apache.calcite.linq4j.tree.Expressions;
-import org.apache.calcite.linq4j.tree.OptimizeVisitor;
-import org.apache.calcite.linq4j.tree.Visitor;
+import org.apache.calcite.linq4j.tree.OptimizeShuttle;
+import org.apache.calcite.linq4j.tree.Shuttle;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -62,8 +62,8 @@ public class BlockBuilderTest {
 
   @Test public void testTestCustomOptimizer() {
     BlockBuilder b = new BlockBuilder() {
-      @Override protected Visitor createOptimizeVisitor() {
-        return new OptimizeVisitor() {
+      @Override protected Shuttle createOptimizeShuttle() {
+        return new OptimizeShuttle() {
           @Override public Expression visit(BinaryExpression binary,
               Expression expression0, Expression expression1) {
             if (binary.getNodeType() == ExpressionType.Add

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/test/java/org/apache/calcite/linq4j/test/ExpressionTest.java
----------------------------------------------------------------------
diff --git a/linq4j/src/test/java/org/apache/calcite/linq4j/test/ExpressionTest.java b/linq4j/src/test/java/org/apache/calcite/linq4j/test/ExpressionTest.java
index 0be06c1..fe4354d 100644
--- a/linq4j/src/test/java/org/apache/calcite/linq4j/test/ExpressionTest.java
+++ b/linq4j/src/test/java/org/apache/calcite/linq4j/test/ExpressionTest.java
@@ -31,8 +31,8 @@ import org.apache.calcite.linq4j.tree.MethodCallExpression;
 import org.apache.calcite.linq4j.tree.NewExpression;
 import org.apache.calcite.linq4j.tree.Node;
 import org.apache.calcite.linq4j.tree.ParameterExpression;
+import org.apache.calcite.linq4j.tree.Shuttle;
 import org.apache.calcite.linq4j.tree.Types;
-import org.apache.calcite.linq4j.tree.Visitor;
 
 import org.junit.Test;
 
@@ -899,7 +899,7 @@ public class ExpressionTest {
     statements.add(Expressions.return_(null, eighteen));
     BlockStatement expression = statements.toBlock();
     assertEquals(expected, Expressions.toString(expression));
-    expression.accept(new Visitor());
+    expression.accept(new Shuttle());
   }
 
   @Test public void testBlockBuilder2() {
@@ -930,7 +930,7 @@ public class ExpressionTest {
             + "      (java.util.Comparator) null).add(null);\n"
             + "}\n",
         Expressions.toString(expression));
-    expression.accept(new Visitor());
+    expression.accept(new Shuttle());
   }
 
   @Test public void testBlockBuilder3() {
@@ -978,7 +978,7 @@ public class ExpressionTest {
             + "  org.apache.calcite.linq4j.test.ExpressionTest.bar(1, _b, _c, _d, org.apache.calcite.linq4j.test.ExpressionTest.foo(_c));\n"
             + "}\n",
         Expressions.toString(expression));
-    expression.accept(new Visitor());
+    expression.accept(new Shuttle());
   }
 
   @Test public void testConstantExpression() {
@@ -1021,7 +1021,7 @@ public class ExpressionTest {
             + "    \"109\",\n"
             + "    null)}",
         constant.toString());
-    constant.accept(new Visitor());
+    constant.accept(new Shuttle());
   }
 
   @Test public void testClassDecl() {
@@ -1056,7 +1056,7 @@ public class ExpressionTest {
             + "  int i;\n"
             + "}",
         Expressions.toString(newExpression));
-    newExpression.accept(new Visitor());
+    newExpression.accept(new Shuttle());
   }
 
   @Test public void testReturn() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/site/_docs/adapter.md
----------------------------------------------------------------------
diff --git a/site/_docs/adapter.md b/site/_docs/adapter.md
index fd06d8c..5f9a20d 100644
--- a/site/_docs/adapter.md
+++ b/site/_docs/adapter.md
@@ -70,15 +70,18 @@ as implemented by Avatica's
 | Property | Description |
 |:-------- |:------------|
 | <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#CASE_SENSITIVE">caseSensitive</a> | Whether identifiers are matched case-sensitively. If not specified, value from `lex` is used.
-| <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#CONFORMANCE">conformance</a> | SQL conformance level. Values: "default" (the default, similar to "pragmatic_2003"), "oracle_10", "pragmatic_99", "pragmatic_2003", "strict_92", "strict_99", "strict_2003".
+| <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#CONFORMANCE">conformance</a> | SQL conformance level. Values: DEFAULT (the default, similar to PRAGMATIC_2003), ORACLE_10, ORACLE_12, PRAGMATIC_99, PRAGMATIC_2003, STRICT_92, STRICT_99, STRICT_2003, SQL_SERVER_2008.
 | <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#CREATE_MATERIALIZATIONS">createMaterializations</a> | Whether Calcite should create materializations. Default false.
 | <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#DEFAULT_NULL_COLLATION">materializationsEnabled</a> | How NULL values should be sorted if neither NULLS FIRST nor NULLS LAST are specified in a query. The default, HIGH, sorts NULL values the same as Oracle.
+| <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#DRUID_FETCH">druidFetch</a> | How many rows the Druid adapter should fetch at a time when executing SELECT queries.
 | <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#FORCE_DECORRELATE">forceDecorrelate</a> | Whether the planner should try de-correlating as much as possible. Default true.
 | <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#FUN">fun</a> | Collection of built-in functions and operators. Valid values: "standard" (the default), "oracle".
 | <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#LEX">lex</a> | Lexical policy. Values are ORACLE (default), MYSQL, MYSQL_ANSI, SQL_SERVER, JAVA.
 | <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#MATERIALIZATIONS_ENABLED">materializationsEnabled</a> | Whether Calcite should use materializations. Default false.
 | <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#MODEL">model</a> | URI of the JSON model file.
+| <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#PARSER_FACTORY">parserFactory</a> | Parser factory. The name of a class that implements <a href="{{ site.apiRoot }}/org/apache/calcite/sql/parser/SqlParserImplFactory.html">SqlParserImplFactory</a> and has a public default constructor or an `INSTANCE` constant.
 | <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#QUOTING">quoting</a> | How identifiers are quoted. Values are DOUBLE_QUOTE, BACK_QUOTE, BRACKET. If not specified, value from `lex` is used.
+| <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#QUOTED_CASING">quotedCasing</a> | How identifiers are stored if they are quoted. Values are UNCHANGED, TO_UPPER, TO_LOWER. If not specified, value from `lex` is used.
 | <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#SCHEMA">schema</a> | Name of initial schema.
 | <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#SCHEMA_FACTORY">schemaFactory</a> | Schema factory. The name of a class that implements <a href="{{ site.apiRoot }}/org/apache/calcite/schema/SchemaFactory.html">SchemaFactory</a> and has a public default constructor or an `INSTANCE` constant. Ignored if `model` is specified.
 | <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#SCHEMA_TYPE">schemaType</a> | Schema type. Value must be "MAP" (the default), "JDBC", or "CUSTOM" (implicit if `schemaFactory` is specified). Ignored if `model` is specified.


[3/3] calcite git commit: [CALCITE-1529] Support CREATE TABLE in tests (and only in tests)

Posted by jh...@apache.org.
[CALCITE-1529] Support CREATE TABLE in tests (and only in tests)

Upgrade freemarker.

Add "parserFactory" to config.


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

Branch: refs/heads/master
Commit: e641211fd72a4f4a24f0f4644034c4b2f3c040ca
Parents: 267e2f3
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Dec 5 22:49:22 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Wed Dec 7 18:35:30 2016 -0800

----------------------------------------------------------------------
 core/src/main/codegen/config.fmpp               |  12 +-
 core/src/main/codegen/templates/Parser.jj       |  61 +++++++
 .../enumerable/EnumerableRelImplementor.java    |  13 ++
 .../enumerable/EnumerableTableModify.java       |   5 +-
 .../adapter/enumerable/EnumerableTableScan.java |   7 +
 .../calcite/config/CalciteConnectionConfig.java |   2 +
 .../config/CalciteConnectionConfigImpl.java     |   6 +
 .../config/CalciteConnectionProperty.java       |   6 +
 .../calcite/prepare/CalcitePrepareImpl.java     |  24 ++-
 .../java/org/apache/calcite/sql/SqlCreate.java  |  46 +++++
 .../org/apache/calcite/sql/SqlDataTypeSpec.java |  37 +++-
 .../java/org/apache/calcite/sql/SqlDrop.java    |  34 ++++
 .../calcite/sql/SqlExecutableStatement.java     |  31 ++++
 core/src/test/codegen/config.fmpp               |  17 +-
 core/src/test/codegen/includes/parserImpls.ftl  |  13 ++
 .../calcite/sql/parser/SqlParserTest.java       |   2 +-
 .../ExtensionSqlParserTest.java                 |   5 +
 .../parserextensiontesting/SqlCreateTable.java  | 169 +++++++++++++++++++
 .../org/apache/calcite/test/CalciteAssert.java  |   3 +
 .../org/apache/calcite/test/QuidemTest.java     |  35 ++--
 core/src/test/resources/sql/blank.iq            |  44 +++++
 pom.xml                                         |   2 +-
 site/_docs/reference.md                         |   1 +
 23 files changed, 538 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/main/codegen/config.fmpp
----------------------------------------------------------------------
diff --git a/core/src/main/codegen/config.fmpp b/core/src/main/codegen/config.fmpp
index 9f7a118..41cfeee 100644
--- a/core/src/main/codegen/config.fmpp
+++ b/core/src/main/codegen/config.fmpp
@@ -70,12 +70,22 @@ data: {
     dataTypeParserMethods: [
     ]
 
-    # List of methods for parsing extensions to ALTER SYSTEM calls.
+    # List of methods for parsing extensions to "ALTER <scope>" calls.
     # Each must accept arguments "(SqlParserPos pos, String scope)".
     # Example: "SqlUploadJarNode"
     alterStatementParserMethods: [
     ]
 
+    # List of methods for parsing extensions to "CREATE [OR REPLACE]" calls.
+    # Each must accept arguments "(SqlParserPos pos, boolean replace)".
+    createStatementParserMethods: [
+    ]
+
+    # List of methods for parsing extensions to "DROP" calls.
+    # Each must accept arguments "(SqlParserPos pos)".
+    dropStatementParserMethods: [
+    ]
+
     # List of files in @includes directory that have parser method
     # implementations for parsing custom SQL statements, literals or types
     # given as part of "statementParserMethods", "literalParserMethods" or

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/main/codegen/templates/Parser.jj
----------------------------------------------------------------------
diff --git a/core/src/main/codegen/templates/Parser.jj b/core/src/main/codegen/templates/Parser.jj
index 390c75c..26d40f4 100644
--- a/core/src/main/codegen/templates/Parser.jj
+++ b/core/src/main/codegen/templates/Parser.jj
@@ -928,6 +928,10 @@ SqlNode SqlStmt() :
         |
         stmt = SqlAlter()
         |
+<#if parser.createStatementParserMethods?size != 0>
+        stmt = SqlCreate()
+        |
+</#if>
         stmt = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY)
         |
         stmt = SqlExplain()
@@ -3088,6 +3092,61 @@ String Scope() :
     ( <SYSTEM> | <SESSION> ) { return token.image.toUpperCase(); }
 }
 
+<#if parser.createStatementParserMethods?size != 0>
+/**
+ * Parses a CREATE statement.
+ */
+SqlCreate SqlCreate() :
+{
+    final SqlParserPos pos;
+    boolean replace = false;
+    final SqlCreate create;
+}
+{
+    <CREATE> { pos = getPos(); }
+    [
+        <OR> <REPLACE> {
+            replace = true;
+        }
+    ]
+    (
+    <#-- additional literal parser methods are included here -->
+    <#list parser.createStatementParserMethods as method>
+        create = ${method}(pos, replace)
+        <#sep>|</#sep>
+    </#list>
+    )
+    {
+        return create;
+    }
+}
+</#if>
+
+<#if parser.dropStatementParserMethods?size != 0>
+/**
+ * Parses a DROP statement.
+ */
+SqlDrop SqlDrop() :
+{
+    final SqlParserPos pos;
+    boolean replace = false;
+    final SqlDrop drop;
+}
+{
+    <DROP> { pos = getPos(); }
+    (
+    <#-- additional literal parser methods are included here -->
+    <#list parser.dropStatementParserMethods as method>
+        drop = ${method}(pos, replace)
+        <#sep>|</#sep>
+    </#list>
+    )
+    {
+        return drop;
+    }
+}
+</#if>
+
 /**
  * Parses a literal expression, allowing continued string literals.
  * Usually returns an SqlLiteral, but a continued string literal
@@ -5333,6 +5392,7 @@ SqlPostfixOperator PostfixRowOperator() :
     | < RELATIVE: "RELATIVE" >
     | < RELEASE: "RELEASE" >
     | < REPEATABLE: "REPEATABLE" >
+    | < REPLACE: "REPLACE" >
     | < RESET: "RESET" >
     | < RESTART: "RESTART" >
     | < RESTRICT: "RESTRICT" >
@@ -5733,6 +5793,7 @@ String CommonNonReservedKeyWord() :
         | <READ>
         | <RELATIVE>
         | <REPEATABLE>
+        | <REPLACE>
         | <RESTART>
         | <RESTRICT>
         | <RETURNED_CARDINALITY>

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java
index 90105e0..6e9033c 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java
@@ -66,6 +66,12 @@ import java.util.Set;
  * operators of {@link EnumerableConvention} calling convention.
  */
 public class EnumerableRelImplementor extends JavaRelImplementor {
+  /** Maximum number of arguments to a constructor. See
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-1097">[CALCITE-1097]
+   * Exception when executing query with too many aggregation columns</a> for
+   * details. */
+  private static final int MAX_CONSTRUCTOR_ARG_COUNT = 10;
+
   public final Map<String, Object> map;
   private final Map<String, RexToLixTranslator.InputGetter> corrVars =
       Maps.newHashMap();
@@ -482,6 +488,13 @@ public class EnumerableRelImplementor extends JavaRelImplementor {
       types.add(type);
       return super.visit(newArrayExpression);
     }
+
+    @Override public Void visit(ConstantExpression constantExpression) {
+      if (constantExpression.value instanceof Type) {
+        types.add((Type) constantExpression.value);
+      }
+      return super.visit(constantExpression);
+    }
   }
 
   /** Adds a declaration of each synthetic type found in a code block. */

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableModify.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableModify.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableModify.java
index 07128e4..14ac0de 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableModify.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableModify.java
@@ -101,9 +101,9 @@ public class EnumerableTableModify extends TableModify
     if (!getInput().getRowType().equals(getRowType())) {
       final JavaTypeFactory typeFactory =
           (JavaTypeFactory) getCluster().getTypeFactory();
+      final JavaRowFormat format = EnumerableTableScan.deduceFormat(table);
       PhysType physType =
-          PhysTypeImpl.of(typeFactory, table.getRowType(),
-              JavaRowFormat.CUSTOM);
+          PhysTypeImpl.of(typeFactory, table.getRowType(), format);
       List<Expression> expressionList = new ArrayList<Expression>();
       final PhysType childPhysType = result.physType;
       final ParameterExpression o_ =
@@ -167,6 +167,7 @@ public class EnumerableTableModify extends TableModify
                 ? JavaRowFormat.ARRAY : JavaRowFormat.SCALAR);
     return implementor.result(physType, builder.toBlock());
   }
+
 }
 
 // End EnumerableTableModify.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScan.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScan.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScan.java
index d7529ce..9fd5d34 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScan.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScan.java
@@ -127,6 +127,13 @@ public class EnumerableTableScan
     }
   }
 
+  public static JavaRowFormat deduceFormat(RelOptTable table) {
+    final Class elementType = deduceElementType(table.unwrap(Table.class));
+    return elementType == Object[].class
+        ? JavaRowFormat.ARRAY
+        : JavaRowFormat.CUSTOM;
+  }
+
   private Expression getExpression(PhysType physType) {
     final Expression expression = table.getExpression(Queryable.class);
     final Expression expression2 = toEnumerable(expression);

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfig.java b/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfig.java
index 1c3b0d6..6eac17d 100644
--- a/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfig.java
+++ b/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfig.java
@@ -48,6 +48,8 @@ public interface CalciteConnectionConfig extends ConnectionConfig {
   Casing quotedCasing();
   /** @see CalciteConnectionProperty#CASE_SENSITIVE */
   boolean caseSensitive();
+  /** @see CalciteConnectionProperty#PARSER_FACTORY */
+  <T> T parserFactory(Class<T> parserFactoryClass, T defaultParserFactory);
   /** @see CalciteConnectionProperty#SCHEMA_FACTORY */
   <T> T schemaFactory(Class<T> schemaFactoryClass, T defaultSchemaFactory);
   /** @see CalciteConnectionProperty#SCHEMA_TYPE */

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfigImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfigImpl.java b/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfigImpl.java
index 5262059..c169d9d 100644
--- a/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfigImpl.java
+++ b/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfigImpl.java
@@ -120,6 +120,12 @@ public class CalciteConnectionConfigImpl extends ConnectionConfigImpl
         .getBoolean(lex().caseSensitive);
   }
 
+  public <T> T parserFactory(Class<T> parserFactoryClass,
+      T defaultParserFactory) {
+    return CalciteConnectionProperty.PARSER_FACTORY.wrap(properties)
+        .getPlugin(parserFactoryClass, defaultParserFactory);
+  }
+
   public <T> T schemaFactory(Class<T> schemaFactoryClass,
       T defaultSchemaFactory) {
     return CalciteConnectionProperty.SCHEMA_FACTORY.wrap(properties)

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/main/java/org/apache/calcite/config/CalciteConnectionProperty.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/config/CalciteConnectionProperty.java b/core/src/main/java/org/apache/calcite/config/CalciteConnectionProperty.java
index e17740d..20baf7f 100644
--- a/core/src/main/java/org/apache/calcite/config/CalciteConnectionProperty.java
+++ b/core/src/main/java/org/apache/calcite/config/CalciteConnectionProperty.java
@@ -78,6 +78,12 @@ public enum CalciteConnectionProperty implements ConnectionProperty {
    *  If not specified, value from {@link #LEX} is used. */
   CASE_SENSITIVE("caseSensitive", Type.BOOLEAN, null, false),
 
+  /** Parser factory.
+   *
+   * <p>The name of a class that implements
+   * {@link org.apache.calcite.sql.parser.SqlParserImplFactory}. */
+  PARSER_FACTORY("parserFactory", Type.PLUGIN, null, false),
+
   /** Name of initial schema. */
   SCHEMA("schema", Type.STRING, null, false),
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
index 9125d0b..ee7d4ee 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -111,6 +111,7 @@ import org.apache.calcite.schema.Schemas;
 import org.apache.calcite.schema.Table;
 import org.apache.calcite.server.CalciteServerStatement;
 import org.apache.calcite.sql.SqlBinaryOperator;
+import org.apache.calcite.sql.SqlExecutableStatement;
 import org.apache.calcite.sql.SqlExplainFormat;
 import org.apache.calcite.sql.SqlExplainLevel;
 import org.apache.calcite.sql.SqlKind;
@@ -121,6 +122,7 @@ import org.apache.calcite.sql.SqlUtil;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.parser.SqlParseException;
 import org.apache.calcite.sql.parser.SqlParser;
+import org.apache.calcite.sql.parser.SqlParserImplFactory;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.util.ChainedSqlOperatorTable;
 import org.apache.calcite.sql.validate.SqlConformance;
@@ -431,6 +433,11 @@ public class CalcitePrepareImpl implements CalcitePrepare {
   }
 
   @Override public void executeDdl(Context context, SqlNode node) {
+    if (node instanceof SqlExecutableStatement) {
+      SqlExecutableStatement statement = (SqlExecutableStatement) node;
+      statement.execute(context);
+      return;
+    }
     throw new UnsupportedOperationException();
   }
 
@@ -708,12 +715,17 @@ public class CalcitePrepareImpl implements CalcitePrepare {
     final Meta.StatementType statementType;
     if (query.sql != null) {
       final CalciteConnectionConfig config = context.config();
-      SqlParser parser = createParser(query.sql,
-          createParserConfig()
-              .setQuotedCasing(config.quotedCasing())
-              .setUnquotedCasing(config.unquotedCasing())
-              .setQuoting(config.quoting())
-              .setConformance(config.conformance()));
+      final SqlParser.ConfigBuilder parserConfig = createParserConfig()
+          .setQuotedCasing(config.quotedCasing())
+          .setUnquotedCasing(config.unquotedCasing())
+          .setQuoting(config.quoting())
+          .setConformance(config.conformance());
+      final SqlParserImplFactory parserFactory =
+          config.parserFactory(SqlParserImplFactory.class, null);
+      if (parserFactory != null) {
+        parserConfig.setParserFactory(parserFactory);
+      }
+      SqlParser parser = createParser(query.sql,  parserConfig);
       SqlNode sqlNode;
       try {
         sqlNode = parser.parseStmt();

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/main/java/org/apache/calcite/sql/SqlCreate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlCreate.java b/core/src/main/java/org/apache/calcite/sql/SqlCreate.java
new file mode 100644
index 0000000..57e9a71
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/sql/SqlCreate.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.sql;
+
+import org.apache.calcite.sql.parser.SqlParserPos;
+
+/**
+ * Base class for an CREATE statements parse tree nodes. The portion of the
+ * statement covered by this class is "CREATE [ OR REPLACE ]". Subclasses handle
+ * whatever comes afterwards.
+ */
+public abstract class SqlCreate extends SqlCall {
+
+  /** Whether "OR REPLACE" was specified. */
+  boolean replace;
+
+  public SqlCreate(SqlParserPos pos, boolean replace) {
+    super(pos);
+    this.replace = replace;
+  }
+
+  public boolean getReplace() {
+    return replace;
+  }
+
+  public void setReplace(boolean replace) {
+    this.replace = replace;
+  }
+
+}
+
+// End SqlCreate.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java b/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java
index c53b832..7c4e2cb 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java
@@ -28,6 +28,8 @@ import org.apache.calcite.sql.validate.SqlValidatorScope;
 import org.apache.calcite.util.Litmus;
 import org.apache.calcite.util.Util;
 
+import com.google.common.base.Preconditions;
+
 import java.nio.charset.Charset;
 import java.util.Objects;
 import java.util.TimeZone;
@@ -158,6 +160,10 @@ public class SqlDataTypeSpec extends SqlNode {
     return timeZone;
   }
 
+  public Boolean getNullable() {
+    return nullable;
+  }
+
   /** Returns a copy of this data type specification with a given
    * nullability. */
   public SqlDataTypeSpec withNullable(Boolean nullable) {
@@ -289,9 +295,22 @@ public class SqlDataTypeSpec extends SqlNode {
    * Does not throw an error if the type is not built-in.
    */
   public RelDataType deriveType(RelDataTypeFactory typeFactory) {
-    String name = typeName.getSimple();
+    return deriveType(typeFactory, false);
+  }
 
-    SqlTypeName sqlTypeName = SqlTypeName.get(name);
+  /**
+   * Converts this type specification to a {@link RelDataType}.
+   *
+   * <p>Does not throw an error if the type is not built-in.
+   *
+   * @param nullable Whether the type is nullable if the type specification
+   *                 does not explicitly state
+   */
+  public RelDataType deriveType(RelDataTypeFactory typeFactory,
+      boolean nullable) {
+    final String name = typeName.getSimple();
+    final SqlTypeName sqlTypeName =
+        Preconditions.checkNotNull(SqlTypeName.get(name));
 
     // NOTE jvs 15-Jan-2009:  earlier validation is supposed to
     // have caught these, which is why it's OK for them
@@ -322,7 +341,8 @@ public class SqlDataTypeSpec extends SqlNode {
         charset = typeFactory.getDefaultCharset();
       } else {
         String javaCharSetName =
-            SqlUtil.translateCharacterSetName(charSetName);
+            Preconditions.checkNotNull(
+                SqlUtil.translateCharacterSetName(charSetName), charSetName);
         charset = Charset.forName(javaCharSetName);
       }
       type =
@@ -334,9 +354,9 @@ public class SqlDataTypeSpec extends SqlNode {
 
     if (null != collectionsTypeName) {
       final String collectionName = collectionsTypeName.getSimple();
-
-      SqlTypeName collectionsSqlTypeName =
-          SqlTypeName.get(collectionName);
+      final SqlTypeName collectionsSqlTypeName =
+          Preconditions.checkNotNull(SqlTypeName.get(collectionName),
+              collectionName);
 
       switch (collectionsSqlTypeName) {
       case MULTISET:
@@ -348,9 +368,10 @@ public class SqlDataTypeSpec extends SqlNode {
       }
     }
 
-    if (nullable != null) {
-      type = typeFactory.createTypeWithNullability(type, nullable);
+    if (this.nullable != null) {
+      nullable = this.nullable;
     }
+    type = typeFactory.createTypeWithNullability(type, nullable);
 
     return type;
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/main/java/org/apache/calcite/sql/SqlDrop.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDrop.java b/core/src/main/java/org/apache/calcite/sql/SqlDrop.java
new file mode 100644
index 0000000..1716d32
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/sql/SqlDrop.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.sql;
+
+import org.apache.calcite.sql.parser.SqlParserPos;
+
+/**
+ * Base class for an DROP statements parse tree nodes. The portion of the
+ * statement covered by this class is "DROP". Subclasses handle
+ * whatever comes afterwards.
+ */
+public abstract class SqlDrop extends SqlCall {
+
+  public SqlDrop(SqlParserPos pos) {
+    super(pos);
+  }
+
+}
+
+// End SqlDrop.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/main/java/org/apache/calcite/sql/SqlExecutableStatement.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlExecutableStatement.java b/core/src/main/java/org/apache/calcite/sql/SqlExecutableStatement.java
new file mode 100644
index 0000000..06ca55f
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/sql/SqlExecutableStatement.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.sql;
+
+import org.apache.calcite.jdbc.CalcitePrepare;
+
+/**
+ * Mix-in interface for {@link SqlNode} that allows DDL commands to be
+ * executed directly.
+ *
+ * <p>NOTE: Subject to change without notice.
+ */
+public interface SqlExecutableStatement {
+  void execute(CalcitePrepare.Context context);
+}
+
+// End SqlExecutableStatement.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/test/codegen/config.fmpp
----------------------------------------------------------------------
diff --git a/core/src/test/codegen/config.fmpp b/core/src/test/codegen/config.fmpp
index 7b8b8e2..bd168b1 100644
--- a/core/src/test/codegen/config.fmpp
+++ b/core/src/test/codegen/config.fmpp
@@ -21,6 +21,8 @@ data: {
 
       # List of import statements.
       imports: [
+        "org.apache.calcite.sql.SqlCreate",
+        "org.apache.calcite.sql.parser.parserextensiontesting.SqlCreateTable",
         "org.apache.calcite.sql.parser.parserextensiontesting.SqlUploadJarNode"
       ]
 
@@ -47,14 +49,25 @@ data: {
       dataTypeParserMethods: [
       ]
 
-      # List of methods for parsing extensions to ALTER SYSTEM calls.
+      # List of methods for parsing extensions to "ALTER <scope>" calls.
       # Each must accept arguments "(SqlParserPos pos, String scope)".
       alterStatementParserMethods: [
         "SqlUploadJarNode"
       ]
 
+      # List of methods for parsing extensions to "CREATE [OR REPLACE]" calls.
+      # Each must accept arguments "(SqlParserPos pos, boolean replace)".
+      createStatementParserMethods: [
+        "SqlCreateTable"
+      ]
+
+      # List of methods for parsing extensions to "DROP" calls.
+      # Each must accept arguments "(SqlParserPos pos)".
+      dropStatementParserMethods: [
+      ]
+
       # List of files in @includes directory that have parser method
-      # implementations for custom SQL statements, literals or types
+      # implementations for parsing custom SQL statements, literals or types
       # given as part of "statementParserMethods", "literalParserMethods" or
       # "dataTypeParserMethods".
       implementationFiles: [

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/test/codegen/includes/parserImpls.ftl
----------------------------------------------------------------------
diff --git a/core/src/test/codegen/includes/parserImpls.ftl b/core/src/test/codegen/includes/parserImpls.ftl
index 2305fc1..56a4099 100644
--- a/core/src/test/codegen/includes/parserImpls.ftl
+++ b/core/src/test/codegen/includes/parserImpls.ftl
@@ -35,3 +35,16 @@ SqlAlter SqlUploadJarNode(SqlParserPos pos, String scope) :
         return new SqlUploadJarNode(pos.plus(getPos()), scope, jarPathsList);
     }
 }
+
+SqlCreate SqlCreateTable(SqlParserPos pos, boolean replace) :
+{
+    final SqlIdentifier id;
+    final SqlNodeList columnList;
+}
+{
+    <TABLE> id = CompoundIdentifier() columnList = ExtendList() {
+        return new SqlCreateTable(pos, id, columnList);
+    }
+}
+
+// End parserImpls.ftl

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java b/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
index 294a2f3..fa12def 100644
--- a/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
@@ -7308,7 +7308,7 @@ public class SqlParserTest {
 
   /** Helper class for building fluent code such as
    * {@code sql("values 1").ok();}. */
-  private class Sql {
+  protected class Sql {
     private final String sql;
 
     Sql(String sql) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/test/java/org/apache/calcite/sql/parser/parserextensiontesting/ExtensionSqlParserTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/parser/parserextensiontesting/ExtensionSqlParserTest.java b/core/src/test/java/org/apache/calcite/sql/parser/parserextensiontesting/ExtensionSqlParserTest.java
index 51e24bd..9d6fcfa 100644
--- a/core/src/test/java/org/apache/calcite/sql/parser/parserextensiontesting/ExtensionSqlParserTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/parser/parserextensiontesting/ExtensionSqlParserTest.java
@@ -44,6 +44,11 @@ public class ExtensionSqlParserTest extends SqlParserTest {
     checkFails("^upload^ jar '/path/to/jar'",
       "(?s).*Encountered \"upload\" at .*");
   }
+
+  @Test public void testCreateTable() {
+    sql("CREATE TABLE foo.baz(i INTEGER, j VARCHAR(10) NOT NULL)")
+        .ok("CREATE TABLE `FOO`.`BAZ` (`I` INTEGER, `J` VARCHAR(10) NOT NULL)");
+  }
 }
 
 // End ExtensionSqlParserTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/test/java/org/apache/calcite/sql/parser/parserextensiontesting/SqlCreateTable.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/parser/parserextensiontesting/SqlCreateTable.java b/core/src/test/java/org/apache/calcite/sql/parser/parserextensiontesting/SqlCreateTable.java
new file mode 100644
index 0000000..3889c12
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/sql/parser/parserextensiontesting/SqlCreateTable.java
@@ -0,0 +1,169 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.sql.parser.parserextensiontesting;
+
+import org.apache.calcite.adapter.java.JavaTypeFactory;
+import org.apache.calcite.jdbc.CalcitePrepare;
+import org.apache.calcite.jdbc.CalciteSchema;
+import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
+import org.apache.calcite.linq4j.Enumerator;
+import org.apache.calcite.linq4j.Linq4j;
+import org.apache.calcite.linq4j.QueryProvider;
+import org.apache.calcite.linq4j.Queryable;
+import org.apache.calcite.linq4j.tree.Expression;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeImpl;
+import org.apache.calcite.rel.type.RelProtoDataType;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.schema.Schemas;
+import org.apache.calcite.schema.impl.AbstractTableQueryable;
+import org.apache.calcite.sql.SqlCreate;
+import org.apache.calcite.sql.SqlDataTypeSpec;
+import org.apache.calcite.sql.SqlExecutableStatement;
+import org.apache.calcite.sql.SqlIdentifier;
+import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlNodeList;
+import org.apache.calcite.sql.SqlOperator;
+import org.apache.calcite.sql.SqlSpecialOperator;
+import org.apache.calcite.sql.SqlWriter;
+import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.calcite.test.JdbcTest;
+import org.apache.calcite.util.Pair;
+import org.apache.calcite.util.Util;
+
+import com.google.common.collect.ImmutableList;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Simple test example of a CREATE TABLE statement.
+ */
+public class SqlCreateTable extends SqlCreate
+    implements SqlExecutableStatement {
+  private final SqlIdentifier name;
+  private final SqlNodeList columnList;
+
+  private static final SqlOperator OPERATOR =
+      new SqlSpecialOperator("CREATE TABLE", SqlKind.OTHER_DDL);
+
+  /** Creates a SqlCreateTable. */
+  public SqlCreateTable(SqlParserPos pos, SqlIdentifier name,
+      SqlNodeList columnList) {
+    super(pos, false);
+    this.name = name;
+    this.columnList = columnList;
+  }
+
+  @Override public SqlOperator getOperator() {
+    return OPERATOR;
+  }
+
+  @Override public List<SqlNode> getOperandList() {
+    return ImmutableList.of(name, columnList);
+  }
+
+  @Override public void unparse(SqlWriter writer, int leftPrec, int rightPrec) {
+    writer.keyword("CREATE");
+    writer.keyword("TABLE");
+    name.unparse(writer, leftPrec, rightPrec);
+    SqlWriter.Frame frame = writer.startList("(", ")");
+    for (Pair<SqlIdentifier, SqlDataTypeSpec> pair : nameTypes()) {
+      writer.sep(",");
+      pair.left.unparse(writer, leftPrec, rightPrec); // name
+      pair.right.unparse(writer, leftPrec, rightPrec); // type
+      if (Boolean.FALSE.equals(pair.right.getNullable())) {
+        writer.keyword("NOT NULL");
+      }
+    }
+    writer.endList(frame);
+  }
+
+  /** Creates a list of (name, type) pairs from {@link #columnList}, in which
+   * they alternate. */
+  private List<Pair<SqlIdentifier, SqlDataTypeSpec>> nameTypes() {
+    final List list = columnList.getList();
+    //noinspection unchecked
+    return Pair.zip((List<SqlIdentifier>) Util.quotientList(list, 2, 0),
+        Util.quotientList((List<SqlDataTypeSpec>) list, 2, 1));
+  }
+
+  public void execute(CalcitePrepare.Context context) {
+    final List<String> path = context.getDefaultSchemaPath();
+    CalciteSchema schema = context.getRootSchema();
+    for (String p : path) {
+      schema = schema.getSubSchema(p, true);
+    }
+    final JavaTypeFactory typeFactory = new JavaTypeFactoryImpl();
+    final RelDataTypeFactory.FieldInfoBuilder builder = typeFactory.builder();
+    for (Pair<SqlIdentifier, SqlDataTypeSpec> pair : nameTypes()) {
+      builder.add(pair.left.getSimple(),
+          pair.right.deriveType(typeFactory, true));
+    }
+    final RelDataType rowType = builder.build();
+    schema.add(name.getSimple(),
+        new MutableArrayTable(name.getSimple(),
+            RelDataTypeImpl.proto(rowType)));
+  }
+
+  /** Table backed by a Java list. */
+  private static class MutableArrayTable
+      extends JdbcTest.AbstractModifiableTable {
+    final List list = new ArrayList();
+    private final RelProtoDataType protoRowType;
+
+    MutableArrayTable(String name, RelProtoDataType protoRowType) {
+      super(name);
+      this.protoRowType = protoRowType;
+    }
+
+    public Collection getModifiableCollection() {
+      return list;
+    }
+
+    public <T> Queryable<T> asQueryable(QueryProvider queryProvider,
+        SchemaPlus schema, String tableName) {
+      return new AbstractTableQueryable<T>(queryProvider, schema, this,
+          tableName) {
+        public Enumerator<T> enumerator() {
+          //noinspection unchecked
+          return (Enumerator<T>) Linq4j.enumerator(list);
+        }
+      };
+    }
+
+    public Type getElementType() {
+      return Object[].class;
+    }
+
+    public Expression getExpression(SchemaPlus schema, String tableName,
+        Class clazz) {
+      return Schemas.tableExpression(schema, getElementType(),
+          tableName, clazz);
+    }
+
+    public RelDataType getRowType(RelDataTypeFactory typeFactory) {
+      return protoRowType.apply(typeFactory);
+    }
+  }
+}
+
+// End SqlCreateTable.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
index 2eb14f4..a6ff27f 100644
--- a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
+++ b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
@@ -684,6 +684,8 @@ public class CalciteAssert {
     case LINGUAL:
       return rootSchema.add("SALES",
           new ReflectiveSchema(new JdbcTest.LingualSchema()));
+    case BLANK:
+      return rootSchema.add("BLANK", new AbstractSchema());
     case ORINOCO:
       final SchemaPlus orinoco = rootSchema.add("ORINOCO", new AbstractSchema());
       orinoco.add("ORDERS",
@@ -1632,6 +1634,7 @@ public class CalciteAssert {
     HR,
     JDBC_SCOTT,
     SCOTT,
+    BLANK,
     LINGUAL,
     POST,
     ORINOCO

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/test/java/org/apache/calcite/test/QuidemTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/QuidemTest.java b/core/src/test/java/org/apache/calcite/test/QuidemTest.java
index 78b202c..88479c6 100644
--- a/core/src/test/java/org/apache/calcite/test/QuidemTest.java
+++ b/core/src/test/java/org/apache/calcite/test/QuidemTest.java
@@ -265,46 +265,48 @@ public class QuidemTest {
         }
         return null;
       }
-      if (name.equals("hr")) {
+      switch (name) {
+      case "hr":
         return CalciteAssert.hr()
             .connect();
-      }
-      if (name.equals("foodmart")) {
+      case "foodmart":
         return CalciteAssert.that()
             .with(CalciteAssert.Config.FOODMART_CLONE)
             .connect();
-      }
-      if (name.equals("scott")) {
+      case "scott":
         return CalciteAssert.that()
             .with(CalciteAssert.Config.SCOTT)
             .connect();
-      }
-      if (name.equals("jdbc_scott")) {
+      case "jdbc_scott":
         return CalciteAssert.that()
             .with(CalciteAssert.Config.JDBC_SCOTT)
             .connect();
-      }
-      if (name.equals("post")) {
+      case "post":
         return CalciteAssert.that()
             .with(CalciteAssert.Config.REGULAR)
             .with(CalciteAssert.SchemaSpec.POST)
             .withDefaultSchema("POST")
             .connect();
-      }
-      if (name.equals("catchall")) {
+      case "catchall":
         return CalciteAssert.that()
             .withSchema("s",
                 new ReflectiveSchema(
                     new ReflectiveSchemaTest.CatchallSchema()))
             .connect();
-      }
-      if (name.equals("orinoco")) {
+      case "orinoco":
         return CalciteAssert.that()
             .with(CalciteAssert.SchemaSpec.ORINOCO)
             .withDefaultSchema("ORINOCO")
             .connect();
-      }
-      if (name.equals("seq")) {
+      case "blank":
+        return CalciteAssert.that()
+            .with("parserFactory",
+                "org.apache.calcite.sql.parser.parserextensiontesting"
+                    + ".ExtensionSqlParserImpl#FACTORY")
+            .with(CalciteAssert.SchemaSpec.BLANK)
+            .withDefaultSchema("BLANK")
+            .connect();
+      case "seq":
         final Connection connection = CalciteAssert.that()
             .withSchema("s", new AbstractSchema())
             .connect();
@@ -323,8 +325,9 @@ public class QuidemTest {
                   }
                 });
         return connection;
+      default:
+        throw new RuntimeException("unknown connection '" + name + "'");
       }
-      throw new RuntimeException("unknown connection '" + name + "'");
     }
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/core/src/test/resources/sql/blank.iq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/blank.iq b/core/src/test/resources/sql/blank.iq
new file mode 100644
index 0000000..e2ce690
--- /dev/null
+++ b/core/src/test/resources/sql/blank.iq
@@ -0,0 +1,44 @@
+# blank.iq - Queries that start from a blank schema and create their own tables
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to you under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+!use blank
+!set outputformat mysql
+
+create table foo (i int not null, j int);
+(-1 rows modified)
+
+!update
+insert into foo values (1, 0);
+(1 row modified)
+
+!update
+insert into foo values (0, 2);
+(1 row modified)
+
+!update
+select * from foo;
++---+---+
+| I | J |
++---+---+
+| 0 | 2 |
+| 1 | 0 |
++---+---+
+(2 rows)
+
+!ok
+
+# End blank.iq

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 2551d53..b342535 100644
--- a/pom.xml
+++ b/pom.xml
@@ -65,7 +65,7 @@ limitations under the License.
     <fmpp-maven-plugin.version>1.0</fmpp-maven-plugin.version>
     <foodmart-data-hsqldb.version>0.3</foodmart-data-hsqldb.version>
     <foodmart-queries.version>0.4.1</foodmart-queries.version>
-    <freemarker.version>2.3.19</freemarker.version>
+    <freemarker.version>2.3.25-incubating</freemarker.version>
     <git-commit-id-plugin.version>2.1.9</git-commit-id-plugin.version>
 
     <!-- We support (and test against) Guava versions between

http://git-wip-us.apache.org/repos/asf/calcite/blob/e641211f/site/_docs/reference.md
----------------------------------------------------------------------
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index 2aec223..6b4c4ab 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -606,6 +606,7 @@ READ,
 RELATIVE,
 **RELEASE**,
 REPEATABLE,
+REPLACE,
 **RESET**,
 RESTART,
 RESTRICT,


[2/3] calcite git commit: [CALCITE-1530] Create a visitor to traverse linq4j expressions without mutating them, and rename Visitor to Shuttle

Posted by jh...@apache.org.
[CALCITE-1530] Create a visitor to traverse linq4j expressions without mutating them, and rename Visitor to Shuttle


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

Branch: refs/heads/master
Commit: 267e2f3e1db71e678f80bb69015164c0d45bcfe4
Parents: 02752fe
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Dec 5 19:53:41 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Wed Dec 7 11:17:40 2016 -0800

----------------------------------------------------------------------
 .../enumerable/EnumerableRelImplementor.java    |  19 +-
 .../calcite/adapter/enumerable/RexImpTable.java |   4 +-
 .../calcite/linq4j/tree/AbstractNode.java       |   2 +-
 .../calcite/linq4j/tree/BinaryExpression.java   |   6 +-
 .../calcite/linq4j/tree/BlockBuilder.java       |  67 +--
 .../calcite/linq4j/tree/BlockStatement.java     |  12 +-
 .../calcite/linq4j/tree/ClassDeclaration.java   |  12 +-
 .../linq4j/tree/ClassDeclarationFinder.java     |   8 +-
 .../linq4j/tree/ConditionalExpression.java      |   6 +-
 .../linq4j/tree/ConditionalStatement.java       |  12 +-
 .../calcite/linq4j/tree/ConstantExpression.java |   6 +-
 .../linq4j/tree/ConstructorDeclaration.java     |  12 +-
 .../linq4j/tree/DeclarationStatement.java       |  12 +-
 .../calcite/linq4j/tree/DefaultExpression.java  |   7 +-
 .../calcite/linq4j/tree/DynamicExpression.java  |   7 +-
 .../apache/calcite/linq4j/tree/Expression.java  |   2 +-
 .../apache/calcite/linq4j/tree/Expressions.java |  44 +-
 .../calcite/linq4j/tree/FieldDeclaration.java   |  12 +-
 .../calcite/linq4j/tree/ForStatement.java       |  18 +-
 .../calcite/linq4j/tree/FunctionExpression.java |  12 +-
 .../calcite/linq4j/tree/GotoStatement.java      |  12 +-
 .../calcite/linq4j/tree/IndexExpression.java    |  13 +-
 .../linq4j/tree/InvocationExpression.java       |   7 +-
 .../calcite/linq4j/tree/LabelStatement.java     |   6 +-
 .../calcite/linq4j/tree/LambdaExpression.java   |   7 +-
 .../calcite/linq4j/tree/ListInitExpression.java |   7 +-
 .../calcite/linq4j/tree/MemberDeclaration.java  |   2 +-
 .../calcite/linq4j/tree/MemberExpression.java   |  12 +-
 .../linq4j/tree/MemberInitExpression.java       |   7 +-
 .../linq4j/tree/MethodCallExpression.java       |  14 +-
 .../calcite/linq4j/tree/MethodDeclaration.java  |  12 +-
 .../calcite/linq4j/tree/NewArrayExpression.java |  14 +-
 .../calcite/linq4j/tree/NewExpression.java      |  14 +-
 .../org/apache/calcite/linq4j/tree/Node.java    |   4 +-
 .../calcite/linq4j/tree/OptimizeShuttle.java    | 422 ++++++++++++++++++
 .../calcite/linq4j/tree/OptimizeVisitor.java    | 423 -------------------
 .../linq4j/tree/ParameterExpression.java        |   6 +-
 .../org/apache/calcite/linq4j/tree/Shuttle.java | 335 +++++++++++++++
 .../apache/calcite/linq4j/tree/Statement.java   |   2 +-
 .../calcite/linq4j/tree/SwitchStatement.java    |   7 +-
 .../calcite/linq4j/tree/TernaryExpression.java  |  16 +-
 .../calcite/linq4j/tree/ThrowStatement.java     |  12 +-
 .../calcite/linq4j/tree/TryStatement.java       |   6 +-
 .../linq4j/tree/TypeBinaryExpression.java       |  12 +-
 .../calcite/linq4j/tree/UnaryExpression.java    |  12 +-
 .../org/apache/calcite/linq4j/tree/Visitor.java | 351 ++-------------
 .../apache/calcite/linq4j/tree/VisitorImpl.java | 206 +++++++++
 .../calcite/linq4j/tree/WhileStatement.java     |  14 +-
 .../calcite/linq4j/test/BlockBuilderTest.java   |   8 +-
 .../calcite/linq4j/test/ExpressionTest.java     |  12 +-
 site/_docs/adapter.md                           |   5 +-
 51 files changed, 1336 insertions(+), 924 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java
index bc88333..90105e0 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java
@@ -36,7 +36,7 @@ import org.apache.calcite.linq4j.tree.ParameterExpression;
 import org.apache.calcite.linq4j.tree.Primitive;
 import org.apache.calcite.linq4j.tree.Statement;
 import org.apache.calcite.linq4j.tree.Types;
-import org.apache.calcite.linq4j.tree.Visitor;
+import org.apache.calcite.linq4j.tree.VisitorImpl;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.runtime.Bindable;
 import org.apache.calcite.util.BuiltInMethod;
@@ -458,26 +458,19 @@ public class EnumerableRelImplementor extends JavaRelImplementor {
   }
 
   /** Visitor that finds types in an {@link Expression} tree. */
-  private static class TypeFinder extends Visitor {
+  private static class TypeFinder extends VisitorImpl<Void> {
     private final Collection<Type> types;
 
     TypeFinder(Collection<Type> types) {
       this.types = types;
     }
 
-    @Override public Expression visit(
-        NewExpression newExpression,
-        List<Expression> arguments,
-        List<MemberDeclaration> memberDeclarations) {
+    @Override public Void visit(NewExpression newExpression) {
       types.add(newExpression.type);
-      return super.visit(
-          newExpression,
-          arguments,
-          memberDeclarations);
+      return super.visit(newExpression);
     }
 
-    @Override public Expression visit(NewArrayExpression newArrayExpression,
-        int dimension, Expression bound, List<Expression> expressions) {
+    @Override public Void visit(NewArrayExpression newArrayExpression) {
       Type type = newArrayExpression.type;
       for (;;) {
         final Type componentType = Types.getComponentType(type);
@@ -487,7 +480,7 @@ public class EnumerableRelImplementor extends JavaRelImplementor {
         type = componentType;
       }
       types.add(type);
-      return super.visit(newArrayExpression, dimension, bound, expressions);
+      return super.visit(newArrayExpression);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
index 5984fca..ddcb8dc 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
@@ -27,7 +27,7 @@ import org.apache.calcite.linq4j.tree.Expression;
 import org.apache.calcite.linq4j.tree.ExpressionType;
 import org.apache.calcite.linq4j.tree.Expressions;
 import org.apache.calcite.linq4j.tree.MemberExpression;
-import org.apache.calcite.linq4j.tree.OptimizeVisitor;
+import org.apache.calcite.linq4j.tree.OptimizeShuttle;
 import org.apache.calcite.linq4j.tree.ParameterExpression;
 import org.apache.calcite.linq4j.tree.Primitive;
 import org.apache.calcite.linq4j.tree.Types;
@@ -640,7 +640,7 @@ public class RexImpTable {
   }
 
   static Expression optimize(Expression expression) {
-    return expression.accept(new OptimizeVisitor());
+    return expression.accept(new OptimizeShuttle());
   }
 
   static Expression optimize2(Expression operand, Expression expression) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/AbstractNode.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/AbstractNode.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/AbstractNode.java
index c74adc6..38aec48 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/AbstractNode.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/AbstractNode.java
@@ -65,7 +65,7 @@ public abstract class AbstractNode implements Node {
         "un-parse not supported: " + getClass() + ":" + nodeType);
   }
 
-  public Node accept(Visitor visitor) {
+  public Node accept(Shuttle shuttle) {
     throw new RuntimeException(
         "visit not supported: " + getClass() + ":" + nodeType);
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BinaryExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BinaryExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BinaryExpression.java
index eb73da3..f8056c7 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BinaryExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BinaryExpression.java
@@ -37,13 +37,17 @@ public class BinaryExpression extends Expression {
     this.primitive = Primitive.of(expression0.getType());
   }
 
-  @Override public Expression accept(Visitor visitor) {
+  @Override public Expression accept(Shuttle visitor) {
     visitor = visitor.preVisit(this);
     Expression expression0 = this.expression0.accept(visitor);
     Expression expression1 = this.expression1.accept(visitor);
     return visitor.visit(this, expression0, expression1);
   }
 
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
+  }
+
   public Object evaluate(Evaluator evaluator) {
     switch (nodeType) {
     case AndAlso:

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockBuilder.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockBuilder.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockBuilder.java
index c58a258..ff13d66 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockBuilder.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockBuilder.java
@@ -32,18 +32,18 @@ import java.util.Set;
  * <p>Has methods that help ensure that variable names are unique.</p>
  */
 public class BlockBuilder {
-  final List<Statement> statements = new ArrayList<Statement>();
-  final Set<String> variables = new HashSet<String>();
+  final List<Statement> statements = new ArrayList<>();
+  final Set<String> variables = new HashSet<>();
   /** Contains final-fine-to-reuse-declarations.
    * An entry to this map is added when adding final declaration of a
    * statement with optimize=true parameter. */
   final Map<Expression, DeclarationStatement> expressionForReuse =
-      new HashMap<Expression, DeclarationStatement>();
+      new HashMap<>();
 
   private final boolean optimizing;
   private final BlockBuilder parent;
 
-  private static final Visitor OPTIMIZE_VISITOR = new OptimizeVisitor();
+  private static final Shuttle OPTIMIZE_SHUTTLE = new OptimizeShuttle();
 
   /**
    * Creates a non-optimizing BlockBuilder.
@@ -111,13 +111,13 @@ public class BlockBuilder {
     }
     Expression result = null;
     final Map<ParameterExpression, Expression> replacements =
-        new IdentityHashMap<ParameterExpression, Expression>();
-    final Visitor visitor = new SubstituteVariableVisitor(replacements);
+        new IdentityHashMap<>();
+    final Shuttle shuttle = new SubstituteVariableVisitor(replacements);
     for (int i = 0; i < block.statements.size(); i++) {
       Statement statement = block.statements.get(i);
       if (!replacements.isEmpty()) {
         // Save effort, and only substitute variables if there are some.
-        statement = statement.accept(visitor);
+        statement = statement.accept(shuttle);
       }
       if (statement instanceof DeclarationStatement) {
         DeclarationStatement declaration = (DeclarationStatement) statement;
@@ -303,11 +303,11 @@ public class BlockBuilder {
       // loop. Optimize should not loop forever, however it is hard to prove if
       // it always finishes in reasonable time.
       for (int i = 0; i < 10; i++) {
-        if (!optimize(createOptimizeVisitor(), true)) {
+        if (!optimize(createOptimizeShuttle(), true)) {
           break;
         }
       }
-      optimize(createFinishingOptimizeVisitor(), false);
+      optimize(createFinishingOptimizeShuttle(), false);
     }
     return Expressions.block(statements);
   }
@@ -318,7 +318,7 @@ public class BlockBuilder {
    *
    * @return whether any optimizations were made
    */
-  private boolean optimize(Visitor optimizer, boolean performInline) {
+  private boolean optimize(Shuttle optimizer, boolean performInline) {
     int optimizeCount = 0;
     final UseCounter useCounter = new UseCounter();
     for (Statement statement : statements) {
@@ -334,12 +334,10 @@ public class BlockBuilder {
       }
     }
     final Map<ParameterExpression, Expression> subMap =
-        new IdentityHashMap<ParameterExpression, Expression>(
-            useCounter.map.size());
+        new IdentityHashMap<>(useCounter.map.size());
     final SubstituteVariableVisitor visitor = new SubstituteVariableVisitor(
         subMap);
-    final ArrayList<Statement> oldStatements = new ArrayList<Statement>(
-        statements);
+    final ArrayList<Statement> oldStatements = new ArrayList<>(statements);
     statements.clear();
 
     for (Statement oldStatement : oldStatements) {
@@ -400,10 +398,10 @@ public class BlockBuilder {
               DeclarationStatement newDecl =
                   (DeclarationStatement) oldStatement;
               subMap.put(newDecl.parameter, normalizeDeclaration(newDecl));
-              oldStatement = OptimizeVisitor.EMPTY_STATEMENT;
+              oldStatement = OptimizeShuttle.EMPTY_STATEMENT;
             }
           }
-          if (oldStatement != OptimizeVisitor.EMPTY_STATEMENT) {
+          if (oldStatement != OptimizeShuttle.EMPTY_STATEMENT) {
             if (oldStatement instanceof DeclarationStatement) {
               addExpressionForReuse((DeclarationStatement) oldStatement);
             }
@@ -420,7 +418,7 @@ public class BlockBuilder {
         if (beforeOptimize != oldStatement) {
           ++optimizeCount;
         }
-        if (oldStatement != OptimizeVisitor.EMPTY_STATEMENT) {
+        if (oldStatement != OptimizeShuttle.EMPTY_STATEMENT) {
           statements.add(oldStatement);
         }
       }
@@ -429,23 +427,23 @@ public class BlockBuilder {
   }
 
   /**
-   * Creates a visitor that will be used during block optimization.
-   * Subclasses might provide more specific optimizations (e.g. partial
+   * Creates a shuttle that will be used during block optimization.
+   * Sub-classes might provide more specific optimizations (e.g. partial
    * evaluation).
    *
-   * @return visitor used to optimize the statements when converting to block
+   * @return shuttle used to optimize the statements when converting to block
    */
-  protected Visitor createOptimizeVisitor() {
-    return OPTIMIZE_VISITOR;
+  protected Shuttle createOptimizeShuttle() {
+    return OPTIMIZE_SHUTTLE;
   }
 
   /**
-   * Creates a final optimization visitor.
+   * Creates a final optimization shuttle.
    * Typically, the visitor will factor out constant expressions.
    *
-   * @return visitor that is used to finalize the optimization
+   * @return shuttle that is used to finalize the optimization
    */
-  protected Visitor createFinishingOptimizeVisitor() {
+  protected Shuttle createFinishingOptimizeShuttle() {
     return ClassDeclarationFinder.create();
   }
 
@@ -484,10 +482,10 @@ public class BlockBuilder {
   }
 
   /** Substitute Variable Visitor. */
-  private static class SubstituteVariableVisitor extends Visitor {
+  private static class SubstituteVariableVisitor extends Shuttle {
     private final Map<ParameterExpression, Expression> map;
     private final Map<ParameterExpression, Boolean> actives =
-        new IdentityHashMap<ParameterExpression, Boolean>();
+        new IdentityHashMap<>();
 
     public SubstituteVariableVisitor(Map<ParameterExpression, Expression> map) {
       this.map = map;
@@ -544,11 +542,10 @@ public class BlockBuilder {
   }
 
   /** Use counter. */
-  private static class UseCounter extends Visitor {
-    private final Map<ParameterExpression, Slot> map =
-        new IdentityHashMap<ParameterExpression, Slot>();
+  private static class UseCounter extends VisitorImpl<Void> {
+    private final Map<ParameterExpression, Slot> map = new IdentityHashMap<>();
 
-    @Override public Expression visit(ParameterExpression parameter) {
+    @Override public Void visit(ParameterExpression parameter) {
       final Slot slot = map.get(parameter);
       if (slot != null) {
         // Count use of parameter, if it's registered. It's OK if
@@ -558,6 +555,14 @@ public class BlockBuilder {
       }
       return super.visit(parameter);
     }
+
+    @Override public Void visit(DeclarationStatement declarationStatement) {
+      // Unlike base class, do not visit declarationStatement.parameter.
+      if (declarationStatement.initializer != null) {
+        declarationStatement.initializer.accept(this);
+      }
+      return null;
+    }
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockStatement.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockStatement.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockStatement.java
index 26a8c09..54e62e4 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockStatement.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockStatement.java
@@ -54,11 +54,15 @@ public class BlockStatement extends Statement {
     return true;
   }
 
-  @Override public BlockStatement accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public BlockStatement accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     List<Statement> newStatements = Expressions.acceptStatements(statements,
-        visitor);
-    return visitor.visit(this, newStatements);
+        shuttle);
+    return shuttle.visit(this, newStatements);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override void accept0(ExpressionWriter writer) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclaration.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclaration.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclaration.java
index 172112f..424ce54 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclaration.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclaration.java
@@ -59,11 +59,15 @@ public class ClassDeclaration extends MemberDeclaration {
     writer.newlineAndIndent();
   }
 
-  public ClassDeclaration accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  public ClassDeclaration accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     final List<MemberDeclaration> members1 =
-        Expressions.acceptMemberDeclarations(memberDeclarations, visitor);
-    return visitor.visit(this, members1);
+        Expressions.acceptMemberDeclarations(memberDeclarations, shuttle);
+    return shuttle.visit(this, members1);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override public boolean equals(Object o) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclarationFinder.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclarationFinder.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclarationFinder.java
index 2388538..3af0fe6 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclarationFinder.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclarationFinder.java
@@ -29,7 +29,7 @@ import java.util.List;
  * Instances of this class should not be reused, so new visitor should be
  * created for optimizing a new expression tree.
  */
-public class ClassDeclarationFinder extends Visitor {
+public class ClassDeclarationFinder extends Shuttle {
   protected final ClassDeclarationFinder parent;
 
   /**
@@ -144,7 +144,7 @@ public class ClassDeclarationFinder extends Visitor {
    * @param newExpression expression to optimize
    * @return nested visitor if anonymous class is given
    */
-  @Override public Visitor preVisit(NewExpression newExpression) {
+  @Override public Shuttle preVisit(NewExpression newExpression) {
     if (newExpression.memberDeclarations == null) {
       return this;
     }
@@ -159,7 +159,7 @@ public class ClassDeclarationFinder extends Visitor {
    * @param classDeclaration expression to optimize
    * @return nested visitor
    */
-  @Override public Visitor preVisit(ClassDeclaration classDeclaration) {
+  @Override public Shuttle preVisit(ClassDeclaration classDeclaration) {
     ClassDeclarationFinder visitor = goDeeper();
     visitor.learnFinalStaticDeclarations(classDeclaration.memberDeclarations);
     return visitor;
@@ -228,7 +228,7 @@ public class ClassDeclarationFinder extends Visitor {
       return memberDeclarations;
     }
     List<MemberDeclaration> newDecls =
-        new ArrayList<MemberDeclaration>(memberDeclarations.size()
+        new ArrayList<>(memberDeclarations.size()
             + addedDeclarations.size());
     newDecls.addAll(memberDeclarations);
     newDecls.addAll(addedDeclarations);

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalExpression.java
index 6491aa0..1b49a81 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalExpression.java
@@ -33,7 +33,7 @@ import java.util.Objects;
  * </p>
  */
 public class ConditionalExpression extends AbstractNode {
-  private final List<Node> expressionList;
+  final List<Node> expressionList;
 
   public ConditionalExpression(List<Node> expressionList, Type type) {
     super(ExpressionType.Conditional, type);
@@ -41,6 +41,10 @@ public class ConditionalExpression extends AbstractNode {
     this.expressionList = expressionList;
   }
 
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
+  }
+
   @Override void accept(ExpressionWriter writer, int lprec, int rprec) {
     for (int i = 0; i < expressionList.size(); i += 2) {
       writer.append(i > 0 ? " else if (" : "if (")

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalStatement.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalStatement.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalStatement.java
index 2334557..64e54d4 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalStatement.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalStatement.java
@@ -40,10 +40,14 @@ public class ConditionalStatement extends Statement {
     this.expressionList = expressionList;
   }
 
-  @Override public Statement accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
-    List<Node> list = Expressions.acceptNodes(expressionList, visitor);
-    return visitor.visit(this, list);
+  @Override public Statement accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
+    List<Node> list = Expressions.acceptNodes(expressionList, shuttle);
+    return shuttle.visit(this, list);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override void accept0(ExpressionWriter writer) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java
index 52c6975..3fc112b 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java
@@ -58,7 +58,11 @@ public class ConstantExpression extends Expression {
     return value;
   }
 
-  @Override public Expression accept(Visitor visitor) {
+  @Override public Expression accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstructorDeclaration.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstructorDeclaration.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstructorDeclaration.java
index 471357d..1aa28b4 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstructorDeclaration.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstructorDeclaration.java
@@ -48,11 +48,15 @@ public class ConstructorDeclaration extends MemberDeclaration {
     this.body = body;
   }
 
-  @Override public MemberDeclaration accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public MemberDeclaration accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     // do not visit parameters
-    final BlockStatement body = this.body.accept(visitor);
-    return visitor.visit(this, body);
+    final BlockStatement body = this.body.accept(shuttle);
+    return shuttle.visit(this, body);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   public void accept(ExpressionWriter writer) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DeclarationStatement.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DeclarationStatement.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DeclarationStatement.java
index f835d1e..c080c84 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DeclarationStatement.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DeclarationStatement.java
@@ -36,13 +36,17 @@ public class DeclarationStatement extends Statement {
     this.initializer = initializer;
   }
 
-  @Override public DeclarationStatement accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public DeclarationStatement accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     // do not visit parameter - visit may not return a ParameterExpression
     Expression initializer = this.initializer != null
-        ? this.initializer.accept(visitor)
+        ? this.initializer.accept(shuttle)
         : null;
-    return visitor.visit(this, initializer);
+    return shuttle.visit(this, initializer);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override void accept0(ExpressionWriter writer) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DefaultExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DefaultExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DefaultExpression.java
index 8569528..c78847d 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DefaultExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DefaultExpression.java
@@ -24,9 +24,14 @@ public class DefaultExpression extends Expression {
     super(ExpressionType.Default, type);
   }
 
-  @Override public Expression accept(Visitor visitor) {
+  @Override public Expression accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
+
 }
 
 // End DefaultExpression.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DynamicExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DynamicExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DynamicExpression.java
index ff03001..f9c7c4f 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DynamicExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DynamicExpression.java
@@ -24,9 +24,14 @@ public class DynamicExpression extends Expression {
     super(ExpressionType.Dynamic, type);
   }
 
-  @Override public Expression accept(Visitor visitor) {
+  @Override public Expression accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
+
 }
 
 // End DynamicExpression.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expression.java
index 4c3427b..ff5f38f 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expression.java
@@ -41,7 +41,7 @@ public abstract class Expression extends AbstractNode {
   }
 
   @Override // More specific return type.
-  public abstract Expression accept(Visitor visitor);
+  public abstract Expression accept(Shuttle shuttle);
 
   /**
    * Indicates that the node can be reduced to a simpler node. If this

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java
index fae932e..0651024 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java
@@ -3090,28 +3090,28 @@ public abstract class Expressions {
     return toCollection(iterable).toArray(a);
   }
 
-  static <T extends Expression> Expression accept(T node, Visitor visitor) {
+  static <T extends Expression> Expression accept(T node, Shuttle shuttle) {
     if (node == null) {
       return null;
     }
-    return node.accept(visitor);
+    return node.accept(shuttle);
   }
 
-  static <T extends Statement> Statement accept(T node, Visitor visitor) {
+  static <T extends Statement> Statement accept(T node, Shuttle shuttle) {
     if (node == null) {
       return null;
     }
-    return node.accept(visitor);
+    return node.accept(shuttle);
   }
 
   static List<Statement> acceptStatements(List<Statement> statements,
-      Visitor visitor) {
+      Shuttle shuttle) {
     if (statements.isEmpty()) {
       return statements; // short cut
     }
     final List<Statement> statements1 = new ArrayList<Statement>();
     for (Statement statement : statements) {
-      Statement newStatement = statement.accept(visitor);
+      Statement newStatement = statement.accept(shuttle);
       if (newStatement instanceof GotoStatement) {
         GotoStatement goto_ = (GotoStatement) newStatement;
         if (goto_.kind == GotoExpressionKind.Sequence
@@ -3125,67 +3125,77 @@ public abstract class Expressions {
     return statements1;
   }
 
-  static List<Node> acceptNodes(List<Node> nodes, Visitor visitor) {
+  static List<Node> acceptNodes(List<Node> nodes, Shuttle shuttle) {
     if (nodes.isEmpty()) {
       return nodes; // short cut
     }
     final List<Node> statements1 = new ArrayList<Node>();
     for (Node node : nodes) {
-      statements1.add(node.accept(visitor));
+      statements1.add(node.accept(shuttle));
     }
     return statements1;
   }
 
   static List<Expression> acceptParameterExpressions(
-      List<ParameterExpression> parameterExpressions, Visitor visitor) {
+      List<ParameterExpression> parameterExpressions, Shuttle shuttle) {
     if (parameterExpressions.isEmpty()) {
       return Collections.emptyList(); // short cut
     }
     final List<Expression> parameterExpressions1 = new ArrayList<Expression>();
     for (ParameterExpression parameterExpression : parameterExpressions) {
-      parameterExpressions1.add(parameterExpression.accept(visitor));
+      parameterExpressions1.add(parameterExpression.accept(shuttle));
     }
     return parameterExpressions1;
   }
 
   static List<DeclarationStatement> acceptDeclarations(
-      List<DeclarationStatement> declarations, Visitor visitor) {
+      List<DeclarationStatement> declarations, Shuttle shuttle) {
     if (declarations == null || declarations.isEmpty()) {
       return declarations; // short cut
     }
     final List<DeclarationStatement> declarations1 =
         new ArrayList<DeclarationStatement>();
     for (DeclarationStatement declaration : declarations) {
-      declarations1.add(declaration.accept(visitor));
+      declarations1.add(declaration.accept(shuttle));
     }
     return declarations1;
   }
 
   static List<MemberDeclaration> acceptMemberDeclarations(
-      List<MemberDeclaration> memberDeclarations, Visitor visitor) {
+      List<MemberDeclaration> memberDeclarations, Shuttle shuttle) {
     if (memberDeclarations == null || memberDeclarations.isEmpty()) {
       return memberDeclarations; // short cut
     }
     final List<MemberDeclaration> memberDeclarations1 =
         new ArrayList<MemberDeclaration>();
     for (MemberDeclaration memberDeclaration : memberDeclarations) {
-      memberDeclarations1.add(memberDeclaration.accept(visitor));
+      memberDeclarations1.add(memberDeclaration.accept(shuttle));
     }
     return memberDeclarations1;
   }
 
   static List<Expression> acceptExpressions(List<Expression> expressions,
-      Visitor visitor) {
+      Shuttle shuttle) {
     if (expressions.isEmpty()) {
       return expressions; // short cut
     }
-    final List<Expression> expressions1 = new ArrayList<Expression>();
+    final List<Expression> expressions1 = new ArrayList<>();
     for (Expression expression : expressions) {
-      expressions1.add(expression.accept(visitor));
+      expressions1.add(expression.accept(shuttle));
     }
     return expressions1;
   }
 
+  static <R> R acceptNodes(List<? extends Node> nodes, Visitor<R> visitor) {
+    R r = null;
+    if (nodes != null) {
+      for (Node node : nodes) {
+        r = node.accept(visitor);
+      }
+    }
+    return r;
+  }
+
   // ~ Classes and interfaces ------------------------------------------------
 
   // Some interfaces we'd rather not implement yet. They don't seem relevant

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FieldDeclaration.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FieldDeclaration.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FieldDeclaration.java
index 2a8db07..29ea7a7 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FieldDeclaration.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FieldDeclaration.java
@@ -35,12 +35,16 @@ public class FieldDeclaration extends MemberDeclaration {
     this.initializer = initializer;
   }
 
-  @Override public MemberDeclaration accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public MemberDeclaration accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     // do not visit parameter - visit may not return a ParameterExpression
     final Expression initializer =
-        this.initializer == null ? null : this.initializer.accept(visitor);
-    return visitor.visit(this, initializer);
+        this.initializer == null ? null : this.initializer.accept(shuttle);
+    return shuttle.visit(this, initializer);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   public void accept(ExpressionWriter writer) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ForStatement.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ForStatement.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ForStatement.java
index e8a9fba..d39809b 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ForStatement.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ForStatement.java
@@ -45,15 +45,19 @@ public class ForStatement extends Statement {
     this.body = body; // may be empty block, not null
   }
 
-  @Override public ForStatement accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public ForStatement accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     List<DeclarationStatement> decls1 =
-        Expressions.acceptDeclarations(declarations, visitor);
+        Expressions.acceptDeclarations(declarations, shuttle);
     final Expression condition1 =
-        condition == null ? null : condition.accept(visitor);
-    final Expression post1 = post == null ? null : post.accept(visitor);
-    final Statement body1 = body.accept(visitor);
-    return visitor.visit(this, decls1, condition1, post1, body1);
+        condition == null ? null : condition.accept(shuttle);
+    final Expression post1 = post == null ? null : post.accept(shuttle);
+    final Statement body1 = body.accept(shuttle);
+    return shuttle.visit(this, decls1, condition1, post1, body1);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override void accept0(ExpressionWriter writer) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FunctionExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FunctionExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FunctionExpression.java
index 4bbc99b..14c67ca 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FunctionExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FunctionExpression.java
@@ -68,10 +68,14 @@ public final class FunctionExpression<F extends Function<?>>
     this(type, null, body, parameters);
   }
 
-  @Override public Expression accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
-    BlockStatement body = this.body.accept(visitor);
-    return visitor.visit(this, body);
+  @Override public Expression accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
+    BlockStatement body = this.body.accept(shuttle);
+    return shuttle.visit(this, body);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   public Invokable compile() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/GotoStatement.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/GotoStatement.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/GotoStatement.java
index 239f0e5..ff5582a 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/GotoStatement.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/GotoStatement.java
@@ -54,11 +54,15 @@ public class GotoStatement extends Statement {
     }
   }
 
-  @Override public Statement accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public Statement accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     Expression expression1 =
-        expression == null ? null : expression.accept(visitor);
-    return visitor.visit(this, expression1);
+        expression == null ? null : expression.accept(shuttle);
+    return shuttle.visit(this, expression1);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override void accept0(ExpressionWriter writer) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/IndexExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/IndexExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/IndexExpression.java
index 9c7eb61..10e8463 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/IndexExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/IndexExpression.java
@@ -35,14 +35,17 @@ public class IndexExpression extends Expression {
     this.indexExpressions = indexExpressions;
   }
 
-  @Override public Expression accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
-    Expression array = this.array.accept(visitor);
+  @Override public Expression accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
+    Expression array = this.array.accept(shuttle);
     List<Expression> indexExpressions = Expressions.acceptExpressions(
-        this.indexExpressions, visitor);
-    return visitor.visit(this, array, indexExpressions);
+        this.indexExpressions, shuttle);
+    return shuttle.visit(this, array, indexExpressions);
   }
 
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
+  }
 
   @Override void accept(ExpressionWriter writer, int lprec, int rprec) {
     array.accept(writer, lprec, nodeType.lprec);

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/InvocationExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/InvocationExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/InvocationExpression.java
index 666ab07..140c20d 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/InvocationExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/InvocationExpression.java
@@ -25,9 +25,14 @@ public class InvocationExpression extends Expression {
     super(nodeType, type);
   }
 
-  @Override public Expression accept(Visitor visitor) {
+  @Override public Expression accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
+
 }
 
 // End InvocationExpression.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LabelStatement.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LabelStatement.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LabelStatement.java
index 15b6f44..4d23339 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LabelStatement.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LabelStatement.java
@@ -33,7 +33,11 @@ public class LabelStatement extends Statement {
     this.defaultValue = defaultValue;
   }
 
-  @Override public LabelStatement accept(Visitor visitor) {
+  @Override public LabelStatement accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LambdaExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LambdaExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LambdaExpression.java
index d406e8f..6fbf61c 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LambdaExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LambdaExpression.java
@@ -25,9 +25,14 @@ public class LambdaExpression extends Expression {
     super(nodeType, type);
   }
 
-  @Override public Expression accept(Visitor visitor) {
+  @Override public Expression accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
+
 }
 
 // End LambdaExpression.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ListInitExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ListInitExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ListInitExpression.java
index bf22c11..daf289a 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ListInitExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ListInitExpression.java
@@ -24,9 +24,14 @@ public class ListInitExpression extends Expression {
     super(nodeType, type);
   }
 
-  @Override public Expression accept(Visitor visitor) {
+  @Override public Expression accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
+
 }
 
 // End ListInitExpression.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberDeclaration.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberDeclaration.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberDeclaration.java
index c3c10b4..b553f7a 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberDeclaration.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberDeclaration.java
@@ -20,7 +20,7 @@ package org.apache.calcite.linq4j.tree;
  * Declaration of a member of a class.
  */
 public abstract class MemberDeclaration implements Node {
-  public abstract MemberDeclaration accept(Visitor visitor);
+  public abstract MemberDeclaration accept(Shuttle shuttle);
 }
 
 // End MemberDeclaration.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberExpression.java
index 9947c10..5e0c72d 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberExpression.java
@@ -40,12 +40,16 @@ public class MemberExpression extends Expression {
     this.field = field;
   }
 
-  @Override public Expression accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public Expression accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     Expression expression1 = expression == null
         ? null
-        : expression.accept(visitor);
-    return visitor.visit(this, expression1);
+        : expression.accept(shuttle);
+    return shuttle.visit(this, expression1);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   public Object evaluate(Evaluator evaluator) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberInitExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberInitExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberInitExpression.java
index 79b4c46..5becd3c 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberInitExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberInitExpression.java
@@ -25,9 +25,14 @@ public class MemberInitExpression extends Expression {
     super(ExpressionType.MemberInit, Void.TYPE);
   }
 
-  @Override public Expression accept(Visitor visitor) {
+  @Override public Expression accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
+
 }
 
 // End MemberInitExpression.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodCallExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodCallExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodCallExpression.java
index 7b63a00..bd3cd91 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodCallExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodCallExpression.java
@@ -53,13 +53,17 @@ public class MethodCallExpression extends Expression {
     this(method.getGenericReturnType(), method, targetExpression, expressions);
   }
 
-  @Override public Expression accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public Expression accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     Expression targetExpression = Expressions.accept(this.targetExpression,
-        visitor);
+        shuttle);
     List<Expression> expressions = Expressions.acceptExpressions(
-        this.expressions, visitor);
-    return visitor.visit(this, targetExpression, expressions);
+        this.expressions, shuttle);
+    return shuttle.visit(this, targetExpression, expressions);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override public Object evaluate(Evaluator evaluator) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodDeclaration.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodDeclaration.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodDeclaration.java
index b279434..800f387 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodDeclaration.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodDeclaration.java
@@ -47,11 +47,15 @@ public class MethodDeclaration extends MemberDeclaration {
     this.body = body;
   }
 
-  @Override public MemberDeclaration accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public MemberDeclaration accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     // do not visit parameters
-    final BlockStatement body = this.body.accept(visitor);
-    return visitor.visit(this, body);
+    final BlockStatement body = this.body.accept(shuttle);
+    return shuttle.visit(this, body);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   public void accept(ExpressionWriter writer) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewArrayExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewArrayExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewArrayExpression.java
index 13670ae..36e64c0 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewArrayExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewArrayExpression.java
@@ -41,14 +41,18 @@ public class NewArrayExpression extends Expression {
     this.expressions = expressions;
   }
 
-  @Override public Expression accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public Expression accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     List<Expression> expressions =
         this.expressions == null
             ? null
-            : Expressions.acceptExpressions(this.expressions, visitor);
-    Expression bound = Expressions.accept(this.bound, visitor);
-    return visitor.visit(this, dimension, bound, expressions);
+            : Expressions.acceptExpressions(this.expressions, shuttle);
+    Expression bound = Expressions.accept(this.bound, shuttle);
+    return shuttle.visit(this, dimension, bound, expressions);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override void accept(ExpressionWriter writer, int lprec, int rprec) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewExpression.java
index e4ca7ea..0c168a3 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewExpression.java
@@ -43,13 +43,17 @@ public class NewExpression extends Expression {
     this.memberDeclarations = memberDeclarations;
   }
 
-  @Override public Expression accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public Expression accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     final List<Expression> arguments = Expressions.acceptExpressions(
-        this.arguments, visitor);
+        this.arguments, shuttle);
     final List<MemberDeclaration> memberDeclarations =
-        Expressions.acceptMemberDeclarations(this.memberDeclarations, visitor);
-    return visitor.visit(this, arguments, memberDeclarations);
+        Expressions.acceptMemberDeclarations(this.memberDeclarations, shuttle);
+    return shuttle.visit(this, arguments, memberDeclarations);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override void accept(ExpressionWriter writer, int lprec, int rprec) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Node.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Node.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Node.java
index 7c04f08..560f66a 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Node.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Node.java
@@ -20,7 +20,9 @@ package org.apache.calcite.linq4j.tree;
  * <p>Parse tree node.</p>
  */
 public interface Node {
-  Node accept(Visitor visitor);
+  <R> R accept(Visitor<R> visitor);
+
+  Node accept(Shuttle shuttle);
 
   void accept(ExpressionWriter expressionWriter);
 }

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/OptimizeShuttle.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/OptimizeShuttle.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/OptimizeShuttle.java
new file mode 100644
index 0000000..fa90a4c
--- /dev/null
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/OptimizeShuttle.java
@@ -0,0 +1,422 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.linq4j.tree;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.EnumMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.apache.calcite.linq4j.tree.ExpressionType.Equal;
+import static org.apache.calcite.linq4j.tree.ExpressionType.NotEqual;
+
+/**
+ * Shuttle that optimizes expressions.
+ *
+ * <p>The optimizations are essential, not mere tweaks. Without
+ * optimization, expressions such as {@code false == null} will be left in,
+ * which are invalid to Janino (because it does not automatically box
+ * primitives).
+ */
+public class OptimizeShuttle extends Shuttle {
+  public static final ConstantExpression FALSE_EXPR =
+      Expressions.constant(false);
+  public static final ConstantExpression TRUE_EXPR =
+      Expressions.constant(true);
+  public static final MemberExpression BOXED_FALSE_EXPR =
+      Expressions.field(null, Boolean.class, "FALSE");
+  public static final MemberExpression BOXED_TRUE_EXPR =
+      Expressions.field(null, Boolean.class, "TRUE");
+  public static final Statement EMPTY_STATEMENT = Expressions.statement(null);
+
+  private static final Set<Method> KNOWN_NON_NULL_METHODS = new HashSet<>();
+
+  static {
+    for (Class aClass : new Class[]{Boolean.class, Byte.class, Short.class,
+      Integer.class, Long.class, String.class}) {
+      for (Method method : aClass.getMethods()) {
+        if ("valueOf".equals(method.getName())
+            && Modifier.isStatic(method.getModifiers())) {
+          KNOWN_NON_NULL_METHODS.add(method);
+        }
+      }
+    }
+  }
+
+  private static final
+  Map<ExpressionType, ExpressionType> NOT_BINARY_COMPLEMENT =
+      new EnumMap<>(ExpressionType.class);
+
+  static {
+    addComplement(ExpressionType.Equal, ExpressionType.NotEqual);
+    addComplement(ExpressionType.GreaterThanOrEqual, ExpressionType.LessThan);
+    addComplement(ExpressionType.GreaterThan, ExpressionType.LessThanOrEqual);
+  }
+
+  private static void addComplement(ExpressionType eq, ExpressionType ne) {
+    NOT_BINARY_COMPLEMENT.put(eq, ne);
+    NOT_BINARY_COMPLEMENT.put(ne, eq);
+  }
+
+  private static final Method BOOLEAN_VALUEOF_BOOL =
+      Types.lookupMethod(Boolean.class, "valueOf", boolean.class);
+
+  @Override public Expression visit(
+      TernaryExpression ternary,
+      Expression expression0,
+      Expression expression1,
+      Expression expression2) {
+    switch (ternary.getNodeType()) {
+    case Conditional:
+      Boolean always = always(expression0);
+      if (always != null) {
+        // true ? y : z  ===  y
+        // false ? y : z  === z
+        return always
+            ? expression1
+            : expression2;
+      }
+      if (expression1.equals(expression2)) {
+        // a ? b : b   ===   b
+        return expression1;
+      }
+      // !a ? b : c == a ? c : b
+      if (expression0 instanceof UnaryExpression) {
+        UnaryExpression una = (UnaryExpression) expression0;
+        if (una.getNodeType() == ExpressionType.Not) {
+          return Expressions.makeTernary(ternary.getNodeType(),
+              una.expression, expression2, expression1);
+        }
+      }
+
+      // a ? true : b  === a || b
+      // a ? false : b === !a && b
+      always = always(expression1);
+      if (always != null && isKnownNotNull(expression2)) {
+        return (always
+                 ? Expressions.orElse(expression0, expression2)
+                 : Expressions.andAlso(Expressions.not(expression0),
+            expression2)).accept(this);
+      }
+
+      // a ? b : true  === !a || b
+      // a ? b : false === a && b
+      always = always(expression2);
+      if (always != null && isKnownNotNull(expression1)) {
+        return (always
+                 ? Expressions.orElse(Expressions.not(expression0),
+                    expression1)
+                 : Expressions.andAlso(expression0, expression1)).accept(this);
+      }
+
+      if (expression0 instanceof BinaryExpression
+          && (expression0.getNodeType() == ExpressionType.Equal
+              || expression0.getNodeType() == ExpressionType.NotEqual)) {
+        BinaryExpression cmp = (BinaryExpression) expression0;
+        Expression expr = null;
+        if (eq(cmp.expression0, expression2)
+            && eq(cmp.expression1, expression1)) {
+          // a == b ? b : a === a (hint: if a==b, then a == b ? a : a)
+          // a != b ? b : a === b (hint: if a==b, then a != b ? b : b)
+          expr = expression0.getNodeType() == ExpressionType.Equal
+              ? expression2 : expression1;
+        }
+        if (eq(cmp.expression0, expression1)
+            && eq(cmp.expression1, expression2)) {
+          // a == b ? a : b === b (hint: if a==b, then a == b ? b : b)
+          // a != b ? a : b === a (hint: if a==b, then a == b ? a : a)
+          expr = expression0.getNodeType() == ExpressionType.Equal
+              ? expression2 : expression1;
+        }
+        if (expr != null) {
+          return expr;
+        }
+      }
+    }
+    return super.visit(ternary, expression0, expression1, expression2);
+  }
+
+  @Override public Expression visit(
+      BinaryExpression binary,
+      Expression expression0,
+      Expression expression1) {
+    //
+    Expression result;
+    switch (binary.getNodeType()) {
+    case AndAlso:
+    case OrElse:
+      if (eq(expression0, expression1)) {
+        return expression0;
+      }
+    }
+    switch (binary.getNodeType()) {
+    case Equal:
+    case NotEqual:
+      if (eq(expression0, expression1)) {
+        return binary.getNodeType() == Equal ? TRUE_EXPR : FALSE_EXPR;
+      } else if (expression0 instanceof ConstantExpression && expression1
+        instanceof ConstantExpression) {
+        ConstantExpression c0 = (ConstantExpression) expression0;
+        ConstantExpression c1 = (ConstantExpression) expression1;
+        if (c0.getType() == c1.getType()
+            || !(Primitive.is(c0.getType()) || Primitive.is(c1.getType()))) {
+          return binary.getNodeType() == NotEqual ? TRUE_EXPR : FALSE_EXPR;
+        }
+      }
+      if (expression0 instanceof TernaryExpression
+          && expression0.getNodeType() == ExpressionType.Conditional) {
+        TernaryExpression ternary = (TernaryExpression) expression0;
+        Expression expr = null;
+        if (eq(ternary.expression1, expression1)) {
+          // (a ? b : c) == b === a || c == b
+          expr = Expressions.orElse(ternary.expression0,
+              Expressions.equal(ternary.expression2, expression1));
+        } else if (eq(ternary.expression2, expression1)) {
+          // (a ? b : c) == c === !a || b == c
+          expr = Expressions.orElse(Expressions.not(ternary.expression0),
+              Expressions.equal(ternary.expression1, expression1));
+        }
+        if (expr != null) {
+          if (binary.getNodeType() == ExpressionType.NotEqual) {
+            expr = Expressions.not(expr);
+          }
+          return expr.accept(this);
+        }
+      }
+      // drop down
+    case AndAlso:
+    case OrElse:
+      result = visit0(binary, expression0, expression1);
+      if (result != null) {
+        return result;
+      }
+      result = visit0(binary, expression1, expression0);
+      if (result != null) {
+        return result;
+      }
+    }
+    return super.visit(binary, expression0, expression1);
+  }
+
+  private Expression visit0(
+      BinaryExpression binary,
+      Expression expression0,
+      Expression expression1) {
+    Boolean always;
+    switch (binary.getNodeType()) {
+    case AndAlso:
+      always = always(expression0);
+      if (always != null) {
+        return always
+            ? expression1
+            : FALSE_EXPR;
+      }
+      break;
+    case OrElse:
+      always = always(expression0);
+      if (always != null) {
+        // true or x  --> true
+        // false or x --> x
+        return always
+            ? TRUE_EXPR
+            : expression1;
+      }
+      break;
+    case Equal:
+      if (isConstantNull(expression1)
+          && Primitive.is(expression0.getType())) {
+        return FALSE_EXPR;
+      }
+      // a == true  -> a
+      // a == false -> !a
+      always = always(expression0);
+      if (always != null) {
+        return always ? expression1 : Expressions.not(expression1);
+      }
+      break;
+    case NotEqual:
+      if (isConstantNull(expression1)
+          && Primitive.is(expression0.getType())) {
+        return TRUE_EXPR;
+      }
+      // a != true  -> !a
+      // a != false -> a
+      always = always(expression0);
+      if (always != null) {
+        return always ? Expressions.not(expression1) : expression1;
+      }
+      break;
+    }
+    return null;
+  }
+
+  @Override public Expression visit(UnaryExpression unaryExpression,
+      Expression expression) {
+    switch (unaryExpression.getNodeType()) {
+    case Convert:
+      if (expression.getType() == unaryExpression.getType()) {
+        return expression;
+      }
+      if (expression instanceof ConstantExpression) {
+        return Expressions.constant(((ConstantExpression) expression).value,
+            unaryExpression.getType());
+      }
+      break;
+    case Not:
+      Boolean always = always(expression);
+      if (always != null) {
+        return always ? FALSE_EXPR : TRUE_EXPR;
+      }
+      if (expression instanceof UnaryExpression) {
+        UnaryExpression arg = (UnaryExpression) expression;
+        if (arg.getNodeType() == ExpressionType.Not) {
+          return arg.expression;
+        }
+      }
+      if (expression instanceof BinaryExpression) {
+        BinaryExpression bin = (BinaryExpression) expression;
+        ExpressionType comp = NOT_BINARY_COMPLEMENT.get(bin.getNodeType());
+        if (comp != null) {
+          return Expressions.makeBinary(comp, bin.expression0, bin.expression1);
+        }
+      }
+    }
+    return super.visit(unaryExpression, expression);
+  }
+
+  @Override public Statement visit(ConditionalStatement conditionalStatement,
+      List<Node> list) {
+    // if (false) { <-- remove branch
+    // } if (true) { <-- stop here
+    // } else if (...)
+    // } else {...}
+    boolean optimal = true;
+    for (int i = 0; i < list.size() - 1 && optimal; i += 2) {
+      Boolean always = always((Expression) list.get(i));
+      if (always == null) {
+        continue;
+      }
+      if (i == 0 && always) {
+        // when the very first test is always true, just return its statement
+        return (Statement) list.get(1);
+      }
+      optimal = false;
+    }
+    if (optimal) {
+      // Nothing to optimize
+      return super.visit(conditionalStatement, list);
+    }
+    List<Node> newList = new ArrayList<>(list.size());
+    // Iterate over all the tests, except the latest "else"
+    for (int i = 0; i < list.size() - 1; i += 2) {
+      Expression test = (Expression) list.get(i);
+      Node stmt = list.get(i + 1);
+      Boolean always = always(test);
+      if (always == null) {
+        newList.add(test);
+        newList.add(stmt);
+        continue;
+      }
+      if (always) {
+        // No need to verify other tests
+        newList.add(stmt);
+        break;
+      }
+    }
+    // We might have dangling "else", however if we have just single item
+    // it means we have if (false) else if(false) else if (true) {...} code.
+    // Then we just return statement from true branch
+    if (list.size() == 1) {
+      return (Statement) list.get(0);
+    }
+    // Add "else" from original list
+    if (newList.size() % 2 == 0 && list.size() % 2 == 1) {
+      Node elseBlock = list.get(list.size() - 1);
+      if (newList.isEmpty()) {
+        return (Statement) elseBlock;
+      }
+      newList.add(elseBlock);
+    }
+    if (newList.isEmpty()) {
+      return EMPTY_STATEMENT;
+    }
+    return super.visit(conditionalStatement, newList);
+  }
+
+  @Override public Expression visit(MethodCallExpression methodCallExpression,
+      Expression targetExpression,
+      List<Expression> expressions) {
+    if (BOOLEAN_VALUEOF_BOOL.equals(methodCallExpression.method)) {
+      Boolean always = always(expressions.get(0));
+      if (always != null) {
+        return always ? TRUE_EXPR : FALSE_EXPR;
+      }
+    }
+    return super.visit(methodCallExpression, targetExpression, expressions);
+  }
+
+  private boolean isConstantNull(Expression expression) {
+    return expression instanceof ConstantExpression
+        && ((ConstantExpression) expression).value == null;
+  }
+
+  /**
+   * Returns whether an expression always evaluates to true or false.
+   * Assumes that expression has already been optimized.
+   */
+  private static Boolean always(Expression x) {
+    if (x.equals(FALSE_EXPR) || x.equals(BOXED_FALSE_EXPR)) {
+      return Boolean.FALSE;
+    }
+    if (x.equals(TRUE_EXPR) || x.equals(BOXED_TRUE_EXPR)) {
+      return Boolean.TRUE;
+    }
+    return null;
+  }
+
+  /**
+   * Returns whether an expression always returns a non-null result.
+   * For instance, primitive types cannot contain null values.
+   *
+   * @param expression expression to test
+   * @return true when the expression is known to be not-null
+   */
+  protected boolean isKnownNotNull(Expression expression) {
+    return Primitive.is(expression.getType())
+        || always(expression) != null
+        || (expression instanceof MethodCallExpression
+            && KNOWN_NON_NULL_METHODS.contains(
+                ((MethodCallExpression) expression).method));
+  }
+
+  /**
+   * Treats two expressions equal even if they represent different null types
+   */
+  private static boolean eq(Expression a, Expression b) {
+    return a.equals(b)
+        || (a instanceof ConstantExpression
+            && b instanceof ConstantExpression
+            && ((ConstantExpression) a).value
+                == ((ConstantExpression) b).value);
+  }
+}
+
+// End OptimizeShuttle.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/OptimizeVisitor.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/OptimizeVisitor.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/OptimizeVisitor.java
deleted file mode 100644
index f0bed0f..0000000
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/OptimizeVisitor.java
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.calcite.linq4j.tree;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.EnumMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static org.apache.calcite.linq4j.tree.ExpressionType.Equal;
-import static org.apache.calcite.linq4j.tree.ExpressionType.NotEqual;
-
-/**
- * Visitor that optimizes expressions.
- *
- * <p>The optimizations are essential, not mere tweaks. Without
- * optimization, expressions such as {@code false == null} will be left in,
- * which are invalid to Janino (because it does not automatically box
- * primitives).</p>
- */
-public class OptimizeVisitor extends Visitor {
-  public static final ConstantExpression FALSE_EXPR =
-      Expressions.constant(false);
-  public static final ConstantExpression TRUE_EXPR =
-      Expressions.constant(true);
-  public static final MemberExpression BOXED_FALSE_EXPR =
-      Expressions.field(null, Boolean.class, "FALSE");
-  public static final MemberExpression BOXED_TRUE_EXPR =
-      Expressions.field(null, Boolean.class, "TRUE");
-  public static final Statement EMPTY_STATEMENT = Expressions.statement(null);
-
-  private static final Set<Method> KNOWN_NON_NULL_METHODS =
-      new HashSet<Method>();
-
-  static {
-    for (Class aClass : new Class[]{Boolean.class, Byte.class, Short.class,
-      Integer.class, Long.class, String.class}) {
-      for (Method method : aClass.getMethods()) {
-        if ("valueOf".equals(method.getName())
-            && Modifier.isStatic(method.getModifiers())) {
-          KNOWN_NON_NULL_METHODS.add(method);
-        }
-      }
-    }
-  }
-
-  private static final Map<ExpressionType, ExpressionType>
-  NOT_BINARY_COMPLEMENT =
-      new EnumMap<ExpressionType, ExpressionType>(ExpressionType.class);
-
-  static {
-    addComplement(ExpressionType.Equal, ExpressionType.NotEqual);
-    addComplement(ExpressionType.GreaterThanOrEqual, ExpressionType.LessThan);
-    addComplement(ExpressionType.GreaterThan, ExpressionType.LessThanOrEqual);
-  }
-
-  private static void addComplement(ExpressionType eq, ExpressionType ne) {
-    NOT_BINARY_COMPLEMENT.put(eq, ne);
-    NOT_BINARY_COMPLEMENT.put(ne, eq);
-  }
-
-  private static final Method BOOLEAN_VALUEOF_BOOL =
-      Types.lookupMethod(Boolean.class, "valueOf", boolean.class);
-
-  @Override public Expression visit(
-      TernaryExpression ternary,
-      Expression expression0,
-      Expression expression1,
-      Expression expression2) {
-    switch (ternary.getNodeType()) {
-    case Conditional:
-      Boolean always = always(expression0);
-      if (always != null) {
-        // true ? y : z  ===  y
-        // false ? y : z  === z
-        return always
-            ? expression1
-            : expression2;
-      }
-      if (expression1.equals(expression2)) {
-        // a ? b : b   ===   b
-        return expression1;
-      }
-      // !a ? b : c == a ? c : b
-      if (expression0 instanceof UnaryExpression) {
-        UnaryExpression una = (UnaryExpression) expression0;
-        if (una.getNodeType() == ExpressionType.Not) {
-          return Expressions.makeTernary(ternary.getNodeType(),
-              una.expression, expression2, expression1);
-        }
-      }
-
-      // a ? true : b  === a || b
-      // a ? false : b === !a && b
-      always = always(expression1);
-      if (always != null && isKnownNotNull(expression2)) {
-        return (always
-                 ? Expressions.orElse(expression0, expression2)
-                 : Expressions.andAlso(Expressions.not(expression0),
-            expression2)).accept(this);
-      }
-
-      // a ? b : true  === !a || b
-      // a ? b : false === a && b
-      always = always(expression2);
-      if (always != null && isKnownNotNull(expression1)) {
-        return (always
-                 ? Expressions.orElse(Expressions.not(expression0),
-                    expression1)
-                 : Expressions.andAlso(expression0, expression1)).accept(this);
-      }
-
-      if (expression0 instanceof BinaryExpression
-          && (expression0.getNodeType() == ExpressionType.Equal
-              || expression0.getNodeType() == ExpressionType.NotEqual)) {
-        BinaryExpression cmp = (BinaryExpression) expression0;
-        Expression expr = null;
-        if (eq(cmp.expression0, expression2)
-            && eq(cmp.expression1, expression1)) {
-          // a == b ? b : a === a (hint: if a==b, then a == b ? a : a)
-          // a != b ? b : a === b (hint: if a==b, then a != b ? b : b)
-          expr = expression0.getNodeType() == ExpressionType.Equal
-              ? expression2 : expression1;
-        }
-        if (eq(cmp.expression0, expression1)
-            && eq(cmp.expression1, expression2)) {
-          // a == b ? a : b === b (hint: if a==b, then a == b ? b : b)
-          // a != b ? a : b === a (hint: if a==b, then a == b ? a : a)
-          expr = expression0.getNodeType() == ExpressionType.Equal
-              ? expression2 : expression1;
-        }
-        if (expr != null) {
-          return expr;
-        }
-      }
-    }
-    return super.visit(ternary, expression0, expression1, expression2);
-  }
-
-  @Override public Expression visit(
-      BinaryExpression binary,
-      Expression expression0,
-      Expression expression1) {
-    //
-    Expression result;
-    switch (binary.getNodeType()) {
-    case AndAlso:
-    case OrElse:
-      if (eq(expression0, expression1)) {
-        return expression0;
-      }
-    }
-    switch (binary.getNodeType()) {
-    case Equal:
-    case NotEqual:
-      if (eq(expression0, expression1)) {
-        return binary.getNodeType() == Equal ? TRUE_EXPR : FALSE_EXPR;
-      } else if (expression0 instanceof ConstantExpression && expression1
-        instanceof ConstantExpression) {
-        ConstantExpression c0 = (ConstantExpression) expression0;
-        ConstantExpression c1 = (ConstantExpression) expression1;
-        if (c0.getType() == c1.getType()
-            || !(Primitive.is(c0.getType()) || Primitive.is(c1.getType()))) {
-          return binary.getNodeType() == NotEqual ? TRUE_EXPR : FALSE_EXPR;
-        }
-      }
-      if (expression0 instanceof TernaryExpression
-          && expression0.getNodeType() == ExpressionType.Conditional) {
-        TernaryExpression ternary = (TernaryExpression) expression0;
-        Expression expr = null;
-        if (eq(ternary.expression1, expression1)) {
-          // (a ? b : c) == b === a || c == b
-          expr = Expressions.orElse(ternary.expression0,
-              Expressions.equal(ternary.expression2, expression1));
-        } else if (eq(ternary.expression2, expression1)) {
-          // (a ? b : c) == c === !a || b == c
-          expr = Expressions.orElse(Expressions.not(ternary.expression0),
-              Expressions.equal(ternary.expression1, expression1));
-        }
-        if (expr != null) {
-          if (binary.getNodeType() == ExpressionType.NotEqual) {
-            expr = Expressions.not(expr);
-          }
-          return expr.accept(this);
-        }
-      }
-      // drop down
-    case AndAlso:
-    case OrElse:
-      result = visit0(binary, expression0, expression1);
-      if (result != null) {
-        return result;
-      }
-      result = visit0(binary, expression1, expression0);
-      if (result != null) {
-        return result;
-      }
-    }
-    return super.visit(binary, expression0, expression1);
-  }
-
-  private Expression visit0(
-      BinaryExpression binary,
-      Expression expression0,
-      Expression expression1) {
-    Boolean always;
-    switch (binary.getNodeType()) {
-    case AndAlso:
-      always = always(expression0);
-      if (always != null) {
-        return always
-            ? expression1
-            : FALSE_EXPR;
-      }
-      break;
-    case OrElse:
-      always = always(expression0);
-      if (always != null) {
-        // true or x  --> true
-        // false or x --> x
-        return always
-            ? TRUE_EXPR
-            : expression1;
-      }
-      break;
-    case Equal:
-      if (isConstantNull(expression1)
-          && Primitive.is(expression0.getType())) {
-        return FALSE_EXPR;
-      }
-      // a == true  -> a
-      // a == false -> !a
-      always = always(expression0);
-      if (always != null) {
-        return always ? expression1 : Expressions.not(expression1);
-      }
-      break;
-    case NotEqual:
-      if (isConstantNull(expression1)
-          && Primitive.is(expression0.getType())) {
-        return TRUE_EXPR;
-      }
-      // a != true  -> !a
-      // a != false -> a
-      always = always(expression0);
-      if (always != null) {
-        return always ? Expressions.not(expression1) : expression1;
-      }
-      break;
-    }
-    return null;
-  }
-
-  @Override public Expression visit(UnaryExpression unaryExpression,
-      Expression expression) {
-    switch (unaryExpression.getNodeType()) {
-    case Convert:
-      if (expression.getType() == unaryExpression.getType()) {
-        return expression;
-      }
-      if (expression instanceof ConstantExpression) {
-        return Expressions.constant(((ConstantExpression) expression).value,
-            unaryExpression.getType());
-      }
-      break;
-    case Not:
-      Boolean always = always(expression);
-      if (always != null) {
-        return always ? FALSE_EXPR : TRUE_EXPR;
-      }
-      if (expression instanceof UnaryExpression) {
-        UnaryExpression arg = (UnaryExpression) expression;
-        if (arg.getNodeType() == ExpressionType.Not) {
-          return arg.expression;
-        }
-      }
-      if (expression instanceof BinaryExpression) {
-        BinaryExpression bin = (BinaryExpression) expression;
-        ExpressionType comp = NOT_BINARY_COMPLEMENT.get(bin.getNodeType());
-        if (comp != null) {
-          return Expressions.makeBinary(comp, bin.expression0, bin.expression1);
-        }
-      }
-    }
-    return super.visit(unaryExpression, expression);
-  }
-
-  @Override public Statement visit(ConditionalStatement conditionalStatement,
-      List<Node> list) {
-    // if (false) { <-- remove branch
-    // } if (true) { <-- stop here
-    // } else if (...)
-    // } else {...}
-    boolean optimal = true;
-    for (int i = 0; i < list.size() - 1 && optimal; i += 2) {
-      Boolean always = always((Expression) list.get(i));
-      if (always == null) {
-        continue;
-      }
-      if (i == 0 && always) {
-        // when the very first test is always true, just return its statement
-        return (Statement) list.get(1);
-      }
-      optimal = false;
-    }
-    if (optimal) {
-      // Nothing to optimize
-      return super.visit(conditionalStatement, list);
-    }
-    List<Node> newList = new ArrayList<Node>(list.size());
-    // Iterate over all the tests, except the latest "else"
-    for (int i = 0; i < list.size() - 1; i += 2) {
-      Expression test = (Expression) list.get(i);
-      Node stmt = list.get(i + 1);
-      Boolean always = always(test);
-      if (always == null) {
-        newList.add(test);
-        newList.add(stmt);
-        continue;
-      }
-      if (always) {
-        // No need to verify other tests
-        newList.add(stmt);
-        break;
-      }
-    }
-    // We might have dangling "else", however if we have just single item
-    // it means we have if (false) else if(false) else if (true) {...} code.
-    // Then we just return statement from true branch
-    if (list.size() == 1) {
-      return (Statement) list.get(0);
-    }
-    // Add "else" from original list
-    if (newList.size() % 2 == 0 && list.size() % 2 == 1) {
-      Node elseBlock = list.get(list.size() - 1);
-      if (newList.isEmpty()) {
-        return (Statement) elseBlock;
-      }
-      newList.add(elseBlock);
-    }
-    if (newList.isEmpty()) {
-      return EMPTY_STATEMENT;
-    }
-    return super.visit(conditionalStatement, newList);
-  }
-
-  @Override public Expression visit(MethodCallExpression methodCallExpression,
-      Expression targetExpression,
-      List<Expression> expressions) {
-    if (BOOLEAN_VALUEOF_BOOL.equals(methodCallExpression.method)) {
-      Boolean always = always(expressions.get(0));
-      if (always != null) {
-        return always ? TRUE_EXPR : FALSE_EXPR;
-      }
-    }
-    return super.visit(methodCallExpression, targetExpression, expressions);
-  }
-
-  private boolean isConstantNull(Expression expression) {
-    return expression instanceof ConstantExpression
-        && ((ConstantExpression) expression).value == null;
-  }
-
-  /**
-   * Returns whether an expression always evaluates to true or false.
-   * Assumes that expression has already been optimized.
-   */
-  private static Boolean always(Expression x) {
-    if (x.equals(FALSE_EXPR) || x.equals(BOXED_FALSE_EXPR)) {
-      return Boolean.FALSE;
-    }
-    if (x.equals(TRUE_EXPR) || x.equals(BOXED_TRUE_EXPR)) {
-      return Boolean.TRUE;
-    }
-    return null;
-  }
-
-  /**
-   * Returns whether an expression always returns a non-null result.
-   * For instance, primitive types cannot contain null values.
-   *
-   * @param expression expression to test
-   * @return true when the expression is known to be not-null
-   */
-  protected boolean isKnownNotNull(Expression expression) {
-    return Primitive.is(expression.getType())
-        || always(expression) != null
-        || (expression instanceof MethodCallExpression
-            && KNOWN_NON_NULL_METHODS.contains(
-                ((MethodCallExpression) expression).method));
-  }
-
-  /**
-   * Treats two expressions equal even if they represent different null types
-   */
-  private static boolean eq(Expression a, Expression b) {
-    return a.equals(b)
-        || (a instanceof ConstantExpression
-            && b instanceof ConstantExpression
-            && ((ConstantExpression) a).value
-                == ((ConstantExpression) b).value);
-  }
-}
-
-// End OptimizeVisitor.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ParameterExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ParameterExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ParameterExpression.java
index a437a46..f883f50 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ParameterExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ParameterExpression.java
@@ -43,7 +43,11 @@ public class ParameterExpression extends Expression {
     this.name = name;
   }
 
-  @Override public Expression accept(Visitor visitor) {
+  @Override public Expression accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }