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 2015/09/03 00:15:49 UTC

[01/50] incubator-calcite git commit: In RelBuilder, calling sort then limit has same effect as calling sortLimit

Repository: incubator-calcite
Updated Branches:
  refs/heads/branch-release 6b16ca59f -> 0c0c203da


In RelBuilder, calling sort then limit has same effect as calling sortLimit


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

Branch: refs/heads/branch-release
Commit: 40c55fd463e4a249953bf298450110027d6c3bd6
Parents: d35df36
Author: Julian Hyde <jh...@apache.org>
Authored: Sun Jul 5 00:05:11 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Jul 6 20:49:53 2015 -0700

----------------------------------------------------------------------
 .../org/apache/calcite/tools/RelBuilder.java    | 33 ++++++++++++
 .../org/apache/calcite/test/RelBuilderTest.java | 54 ++++++++++++++++++++
 2 files changed, 87 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/40c55fd4/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
index f664baf..13cf96e 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -28,6 +28,7 @@ import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.core.Values;
@@ -865,6 +866,38 @@ public class RelBuilder {
     final RexNode offsetNode = offset <= 0 ? null : literal(offset);
     final RexNode fetchNode = fetch < 0 ? null : literal(fetch);
     final boolean addedFields = extraNodes.size() > originalExtraNodes.size();
+    if (fieldCollations.isEmpty()) {
+      assert !addedFields;
+      RelNode top = peek();
+      if (top instanceof Sort) {
+        final Sort sort2 = (Sort) top;
+        if (sort2.offset == null && sort2.fetch == null) {
+          Stacks.pop(stack);
+          push(sort2.getInput());
+          final RelNode sort =
+              sortFactory.createSort(build(), sort2.collation,
+                  offsetNode, fetchNode);
+          push(sort);
+          return this;
+        }
+      }
+      if (top instanceof Project) {
+        final Project project = (Project) top;
+        if (project.getInput() instanceof Sort) {
+          final Sort sort2 = (Sort) project.getInput();
+          if (sort2.offset == null && sort2.fetch == null) {
+            Stacks.pop(stack);
+            push(sort2.getInput());
+            final RelNode sort =
+                sortFactory.createSort(build(), sort2.collation,
+                    offsetNode, fetchNode);
+            push(sort);
+            project(project.getProjects());
+            return this;
+          }
+        }
+      }
+    }
     if (addedFields) {
       project(extraNodes);
     }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/40c55fd4/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
index 0a2b990..0474590 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -625,6 +625,60 @@ public class RelBuilderTest {
             + "  LogicalTableScan(table=[[scott, EMP]])\n";
     assertThat(str(root), is(expected));
   }
+
+  /** Tests that a sort on a field followed by a limit gives the same
+   * effect as calling sortLimit.
+   *
+   * <p>In general a relational operator cannot rely on the order of its input,
+   * but it is reasonable to merge sort and limit if they were created by
+   * consecutive builder operations. And clients such as Piglet rely on it. */
+  @Test public void testSortThenLimit() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    final RelNode root =
+        builder.scan("EMP")
+            .sort(builder.desc(builder.field("DEPTNO")))
+            .limit(-1, 10)
+            .build();
+    final String expected = ""
+        + "LogicalSort(sort0=[$7], dir0=[DESC], fetch=[10])\n"
+        + "  LogicalTableScan(table=[[scott, EMP]])\n";
+    assertThat(RelOptUtil.toString(root), is(expected));
+
+    final RelNode root2 =
+        builder.scan("EMP")
+            .sortLimit(-1, 10, builder.desc(builder.field("DEPTNO")))
+            .build();
+    assertThat(RelOptUtil.toString(root2), is(expected));
+  }
+
+  /** Tests that a sort on an expression followed by a limit gives the same
+   * effect as calling sortLimit. */
+  @Test public void testSortExpThenLimit() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    final RelNode root =
+        builder.scan("DEPT")
+            .sort(
+                builder.desc(
+                    builder.call(SqlStdOperatorTable.PLUS,
+                        builder.field("DEPTNO"), builder.literal(1))))
+            .limit(3, 10)
+            .build();
+    final String expected = ""
+        + "LogicalProject(DEPTNO=[$0], DNAME=[$1], LOC=[$2])\n"
+        + "  LogicalSort(sort0=[$3], dir0=[DESC], offset=[3], fetch=[10])\n"
+        + "    LogicalProject(DEPTNO=[$0], DNAME=[$1], LOC=[$2], $f3=[+($0, 1)])\n"
+        + "      LogicalTableScan(table=[[scott, DEPT]])\n";
+    assertThat(RelOptUtil.toString(root), is(expected));
+
+    final RelNode root2 =
+        builder.scan("DEPT")
+            .sortLimit(3, 10,
+                builder.desc(
+                    builder.call(SqlStdOperatorTable.PLUS,
+                        builder.field("DEPTNO"), builder.literal(1))))
+            .build();
+    assertThat(RelOptUtil.toString(root2), is(expected));
+  }
 }
 
 // End RelBuilderTest.java


[48/50] incubator-calcite git commit: Update POM to major version 1, minor version 4. Update README to 1.4.0

Posted by jh...@apache.org.
Update POM to major version 1, minor version 4.  Update README to 1.4.0


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

Branch: refs/heads/branch-release
Commit: a3d3fcde28ba0b3941bb354abd5decbcdf86e6c8
Parents: ce2f17a
Author: Jacques Nadeau <ja...@apache.org>
Authored: Sun Aug 23 12:47:28 2015 -0700
Committer: Jacques Nadeau <ja...@apache.org>
Committed: Sun Aug 23 20:53:35 2015 -0700

----------------------------------------------------------------------
 README  | 2 +-
 pom.xml | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/a3d3fcde/README
----------------------------------------------------------------------
diff --git a/README b/README
index e06064c..d1de7da 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-Apache Calcite release 1.3.0 (incubating)
+Apache Calcite release 1.4.0 (incubating)
 
 This is a source or binary distribution of Apache Calcite.
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/a3d3fcde/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index eab243c..3dea676 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,7 +49,7 @@ limitations under the License.
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <top.dir>${project.basedir}</top.dir>
     <version.major>1</version.major>
-    <version.minor>3</version.minor>
+    <version.minor>4</version.minor>
   </properties>
 
   <issueManagement>


[11/50] incubator-calcite git commit: Remove duplicate resources from XML test reference files

Posted by jh...@apache.org.
Remove duplicate resources from XML test reference files


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

Branch: refs/heads/branch-release
Commit: 220a085135a0c09798fc330ba73b752af89e92d6
Parents: efecdad
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Jul 16 11:11:35 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jul 16 11:11:35 2015 -0700

----------------------------------------------------------------------
 .../org/apache/calcite/test/DiffRepository.java | 163 ++++++----
 .../calcite/test/SqlToRelConverterTest.java     |   2 +-
 .../calcite/test/SqlToRelConverterTest.xml      | 312 -------------------
 3 files changed, 98 insertions(+), 379 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/220a0851/core/src/test/java/org/apache/calcite/test/DiffRepository.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/DiffRepository.java b/core/src/test/java/org/apache/calcite/test/DiffRepository.java
index ae06e94..fb6b325 100644
--- a/core/src/test/java/org/apache/calcite/test/DiffRepository.java
+++ b/core/src/test/java/org/apache/calcite/test/DiffRepository.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.test;
 
+import org.apache.calcite.avatica.util.Spaces;
 import org.apache.calcite.util.Util;
 import org.apache.calcite.util.XmlOutput;
 
@@ -36,7 +37,9 @@ import java.io.FileWriter;
 import java.io.IOException;
 import java.io.Writer;
 import java.net.URL;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
@@ -48,24 +51,24 @@ import javax.xml.parsers.ParserConfigurationException;
  * <p>Loads files containing test input and output into memory. If there are
  * differences, writes out a log file containing the actual output.
  *
- * <p>Typical usage is as follows. A testcase class defines a method
+ * <p>Typical usage is as follows. A test case class defines a method
  *
  * <blockquote><pre><code>
  *
  * package com.acme.test;
  *
  * public class MyTest extends TestCase {
- *     public DiffRepository getDiffRepos() {
- *         return DiffRepository.lookup(MyTest.class);
- *     }
+ *   public DiffRepository getDiffRepos() {
+ *     return DiffRepository.lookup(MyTest.class);
+ *   }
  *
- *     &#64;Test public void testToUpper() {
- *          getDiffRepos().assertEquals("${result}", "${string}");
- *     }
+ *   &#64;Test public void testToUpper() {
+ *     getDiffRepos().assertEquals("${result}", "${string}");
+ *   }
  *
- *     &#64;Test public void testToLower() {
- *          getDiffRepos().assertEquals("Multi-line\nstring", "${string}");
- *     }
+ *   &#64;Test public void testToLower() {
+ *     getDiffRepos().assertEquals("Multi-line\nstring", "${string}");
+ *   }
  * }
  * </code></pre></blockquote>
  *
@@ -93,7 +96,7 @@ import javax.xml.parsers.ParserConfigurationException;
  *
  * </code></pre></blockquote>
  *
- * <p>If any of the testcases fails, a log file is generated, called
+ * <p>If any of the test cases fails, a log file is generated, called
  * <code>target/surefire/com/acme/test/MyTest.xml</code>, containing the actual
  * output.</p>
  *
@@ -110,9 +113,9 @@ import javax.xml.parsers.ParserConfigurationException;
  * <blockquote><code>cp target/surefire/com/acme/test/MyTest.xml
  * src/test/resources/com/acme/test/MyTest.xml</code></blockquote>
  *
- * <p>If a resource or testcase does not exist, <code>DiffRepository</code>
+ * <p>If a resource or test case does not exist, <code>DiffRepository</code>
  * creates them in the log file. Because DiffRepository is so forgiving, it is
- * very easy to create new tests and testcases.</p>
+ * very easy to create new tests and test cases.</p>
  *
  * <p>The {@link #lookup} method ensures that all test cases share the same
  * instance of the repository. This is important more than one one test case
@@ -153,16 +156,17 @@ public class DiffRepository {
   private static final String RESOURCE_NAME_ATTR = "name";
 
   /**
-   * Holds one diff-repository per class. It is necessary for all testcases in
-   * the same class to share the same diff-repository: if the repos gets
-   * loaded once per testcase, then only one diff is recorded.
+   * Holds one diff-repository per class. It is necessary for all test cases in
+   * the same class to share the same diff-repository: if the repository gets
+   * loaded once per test case, then only one diff is recorded.
    */
-  private static final Map<Class, DiffRepository> MAP_CLASS_TO_REPOS =
-      new HashMap<Class, DiffRepository>();
+  private static final Map<Class, DiffRepository> MAP_CLASS_TO_REPOSITORY =
+      new HashMap<>();
 
   //~ Instance fields --------------------------------------------------------
 
-  private final DiffRepository baseRepos;
+  private final DiffRepository baseRepository;
+  private final int indent;
   private Document doc;
   private final Element root;
   private final File logFile;
@@ -175,15 +179,15 @@ public class DiffRepository {
    *
    * @param refFile   Reference file
    * @param logFile   Log file
-   * @param baseRepos Parent repository or null
+   * @param baseRepository Parent repository or null
    * @param filter    Filter or null
    */
   private DiffRepository(
       URL refFile,
       File logFile,
-      DiffRepository baseRepos,
+      DiffRepository baseRepository,
       Filter filter) {
-    this.baseRepos = baseRepos;
+    this.baseRepository = baseRepository;
     this.filter = filter;
     if (refFile == null) {
       throw new IllegalArgumentException("url must not be null");
@@ -211,11 +215,12 @@ public class DiffRepository {
         throw new RuntimeException("expected root element of type '" + ROOT_TAG
             + "', but found '" + root.getNodeName() + "'");
       }
-    } catch (ParserConfigurationException e) {
-      throw Util.newInternal(e, "error while creating xml parser");
-    } catch (SAXException e) {
+    } catch (ParserConfigurationException | SAXException e) {
       throw Util.newInternal(e, "error while creating xml parser");
     }
+    indent = logFile.getPath().contains("RelOptRulesTest")
+        || logFile.getPath().contains("SqlToRelConverterTest")
+        || logFile.getPath().contains("SqlLimitsTest") ? 4 : 2;
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -260,7 +265,7 @@ public class DiffRepository {
       // what is in the Java. It helps to have a redundant copy in the
       // resource file.
       final String testCaseName = getCurrentTestCaseName(true);
-      if (baseRepos == null || baseRepos.get(testCaseName, tag) == null) {
+      if (baseRepository == null || baseRepository.get(testCaseName, tag) == null) {
         set(tag, text);
       }
       return text;
@@ -268,7 +273,7 @@ public class DiffRepository {
   }
 
   /**
-   * Sets the value of a given resource of the current testcase.
+   * Sets the value of a given resource of the current test case.
    *
    * @param resourceName Name of the resource, e.g. "sql"
    * @param value        Value of the resource
@@ -288,7 +293,7 @@ public class DiffRepository {
   }
 
   /**
-   * Returns a given resource from a given testcase.
+   * Returns a given resource from a given test case.
    *
    * @param testCaseName Name of test case, e.g. "testFoo"
    * @param resourceName Name of resource, e.g. "sql", "plan"
@@ -299,8 +304,8 @@ public class DiffRepository {
       String resourceName) {
     Element testCaseElement = getTestCaseElement(testCaseName, true);
     if (testCaseElement == null) {
-      if (baseRepos != null) {
-        return baseRepos.get(testCaseName, resourceName);
+      if (baseRepository != null) {
+        return baseRepository.get(testCaseName, resourceName);
       } else {
         return null;
       }
@@ -359,13 +364,13 @@ public class DiffRepository {
         if (testCaseName.equals(
             testCase.getAttribute(TEST_CASE_NAME_ATTR))) {
           if (checkOverride
-              && (baseRepos != null)
-              && (baseRepos.getTestCaseElement(testCaseName, false) != null)
+              && (baseRepository != null)
+              && (baseRepository.getTestCaseElement(testCaseName, false) != null)
               && !"true".equals(
                   testCase.getAttribute(TEST_CASE_OVERRIDES_ATTR))) {
             throw new RuntimeException(
                 "TestCase  '" + testCaseName + "' overrides a "
-                + "testcase in the base repository, but does "
+                + "test case in the base repository, but does "
                 + "not specify 'overrides=true'");
           }
           return testCase;
@@ -376,11 +381,11 @@ public class DiffRepository {
   }
 
   /**
-   * Returns the name of the current testcase by looking up the call stack for
+   * Returns the name of the current test case by looking up the call stack for
    * a method whose name starts with "test", for example "testFoo".
    *
    * @param fail Whether to fail if no method is found
-   * @return Name of current testcase, or null if not found
+   * @return Name of current test case, or null if not found
    */
   private String getCurrentTestCaseName(boolean fail) {
     // REVIEW jvs 12-Mar-2006: Too clever by half.  Someone might not know
@@ -390,7 +395,7 @@ public class DiffRepository {
     // failing here if they forgot?
 
     // Clever, this. Dump the stack and look up it for a method which
-    // looks like a testcase name, e.g. "testFoo".
+    // looks like a test case name, e.g. "testFoo".
     final StackTraceElement[] stackTrace;
     Throwable runtimeException = new Throwable();
     runtimeException.fillInStackTrace();
@@ -402,7 +407,7 @@ public class DiffRepository {
       }
     }
     if (fail) {
-      throw new RuntimeException("no testcase on current callstack");
+      throw new RuntimeException("no test case on current call stack");
     } else {
       return null;
     }
@@ -414,7 +419,7 @@ public class DiffRepository {
     if (expected2 == null) {
       update(testCaseName, expected, actual);
       throw new AssertionError("reference file does not contain resource '"
-          + expected + "' for testcase '" + testCaseName + "'");
+          + expected + "' for test case '" + testCaseName + "'");
     } else {
       try {
         // TODO jvs 25-Apr-2006:  reuse bulk of
@@ -430,6 +435,7 @@ public class DiffRepository {
             tag,
             expected2Canonical,
             actualCanonical);
+        amend(expected, actual);
       } catch (ComparisonFailure e) {
         amend(expected, actual);
         throw e;
@@ -458,7 +464,7 @@ public class DiffRepository {
       root.appendChild(testCaseElement);
     }
     Element resourceElement =
-        getResourceElement(testCaseElement, resourceName);
+        getResourceElement(testCaseElement, resourceName, true);
     if (resourceElement == null) {
       resourceElement = doc.createElement(RESOURCE_TAG);
       resourceElement.setAttribute(RESOURCE_NAME_ATTR, resourceName);
@@ -483,7 +489,7 @@ public class DiffRepository {
       boolean b = logFile.getParentFile().mkdirs();
       Util.discard(b);
       w = new FileWriter(logFile);
-      write(doc, w);
+      write(doc, w, indent);
     } catch (IOException e) {
       throw Util.newInternal(e,
           "error while writing test reference log '" + logFile + "'");
@@ -499,7 +505,7 @@ public class DiffRepository {
   }
 
   /**
-   * Returns a given resource from a given testcase.
+   * Returns a given resource from a given test case.
    *
    * @param testCaseElement The enclosing TestCase element, e.g. <code>
    *                        &lt;TestCase name="testFoo"&gt;</code>.
@@ -509,16 +515,40 @@ public class DiffRepository {
   private static Element getResourceElement(
       Element testCaseElement,
       String resourceName) {
+    return getResourceElement(testCaseElement, resourceName, false);
+  }
+
+  /**
+   * Returns a given resource from a given test case.
+   *
+   * @param testCaseElement The enclosing TestCase element, e.g. <code>
+   *                        &lt;TestCase name="testFoo"&gt;</code>.
+   * @param resourceName    Name of resource, e.g. "sql", "plan"
+   * @param killYoungerSiblings Whether to remove resources with the same
+   *                        name and the same parent that are eclipsed
+   * @return The value of the resource, or null if not found
+   */
+  private static Element getResourceElement(Element testCaseElement,
+      String resourceName, boolean killYoungerSiblings) {
     final NodeList childNodes = testCaseElement.getChildNodes();
+    Element found = null;
+    final List<Node> kills = new ArrayList<>();
     for (int i = 0; i < childNodes.getLength(); i++) {
       Node child = childNodes.item(i);
       if (child.getNodeName().equals(RESOURCE_TAG)
           && resourceName.equals(
               ((Element) child).getAttribute(RESOURCE_NAME_ATTR))) {
-        return (Element) child;
+        if (found == null) {
+          found = (Element) child;
+        } else if (killYoungerSiblings) {
+          kills.add(child);
+        }
       }
     }
-    return null;
+    for (Node kill : kills) {
+      testCaseElement.removeChild(kill);
+    }
+    return found;
   }
 
   private static void removeAllChildren(Element element) {
@@ -534,10 +564,10 @@ public class DiffRepository {
    * <p>FIXME: I'm sure there's a library call to do this, but I'm danged if I
    * can find it. -- jhyde, 2006/2/9.
    */
-  private static void write(Document doc, Writer w) {
+  private static void write(Document doc, Writer w, int indent) {
     final XmlOutput out = new XmlOutput(w);
     out.setGlob(true);
-    out.setIndentString("    ");
+    out.setIndentString(Spaces.of(indent));
     writeNode(doc, out);
   }
 
@@ -634,8 +664,8 @@ public class DiffRepository {
    * Finds the repository instance for a given class, with no base
    * repository or filter.
    *
-   * @param clazz Testcase class
-   * @return The diff repository shared between testcases in this class.
+   * @param clazz Test case class
+   * @return The diff repository shared between test cases in this class.
    */
   public static DiffRepository lookup(Class clazz) {
     return lookup(clazz, null);
@@ -645,28 +675,28 @@ public class DiffRepository {
    * Finds the repository instance for a given class and inheriting from
    * a given repository.
    *
-   * @param clazz     Testcase class
-   * @param baseRepos Base class of test class
-   * @return The diff repository shared between testcases in this class.
+   * @param clazz     Test case class
+   * @param baseRepository Base class of test class
+   * @return The diff repository shared between test cases in this class.
    */
   public static DiffRepository lookup(
       Class clazz,
-      DiffRepository baseRepos) {
-    return lookup(clazz, baseRepos, null);
+      DiffRepository baseRepository) {
+    return lookup(clazz, baseRepository, null);
   }
 
   /**
    * Finds the repository instance for a given class.
    *
-   * <p>It is important that all testcases in a class share the same
-   * repository instance. This ensures that, if two or more testcases fail,
-   * the log file will contains the actual results of both testcases.
+   * <p>It is important that all test cases in a class share the same
+   * repository instance. This ensures that, if two or more test cases fail,
+   * the log file will contains the actual results of both test cases.
    *
-   * <p>The <code>baseRepos</code> parameter is useful if the test is an
+   * <p>The <code>baseRepository</code> parameter is useful if the test is an
    * extension to a previous test. If the test class has a base class which
    * also has a repository, specify the repository here. DiffRepository will
    * look for resources in the base class if it cannot find them in this
-   * repository. If test resources from testcases in the base class are
+   * repository. If test resources from test cases in the base class are
    * missing or incorrect, it will not write them to the log file -- you
    * probably need to fix the base test.
    *
@@ -675,24 +705,25 @@ public class DiffRepository {
    * if the behavior of a derived test is slightly different than a base
    * test. If you do not specify a filter, no filtering will happen.
    *
-   * @param clazz     Testcase class
-   * @param baseRepos Base repository
+   * @param clazz     Test case class
+   * @param baseRepository Base repository
    * @param filter    Filters each string returned by the repository
-   * @return The diff repository shared between testcases in this class.
+   * @return The diff repository shared between test cases in this class.
    */
   public static synchronized DiffRepository lookup(
       Class clazz,
-      DiffRepository baseRepos,
+      DiffRepository baseRepository,
       Filter filter) {
-    DiffRepository diffRepos = MAP_CLASS_TO_REPOS.get(clazz);
-    if (diffRepos == null) {
+    DiffRepository diffRepository = MAP_CLASS_TO_REPOSITORY.get(clazz);
+    if (diffRepository == null) {
       final URL refFile = findFile(clazz, ".xml");
       final File logFile =
           new File(refFile.getFile().replace("test-classes", "surefire"));
-      diffRepos = new DiffRepository(refFile, logFile, baseRepos, filter);
-      MAP_CLASS_TO_REPOS.put(clazz, diffRepos);
+      diffRepository =
+          new DiffRepository(refFile, logFile, baseRepository, filter);
+      MAP_CLASS_TO_REPOSITORY.put(clazz, diffRepository);
     }
-    return diffRepos;
+    return diffRepository;
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/220a0851/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
index ee7f2c9..3a08601 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
@@ -1132,7 +1132,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
    * [CALCITE-753] Test aggregate operators do not derive row types with duplicate column names
    */
   @Test public void testAggNoDuplicateColumnNames() {
-    sql("SELECT empno, EXPR$2, COUNT(empno) FROM (SELECT empno, deptno AS EXPR$2 "
+    sql("SELECT empno, EXPR$2, COUNT(empno) FROM (SELECT empno, deptno AS EXPR$2\n"
             + "FROM emp) GROUP BY empno, EXPR$2").convertsTo("${plan}");
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/220a0851/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
index 1130160..fc9fe91 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -26,13 +26,6 @@ LogicalProject(EXPR$0=[CASE(=('a', 'a'), 1, null)])
         <Resource name="sql">
             <![CDATA[values (case 'a' when 'a' then 1 end)]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EXPR$0=[$0])
-  ProjectRel(EXPR$0=[CASE(=(_ISO-8859-1'a', _ISO-8859-1'a'), 1, CAST(null):INTEGER)])
-    OneRowRel
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testGroup">
         <Resource name="plan">
@@ -45,14 +38,6 @@ LogicalAggregate(group=[{0}])
         <Resource name="sql">
             <![CDATA[select deptno from emp group by deptno]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(DEPTNO=[$0])
-  AggregateRel(groupCount=[1])
-    ProjectRel($f0=[$7])
-      TableAccessRel(table=[[SALES, EMP]])
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testGroupJustOneAgg">
         <Resource name="plan">
@@ -65,14 +50,6 @@ LogicalAggregate(group=[{0}], SUM_SAL=[SUM($1)])
         <Resource name="sql">
             <![CDATA[select deptno, sum(sal) as sum_sal from emp group by deptno]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(DEPTNO=[$0], EXPR$1=[$1])
-  AggregateRel(groupCount=[1], agg#0=[SUM(1)])
-    ProjectRel($f0=[$7], $f1=[$5])
-      TableAccessRel(table=[[SALES, EMP]])
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testGroupExpressionsInsideAndOut">
         <Resource name="plan">
@@ -86,14 +63,6 @@ LogicalProject(EXPR$0=[+($0, 4)], EXPR$1=[$1], EXPR$2=[$2], EXPR$3=[*(2, $3)])
         <Resource name="sql">
             <![CDATA[select deptno + 4, sum(sal), sum(3 + sal), 2 * count(sal) from emp group by deptno]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EXPR$0=[+($0, 4)], EXPR$1=[$1], EXPR$2=[$2], EXPR$3=[*(2, $3)])
-  AggregateRel(groupCount=[1], agg#0=[SUM(1)], agg#1=[SUM(2)], agg#2=[COUNT(1)])
-    ProjectRel($f0=[$7], $f1=[$5], $f2=[+(3, $5)])
-      TableAccessRel(table=[[SALES, EMP]])
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testHaving">
         <Resource name="plan">
@@ -108,15 +77,6 @@ LogicalProject(EXPR$0=[$0])
         <Resource name="sql">
             <![CDATA[select sum(sal + sal) from emp having sum(sal) > 10]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EXPR$0=[$0])
-  FilterRel(condition=[>($1, 10)])
-    AggregateRel(groupCount=[0], agg#0=[SUM(0)], agg#1=[SUM(1)])
-      ProjectRel($f0=[+($5, $5)], $f1=[$5])
-        TableAccessRel(table=[[SALES, EMP]])
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testGroupBug281">
         <Resource name="plan">
@@ -130,15 +90,6 @@ LogicalProject(NAME=[$0])
         <Resource name="sql">
             <![CDATA[select name from (select name from dept group by name)]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(NAME=[$0])
-  ProjectRel(NAME=[$0])
-    AggregateRel(groupCount=[1])
-      ProjectRel($f0=[$1])
-        TableAccessRel(table=[[SALES, DEPT]])
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testGroupBug281b">
         <Resource name="plan">
@@ -153,15 +104,6 @@ LogicalProject(NAME=[$1], FOO=[$2])
         <Resource name="sql">
             <![CDATA[select name, foo from (select deptno, name, count(deptno) as foo from dept group by name, deptno, name)]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(NAME=[$1], FOO=[$2])
-  ProjectRel(DEPTNO=[$1], NAME=[$0], FOO=[$3])
-    AggregateRel(groupCount=[3], agg#0=[COUNT(1)])
-      ProjectRel($f0=[$1], $f1=[$0], $f2=[$1])
-        TableAccessRel(table=[[SALES, DEPT]])
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testAggDistinct">
         <Resource name="plan">
@@ -174,14 +116,6 @@ LogicalAggregate(group=[{0}], EXPR$1=[SUM($1)], EXPR$2=[SUM(DISTINCT $1)], EXPR$
         <Resource name="sql">
             <![CDATA[select deptno, sum(sal), sum(distinct sal), count(*) from emp group by deptno]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(DEPTNO=[$0], EXPR$1=[$1], EXPR$2=[$2], EXPR$3=[$3])
-  AggregateRel(groupCount=[1], agg#0=[SUM(1)], agg#1=[SUM(DISTINCT 1)], agg#2=[COUNT()])
-    ProjectRel($f0=[$7], $f1=[$5])
-      TableAccessRel(table=[[SALES, EMP]])
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testUnnest">
         <Resource name="plan">
@@ -196,19 +130,6 @@ LogicalProject(EXPR$0=[$0])
         <Resource name="sql">
             <![CDATA[select*from unnest(multiset[1,2])]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EXPR$0=[$0])
-  UncollectRel
-    ProjectRel(EXPR$0=[$SLICE($0)])
-      CollectRel
-        UnionRel(all=[true])
-          ProjectRel(EXPR$0=[1])
-            OneRowRel
-          ProjectRel(EXPR$0=[2])
-            OneRowRel
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testUnnestSubquery">
         <Resource name="plan">
@@ -223,16 +144,6 @@ LogicalProject(DEPTNO=[$0], NAME=[$1])
         <Resource name="sql">
             <![CDATA[select*from unnest(multiset(select*from dept))]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(DEPTNO=[$0], NAME=[$1])
-  UncollectRel
-    ProjectRel(EXPR$0=[$0])
-      CollectRel
-        ProjectRel(DEPTNO=[$0], NAME=[$1])
-          TableAccessRel(table=[[SALES, DEPT]])
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testMultisetSubquery">
         <Resource name="plan">
@@ -248,18 +159,6 @@ LogicalProject(EXPR$0=[$1])
         <Resource name="sql">
             <![CDATA[select multiset(select deptno from dept) from (values(true))]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EXPR$0=[$1])
-  JoinRel(condition=[true], joinType=[inner])
-    ProjectRel(EXPR$0=[$0])
-      ProjectRel(EXPR$0=[true])
-        OneRowRel
-    CollectRel
-      ProjectRel(DEPTNO=[$0])
-        TableAccessRel(table=[[SALES, DEPT]])
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testMultiset">
         <Resource name="plan">
@@ -274,17 +173,6 @@ LogicalProject(EXPR$0=['a'], EXPR$1=[$SLICE($2)])
         <Resource name="sql">
             <![CDATA[select 'a',multiset[10] from dept]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EXPR$0=[_ISO-8859-1'a'], EXPR$1=[$SLICE($2)])
-  JoinRel(condition=[true], joinType=[inner])
-    TableAccessRel(table=[[SALES, DEPT]])
-    CollectRel
-      UnionRel(all=[true])
-        ProjectRel(EXPR$0=[10])
-          OneRowRel
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testMultisetOfColumns">
         <Resource name="plan">
@@ -303,19 +191,6 @@ LogicalProject(EXPR$0=['abc'], EXPR$1=[$SLICE($9)])
         <Resource name="sql">
             <![CDATA[select 'abc',multiset[deptno,sal] from emp]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EXPR$0=[_ISO-8859-1'abc'], EXPR$1=[$SLICE($8)])
-  CorrelatorRel(condition=[true], joinType=[inner], correlations=[[var0=offset7, var1=offset5]])
-    TableAccessRel(table=[[SALES, EMP]])
-    CollectRel
-      UnionRel(all=[true])
-        ProjectRel(EXPR$0=[$cor0.DEPTNO])
-          OneRowRel
-        ProjectRel(EXPR$0=[$cor1.SAL])
-          OneRowRel
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testCorrelationJoin">
         <Resource name="plan">
@@ -332,17 +207,6 @@ LogicalProject(DEPTNO=[$0], NAME=[$1], EMPSET=[$2])
         <Resource name="sql">
             <![CDATA[select *,         multiset(select * from emp where deptno=dept.deptno)                as empset      from dept]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(DEPTNO=[$0], NAME=[$1], EMPSET=[$2])
-  CorrelatorRel(condition=[true], joinType=[inner], correlations=[[var0=offset0]])
-    TableAccessRel(table=[[SALES, DEPT]])
-    CollectRel
-      ProjectRel(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7])
-        FilterRel(condition=[=($7, $cor0.DEPTNO)])
-          TableAccessRel(table=[[SALES, EMP]])
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testExists">
         <Resource name="plan">
@@ -361,18 +225,6 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
         <Resource name="sql">
             <![CDATA[select*from emp where exists (select 1 from dept where deptno=55)]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7])
-  FilterRel(condition=[IS NULL($9)])
-    JoinRel(condition=[true], joinType=[left])
-      TableAccessRel(table=[[SALES, EMP]])
-      ProjectRel(EXPR$0=[$0], $indicator=[true])
-        ProjectRel(EXPR$0=[1])
-          FilterRel(condition=[=($0, 55)])
-            TableAccessRel(table=[[SALES, DEPT]])
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testExistsCorrelated">
         <Resource name="plan">
@@ -391,18 +243,6 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
         <Resource name="sql">
             <![CDATA[select*from emp where exists (select 1 from dept where emp.deptno=dept.deptno)]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7])
-  FilterRel(condition=[IS NULL($9)])
-    CorrelatorRel(condition=[true], joinType=[left], correlations=[[var0=offset7]])
-      TableAccessRel(table=[[SALES, EMP]])
-      ProjectRel(EXPR$0=[$0], $indicator=[true])
-        ProjectRel(EXPR$0=[1])
-          FilterRel(condition=[=($cor0.DEPTNO, $0)])
-            TableAccessRel(table=[[SALES, DEPT]])
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testUnnestSelect">
         <Resource name="plan">
@@ -421,20 +261,6 @@ LogicalProject(EXPR$0=[$0])
         <Resource name="sql">
             <![CDATA[select*from unnest(select multiset[deptno] from dept)]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EXPR$0=[$0])
-  UncollectRel
-    ProjectRel(EXPR$0=[$0])
-      ProjectRel(EXPR$0=[$SLICE($2)])
-        CorrelatorRel(condition=[true], joinType=[inner], correlations=[[var0=offset0]])
-          TableAccessRel(table=[[SALES, DEPT]])
-          CollectRel
-            UnionRel(all=[true])
-              ProjectRel(EXPR$0=[$cor0.DEPTNO])
-                OneRowRel
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testLateral">
         <Resource name="plan">
@@ -450,16 +276,6 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
         <Resource name="sql">
             <![CDATA[select * from emp, LATERAL (select * from dept where emp.deptno=dept.deptno)]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], DEPTNO0=[$8], NAME=[$9])
-  CorrelatorRel(condition=[true], joinType=[inner], correlations=[[var0=offset7]])
-    TableAccessRel(table=[[SALES, EMP]])
-    ProjectRel(DEPTNO=[$0], NAME=[$1])
-      FilterRel(condition=[=($cor0.DEPTNO, $0)])
-        TableAccessRel(table=[[SALES, DEPT]])
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testElement">
         <Resource name="plan">
@@ -474,17 +290,6 @@ LogicalProject(EXPR$0=[ELEMENT($SLICE($9))])
         <Resource name="sql">
             <![CDATA[select element(multiset[5]) from emp]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EXPR$0=[ELEMENT($SLICE($8))])
-  JoinRel(condition=[true], joinType=[inner])
-    TableAccessRel(table=[[SALES, EMP]])
-    CollectRel
-      UnionRel(all=[true])
-        ProjectRel(EXPR$0=[5])
-          OneRowRel
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testElementInValues">
         <Resource name="plan">
@@ -497,16 +302,6 @@ LogicalProject(EXPR$0=[ELEMENT($SLICE($0))])
         <Resource name="sql">
             <![CDATA[values element(multiset[5])]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EXPR$0=[$0])
-  ProjectRel(EXPR$0=[ELEMENT($SLICE($0))])
-    CollectRel
-      UnionRel(all=[true])
-        ProjectRel(EXPR$0=[5])
-          OneRowRel
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testUnionAll">
         <Resource name="plan">
@@ -521,15 +316,6 @@ LogicalUnion(all=[true])
         <Resource name="sql">
             <![CDATA[select empno from emp union all select deptno from dept]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-UnionRel(all=[true])
-  ProjectRel(EMPNO=[$0])
-    TableAccessRel(table=[[SALES, EMP]])
-  ProjectRel(DEPTNO=[$0])
-    TableAccessRel(table=[[SALES, DEPT]])
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testUnion">
         <Resource name="plan">
@@ -544,15 +330,6 @@ LogicalUnion(all=[false])
         <Resource name="sql">
             <![CDATA[select empno from emp union select deptno from dept]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-UnionRel(all=[false])
-  ProjectRel(EMPNO=[$0])
-    TableAccessRel(table=[[SALES, EMP]])
-  ProjectRel(DEPTNO=[$0])
-    TableAccessRel(table=[[SALES, DEPT]])
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testUnionValues">
         <Resource name="plan">
@@ -575,26 +352,6 @@ union all
 select 34 from emp
 union all values (30), (45 + 10)]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-UnionRel(all=[true])
-  UnionRel(all=[true])
-    ProjectRel(EXPR$0=[$0])
-      UnionRel(all=[true])
-        ProjectRel(EXPR$0=[10])
-          OneRowRel
-        ProjectRel(EXPR$0=[20])
-          OneRowRel
-    ProjectRel(EXPR$0=[34])
-      TableAccessRel(table=[[SALES, EMP]])
-  ProjectRel(EXPR$0=[$0])
-    UnionRel(all=[true])
-      ProjectRel(EXPR$0=[30])
-        OneRowRel
-      ProjectRel(EXPR$0=[+(45, 10)])
-        OneRowRel
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testUnionSubquery">
         <Resource name="plan">
@@ -618,26 +375,6 @@ LogicalProject(DEPTNO=[$7])
   select deptno from dept where deptno > 20 union all
   values (45), (67))]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(DEPTNO=[$7])
-  JoinRel(condition=[true], joinType=[inner])
-    TableAccessRel(table=[[SALES, EMP]])
-    UnionRel(all=[true])
-      UnionRel(all=[true])
-        ProjectRel(EMPNO=[$0])
-          TableAccessRel(table=[[SALES, EMP]])
-        ProjectRel(DEPTNO=[$0])
-          FilterRel(condition=[>($0, 20)])
-            TableAccessRel(table=[[SALES, DEPT]])
-      ProjectRel(EXPR$0=[$0])
-        UnionRel(all=[true])
-          ProjectRel(EXPR$0=[45])
-            OneRowRel
-          ProjectRel(EXPR$0=[67])
-            OneRowRel
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testIsDistinctFrom">
         <Resource name="plan">
@@ -649,14 +386,6 @@ LogicalProject(EXPR$0=[CAST(CASE(IS NULL(1), IS NOT NULL(2), IS NULL(2), IS NOT
         <Resource name="sql">
             <![CDATA[select 1 is distinct from 2 from (values(true))]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EXPR$0=[CASE(IS NULL(1), IS NOT NULL(2), IS NULL(2), IS NOT NULL(1), <>(1, 2))])
-  ProjectRel(EXPR$0=[$0])
-    ProjectRel(EXPR$0=[true])
-      OneRowRel
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testIsNotDistinctFrom">
         <Resource name="plan">
@@ -668,14 +397,6 @@ LogicalProject(EXPR$0=[CAST(CASE(IS NULL(1), IS NULL(2), IS NULL(2), IS NULL(1),
         <Resource name="sql">
             <![CDATA[select 1 is not distinct from 2 from (values(true))]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EXPR$0=[CASE(IS NULL(1), IS NULL(2), IS NULL(2), IS NULL(1), =(1, 2))])
-  ProjectRel(EXPR$0=[$0])
-    ProjectRel(EXPR$0=[true])
-      OneRowRel
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testNotLike">
         <Resource name="plan">
@@ -687,13 +408,6 @@ LogicalProject(EXPR$0=[NOT(LIKE('a', 'b', 'c'))])
         <Resource name="sql">
             <![CDATA[values ('a' not like 'b' escape 'c')]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EXPR$0=[$0])
-  ProjectRel(EXPR$0=[NOT(LIKE(_ISO-8859-1'a', _ISO-8859-1'b', _ISO-8859-1'c'))])
-    OneRowRel
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testOverMultiple">
         <Resource name="plan">
@@ -713,13 +427,6 @@ window w1 as (partition by job order by hiredate rows 2 preceding),
   w2 as (partition by job order by hiredate rows 3 preceding disallow partial),
   w3 as (partition by job order by hiredate range interval '1' second preceding)]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EXPR$0=[SUM($5) OVER (PARTITION BY $2 ORDER BY $4 ROWS 2 PRECEDING)], EXPR$1=[SUM($7) OVER (PARTITION BY $2 ORDER BY $4 ROWS 2 PRECEDING)], EXPR$2=[SUM($7) OVER (PARTITION BY $2 ORDER BY $4 ROWS 3 PRECEDING)])
-  FilterRel(condition=[>(SUM(-($7, $5)) OVER (PARTITION BY $2 ORDER BY $4 ROWS 2 PRECEDING), 999)])
-    TableAccessRel(table=[[SALES, EMP]])
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testCharLength">
         <Resource name="plan">
@@ -731,13 +438,6 @@ LogicalProject(EXPR$0=[CHAR_LENGTH('foo')])
         <Resource name="sql">
             <![CDATA[values (character_length('foo'))]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EXPR$0=[$0])
-  ProjectRel(EXPR$0=[CHAR_LENGTH(_ISO-8859-1'foo')])
-    OneRowRel
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testOverAvg">
         <Resource name="plan">
@@ -752,12 +452,6 @@ LogicalProject(EXPR$0=[CASE(>(COUNT($5) OVER (PARTITION BY $2 ORDER BY $4 ROWS B
 from emp
 window w1 as (partition by job order by hiredate rows 2 preceding)]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EXPR$0=[SUM($5) OVER (PARTITION BY $2 ORDER BY $4 ROWS 2 PRECEDING)], EXPR$1=[CASE(=(COUNT($5) OVER (PARTITION BY $2 ORDER BY $4 ROWS 2 PRECEDING), 0), CAST(null):INTEGER, /(SUM($5) OVER (PARTITION BY $2 ORDER BY $4 ROWS 2 PRECEDING), COUNT($5) OVER (PARTITION BY $2 ORDER BY $4 ROWS 2 PRECEDING)))])
-  TableAccessRel(table=[[SALES, EMP]])
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testOverCountStar">
         <Resource name="plan">
@@ -772,12 +466,6 @@ LogicalProject(EXPR$0=[COUNT($5) OVER (PARTITION BY $2 ORDER BY $4 ROWS BETWEEN
 from emp
 window w1 as (partition by job order by hiredate rows 2 preceding)]]>
         </Resource>
-        <Resource name="plan">
-            <![CDATA[
-ProjectRel(EXPR$0=[COUNT($5) OVER (PARTITION BY $2 ORDER BY $4 ROWS 2 PRECEDING)], EXPR$1=[COUNT() OVER (PARTITION BY $2 ORDER BY $4 ROWS 2 PRECEDING)])
-  TableAccessRel(table=[[SALES, EMP]])
-]]>
-        </Resource>
     </TestCase>
     <TestCase name="testIntegerLiteral">
         <Resource name="sql">



[15/50] incubator-calcite git commit: [CALCITE-800] Window function defined within another window function should be invalid (Hsuan-Yi Chu)

Posted by jh...@apache.org.
[CALCITE-800] Window function defined within another window function should be invalid (Hsuan-Yi Chu)

Close apache/incubator-calcite#106


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

Branch: refs/heads/branch-release
Commit: ef5833f3f4b8b6a2296a6f43170981dac03012ad
Parents: d38e6b1
Author: Hsuan-Yi Chu <hs...@usc.edu>
Authored: Mon Jul 13 15:59:39 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jul 16 17:20:10 2015 -0700

----------------------------------------------------------------------
 .../apache/calcite/runtime/CalciteResource.java |  6 ++++
 .../org/apache/calcite/sql/SqlRankFunction.java |  6 ++--
 .../java/org/apache/calcite/sql/SqlWindow.java  | 15 ++++++++
 .../calcite/sql/fun/SqlStdOperatorTable.java    | 10 +++---
 .../main/java/org/apache/calcite/util/Util.java | 17 +++++++++
 .../calcite/runtime/CalciteResource.properties  |  2 ++
 .../apache/calcite/test/SqlValidatorTest.java   | 36 +++++++++++++++++++-
 7 files changed, 84 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/ef5833f3/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
index ee3cb5a..007a410 100644
--- a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
+++ b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
@@ -332,6 +332,12 @@ public interface CalciteResource {
   @BaseMessage("Window specification must contain an ORDER BY clause")
   ExInst<SqlValidatorException> overMissingOrderBy();
 
+  @BaseMessage("PARTITION BY expression should not contain OVER clause")
+  ExInst<SqlValidatorException> partitionbyShouldNotContainOver();
+
+  @BaseMessage("ORDER BY expression should not contain OVER clause")
+  ExInst<SqlValidatorException> orderbyShouldNotContainOver();
+
   @BaseMessage("UNBOUNDED FOLLOWING cannot be specified for the lower frame boundary")
   ExInst<SqlValidatorException> badLowerBoundary();
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/ef5833f3/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java
index 85712d3..11b5ca1 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java
@@ -31,11 +31,12 @@ import java.util.List;
 public class SqlRankFunction extends SqlAggFunction {
   //~ Instance fields --------------------------------------------------------
 
+  private final boolean requiresOrder;
   private final RelDataType type = null;
 
   //~ Constructors -----------------------------------------------------------
 
-  public SqlRankFunction(String name) {
+  public SqlRankFunction(String name, boolean requiresOrder) {
     super(
         name,
         SqlKind.OTHER_FUNCTION,
@@ -43,12 +44,13 @@ public class SqlRankFunction extends SqlAggFunction {
         null,
         OperandTypes.NILADIC,
         SqlFunctionCategory.NUMERIC);
+    this.requiresOrder = requiresOrder;
   }
 
   //~ Methods ----------------------------------------------------------------
 
   @Override public boolean requiresOrder() {
-    return true;
+    return requiresOrder;
   }
 
   @Override public boolean allowsFraming() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/ef5833f3/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlWindow.java b/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
index a8ae456..40ba4ee 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
@@ -27,6 +27,7 @@ import org.apache.calcite.sql.util.SqlVisitor;
 import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.sql.validate.SqlValidatorScope;
 import org.apache.calcite.sql.validate.SqlValidatorUtil;
+import org.apache.calcite.util.ControlFlowException;
 import org.apache.calcite.util.ImmutableNullableList;
 import org.apache.calcite.util.Util;
 
@@ -523,6 +524,13 @@ public class SqlWindow extends SqlCall {
     }
 
     for (SqlNode partitionItem : partitionList) {
+      try {
+        partitionItem.accept(Util.OverFinder.INSTANCE);
+      } catch (ControlFlowException e) {
+        throw validator.newValidationError(this,
+            RESOURCE.partitionbyShouldNotContainOver());
+      }
+
       partitionItem.validateExpr(validator, operandScope);
     }
 
@@ -531,6 +539,13 @@ public class SqlWindow extends SqlCall {
           validator.getColumnReferenceExpansion();
       validator.setColumnReferenceExpansion(false);
       try {
+        orderItem.accept(Util.OverFinder.INSTANCE);
+      } catch (ControlFlowException e) {
+        throw validator.newValidationError(this,
+            RESOURCE.orderbyShouldNotContainOver());
+      }
+
+      try {
         orderItem.validateExpr(validator, scope);
       } finally {
         validator.setColumnReferenceExpansion(

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/ef5833f3/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
index 7a724b9..fa5fda5 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
@@ -850,30 +850,30 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable {
    * <code>CUME_DIST</code> Window function.
    */
   public static final SqlRankFunction CUME_DIST =
-      new SqlRankFunction("CUME_DIST");
+      new SqlRankFunction("CUME_DIST", true);
 
   /**
    * <code>DENSE_RANK</code> Window function.
    */
   public static final SqlRankFunction DENSE_RANK =
-      new SqlRankFunction("DENSE_RANK");
+      new SqlRankFunction("DENSE_RANK", true);
 
   /**
    * <code>PERCENT_RANK</code> Window function.
    */
   public static final SqlRankFunction PERCENT_RANK =
-      new SqlRankFunction("PERCENT_RANK");
+      new SqlRankFunction("PERCENT_RANK", true);
 
   /**
    * <code>RANK</code> Window function.
    */
-  public static final SqlRankFunction RANK = new SqlRankFunction("RANK");
+  public static final SqlRankFunction RANK = new SqlRankFunction("RANK", true);
 
   /**
    * <code>ROW_NUMBER</code> Window function.
    */
   public static final SqlRankFunction ROW_NUMBER =
-      new SqlRankFunction("ROW_NUMBER");
+      new SqlRankFunction("ROW_NUMBER", false);
 
   //-------------------------------------------------------------
   //                   SPECIAL OPERATORS

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/ef5833f3/core/src/main/java/org/apache/calcite/util/Util.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/Util.java b/core/src/main/java/org/apache/calcite/util/Util.java
index f739fbd..040775f 100644
--- a/core/src/main/java/org/apache/calcite/util/Util.java
+++ b/core/src/main/java/org/apache/calcite/util/Util.java
@@ -21,10 +21,12 @@ import org.apache.calcite.linq4j.Ord;
 import org.apache.calcite.runtime.CalciteException;
 import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlCall;
+import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlValuesOperator;
 import org.apache.calcite.sql.fun.SqlRowOperator;
+import org.apache.calcite.sql.util.SqlBasicVisitor;
 
 import com.google.common.base.Function;
 import com.google.common.base.Objects;
@@ -2175,6 +2177,21 @@ public class Util {
       return node;
     }
   }
+
+  /**
+   * Visitor which looks for an OVER clause inside a tree of
+   * {@link SqlNode} objects.
+   */
+  public static class OverFinder extends SqlBasicVisitor<Void> {
+    public static final OverFinder INSTANCE = new Util.OverFinder();
+
+    @Override public Void visit(SqlCall call) {
+      if (call.getKind() == SqlKind.OVER) {
+        throw FoundOne.NULL;
+      }
+      return super.visit(call);
+    }
+  }
 }
 
 // End Util.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/ef5833f3/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
----------------------------------------------------------------------
diff --git a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
index e170b67..3aec262 100644
--- a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
+++ b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
@@ -113,6 +113,8 @@ OrderByRangeMismatch=Data Type mismatch between ORDER BY and RANGE clause
 DateRequiresInterval=Window ORDER BY expression of type DATE requires range of type INTERVAL
 RowMustBeNonNegativeIntegral=ROWS value must be a non-negative integral constant
 OverMissingOrderBy=Window specification must contain an ORDER BY clause
+PartitionbyShouldNotContainOver=PARTITION BY expression should not contain OVER clause
+OrderbyShouldNotContainOver=ORDER BY expression should not contain OVER clause
 BadLowerBoundary=UNBOUNDED FOLLOWING cannot be specified for the lower frame boundary
 BadUpperBoundary=UNBOUNDED PRECEDING cannot be specified for the upper frame boundary
 CurrentRowPrecedingError=Upper frame boundary cannot be PRECEDING when lower boundary is CURRENT ROW

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/ef5833f3/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index cc8153e..76413ec 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -3801,6 +3801,32 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
     // Test specified collation, window clause syntax rule 4,5.
   }
 
+  @Test public void testOverInPartitionBy() {
+    winSql(
+        "select sum(deptno) over ^(partition by sum(deptno) \n"
+        + "over(order by deptno))^ from emp")
+        .fails("PARTITION BY expression should not contain OVER clause");
+
+    winSql(
+        "select sum(deptno) over w \n"
+        + "from emp \n"
+        + "window w as ^(partition by sum(deptno) over(order by deptno))^")
+        .fails("PARTITION BY expression should not contain OVER clause");
+  }
+
+  @Test public void testOverInOrderBy() {
+    winSql(
+        "select sum(deptno) over ^(order by sum(deptno) \n"
+        + "over(order by deptno))^ from emp")
+        .fails("ORDER BY expression should not contain OVER clause");
+
+    winSql(
+        "select sum(deptno) over w \n"
+        + "from emp \n"
+        + "window w as ^(order by sum(deptno) over(order by deptno))^")
+        .fails("ORDER BY expression should not contain OVER clause");
+  }
+
   @Test public void testWindowFunctions() {
     // SQL 03 Section 6.10
 
@@ -3859,8 +3885,15 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
             "RANK or DENSE_RANK functions require ORDER BY clause in window specification");
     winSql("select rank() over w2 from emp\n"
         + "window w as (partition by sal), w2 as (w order by deptno)").ok();
+
     // row_number function
     winExp("row_number() over (order by deptno)").ok();
+    winExp("row_number() over (partition by deptno)").ok();
+    winExp("row_number() over ()").ok();
+    winExp("row_number() over (order by deptno ^rows^ 2 preceding)")
+        .fails("ROW/RANGE not allowed with RANK or DENSE_RANK functions");
+    winExp("row_number() over (order by deptno ^range^ 2 preceding)")
+        .fails("ROW/RANGE not allowed with RANK or DENSE_RANK functions");
 
     // rank function type
     if (defined.contains("DENSE_RANK")) {
@@ -4187,7 +4220,8 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
         "Expression 'COMM' is not being grouped");
 
     // syntax rule 7
-    win("window w as (order by rank() over (order by sal))").ok();
+    win("window w as ^(order by rank() over (order by sal))^")
+        .fails("ORDER BY expression should not contain OVER clause");
 
     // ------------------------------------
     // ---- window frame between tests ----


[21/50] incubator-calcite git commit: Document JSON model, making javadoc consistent with the model reference

Posted by jh...@apache.org.
Document JSON model, making javadoc consistent with the model reference


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

Branch: refs/heads/branch-release
Commit: 629a56e5ed93d1493af508773075a8c0ffc9e486
Parents: b550ff8
Author: Julian Hyde <jh...@apache.org>
Authored: Fri Jun 26 12:39:45 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jul 21 13:00:15 2015 -0700

----------------------------------------------------------------------
 .../org/apache/calcite/model/JsonColumn.java    |  6 ++
 .../apache/calcite/model/JsonCustomSchema.java  | 15 ++++-
 .../apache/calcite/model/JsonCustomTable.java   | 15 ++++-
 .../org/apache/calcite/model/JsonFunction.java  | 31 +++++++++
 .../apache/calcite/model/JsonJdbcSchema.java    | 33 ++++++++++
 .../org/apache/calcite/model/JsonLattice.java   | 41 ++++++++----
 .../org/apache/calcite/model/JsonMapSchema.java | 16 ++++-
 .../calcite/model/JsonMaterialization.java      |  8 +++
 .../org/apache/calcite/model/JsonMeasure.java   |  6 ++
 .../java/org/apache/calcite/model/JsonRoot.java | 18 ++++-
 .../org/apache/calcite/model/JsonSchema.java    | 35 ++++++++--
 .../org/apache/calcite/model/JsonStream.java    | 12 +++-
 .../org/apache/calcite/model/JsonTable.java     | 16 ++++-
 .../java/org/apache/calcite/model/JsonTile.java | 18 +++--
 .../java/org/apache/calcite/model/JsonView.java | 43 +++++++++++-
 .../org/apache/calcite/model/ModelHandler.java  |  3 +-
 site/_docs/model.md                             | 69 +++++++++++++++++---
 17 files changed, 334 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/629a56e5/core/src/main/java/org/apache/calcite/model/JsonColumn.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/model/JsonColumn.java b/core/src/main/java/org/apache/calcite/model/JsonColumn.java
index 2b9a361..843610f 100644
--- a/core/src/main/java/org/apache/calcite/model/JsonColumn.java
+++ b/core/src/main/java/org/apache/calcite/model/JsonColumn.java
@@ -19,9 +19,15 @@ package org.apache.calcite.model;
 /**
  * JSON object representing a column.
  *
+ * <p>Occurs within {@link JsonTable#columns}.
+ *
  * @see JsonRoot Description of JSON schema elements
  */
 public class JsonColumn {
+  /** Column name.
+   *
+   * Required, and must be unique within the table.
+   */
   public String name;
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/629a56e5/core/src/main/java/org/apache/calcite/model/JsonCustomSchema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/model/JsonCustomSchema.java b/core/src/main/java/org/apache/calcite/model/JsonCustomSchema.java
index 3144d38..0e656cd 100644
--- a/core/src/main/java/org/apache/calcite/model/JsonCustomSchema.java
+++ b/core/src/main/java/org/apache/calcite/model/JsonCustomSchema.java
@@ -21,15 +21,24 @@ import java.util.Map;
 /**
  * JSON schema element that represents a custom schema.
  *
+ * <p>Like the base class {@link JsonSchema},
+ * occurs within {@link JsonRoot#schemas}.
+ *
  * @see org.apache.calcite.model.JsonRoot Description of schema elements
  */
 public class JsonCustomSchema extends JsonMapSchema {
-  /** Name of the factory class for this schema. Must implement interface
+  /** Name of the factory class for this schema.
+   *
+   * <p>Required. Must implement interface
    * {@link org.apache.calcite.schema.SchemaFactory} and have a public default
-   * constructor. */
+   * constructor.
+   */
   public String factory;
 
-  /** Operand. May be a JSON object (represented as Map) or null. */
+  /** Contains attributes to be passed to the factory.
+   *
+   * <p>May be a JSON object (represented as Map) or null.
+   */
   public Map<String, Object> operand;
 
   public void accept(ModelHandler handler) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/629a56e5/core/src/main/java/org/apache/calcite/model/JsonCustomTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/model/JsonCustomTable.java b/core/src/main/java/org/apache/calcite/model/JsonCustomTable.java
index 07a73d9..1619f7f 100644
--- a/core/src/main/java/org/apache/calcite/model/JsonCustomTable.java
+++ b/core/src/main/java/org/apache/calcite/model/JsonCustomTable.java
@@ -21,15 +21,24 @@ import java.util.Map;
 /**
  * Custom table schema element.
  *
+ * <p>Like base class {@link JsonTable},
+ * occurs within {@link JsonMapSchema#tables}.
+ *
  * @see JsonRoot Description of schema elements
  */
 public class JsonCustomTable extends JsonTable {
-  /** Name of the factory class for this table. Must implement interface
+  /** Name of the factory class for this table.
+   *
+   * <p>Required. Must implement interface
    * {@link org.apache.calcite.schema.TableFactory} and have a public default
-   * constructor. */
+   * constructor.
+   */
   public String factory;
 
-  /** Operand. May be a JSON object (represented as Map) or null. */
+  /** Contains attributes to be passed to the factory.
+   *
+   * <p>May be a JSON object (represented as Map) or null.
+   */
   public Map<String, Object> operand;
 
   public void accept(ModelHandler handler) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/629a56e5/core/src/main/java/org/apache/calcite/model/JsonFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/model/JsonFunction.java b/core/src/main/java/org/apache/calcite/model/JsonFunction.java
index 5c24ec9..e7a2bec 100644
--- a/core/src/main/java/org/apache/calcite/model/JsonFunction.java
+++ b/core/src/main/java/org/apache/calcite/model/JsonFunction.java
@@ -24,9 +24,40 @@ import java.util.List;
  * @see JsonRoot Description of schema elements
  */
 public class JsonFunction {
+  /** Name of this function.
+   *
+   * <p>Required.
+   */
   public String name;
+
+  /** Name of the class that implements this function.
+   *
+   * <p>Required.
+   */
   public String className;
+
+  /** Name of the method that implements this function.
+   *
+   * <p>Optional.
+   *
+   * <p>If specified, the method must exist (case-sensitive) and Calcite
+   * will create a scalar function. The method may be static or non-static, but
+   * if non-static, the class must have a public constructor with no parameters.
+   *
+   * <p>If "*", Calcite creates a function for every method
+   * in this class.
+   *
+   * <p>If not specified, Calcite looks for a method called "eval", and
+   * if found, creates a a table macro or scalar function.
+   * It also looks for methods "init", "add", "merge", "result", and
+   * if found, creates an aggregate function.
+   */
   public String methodName;
+
+  /** Path for resolving this function.
+   *
+   * <p>Optional.
+   */
   public List<String> path;
 
   public void accept(ModelHandler handler) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/629a56e5/core/src/main/java/org/apache/calcite/model/JsonJdbcSchema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/model/JsonJdbcSchema.java b/core/src/main/java/org/apache/calcite/model/JsonJdbcSchema.java
index 61923d9..5eb203b 100644
--- a/core/src/main/java/org/apache/calcite/model/JsonJdbcSchema.java
+++ b/core/src/main/java/org/apache/calcite/model/JsonJdbcSchema.java
@@ -19,14 +19,47 @@ package org.apache.calcite.model;
 /**
  * JSON object representing a schema that maps to a JDBC database.
  *
+ * <p>Like the base class {@link JsonSchema},
+ * occurs within {@link JsonRoot#schemas}.
+ *
  * @see JsonRoot Description of JSON schema elements
  */
 public class JsonJdbcSchema extends JsonSchema {
+  /** The name of the JDBC driver class.
+   *
+   * <p>Optional. If not specified, uses whichever class the JDBC
+   * {@link java.sql.DriverManager} chooses.
+   */
   public String jdbcDriver;
+
+  /** JDBC connect string, for example “jdbc:mysql://localhost/foodmart”.
+   *
+   * <p>Optional.
+   */
   public String jdbcUrl;
+
+  /** JDBC user name.
+   *
+   * <p>Optional.
+   */
   public String jdbcUser;
+
+  /** JDBC connect string, for example “jdbc:mysql://localhost/foodmart”.
+   *
+   * <p>Optional.
+   */
   public String jdbcPassword;
+
+  /** Name of the initial catalog in the JDBC data source.
+   *
+   * <p>Optional.
+   */
   public String jdbcCatalog;
+
+  /** Name of the initial schema in the JDBC data source.
+   *
+   * <p>Optional.
+   */
   public String jdbcSchema;
 
   @Override public void accept(ModelHandler handler) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/629a56e5/core/src/main/java/org/apache/calcite/model/JsonLattice.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/model/JsonLattice.java b/core/src/main/java/org/apache/calcite/model/JsonLattice.java
index d96eb06..15f1fcd 100644
--- a/core/src/main/java/org/apache/calcite/model/JsonLattice.java
+++ b/core/src/main/java/org/apache/calcite/model/JsonLattice.java
@@ -16,8 +16,7 @@
  */
 package org.apache.calcite.model;
 
-import com.google.common.collect.Lists;
-
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -25,29 +24,48 @@ import java.util.List;
  * recognizing, and recommending materialized views at various levels of
  * aggregation.
  *
+ * <p>Occurs within {@link JsonSchema#lattices}.
+ *
  * @see JsonRoot Description of schema elements
  */
 public class JsonLattice {
+  /** The name of this lattice.
+   *
+   * <p>Required.
+   */
   public String name;
 
   /** SQL query that defines the lattice.
    *
-   * <p>Must be a string or a list of strings (which are concatenated separated
-   * by newlines).
+   * <p>Must be a string or a list of strings (which are concatenated into a
+   * multi-line SQL string, separated by newlines).
+   *
+   * <p>The structure of the SQL statement, and in particular the order of
+   * items in the FROM clause, defines the fact table, dimension tables, and
+   * join paths for this lattice.
    */
   public Object sql;
 
-  /** Whether to create in-memory materialized aggregates on demand.
+  /** Whether to materialize tiles on demand as queries are executed.
    *
-   * <p>Default is true. */
+   * <p>Optional; default is true.
+   */
   public boolean auto = true;
 
-  /** Whether to use an algorithm to suggest aggregates.
+  /** Whether to use an optimization algorithm to suggest and populate an
+   * initial set of tiles.
    *
-   * <p>Default is false. */
+   * <p>Optional; default is false.
+   */
   public boolean algorithm = false;
 
-  /** Maximum time to run the algorithm. Default is -1, meaning no timeout. */
+  /** Maximum time (in milliseconds) to run the algorithm.
+   *
+   * <p>Optional; default is -1, meaning no timeout.
+   *
+   * <p>When the timeout is reached, Calcite uses the best result that has
+   * been obtained so far.
+   */
   public long algorithmMaxMillis = -1;
 
   /** Estimated number of rows.
@@ -69,13 +87,14 @@ public class JsonLattice {
   public String statisticProvider;
 
   /** List of materialized aggregates to create up front. */
-  public final List<JsonTile> tiles = Lists.newArrayList();
+  public final List<JsonTile> tiles = new ArrayList<>();
 
   /** List of measures that a tile should have by default.
    *
    * <p>A tile can define its own measures, including measures not in this list.
    *
-   * <p>The default list is just count. */
+   * <p>Optional. The default list is just "count(*)".
+   */
   public List<JsonMeasure> defaultMeasures;
 
   public void accept(ModelHandler handler) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/629a56e5/core/src/main/java/org/apache/calcite/model/JsonMapSchema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/model/JsonMapSchema.java b/core/src/main/java/org/apache/calcite/model/JsonMapSchema.java
index e65a211..a7e8783 100644
--- a/core/src/main/java/org/apache/calcite/model/JsonMapSchema.java
+++ b/core/src/main/java/org/apache/calcite/model/JsonMapSchema.java
@@ -22,11 +22,23 @@ import java.util.List;
 /**
  * JSON object representing a schema whose tables are explicitly specified.
  *
+ * <p>Like the base class {@link JsonSchema},
+ * occurs within {@link JsonRoot#schemas}.
+ *
  * @see JsonRoot Description of JSON schema elements
  */
 public class JsonMapSchema extends JsonSchema {
-  public final List<JsonTable> tables = new ArrayList<JsonTable>();
-  public final List<JsonFunction> functions = new ArrayList<JsonFunction>();
+  /** Tables in this schema.
+   *
+   * <p>The list may be empty.
+   */
+  public final List<JsonTable> tables = new ArrayList<>();
+
+  /** Functions in this schema.
+   *
+   * <p>The list may be empty.
+   */
+  public final List<JsonFunction> functions = new ArrayList<>();
 
   @Override public void accept(ModelHandler handler) {
     handler.visit(this);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/629a56e5/core/src/main/java/org/apache/calcite/model/JsonMaterialization.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/model/JsonMaterialization.java b/core/src/main/java/org/apache/calcite/model/JsonMaterialization.java
index 59b4828..e8165c8 100644
--- a/core/src/main/java/org/apache/calcite/model/JsonMaterialization.java
+++ b/core/src/main/java/org/apache/calcite/model/JsonMaterialization.java
@@ -19,11 +19,19 @@ package org.apache.calcite.model;
 /**
  * Element that describes how a table is a materialization of a query.
  *
+ * <p>Occurs within {@link JsonSchema#materializations}.
+ *
  * @see JsonRoot Description of schema elements
  */
 public class JsonMaterialization {
   public String view;
   public String table;
+
+  /** SQL query that defines the materialization.
+   *
+   * <p>Must be a string or a list of strings (which are concatenated into a
+   * multi-line SQL string, separated by newlines).
+   */
   public Object sql;
 
   public void accept(ModelHandler handler) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/629a56e5/core/src/main/java/org/apache/calcite/model/JsonMeasure.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/model/JsonMeasure.java b/core/src/main/java/org/apache/calcite/model/JsonMeasure.java
index e813c22..3071b00 100644
--- a/core/src/main/java/org/apache/calcite/model/JsonMeasure.java
+++ b/core/src/main/java/org/apache/calcite/model/JsonMeasure.java
@@ -26,7 +26,13 @@ package org.apache.calcite.model;
  * @see JsonRoot Description of schema elements
  */
 public class JsonMeasure {
+  /** The name of an aggregate function.
+   *
+   * <p>Required. Usually {@code count}, {@code sum},
+   * {@code min}, {@code max}.
+   */
   public String agg;
+
   /** Arguments to the measure.
    *
    * <p>Valid values are:

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/629a56e5/core/src/main/java/org/apache/calcite/model/JsonRoot.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/model/JsonRoot.java b/core/src/main/java/org/apache/calcite/model/JsonRoot.java
index 44703aa..d85d8e6 100644
--- a/core/src/main/java/org/apache/calcite/model/JsonRoot.java
+++ b/core/src/main/java/org/apache/calcite/model/JsonRoot.java
@@ -43,11 +43,27 @@ import java.util.List;
  *     {@link JsonMaterialization} (in collection {@link JsonSchema#materializations materializations})
  * </pre>
  * <!-- CHECKSTYLE: ON -->
+ *
+ * <p>See the <a href="http://calcite.incubator.apache.org/docs/model.html">JSON
+ * model reference</a>.
  */
 public class JsonRoot {
+  /** Schema model version number. Required, must have value "1.0". */
   public String version;
+
+  /** Name of the schema that will become the default schema for connections
+   * to Calcite that use this model.
+   *
+   * <p>Optional, case-sensitive. If specified, there must be a schema in this
+   * model with this name.
+   */
   public String defaultSchema;
-  public final List<JsonSchema> schemas = new ArrayList<JsonSchema>();
+
+  /** List of schema elements.
+   *
+   * <p>The list may be empty.
+   */
+  public final List<JsonSchema> schemas = new ArrayList<>();
 }
 
 // End JsonRoot.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/629a56e5/core/src/main/java/org/apache/calcite/model/JsonSchema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/model/JsonSchema.java b/core/src/main/java/org/apache/calcite/model/JsonSchema.java
index 07e326f..d1c46f1 100644
--- a/core/src/main/java/org/apache/calcite/model/JsonSchema.java
+++ b/core/src/main/java/org/apache/calcite/model/JsonSchema.java
@@ -18,13 +18,15 @@ package org.apache.calcite.model;
 
 import com.fasterxml.jackson.annotation.JsonSubTypes;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import com.google.common.collect.Lists;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
  * Schema schema element.
  *
+ * <p>Occurs within {@link JsonRoot#schemas}.
+ *
  * @see JsonRoot Description of schema elements
  */
 @JsonTypeInfo(
@@ -36,16 +38,37 @@ import java.util.List;
     @JsonSubTypes.Type(value = JsonJdbcSchema.class, name = "jdbc"),
     @JsonSubTypes.Type(value = JsonCustomSchema.class, name = "custom") })
 public abstract class JsonSchema {
+  /** Name of the schema.
+   *
+   * <p>Required.
+   *
+   * @see JsonRoot#defaultSchema
+   */
   public String name;
 
-  /** SQL-path. May be null, or a list, each element of which is a string or a
-   * string-list. */
+  /** SQL path that is used to resolve functions used in this schema.
+   *
+   * <p>May be null, or a list, each element of which is a string or a
+   * string-list.
+   *
+   * <p>For example,
+   *
+   * <blockquote><pre>path: [ ['usr', 'lib'], 'lib' ]</pre></blockquote>
+   *
+   * <p>declares a path with two elements: the schema ‘/usr/lib’ and the schema
+   * ‘/lib’. Most schemas are at the top level, and for these you can use a
+   * string.
+   */
   public List<Object> path;
 
-  public final List<JsonMaterialization> materializations =
-      Lists.newArrayList();
+  /**
+   * List of tables in this schema that are materializations of queries.
+   *
+   * <p>The list may be empty.
+   */
+  public final List<JsonMaterialization> materializations = new ArrayList<>();
 
-  public final List<JsonLattice> lattices = Lists.newArrayList();
+  public final List<JsonLattice> lattices = new ArrayList<>();
 
   /** Whether to cache metadata (tables, functions and sub-schemas) generated
    * by this schema. Default value is {@code true}.

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/629a56e5/core/src/main/java/org/apache/calcite/model/JsonStream.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/model/JsonStream.java b/core/src/main/java/org/apache/calcite/model/JsonStream.java
index f8d728a..714af5f 100644
--- a/core/src/main/java/org/apache/calcite/model/JsonStream.java
+++ b/core/src/main/java/org/apache/calcite/model/JsonStream.java
@@ -19,14 +19,22 @@ package org.apache.calcite.model;
 /**
  * Information about whether a table allows streaming.
  *
+ * <p>Occurs within {@link JsonTable#stream}.
+ *
  * @see org.apache.calcite.model.JsonRoot Description of schema elements
  * @see org.apache.calcite.model.JsonTable#stream
  */
 public class JsonStream {
-  /** Whether the table allows streaming. */
+  /** Whether the table allows streaming.
+   *
+   * <p>Optional; default true.
+   */
   public boolean stream = true;
 
-  /** Whether the history of the table is available. */
+  /** Whether the history of the table is available.
+   *
+   * <p>Optional; default false.
+   */
   public boolean history = false;
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/629a56e5/core/src/main/java/org/apache/calcite/model/JsonTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/model/JsonTable.java b/core/src/main/java/org/apache/calcite/model/JsonTable.java
index 806405b..9673667 100644
--- a/core/src/main/java/org/apache/calcite/model/JsonTable.java
+++ b/core/src/main/java/org/apache/calcite/model/JsonTable.java
@@ -18,13 +18,15 @@ package org.apache.calcite.model;
 
 import com.fasterxml.jackson.annotation.JsonSubTypes;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import com.google.common.collect.Lists;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
  * Table schema element.
  *
+ * <p>Occurs within {@link JsonMapSchema#tables}.
+ *
  * @see JsonRoot Description of schema elements
  */
 @JsonTypeInfo(
@@ -35,8 +37,18 @@ import java.util.List;
     @JsonSubTypes.Type(value = JsonCustomTable.class, name = "custom"),
     @JsonSubTypes.Type(value = JsonView.class, name = "view") })
 public abstract class JsonTable {
+  /** Name of this table.
+   *
+   * <p>Required. Must be unique within the schema.
+   */
   public String name;
-  public final List<JsonColumn> columns = Lists.newArrayList();
+
+  /** Definition of the columns of this table.
+   *
+   * <p>Required for some kinds of type,
+   * optional for others (such as {@link JsonView}).
+   */
+  public final List<JsonColumn> columns = new ArrayList<>();
 
   /** Information about whether the table can be streamed, and if so, whether
    * the history of the table is also available. */

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/629a56e5/core/src/main/java/org/apache/calcite/model/JsonTile.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/model/JsonTile.java b/core/src/main/java/org/apache/calcite/model/JsonTile.java
index aef1d2e..f718777 100644
--- a/core/src/main/java/org/apache/calcite/model/JsonTile.java
+++ b/core/src/main/java/org/apache/calcite/model/JsonTile.java
@@ -16,8 +16,7 @@
  */
 package org.apache.calcite.model;
 
-import com.google.common.collect.Lists;
-
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -27,14 +26,21 @@ import java.util.List;
  * drawn from the lattice) and measures (aggregate functions applied to
  * lattice columns).
  *
+ * <p>Occurs within {@link JsonLattice#tiles}.
+ *
  * @see JsonRoot Description of schema elements
  */
 public class JsonTile {
-  /** List of grouping columns that define this tile.
+  /** List of dimensions that define this tile.
    *
-   * <p>Elements are either strings (column names unique within the lattice)
-   * or string lists (pairs of table alias and column name). */
-  public final List dimensions = Lists.newArrayList();
+   * <p>Each dimension is a column from the lattice. The list of dimensions
+   * defines the level of aggregation, like a {@code GROUP BY} clause.
+   *
+   * <p>Required, but may be empty. Each element is either a string
+   * (the unique label of the column within the lattice)
+   * or a string list (a pair consisting of a table alias and a column name).
+   */
+  public final List dimensions = new ArrayList();
 
   /** List of measures in this tile.
    *

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/629a56e5/core/src/main/java/org/apache/calcite/model/JsonView.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/model/JsonView.java b/core/src/main/java/org/apache/calcite/model/JsonView.java
index 48e1cf3..ccacc11 100644
--- a/core/src/main/java/org/apache/calcite/model/JsonView.java
+++ b/core/src/main/java/org/apache/calcite/model/JsonView.java
@@ -21,14 +21,51 @@ import java.util.List;
 /**
  * View schema element.
  *
+ * <p>Like base class {@link JsonTable},
+ * occurs within {@link JsonMapSchema#tables}.
+ *
+ * <h2>Modifiable views</h2>
+ *
+ * <p>A view is modifiable if contains only SELECT, FROM, WHERE (no JOIN,
+ * aggregation or sub-queries) and every column:
+ *
+ * <ul>
+ *   <li>is specified once in the SELECT clause; or
+ *   <li>occurs in the WHERE clause with a column = literal predicate; or
+ *   <li>is nullable.
+ * </ul>
+ *
+ * <p>The second clause allows Calcite to automatically provide the correct
+ * value for hidden columns. It is useful in, say, a multi-tenant environment,
+ * where the {@code tenantId} column is hidden, mandatory (NOT NULL), and has a
+ * constant value for a particular view.
+ *
+ * <p>Errors regarding modifiable views:
+ *
+ * <ul>
+ *   <li>If a view is marked modifiable: true and is not modifiable, Calcite
+ *   throws an error while reading the schema.
+ *   <li>If you submit an INSERT, UPDATE or UPSERT command to a non-modifiable
+ *   view, Calcite throws an error when validating the statement.
+ *   <li>If a DML statement creates a row that would not appear in the view
+ *   (for example, a row in female_emps, above, with gender = 'M'), Calcite
+ *   throws an error when executing the statement.
+ * </ul>
+ *
  * @see JsonRoot Description of schema elements
  */
 public class JsonView extends JsonTable {
-  /** SQL query that is the definition of the view. */
+  /** SQL query that is the definition of the view.
+   *
+   * <p>Must be a string or a list of strings (which are concatenated into a
+   * multi-line SQL string, separated by newlines).
+   */
   public Object sql;
 
-  /** Schema name(s) to use when resolving query. If not specified, defaults
-   * to current schema. */
+  /** Schema name(s) to use when resolving query.
+   *
+   * <p>If not specified, defaults to current schema.
+   */
   public List<String> path;
 
   /** Whether this view should allow INSERT requests.

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/629a56e5/core/src/main/java/org/apache/calcite/model/ModelHandler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/model/ModelHandler.java b/core/src/main/java/org/apache/calcite/model/ModelHandler.java
index 0c0efa8..1afaf41 100644
--- a/core/src/main/java/org/apache/calcite/model/ModelHandler.java
+++ b/core/src/main/java/org/apache/calcite/model/ModelHandler.java
@@ -62,8 +62,7 @@ import static org.apache.calcite.util.Stacks.push;
  */
 public class ModelHandler {
   private final CalciteConnection connection;
-  private final List<Pair<String, SchemaPlus>> schemaStack =
-      new ArrayList<Pair<String, SchemaPlus>>();
+  private final List<Pair<String, SchemaPlus>> schemaStack = new ArrayList<>();
   private final String modelUri;
   Lattice.Builder latticeBuilder;
   Lattice.TileBuilder tileBuilder;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/629a56e5/site/_docs/model.md
----------------------------------------------------------------------
diff --git a/site/_docs/model.md b/site/_docs/model.md
index a6514a3..0f9a548 100644
--- a/site/_docs/model.md
+++ b/site/_docs/model.md
@@ -79,7 +79,7 @@ strings. For example,
 {% endhighlight %}
 
 declares a path with two elements: the schema '/usr/lib' and the
-schema '/lib'. Most schemas are at the top level, so you can use a
+schema '/lib'. Most schemas are at the top level, and for these you can use a
 string.
 
 `materializations` (optional list of
@@ -176,7 +176,7 @@ Like base class <a href="#schema">Schema</a>, occurs within `root.schemas`.
 `name`, `type`, `path`, `cache`, `materializations` inherited from
 <a href="#schema">Schema</a>.
 
-`jdbcDriver` (optional string) is the name of the JDBC driver class. It not
+`jdbcDriver` (optional string) is the name of the JDBC driver class. If not
 specified, uses whichever class the JDBC DriverManager chooses.
 
 `jdbcUrl` (optional string) is the JDBC connect string, for example
@@ -229,7 +229,8 @@ Occurs within `root.schemas.tables`.
 * `custom` for <a href="#custom-table">Custom Table</a>
 * `view` for <a href="#view">View</a>
 
-`columns` (optional list of <a href="#column">Column</a> elements)
+`columns` (list of <a href="#column">Column</a> elements, required for
+some kinds of table, optional for others such as View)
 
 ### View
 
@@ -302,6 +303,24 @@ and have a public default constructor.
 `operand` (optional map) contains attributes to be passed to the
 factory.
 
+### Stream
+
+Information about whether a table allows streaming.
+
+Occurs within `root.schemas.tables.stream`.
+
+{% highlight json %}
+{
+  stream: true,
+  history: false
+}
+{% endhighlight %}
+
+`stream` (optional; default true) is whether the table allows streaming.
+
+`history` (optional; default false) is whether the history of the stream is
+available.
+
 ### Column
 
 Occurs within `root.schemas.tables.columns`.
@@ -335,6 +354,18 @@ function.
 `methodName` (optional string) is the name of the method that implements this
 function.
 
+If `methodName` is specified, the method must exist (case-sensitive) and Calcite
+will create a scalar function. The method may be static or non-static, but
+if non-static, the class must have a public constructor with no parameters.
+
+If `methodName` is "*", Calcite creates a function for every method
+in the class.
+
+If `methodName` is not specified, Calcite looks for a method called "eval", and
+if found, creates a a table macro or scalar function.
+It also looks for methods "init", "add", "merge", "result", and
+if found, creates an aggregate function.
+
 `path` (optional list of string) is the path for resolving this function.
 
 ### Lattice
@@ -389,7 +420,7 @@ maximum number of milliseconds for which to run the algorithm. After this point,
 takes the best result the algorithm has come up with so far.
 
 `rowCountEstimate` (optional double, default 1000.0) estimated number of rows in
-the star
+the lattice
 
 `tiles` (optional list of <a href="#tile">Tile</a> elements) is a list of
 materialized aggregates to create up front.
@@ -435,9 +466,12 @@ Occurs within `root.schemas.lattices.tiles`.
 }
 {% endhighlight %}
 
-`dimensions` is a list of dimensions (columns from the star), like a `GROUP BY`
-clause. Each element is either a string (the unique label of the column within
-the star) or a string list (a column name qualified by a table name).
+`dimensions` (list of strings or string lists, required, but may be empty)
+defines the dimensionality of this tile.
+Each dimension is a column from the lattice, like a `GROUP BY` clause.
+Each element can be either a string
+(the unique label of the column within the lattice)
+or a string list (a pair consisting of a table alias and a column name).
 
 `measures` (optional list of <a href="#measure">Measure</a> elements) is a list
 of aggregate functions applied to arguments. If not specified, uses the
@@ -458,6 +492,21 @@ and `root.schemas.lattices.tiles.measures`.
 `agg` is the name of an aggregate function (usually 'count', 'sum', 'min',
 'max').
 
-`args` (optional) is a column label (string), or list of zero or more columns.
-If a list, each element is either a string (the unique label of the column
-within the star) or a string list (a column name qualified by a table name).
+`args` (optional) is a column label (string), or list of zero or more column
+labels
+
+Valid values are:
+
+* Not specified: no arguments
+* null: no arguments
+* Empty list: no arguments
+* String: single argument, the name of a lattice column
+* List: multiple arguments, each a column label
+
+Unlike lattice dimensions, measures can not be specified in qualified
+format, {@code ["table", "column"]}. When you define a lattice, make sure
+that each column you intend to use as a measure has a unique label within
+the lattice (using "{@code AS label}" if necessary), and use that label
+when you want to pass the column as a measure argument.
+
+<!-- End model.md -->


[35/50] incubator-calcite git commit: [CALCITE-811] Extend JoinProjectTransposeRule with option to support outer joins

Posted by jh...@apache.org.
[CALCITE-811] Extend JoinProjectTransposeRule with option to support outer joins

Close apache/incubator-calcite#109


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

Branch: refs/heads/branch-release
Commit: 2376ae4a876b421ee19c2b2a05a6bd1d306e442b
Parents: 5cb95e6
Author: Jesus Camacho Rodriguez <jc...@apache.org>
Authored: Mon Jul 27 19:41:36 2015 +0100
Committer: Jesus Camacho Rodriguez <jc...@apache.org>
Committed: Mon Jul 27 19:48:48 2015 +0100

----------------------------------------------------------------------
 .../rel/rules/JoinProjectTransposeRule.java     | 61 +++++++++++++++++---
 .../apache/calcite/test/RelOptRulesTest.java    | 24 ++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml | 31 ++++++++++
 3 files changed, 107 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2376ae4a/core/src/main/java/org/apache/calcite/rel/rules/JoinProjectTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinProjectTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinProjectTransposeRule.java
index 2f41648..afcea6b 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinProjectTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinProjectTransposeRule.java
@@ -75,20 +75,52 @@ public class JoinProjectTransposeRule extends RelOptRule {
               operand(LogicalProject.class, any())),
           "JoinProjectTransposeRule(Other-Project)");
 
+  public static final JoinProjectTransposeRule BOTH_PROJECT_INCLUDE_OUTER =
+      new JoinProjectTransposeRule(
+          operand(LogicalJoin.class,
+              operand(LogicalProject.class, any()),
+              operand(LogicalProject.class, any())),
+          "Join(IncludingOuter)ProjectTransposeRule(Project-Project)",
+          true, RelFactories.DEFAULT_PROJECT_FACTORY);
+
+  public static final JoinProjectTransposeRule LEFT_PROJECT_INCLUDE_OUTER =
+      new JoinProjectTransposeRule(
+          operand(LogicalJoin.class,
+              some(operand(LogicalProject.class, any()))),
+          "Join(IncludingOuter)ProjectTransposeRule(Project-Other)",
+          true, RelFactories.DEFAULT_PROJECT_FACTORY);
+
+  public static final JoinProjectTransposeRule RIGHT_PROJECT_INCLUDE_OUTER =
+      new JoinProjectTransposeRule(
+          operand(
+              LogicalJoin.class,
+              operand(RelNode.class, any()),
+              operand(LogicalProject.class, any())),
+          "Join(IncludingOuter)ProjectTransposeRule(Other-Project)",
+          true, RelFactories.DEFAULT_PROJECT_FACTORY);
+
+  private final boolean includeOuter;
   private final ProjectFactory projectFactory;
 
   //~ Constructors -----------------------------------------------------------
   public JoinProjectTransposeRule(
       RelOptRuleOperand operand,
       String description) {
-    this(operand, description, RelFactories.DEFAULT_PROJECT_FACTORY);
+    this(operand, description, false, RelFactories.DEFAULT_PROJECT_FACTORY);
   }
 
-  public JoinProjectTransposeRule(
-      RelOptRuleOperand operand,
-      String description, ProjectFactory pFactory) {
+  @Deprecated
+  public JoinProjectTransposeRule(RelOptRuleOperand operand,
+      String description, ProjectFactory projectFactory) {
+    this(operand, description, false, projectFactory);
+  }
+
+  public JoinProjectTransposeRule(RelOptRuleOperand operand,
+      String description, boolean includeOuter,
+      ProjectFactory projectFactory) {
     super(operand, description);
-    projectFactory = pFactory;
+    this.includeOuter = includeOuter;
+    this.projectFactory = projectFactory;
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -103,15 +135,18 @@ public class JoinProjectTransposeRule extends RelOptRule {
     RelNode leftJoinChild;
     RelNode rightJoinChild;
 
-    // see if at least one input's projection doesn't generate nulls
-    if (hasLeftChild(call) && !joinType.generatesNullsOnLeft()) {
+    // If 1) the rule works on outer joins, or
+    //    2) input's projection doesn't generate nulls
+    if (hasLeftChild(call)
+            && (includeOuter || !joinType.generatesNullsOnLeft())) {
       leftProj = call.rel(1);
       leftJoinChild = getProjectChild(call, leftProj, true);
     } else {
       leftProj = null;
       leftJoinChild = call.rel(1);
     }
-    if (hasRightChild(call) && !joinType.generatesNullsOnRight()) {
+    if (hasRightChild(call)
+            && (includeOuter || !joinType.generatesNullsOnRight())) {
       rightProj = getRightChild(call);
       rightJoinChild = getProjectChild(call, rightProj, false);
     } else {
@@ -235,6 +270,14 @@ public class JoinProjectTransposeRule extends RelOptRule {
     // finally, create the projection on top of the join
     RelNode newProjRel = projectFactory.createProject(newJoinRel, newProjExprs,
         joinRel.getRowType().getFieldNames());
+    // if the join was outer, we might need a cast after the
+    // projection to fix differences wrt nullability of fields
+    if (joinType != JoinRelType.INNER) {
+      RelNode newTopProjRel = RelOptUtil.createCastRel(newProjRel, joinRel.getRowType(),
+          false, projectFactory);
+      call.transformTo(newTopProjRel);
+      return;
+    }
 
     call.transformTo(newProjRel);
   }
@@ -294,7 +337,7 @@ public class JoinProjectTransposeRule extends RelOptRule {
    *                           removed)
    * @param projects           Projection expressions &amp; names to be created
    */
-  private void createProjectExprs(
+  protected void createProjectExprs(
       Project projRel,
       RelNode joinChild,
       int adjustmentAmount,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2376ae4a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index 1901f89..013405c 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -51,6 +51,7 @@ import org.apache.calcite.rel.rules.FilterToCalcRule;
 import org.apache.calcite.rel.rules.JoinAddRedundantSemiJoinRule;
 import org.apache.calcite.rel.rules.JoinCommuteRule;
 import org.apache.calcite.rel.rules.JoinExtractFilterRule;
+import org.apache.calcite.rel.rules.JoinProjectTransposeRule;
 import org.apache.calcite.rel.rules.JoinPushTransitivePredicatesRule;
 import org.apache.calcite.rel.rules.JoinToMultiJoinRule;
 import org.apache.calcite.rel.rules.JoinUnionTransposeRule;
@@ -296,6 +297,29 @@ public class RelOptRulesTest extends RelOptTestBase {
             + "right join dept c on b.deptno > 10\n");
   }
 
+  @Test public void testJoinProjectTranspose() {
+    final HepProgram preProgram =
+        HepProgram.builder()
+            .addRuleInstance(ProjectJoinTransposeRule.INSTANCE)
+            .addRuleInstance(ProjectMergeRule.INSTANCE)
+            .build();
+    final HepProgram program =
+        HepProgram.builder()
+            .addRuleInstance(JoinProjectTransposeRule.LEFT_PROJECT_INCLUDE_OUTER)
+            .addRuleInstance(ProjectMergeRule.INSTANCE)
+            .addRuleInstance(JoinProjectTransposeRule.RIGHT_PROJECT_INCLUDE_OUTER)
+            .addRuleInstance(JoinProjectTransposeRule.LEFT_PROJECT_INCLUDE_OUTER)
+            .addRuleInstance(ProjectMergeRule.INSTANCE)
+            .build();
+    checkPlanning(tester,
+        preProgram,
+        new HepPlanner(program),
+        "select a.name\n"
+            + "from dept a\n"
+            + "left join dept b on b.deptno > 10\n"
+            + "right join dept c on b.deptno > 10\n");
+  }
+
   @Test public void testSemiJoinRule() {
     final HepProgram preProgram =
         HepProgram.builder()

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2376ae4a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index 04d0fe2..bd650ce 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -3255,6 +3255,37 @@ LogicalProject(NAME=[$1])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testJoinProjectTranspose">
+        <Resource name="sql">
+            <![CDATA[select a.name
+from dept a
+left join dept b on b.deptno > 10
+right join dept c on b.deptno > 10
+]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(NAME=[$1])
+  LogicalJoin(condition=[$4], joinType=[right])
+    LogicalProject(DEPTNO=[$0], NAME=[$1], DEPTNO0=[$2], NAME0=[$3], $f4=[>($2, 10)])
+      LogicalJoin(condition=[$4], joinType=[left])
+        LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+        LogicalProject(DEPTNO=[$0], NAME=[$1], $f2=[>($0, 10)])
+          LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+    LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalProject(NAME=[$1])
+  LogicalJoin(condition=[>($2, 10)], joinType=[right])
+    LogicalJoin(condition=[>($2, 10)], joinType=[left])
+      LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+      LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+    LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testMergeFilter">
         <Resource name="sql">
             <![CDATA[select name from (


[07/50] incubator-calcite git commit: [CALCITE-801] NullPointerException using USING on table alias with column aliases

Posted by jh...@apache.org.
[CALCITE-801] NullPointerException using USING on table alias with column aliases

Fix an issue numbering the fields in a RelCrossType


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

Branch: refs/heads/branch-release
Commit: c57d80725766c84834a35e4f3b68feb38540b66c
Parents: 23396f0
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Jul 13 12:35:46 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Jul 13 12:44:27 2015 -0700

----------------------------------------------------------------------
 .../apache/calcite/rel/type/RelCrossType.java   |  1 -
 .../rel/type/RelDataTypeFactoryImpl.java        | 48 ++++++-------
 .../calcite/sql2rel/SqlToRelConverter.java      | 65 +++++++++--------
 .../calcite/test/SqlToRelConverterTest.java     | 39 +++++++----
 .../calcite/test/SqlToRelConverterTest.xml      | 73 +++++++++++++-------
 core/src/test/resources/sql/join.oq             | 20 ++++++
 6 files changed, 148 insertions(+), 98 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c57d8072/core/src/main/java/org/apache/calcite/rel/type/RelCrossType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/type/RelCrossType.java b/core/src/main/java/org/apache/calcite/rel/type/RelCrossType.java
index d361b7b..ba2ac85 100644
--- a/core/src/main/java/org/apache/calcite/rel/type/RelCrossType.java
+++ b/core/src/main/java/org/apache/calcite/rel/type/RelCrossType.java
@@ -44,7 +44,6 @@ public class RelCrossType extends RelDataTypeImpl {
       List<RelDataTypeField> fields) {
     super(fields);
     this.types = ImmutableList.copyOf(types);
-    assert types != null;
     assert types.size() >= 1;
     for (RelDataType type : types) {
       assert !(type instanceof RelCrossType);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c57d8072/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java
index e9016b8..46f8ba3 100644
--- a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java
+++ b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java
@@ -126,12 +126,10 @@ public abstract class RelDataTypeFactoryImpl implements RelDataTypeFactory {
   public RelDataType createJoinType(RelDataType... types) {
     assert types != null;
     assert types.length >= 1;
-    final List<RelDataType> flattenedTypes =
-        getTypeArray(ImmutableList.copyOf(types));
+    final List<RelDataType> flattenedTypes = new ArrayList<>();
+    getTypeList(ImmutableList.copyOf(types), flattenedTypes);
     return canonize(
-        new RelCrossType(
-            flattenedTypes,
-            getFieldArray(flattenedTypes)));
+        new RelCrossType(flattenedTypes, getFieldList(flattenedTypes)));
   }
 
   // implement RelDataTypeFactory
@@ -359,11 +357,10 @@ public abstract class RelDataTypeFactoryImpl implements RelDataTypeFactory {
   }
 
   /**
-   * Returns an array of the fields in an array of types.
+   * Returns a list of the fields in a list of types.
    */
-  private static List<RelDataTypeField> getFieldArray(List<RelDataType> types) {
-    ArrayList<RelDataTypeField> fieldList =
-        new ArrayList<RelDataTypeField>();
+  private static List<RelDataTypeField> getFieldList(List<RelDataType> types) {
+    final List<RelDataTypeField> fieldList = new ArrayList<>();
     for (RelDataType type : types) {
       addFields(type, fieldList);
     }
@@ -371,20 +368,14 @@ public abstract class RelDataTypeFactoryImpl implements RelDataTypeFactory {
   }
 
   /**
-   * Returns an array of all atomic types in an array.
+   * Returns a list of all atomic types in a list.
    */
-  private static List<RelDataType> getTypeArray(List<RelDataType> types) {
-    List<RelDataType> flatTypes = new ArrayList<RelDataType>();
-    getTypeArray(types, flatTypes);
-    return flatTypes;
-  }
-
-  private static void getTypeArray(
-      List<RelDataType> inTypes,
+  private static void getTypeList(
+      ImmutableList<RelDataType> inTypes,
       List<RelDataType> flatTypes) {
     for (RelDataType inType : inTypes) {
       if (inType instanceof RelCrossType) {
-        getTypeArray(((RelCrossType) inType).types, flatTypes);
+        getTypeList(((RelCrossType) inType).types, flatTypes);
       } else {
         flatTypes.add(inType);
       }
@@ -392,11 +383,13 @@ public abstract class RelDataTypeFactoryImpl implements RelDataTypeFactory {
   }
 
   /**
-   * Adds all fields in <code>type</code> to <code>fieldList</code>.
+   * Adds all fields in <code>type</code> to <code>fieldList</code>,
+   * renumbering the fields (if necessary) to ensure that their index
+   * matches their position in the list.
    */
   private static void addFields(
       RelDataType type,
-      ArrayList<RelDataTypeField> fieldList) {
+      List<RelDataTypeField> fieldList) {
     if (type instanceof RelCrossType) {
       final RelCrossType crossType = (RelCrossType) type;
       for (RelDataType type1 : crossType.types) {
@@ -405,6 +398,10 @@ public abstract class RelDataTypeFactoryImpl implements RelDataTypeFactory {
     } else {
       List<RelDataTypeField> fields = type.getFieldList();
       for (RelDataTypeField field : fields) {
+        if (field.getIndex() != fieldList.size()) {
+          field = new RelDataTypeFieldImpl(field.getName(), fieldList.size(),
+              field.getType());
+        }
         fieldList.add(field);
       }
     }
@@ -415,8 +412,7 @@ public abstract class RelDataTypeFactoryImpl implements RelDataTypeFactory {
   }
 
   private List<RelDataTypeFieldImpl> fieldsOf(Class clazz) {
-    final List<RelDataTypeFieldImpl> list =
-        new ArrayList<RelDataTypeFieldImpl>();
+    final List<RelDataTypeFieldImpl> list = new ArrayList<>();
     for (Field field : clazz.getFields()) {
       if (Modifier.isStatic(field.getModifiers())) {
         continue;
@@ -436,8 +432,10 @@ public abstract class RelDataTypeFactoryImpl implements RelDataTypeFactory {
   }
 
   /**
-   * implement RelDataTypeFactory with SQL 2003 compliant behavior. Let p1, s1
-   * be the precision and scale of the first operand Let p2, s2 be the
+   * {@inheritDoc}
+   *
+   * <p>Implement RelDataTypeFactory with SQL 2003 compliant behavior. Let p1,
+   * s1 be the precision and scale of the first operand Let p2, s2 be the
    * precision and scale of the second operand Let p, s be the precision and
    * scale of the result, Then the result type is a decimal with:
    *

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c57d8072/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index 5ca783f..e733d13 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -562,8 +562,8 @@ public class SqlToRelConverter {
     RelDataType validatedRowType = validator.getValidatedNodeType(query);
     validatedRowType = uniquifyFields(validatedRowType);
 
-    return RelOptUtil.equal(
-        "validated row type", validatedRowType, "converted row type", convertedRowType, false);
+    return RelOptUtil.equal("validated row type", validatedRowType,
+        "converted row type", convertedRowType, false);
   }
 
   protected RelDataType uniquifyFields(RelDataType rowType) {
@@ -1910,16 +1910,22 @@ public class SqlToRelConverter {
       RelNode rightRel = rightBlackboard.root;
       JoinRelType convertedJoinType = convertJoinType(joinType);
       RexNode conditionExp;
+      final SqlValidatorNamespace leftNamespace = validator.getNamespace(left);
+      final SqlValidatorNamespace rightNamespace = validator.getNamespace(right);
       if (isNatural) {
+        final RelDataType leftRowType = leftNamespace.getRowType();
+        final RelDataType rightRowType = rightNamespace.getRowType();
         final List<String> columnList =
-            SqlValidatorUtil.deriveNaturalJoinColumnList(
-                validator.getNamespace(left).getRowType(),
-                validator.getNamespace(right).getRowType());
-        conditionExp = convertUsing(leftRel, rightRel, columnList);
+            SqlValidatorUtil.deriveNaturalJoinColumnList(leftRowType,
+                rightRowType);
+        conditionExp = convertUsing(leftNamespace, rightNamespace,
+            columnList);
       } else {
         conditionExp =
             convertJoinCondition(
                 fromBlackboard,
+                leftNamespace,
+                rightNamespace,
                 join.getCondition(),
                 join.getConditionType(),
                 leftRel,
@@ -2253,8 +2259,9 @@ public class SqlToRelConverter {
     return Collections.emptyList();
   }
 
-  private RexNode convertJoinCondition(
-      Blackboard bb,
+  private RexNode convertJoinCondition(Blackboard bb,
+      SqlValidatorNamespace leftNamespace,
+      SqlValidatorNamespace rightNamespace,
       SqlNode condition,
       JoinConditionType conditionType,
       RelNode leftRel,
@@ -2276,7 +2283,7 @@ public class SqlToRelConverter {
         String name = id.getSimple();
         nameList.add(name);
       }
-      return convertUsing(leftRel, rightRel, nameList);
+      return convertUsing(leftNamespace, rightNamespace, nameList);
     default:
       throw Util.unexpected(conditionType);
     }
@@ -2287,37 +2294,29 @@ public class SqlToRelConverter {
    * from NATURAL JOIN. "a JOIN b USING (x, y)" becomes "a.x = b.x AND a.y =
    * b.y". Returns null if the column list is empty.
    *
-   * @param leftRel  Left input to the join
-   * @param rightRel Right input to the join
+   * @param leftNamespace Namespace of left input to join
+   * @param rightNamespace Namespace of right input to join
    * @param nameList List of column names to join on
    * @return Expression to match columns from name list, or true if name list
    * is empty
    */
-  private RexNode convertUsing(
-      RelNode leftRel,
-      RelNode rightRel,
+  private RexNode convertUsing(SqlValidatorNamespace leftNamespace,
+      SqlValidatorNamespace rightNamespace,
       List<String> nameList) {
     final List<RexNode> list = Lists.newArrayList();
     for (String name : nameList) {
-      final RelDataType leftRowType = leftRel.getRowType();
-      RelDataTypeField leftField = catalogReader.field(leftRowType, name);
-      RexNode left =
-          rexBuilder.makeInputRef(
-              leftField.getType(),
-              leftField.getIndex());
-      final RelDataType rightRowType = rightRel.getRowType();
-      RelDataTypeField rightField =
-          catalogReader.field(rightRowType, name);
-      RexNode right =
-          rexBuilder.makeInputRef(
-              rightField.getType(),
-              leftRowType.getFieldList().size() + rightField.getIndex());
-      RexNode equalsCall =
-          rexBuilder.makeCall(
-              SqlStdOperatorTable.EQUALS,
-              left,
-              right);
-      list.add(equalsCall);
+      List<RexNode> operands = new ArrayList<>();
+      int offset = 0;
+      for (SqlValidatorNamespace n : ImmutableList.of(leftNamespace,
+          rightNamespace)) {
+        final RelDataType rowType = n.getRowType();
+        final RelDataTypeField field = catalogReader.field(rowType, name);
+        operands.add(
+            rexBuilder.makeInputRef(field.getType(),
+                offset + field.getIndex()));
+        offset += rowType.getFieldList().size();
+      }
+      list.add(rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, operands));
     }
     return RexUtil.composeConjunction(rexBuilder, list, false);
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c57d8072/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
index 083367e..ee7f2c9 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
@@ -151,6 +151,19 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
         "${plan}");
   }
 
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-801">[CALCITE-801]
+   * NullPointerException using USING on table alias with column
+   * aliases</a>. */
+  @Test public void testValuesUsing() {
+    check("select d.deptno, min(e.empid) as empid\n"
+            + "from (values (100, 'Bill', 1)) as e(empid, name, deptno)\n"
+            + "join (values (1, 'LeaderShip')) as d(deptno, name)\n"
+            + "  using (deptno)\n"
+            + "group by d.deptno",
+        "${plan}");
+  }
+
   @Test public void testJoinNatural() {
     check(
         "SELECT * FROM emp NATURAL JOIN dept",
@@ -1198,7 +1211,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
   @Test public void testSubqueryLimitOne() {
     sql("select deptno\n"
         + "from EMP\n"
-        + "where deptno > (select deptno \n"
+        + "where deptno > (select deptno\n"
         + "from EMP order by deptno limit 1)")
         .convertsTo("${plan}");
   }
@@ -1222,10 +1235,10 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
    * Scan HAVING clause for sub-queries and IN-lists</a> relating to IN.
    */
   @Test public void testHavingAggrFunctionIn() {
-    sql("select deptno \n"
-        + "from emp \n"
-        + "group by deptno \n"
-        + "having sum(case when deptno in (1, 2) then 0 else 1 end) + \n"
+    sql("select deptno\n"
+        + "from emp\n"
+        + "group by deptno\n"
+        + "having sum(case when deptno in (1, 2) then 0 else 1 end) +\n"
         + "sum(case when deptno in (3, 4) then 0 else 1 end) > 10")
         .convertsTo("${plan}");
   }
@@ -1237,14 +1250,14 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
    * the HAVING clause.
    */
   @Test public void testHavingInSubqueryWithAggrFunction() {
-    sql("select sal \n"
-        + "from emp \n"
-        + "group by sal \n"
-        + "having sal in \n"
-            + "(select deptno \n"
-            + "from dept \n"
-            + "group by deptno \n"
-            + "having sum(deptno) > 0)")
+    sql("select sal\n"
+        + "from emp\n"
+        + "group by sal\n"
+        + "having sal in (\n"
+        + "  select deptno\n"
+        + "  from dept\n"
+        + "  group by deptno\n"
+        + "  having sum(deptno) > 0)")
         .convertsTo("${plan}");
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c57d8072/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
index 075ccd2..1130160 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -2438,7 +2438,7 @@ LogicalAggregate(group=[{0}], EXPR$1=[SUM($1) FILTER $2], EXPR$2=[COUNT()])
         <Resource name="sql">
             <![CDATA[select deptno
 from EMP
-where deptno > (select min(deptno) * 2 + 10 from EMP]]>
+where deptno > (select min(deptno) * 2 + 10 from EMP)]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2508,7 +2508,7 @@ LogicalProject(DEPTNO=[$7])
 from emp
 group by deptno
 having sum(case when deptno in (1, 2) then 0 else 1 end) +
-sum(case when deptno in (3, 4) then 0 else 1 end) > 10)]]>
+sum(case when deptno in (3, 4) then 0 else 1 end) > 10]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2525,11 +2525,11 @@ LogicalProject(DEPTNO=[$0])
             <![CDATA[select sal
 from emp
 group by sal
-having sal in
-(select deptno
-from dept
-group by deptno
-having sum(deptno) > 0)]]>
+having sal in (
+  select deptno
+  from dept
+  group by deptno
+  having sum(deptno) > 0)]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2633,9 +2633,10 @@ LogicalTableModify(table=[[CATALOG, SALES, EMP]], operation=[INSERT], updateColu
     </TestCase>
     <TestCase name="testWindowAggWithGroupBy">
         <Resource name="sql">
-            <![CDATA[select min(deptno), rank() over (order by empno)
-            max(empno) over (partition by deptno)
-            from emp group by deptno, empno]]>
+            <![CDATA[select min(deptno), rank() over (order by empno),
+max(empno) over (partition by deptno)
+from emp group by deptno, empno
+]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2646,13 +2647,14 @@ LogicalProject(EXPR$0=[$2], EXPR$1=[RANK() OVER (ORDER BY $1 RANGE BETWEEN UNBOU
 ]]>
         </Resource>
     </TestCase>
-        <TestCase name="testWindowAggWithGroupByAndJoin">
+    <TestCase name="testWindowAggWithGroupByAndJoin">
         <Resource name="sql">
             <![CDATA[select min(d.deptno), rank() over (order by e.empno),
-            max(e.empno) over (partition by e.deptno)
-            from emp e, dept d
-            where e.deptno = d.deptno
-            group by d.deptno, e.empno, e.deptno]]>
+ max(e.empno) over (partition by e.deptno)
+from emp e, dept d
+where e.deptno = d.deptno
+group by d.deptno, e.empno, e.deptno
+]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2669,9 +2671,10 @@ LogicalProject(EXPR$0=[$3], EXPR$1=[RANK() OVER (ORDER BY $1 RANGE BETWEEN UNBOU
     <TestCase name="testWindowAggWithGroupByAndHaving">
         <Resource name="sql">
             <![CDATA[select min(deptno), rank() over (order by empno),
-            max(empno) over (partition by deptno)
-            from emp group by deptno, empno
-            having empno < 10 and min(deptno) < 20]]>
+max(empno) over (partition by deptno)
+from emp group by deptno, empno
+having empno < 10 and min(deptno) < 20
+]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2684,14 +2687,14 @@ LogicalProject(EXPR$0=[$2], EXPR$1=[RANK() OVER (ORDER BY $1 RANGE BETWEEN UNBOU
         </Resource>
     </TestCase>
     <TestCase name="testWindowAggInSubqueryJoin">
-    <Resource name="sql">
-            <![CDATA[select T.x, T.y, T.z,
-        emp.empno from (select min(deptno) as x,
-        rank() over (order by empno) as y,
-        max(empno) over (partition by deptno) as z
-        from emp group by deptno, empno) as T
-        inner join emp on T.x = emp.deptno
-        and T.y = emp.empno]]>
+        <Resource name="sql">
+            <![CDATA[select T.x, T.y, T.z, emp.empno from (select min(deptno) as x,
+   rank() over (order by empno) as y,
+   max(empno) over (partition by deptno) as z
+   from emp group by deptno, empno) as T
+ inner join emp on T.x = emp.deptno
+ and T.y = emp.empno
+]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2705,4 +2708,22 @@ LogicalProject(X=[$0], Y=[$1], Z=[$2], EMPNO=[$3])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testValuesUsing">
+        <Resource name="sql">
+            <![CDATA[select d.deptno, min(e.empid) as empid
+from (values (100, 'Bill', 1)) as e(empid, name, deptno)
+join (values (1, 'LeaderShip')) as d(deptno, name)
+  using (deptno)
+group by d.deptno]]>
+        </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalAggregate(group=[{0}], EMPID=[MIN($1)])
+  LogicalProject(DEPTNO=[$3], EXPR$0=[$0])
+    LogicalJoin(condition=[=($2, $3)], joinType=[inner])
+      LogicalValues(tuples=[[{ 100, 'Bill', 1 }]])
+      LogicalValues(tuples=[[{ 1, 'LeaderShip' }]])
+]]>
+        </Resource>
+    </TestCase>
 </Root>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c57d8072/core/src/test/resources/sql/join.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/join.oq b/core/src/test/resources/sql/join.oq
index 97898bf..83cfb7c 100644
--- a/core/src/test/resources/sql/join.oq
+++ b/core/src/test/resources/sql/join.oq
@@ -235,4 +235,24 @@ EnumerableCalc(expr#0..3=[{inputs}], DEPTNO=[$t2], DEPTNO0=[$t0])
       EnumerableTableScan(table=[[scott, EMP]])
 !plan
 
+### [CALCITE-801] NullPointerException using USING on table alias with column aliases
+select *
+from (values (100, 'Bill', 1),
+             (200, 'Eric', 1),
+             (150, 'Sebastian', 3)) as e(empid, name, deptno)
+join (values (1, 'LeaderShip'),
+             (2, 'TestGroup'),
+             (3, 'Development')) as d(deptno, name)
+using (deptno);
++-------+-----------+--------+---------+-------------+
+| EMPID | NAME      | DEPTNO | DEPTNO0 | NAME0       |
++-------+-----------+--------+---------+-------------+
+|   100 | Bill      |      1 |       1 | LeaderShip  |
+|   150 | Sebastian |      3 |       3 | Development |
+|   200 | Eric      |      1 |       1 | LeaderShip  |
++-------+-----------+--------+---------+-------------+
+(3 rows)
+
+!ok
+
 # End join.oq


[30/50] incubator-calcite git commit: [CALCITE-813] Upgrade updateCount, maxRows from int to long

Posted by jh...@apache.org.
[CALCITE-813] Upgrade updateCount, maxRows from int to long


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

Branch: refs/heads/branch-release
Commit: c818d50bb6a07be251ce4b395e9a9e60ae58743a
Parents: e03dafc
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Jul 23 18:02:30 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jul 23 21:02:14 2015 -0700

----------------------------------------------------------------------
 .../apache/calcite/avatica/jdbc/JdbcMeta.java   |  82 ++++++++-----
 .../calcite/avatica/jdbc/JdbcResultSet.java     |  10 +-
 .../calcite/avatica/remote/RemoteMetaTest.java  |   5 +-
 .../calcite/avatica/AvaticaConnection.java      |   4 +-
 .../avatica/AvaticaPreparedStatement.java       |   6 +-
 .../calcite/avatica/AvaticaStatement.java       |  28 ++++-
 .../apache/calcite/avatica/AvaticaUtils.java    |  86 +++++++++++++
 .../java/org/apache/calcite/avatica/Meta.java   |  26 ++--
 .../org/apache/calcite/avatica/MetaImpl.java    |   2 +-
 .../calcite/avatica/UnregisteredDriver.java     |   2 +-
 .../calcite/avatica/remote/LocalService.java    |   2 +-
 .../calcite/avatica/remote/RemoteMeta.java      |   6 +-
 .../apache/calcite/avatica/remote/Service.java  |  22 ++--
 .../calcite/jdbc/CalciteConnectionImpl.java     |   2 +-
 .../apache/calcite/jdbc/CalciteMetaImpl.java    |  12 +-
 .../org/apache/calcite/jdbc/CalcitePrepare.java |   6 +-
 .../calcite/prepare/CalcitePrepareImpl.java     |   8 +-
 .../calcite/linq4j/EnumerableDefaults.java      | 122 +++++++++++++++++--
 18 files changed, 330 insertions(+), 101 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c818d50b/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java b/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
index d1a2049..18a0554 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.avatica.jdbc;
 
 import org.apache.calcite.avatica.AvaticaParameter;
+import org.apache.calcite.avatica.AvaticaUtils;
 import org.apache.calcite.avatica.ColumnMetaData;
 import org.apache.calcite.avatica.ConnectionPropertiesImpl;
 import org.apache.calcite.avatica.Meta;
@@ -377,11 +378,10 @@ public class JdbcMeta implements Meta {
   public MetaResultSet getTables(String catalog, Pat schemaPattern,
       Pat tableNamePattern, List<String> typeList) {
     try {
-      String[] types = new String[typeList == null ? 0 : typeList.size()];
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1,
+      final ResultSet rs =
           connection.getMetaData().getTables(catalog, schemaPattern.s,
-              tableNamePattern.s,
-              typeList == null ? types : typeList.toArray(types)));
+              tableNamePattern.s, toArray(typeList));
+      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -390,9 +390,10 @@ public class JdbcMeta implements Meta {
   public MetaResultSet getColumns(String catalog, Pat schemaPattern,
       Pat tableNamePattern, Pat columnNamePattern) {
     try {
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1,
+      final ResultSet rs =
           connection.getMetaData().getColumns(catalog, schemaPattern.s,
-              tableNamePattern.s, columnNamePattern.s));
+              tableNamePattern.s, columnNamePattern.s);
+      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -400,8 +401,9 @@ public class JdbcMeta implements Meta {
 
   public MetaResultSet getSchemas(String catalog, Pat schemaPattern) {
     try {
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1,
-          connection.getMetaData().getSchemas(catalog, schemaPattern.s));
+      final ResultSet rs =
+          connection.getMetaData().getSchemas(catalog, schemaPattern.s);
+      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -409,8 +411,8 @@ public class JdbcMeta implements Meta {
 
   public MetaResultSet getCatalogs() {
     try {
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1,
-          connection.getMetaData().getCatalogs());
+      final ResultSet rs = connection.getMetaData().getCatalogs();
+      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -418,8 +420,8 @@ public class JdbcMeta implements Meta {
 
   public MetaResultSet getTableTypes() {
     try {
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1,
-          connection.getMetaData().getTableTypes());
+      final ResultSet rs = connection.getMetaData().getTableTypes();
+      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -428,9 +430,10 @@ public class JdbcMeta implements Meta {
   public MetaResultSet getProcedures(String catalog, Pat schemaPattern,
       Pat procedureNamePattern) {
     try {
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1,
+      final ResultSet rs =
           connection.getMetaData().getProcedures(catalog, schemaPattern.s,
-              procedureNamePattern.s));
+              procedureNamePattern.s);
+      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -439,9 +442,10 @@ public class JdbcMeta implements Meta {
   public MetaResultSet getProcedureColumns(String catalog, Pat schemaPattern,
       Pat procedureNamePattern, Pat columnNamePattern) {
     try {
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1,
+      final ResultSet rs =
           connection.getMetaData().getProcedureColumns(catalog,
-              schemaPattern.s, procedureNamePattern.s, columnNamePattern.s));
+              schemaPattern.s, procedureNamePattern.s, columnNamePattern.s);
+      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -450,9 +454,10 @@ public class JdbcMeta implements Meta {
   public MetaResultSet getColumnPrivileges(String catalog, String schema,
       String table, Pat columnNamePattern) {
     try {
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1,
+      final ResultSet rs =
           connection.getMetaData().getColumnPrivileges(catalog, schema,
-              table, columnNamePattern.s));
+              table, columnNamePattern.s);
+      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -461,9 +466,10 @@ public class JdbcMeta implements Meta {
   public MetaResultSet getTablePrivileges(String catalog, Pat schemaPattern,
       Pat tableNamePattern) {
     try {
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1,
+      final ResultSet rs =
           connection.getMetaData().getTablePrivileges(catalog,
-              schemaPattern.s, tableNamePattern.s));
+              schemaPattern.s, tableNamePattern.s);
+      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -476,9 +482,10 @@ public class JdbcMeta implements Meta {
           + " table:" + table + " scope:" + scope + " nullable:" + nullable);
     }
     try {
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1,
+      final ResultSet rs =
           connection.getMetaData().getBestRowIdentifier(catalog, schema,
-              table, scope, nullable));
+              table, scope, nullable);
+      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -490,8 +497,9 @@ public class JdbcMeta implements Meta {
       LOG.trace("getVersionColumns catalog:" + catalog + " schema:" + schema + " table:" + table);
     }
     try {
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1,
-          connection.getMetaData().getVersionColumns(catalog, schema, table));
+      final ResultSet rs =
+          connection.getMetaData().getVersionColumns(catalog, schema, table);
+      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -503,8 +511,9 @@ public class JdbcMeta implements Meta {
       LOG.trace("getPrimaryKeys catalog:" + catalog + " schema:" + schema + " table:" + table);
     }
     try {
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1,
-          connection.getMetaData().getPrimaryKeys(catalog, schema, table));
+      final ResultSet rs =
+          connection.getMetaData().getPrimaryKeys(catalog, schema, table);
+      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -528,8 +537,8 @@ public class JdbcMeta implements Meta {
 
   public MetaResultSet getTypeInfo() {
     try {
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1,
-          connection.getMetaData().getTypeInfo());
+      final ResultSet rs = connection.getMetaData().getTypeInfo();
+      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -696,7 +705,7 @@ public class JdbcMeta implements Meta {
   }
 
   public StatementHandle prepare(ConnectionHandle ch, String sql,
-      int maxRowCount) {
+      long maxRowCount) {
     try {
       final Connection conn = getConnection(ch.id);
       final PreparedStatement statement = conn.prepareStatement(sql);
@@ -715,7 +724,7 @@ public class JdbcMeta implements Meta {
   }
 
   public ExecuteResult prepareAndExecute(StatementHandle h, String sql,
-      int maxRowCount, PrepareCallback callback) {
+      long maxRowCount, PrepareCallback callback) {
     try {
       final StatementInfo info = statementCache.getIfPresent(h.id);
       if (info == null) {
@@ -725,7 +734,7 @@ public class JdbcMeta implements Meta {
       final Statement statement = info.statement;
       // Special handling of maxRowCount as JDBC 0 is unlimited, our meta 0 row
       if (maxRowCount > 0) {
-        statement.setMaxRows(maxRowCount);
+        AvaticaUtils.setLargeMaxRows(statement, maxRowCount);
       } else if (maxRowCount < 0) {
         statement.setMaxRows(0);
       }
@@ -737,7 +746,7 @@ public class JdbcMeta implements Meta {
         // Create a special result set that just carries update count
         resultSets.add(
             MetaResultSet.count(h.connectionId, h.id,
-                statement.getUpdateCount()));
+                AvaticaUtils.getLargeUpdateCount(statement)));
       } else {
         resultSets.add(
             JdbcResultSet.create(h.connectionId, h.id, info.resultSet,
@@ -754,7 +763,7 @@ public class JdbcMeta implements Meta {
   }
 
   public Frame fetch(StatementHandle h, List<TypedValue> parameterValues,
-      int offset, int fetchMaxRowCount) {
+      long offset, int fetchMaxRowCount) {
     if (LOG.isTraceEnabled()) {
       LOG.trace("fetching " + h + " offset:" + offset + " fetchMaxRowCount:"
           + fetchMaxRowCount);
@@ -789,6 +798,13 @@ public class JdbcMeta implements Meta {
     }
   }
 
+  private static String[] toArray(List<String> typeList) {
+    if (typeList == null) {
+      return new String[0];
+    }
+    return typeList.toArray(new String[typeList.size()]);
+  }
+
   /** All we know about a statement. */
   private static class StatementInfo {
     final Statement statement; // sometimes a PreparedStatement

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c818d50b/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java b/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java
index ae67b50..dc50405 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java
@@ -37,7 +37,7 @@ import java.util.List;
 class JdbcResultSet extends Meta.MetaResultSet {
   protected JdbcResultSet(String connectionId, int statementId,
       boolean ownStatement, Meta.Signature signature, Meta.Frame firstFrame) {
-    super(connectionId, statementId, ownStatement, signature, firstFrame, -1);
+    super(connectionId, statementId, ownStatement, signature, firstFrame, -1L);
   }
 
   /** Creates a result set. */
@@ -48,12 +48,12 @@ class JdbcResultSet extends Meta.MetaResultSet {
 
   /** Creates a result set with maxRowCount. */
   public static JdbcResultSet create(String connectionId, int statementId,
-      ResultSet resultSet, int maxRowCount) {
+      ResultSet resultSet, long maxRowCount) {
     try {
       Meta.Signature sig = JdbcMeta.signature(resultSet.getMetaData());
       final Calendar calendar = Calendar.getInstance(DateTimeUtils.GMT_ZONE);
       final int fetchRowCount =
-        (maxRowCount == -1 || maxRowCount > 100) ? 100 : maxRowCount;
+        (maxRowCount == -1 || maxRowCount > 100) ? 100 : (int) maxRowCount;
       final Meta.Frame firstFrame = frame(resultSet, 0, fetchRowCount, calendar);
       if (firstFrame.done) {
         resultSet.close();
@@ -67,7 +67,7 @@ class JdbcResultSet extends Meta.MetaResultSet {
 
   /** Creates a frame containing a given number or unlimited number of rows
    * from a result set. */
-  static Meta.Frame frame(ResultSet resultSet, int offset,
+  static Meta.Frame frame(ResultSet resultSet, long offset,
       int fetchMaxRowCount, Calendar calendar) throws SQLException {
     final ResultSetMetaData metaData = resultSet.getMetaData();
     final int columnCount = metaData.getColumnCount();
@@ -77,7 +77,7 @@ class JdbcResultSet extends Meta.MetaResultSet {
     }
     final List<Object> rows = new ArrayList<>();
     // Meta prepare/prepareAndExecute 0 return 0 row and done
-    boolean done = fetchMaxRowCount == 0 ? true : false;
+    boolean done = fetchMaxRowCount == 0;
     for (int i = 0; fetchMaxRowCount < 0 || i < fetchMaxRowCount; i++) {
       if (!resultSet.next()) {
         done = true;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c818d50b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
index 27dcfa4..2a9e846 100644
--- a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
+++ b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
@@ -97,8 +97,9 @@ public class RemoteMetaTest {
 
   private static Meta.ExecuteResult prepareAndExecuteInternal(AvaticaConnection conn,
     final AvaticaStatement statement, String sql, int maxRowCount) throws Exception {
-    Method m = AvaticaConnection.class.getDeclaredMethod("prepareAndExecuteInternal",
-      AvaticaStatement.class, String.class, int.class);
+    Method m =
+        AvaticaConnection.class.getDeclaredMethod("prepareAndExecuteInternal",
+            AvaticaStatement.class, String.class, long.class);
     m.setAccessible(true);
     return (Meta.ExecuteResult) m.invoke(conn, statement, sql, maxRowCount);
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c818d50b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java
index 1ed561c..e602ed7 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java
@@ -436,7 +436,7 @@ public abstract class AvaticaConnection implements Connection {
   }
 
   protected Meta.ExecuteResult prepareAndExecuteInternal(
-      final AvaticaStatement statement, String sql, int maxRowCount)
+      final AvaticaStatement statement, String sql, long maxRowCount)
       throws SQLException {
     final Meta.PrepareCallback callback =
         new Meta.PrepareCallback() {
@@ -458,7 +458,7 @@ public abstract class AvaticaConnection implements Connection {
           }
 
           public void assign(Meta.Signature signature, Meta.Frame firstFrame,
-              int updateCount) throws SQLException {
+              long updateCount) throws SQLException {
             if (updateCount != -1) {
               statement.updateCount = updateCount;
             } else {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c818d50b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaPreparedStatement.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaPreparedStatement.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaPreparedStatement.java
index e489c07..af00378 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaPreparedStatement.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaPreparedStatement.java
@@ -114,7 +114,11 @@ public abstract class AvaticaPreparedStatement
     return this;
   }
 
-  public int executeUpdate() throws SQLException {
+  public final int executeUpdate() throws SQLException {
+    return (int) executeLargeUpdate();
+  }
+
+  public long executeLargeUpdate() throws SQLException {
     getConnection().executeQueryInternal(this, signature, null);
     return updateCount;
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c818d50b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaStatement.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaStatement.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaStatement.java
index 78ec1cc..bed506d 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaStatement.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaStatement.java
@@ -52,7 +52,7 @@ public abstract class AvaticaStatement
   protected AvaticaResultSet openResultSet;
 
   /** Current update count. Same lifecycle as {@link #openResultSet}. */
-  protected int updateCount;
+  protected long updateCount;
 
   private int queryTimeoutMillis;
   final int resultSetType;
@@ -60,7 +60,7 @@ public abstract class AvaticaStatement
   final int resultSetHoldability;
   private int fetchSize;
   private int fetchDirection;
-  protected int maxRowCount = 0;
+  protected long maxRowCount = 0;
 
   /**
    * Creates an AvaticaStatement.
@@ -105,7 +105,7 @@ public abstract class AvaticaStatement
     this.updateCount = -1;
     try {
       // In JDBC, maxRowCount = 0 means no limit; in prepare it means LIMIT 0
-      final int maxRowCount1 = maxRowCount <= 0 ? -1 : maxRowCount;
+      final long maxRowCount1 = maxRowCount <= 0 ? -1 : maxRowCount;
       Meta.ExecuteResult x =
           connection.prepareAndExecuteInternal(this, sql, maxRowCount1);
     } catch (RuntimeException e) {
@@ -139,7 +139,11 @@ public abstract class AvaticaStatement
     }
   }
 
-  public int executeUpdate(String sql) throws SQLException {
+  public final int executeUpdate(String sql) throws SQLException {
+    return (int) executeLargeUpdate(sql);
+  }
+
+  public long executeLargeUpdate(String sql) throws SQLException {
     checkNotPreparedOrCallable("executeUpdate(String)");
     executeInternal(sql);
     return updateCount;
@@ -182,11 +186,19 @@ public abstract class AvaticaStatement
     throw connection.helper.unsupported();
   }
 
-  public int getMaxRows() {
+  public final int getMaxRows() {
+    return (int) getLargeMaxRows();
+  }
+
+  public long getLargeMaxRows() {
     return maxRowCount;
   }
 
-  public void setMaxRows(int maxRowCount) throws SQLException {
+  public final void setMaxRows(int maxRowCount) throws SQLException {
+    setLargeMaxRows(maxRowCount);
+  }
+
+  public void setLargeMaxRows(long maxRowCount) throws SQLException {
     if (maxRowCount < 0) {
       throw connection.helper.createException(
           "illegal maxRows value: " + maxRowCount);
@@ -255,6 +267,10 @@ public abstract class AvaticaStatement
   }
 
   public int getUpdateCount() throws SQLException {
+    return (int) updateCount;
+  }
+
+  public long getLargeUpdateCount() throws SQLException {
     return updateCount;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c818d50b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
index 0ee030d..a9975e0 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
@@ -19,7 +19,12 @@ package org.apache.calcite.avatica;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
 import java.lang.reflect.Field;
+import java.sql.SQLException;
+import java.sql.Statement;
 import java.util.AbstractList;
 import java.util.HashMap;
 import java.util.List;
@@ -29,6 +34,13 @@ import java.util.Map;
 public class AvaticaUtils {
   private static final Map<Class, Class> BOX;
 
+  private static final MethodHandle SET_LARGE_MAX_ROWS =
+      method(void.class, Statement.class, "setLargeMaxRows", long.class);
+  private static final MethodHandle GET_LARGE_MAX_ROWS =
+      method(long.class, Statement.class, "getLargeMaxRows");
+  private static final MethodHandle GET_LARGE_UPDATE_COUNT =
+      method(void.class, Statement.class, "getLargeUpdateCount");
+
   private AvaticaUtils() {}
 
   static {
@@ -43,6 +55,19 @@ public class AvaticaUtils {
     BOX.put(double.class, Double.class);
   }
 
+  private static MethodHandle method(Class returnType, Class targetType,
+      String name, Class... argTypes) {
+    final MethodHandles.Lookup lookup = MethodHandles.lookup();
+    try {
+      return lookup.findVirtual(targetType, name,
+          MethodType.methodType(returnType, targetType, argTypes));
+    } catch (NoSuchMethodException e) {
+      return null;
+    } catch (IllegalAccessException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
   /**
    * Does nothing with its argument. Call this method when you have a value
    * you are not interested in, but you don't want the compiler to warn that
@@ -182,6 +207,67 @@ public class AvaticaUtils {
     }
     return baos.toString();
   }
+
+  /** Invokes {@code Statement#setLargeMaxRows}, falling back on
+   * {@link Statement#setMaxRows(int)} if the method does not exist (before
+   * JDK 1.8) or throws {@link UnsupportedOperationException}. */
+  public static void setLargeMaxRows(Statement statement, long n)
+      throws SQLException {
+    if (SET_LARGE_MAX_ROWS != null) {
+      try {
+        // Call Statement.setLargeMaxRows
+        SET_LARGE_MAX_ROWS.invokeExact(n);
+        return;
+      } catch (UnsupportedOperationException e) {
+        // ignore, and fall through to call Statement.setMaxRows
+      } catch (Error | RuntimeException | SQLException e) {
+        throw e;
+      } catch (Throwable e) {
+        throw new RuntimeException(e);
+      }
+    }
+    int i = (int) Math.max(Math.min(n, Integer.MAX_VALUE), Integer.MIN_VALUE);
+    statement.setMaxRows(i);
+  }
+
+  /** Invokes {@code Statement#getLargeMaxRows}, falling back on
+   * {@link Statement#getMaxRows()} if the method does not exist (before
+   * JDK 1.8) or throws {@link UnsupportedOperationException}. */
+  public static long getLargeMaxRows(Statement statement) throws SQLException {
+    if (GET_LARGE_MAX_ROWS != null) {
+      try {
+        // Call Statement.getLargeMaxRows
+        return (long) GET_LARGE_MAX_ROWS.invokeExact();
+      } catch (UnsupportedOperationException e) {
+        // ignore, and fall through to call Statement.getMaxRows
+      } catch (Error | RuntimeException | SQLException e) {
+        throw e;
+      } catch (Throwable e) {
+        throw new RuntimeException(e);
+      }
+    }
+    return statement.getMaxRows();
+  }
+
+  /** Invokes {@code Statement#getLargeUpdateCount}, falling back on
+   * {@link Statement#getUpdateCount()} if the method does not exist (before
+   * JDK 1.8) or throws {@link UnsupportedOperationException}. */
+  public static long getLargeUpdateCount(Statement statement)
+      throws SQLException {
+    if (GET_LARGE_UPDATE_COUNT != null) {
+      try {
+        // Call Statement.getLargeUpdateCount
+        return (long) GET_LARGE_UPDATE_COUNT.invokeExact();
+      } catch (UnsupportedOperationException e) {
+        // ignore, and fall through to call Statement.getUpdateCount
+      } catch (Error | RuntimeException | SQLException e) {
+        throw e;
+      } catch (Throwable e) {
+        throw new RuntimeException(e);
+      }
+    }
+    return statement.getUpdateCount();
+  }
 }
 
 // End AvaticaUtils.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c818d50b/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/Meta.java b/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
index a15a769..d9fab4d 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
@@ -190,7 +190,7 @@ public interface Meta {
    * @param maxRowCount Negative for no limit (different meaning than JDBC)
    * @return Signature of prepared statement
    */
-  StatementHandle prepare(ConnectionHandle ch, String sql, int maxRowCount);
+  StatementHandle prepare(ConnectionHandle ch, String sql, long maxRowCount);
 
   /** Prepares and executes a statement.
    *
@@ -203,7 +203,7 @@ public interface Meta {
    *     first frame of data
    */
   ExecuteResult prepareAndExecute(StatementHandle h, String sql,
-      int maxRowCount, PrepareCallback callback);
+      long maxRowCount, PrepareCallback callback);
 
   /** Returns a frame of rows.
    *
@@ -221,7 +221,7 @@ public interface Meta {
    * no limit
    * @return Frame, or null if there are no more
    */
-  Frame fetch(StatementHandle h, List<TypedValue> parameterValues, int offset,
+  Frame fetch(StatementHandle h, List<TypedValue> parameterValues, long offset,
       int fetchMaxRowCount);
 
   /** Called during the creation of a statement to allocate a new handle.
@@ -356,11 +356,19 @@ public interface Meta {
     public final boolean ownStatement;
     public final Frame firstFrame;
     public final Signature signature;
-    public final int updateCount;
+    public final long updateCount;
 
+    @Deprecated // to be removed before 2.0
     protected MetaResultSet(String connectionId, int statementId,
         boolean ownStatement, Signature signature, Frame firstFrame,
         int updateCount) {
+      this(connectionId, statementId, ownStatement, signature, firstFrame,
+          (long) updateCount);
+    }
+
+    protected MetaResultSet(String connectionId, int statementId,
+        boolean ownStatement, Signature signature, Frame firstFrame,
+        long updateCount) {
       this.signature = signature;
       this.connectionId = connectionId;
       this.statementId = statementId;
@@ -372,11 +380,11 @@ public interface Meta {
     public static MetaResultSet create(String connectionId, int statementId,
         boolean ownStatement, Signature signature, Frame firstFrame) {
       return new MetaResultSet(connectionId, statementId, ownStatement,
-          Objects.requireNonNull(signature), firstFrame, -1);
+          Objects.requireNonNull(signature), firstFrame, -1L);
     }
 
     public static MetaResultSet count(String connectionId, int statementId,
-        int updateCount) {
+        long updateCount) {
       assert updateCount >= 0;
       return new MetaResultSet(connectionId, statementId, false, null, null,
           updateCount);
@@ -549,7 +557,7 @@ public interface Meta {
         new Frame(0, false, Collections.emptyList());
 
     /** Zero-based offset of first row. */
-    public final int offset;
+    public final long offset;
     /** Whether this is definitely the last frame of rows.
      * If true, there are no more rows.
      * If false, there may or may not be more rows. */
@@ -557,7 +565,7 @@ public interface Meta {
     /** The rows. */
     public final Iterable<Object> rows;
 
-    public Frame(int offset, boolean done, Iterable<Object> rows) {
+    public Frame(long offset, boolean done, Iterable<Object> rows) {
       this.offset = offset;
       this.done = done;
       this.rows = rows;
@@ -686,7 +694,7 @@ public interface Meta {
   interface PrepareCallback {
     Object getMonitor();
     void clear() throws SQLException;
-    void assign(Signature signature, Frame firstFrame, int updateCount)
+    void assign(Signature signature, Frame firstFrame, long updateCount)
         throws SQLException;
     void execute() throws SQLException;
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c818d50b/avatica/src/main/java/org/apache/calcite/avatica/MetaImpl.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/MetaImpl.java b/avatica/src/main/java/org/apache/calcite/avatica/MetaImpl.java
index 504c929..e67b64c 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/MetaImpl.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/MetaImpl.java
@@ -737,7 +737,7 @@ public abstract class MetaImpl implements Meta {
   }
 
   public Frame fetch(StatementHandle h, List<TypedValue> parameterValues,
-      int offset, int fetchMaxRowCount) {
+      long offset, int fetchMaxRowCount) {
     return null;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c818d50b/avatica/src/main/java/org/apache/calcite/avatica/UnregisteredDriver.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/UnregisteredDriver.java b/avatica/src/main/java/org/apache/calcite/avatica/UnregisteredDriver.java
index 5f8d492..96d2459 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/UnregisteredDriver.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/UnregisteredDriver.java
@@ -42,7 +42,7 @@ import java.util.logging.Logger;
  *
  * <p>The provider must implement:</p>
  * <ul>
- *   <li>{@link Meta#prepare(Meta.ConnectionHandle, String, int)}
+ *   <li>{@link Meta#prepare(Meta.ConnectionHandle, String, long)}
  *   <li>{@link Meta#createIterable(org.apache.calcite.avatica.Meta.StatementHandle, org.apache.calcite.avatica.Meta.Signature, java.util.List, Meta.Frame)}
  * </ul>
  */

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c818d50b/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalService.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalService.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalService.java
index f03d55b..f6e23b8 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalService.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalService.java
@@ -148,7 +148,7 @@ public class LocalService implements Service {
               }
 
               @Override public void assign(Meta.Signature signature,
-                  Meta.Frame firstFrame, int updateCount) {
+                  Meta.Frame firstFrame, long updateCount) {
               }
 
               @Override public void execute() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c818d50b/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteMeta.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteMeta.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteMeta.java
index f0abe2d..b5404dc 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteMeta.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteMeta.java
@@ -158,7 +158,7 @@ class RemoteMeta extends MetaImpl {
   }
 
   @Override public StatementHandle prepare(ConnectionHandle ch, String sql,
-      int maxRowCount) {
+      long maxRowCount) {
     connectionSync(ch, new ConnectionPropertiesImpl()); // sync connection state if necessary
     final Service.PrepareResponse response = service.apply(
         new Service.PrepareRequest(ch.id, sql, maxRowCount));
@@ -166,7 +166,7 @@ class RemoteMeta extends MetaImpl {
   }
 
   @Override public ExecuteResult prepareAndExecute(StatementHandle h,
-      String sql, int maxRowCount, PrepareCallback callback) {
+      String sql, long maxRowCount, PrepareCallback callback) {
     // sync connection state if necessary
     connectionSync(new ConnectionHandle(h.connectionId),
       new ConnectionPropertiesImpl());
@@ -195,7 +195,7 @@ class RemoteMeta extends MetaImpl {
   }
 
   @Override public Frame fetch(StatementHandle h,
-      List<TypedValue> parameterValues, int offset, int fetchMaxRowCount) {
+      List<TypedValue> parameterValues, long offset, int fetchMaxRowCount) {
     final Service.FetchResponse response =
         service.apply(
             new Service.FetchRequest(h.connectionId, h.id, parameterValues,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c818d50b/avatica/src/main/java/org/apache/calcite/avatica/remote/Service.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/Service.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/Service.java
index 9a8b5da..1171d76 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/Service.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/Service.java
@@ -221,7 +221,7 @@ public interface Service {
     public final boolean ownStatement;
     public final Meta.Signature signature;
     public final Meta.Frame firstFrame;
-    public final int updateCount;
+    public final long updateCount;
 
     @JsonCreator
     public ResultSetResponse(
@@ -230,7 +230,7 @@ public interface Service {
         @JsonProperty("ownStatement") boolean ownStatement,
         @JsonProperty("signature") Meta.Signature signature,
         @JsonProperty("firstFrame") Meta.Frame firstFrame,
-        @JsonProperty("updateCount") int updateCount) {
+        @JsonProperty("updateCount") long updateCount) {
       this.connectionId = connectionId;
       this.statementId = statementId;
       this.ownStatement = ownStatement;
@@ -241,11 +241,11 @@ public interface Service {
   }
 
   /** Request for
-   * {@link org.apache.calcite.avatica.Meta#prepareAndExecute(Meta.StatementHandle, String, int, Meta.PrepareCallback)}. */
+   * {@link Meta#prepareAndExecute(Meta.StatementHandle, String, long, Meta.PrepareCallback)}. */
   class PrepareAndExecuteRequest extends Request {
     public final String connectionId;
     public final String sql;
-    public final int maxRowCount;
+    public final long maxRowCount;
     public final int statementId;
 
     @JsonCreator
@@ -253,7 +253,7 @@ public interface Service {
         @JsonProperty("connectionId") String connectionId,
         @JsonProperty("statementId") int statementId,
         @JsonProperty("sql") String sql,
-        @JsonProperty("maxRowCount") int maxRowCount) {
+        @JsonProperty("maxRowCount") long maxRowCount) {
       this.connectionId = connectionId;
       this.statementId = statementId;
       this.sql = sql;
@@ -278,17 +278,17 @@ public interface Service {
   }
 
   /** Request for
-   * {@link org.apache.calcite.avatica.Meta#prepare(org.apache.calcite.avatica.Meta.ConnectionHandle, String, int)}. */
+   * {@link Meta#prepare(Meta.ConnectionHandle, String, long)}. */
   class PrepareRequest extends Request {
     public final String connectionId;
     public final String sql;
-    public final int maxRowCount;
+    public final long maxRowCount;
 
     @JsonCreator
     public PrepareRequest(
         @JsonProperty("connectionId") String connectionId,
         @JsonProperty("sql") String sql,
-        @JsonProperty("maxRowCount") int maxRowCount) {
+        @JsonProperty("maxRowCount") long maxRowCount) {
       this.connectionId = connectionId;
       this.sql = sql;
       this.maxRowCount = maxRowCount;
@@ -312,11 +312,11 @@ public interface Service {
   }
 
   /** Request for
-   * {@link org.apache.calcite.avatica.Meta#fetch(Meta.StatementHandle, List, int, int)}. */
+   * {@link Meta#fetch(Meta.StatementHandle, List, long, int)}. */
   class FetchRequest extends Request {
     public final String connectionId;
     public final int statementId;
-    public final int offset;
+    public final long offset;
     /** Maximum number of rows to be returned in the frame. Negative means no
      * limit. */
     public final int fetchMaxRowCount;
@@ -329,7 +329,7 @@ public interface Service {
         @JsonProperty("connectionId") String connectionId,
         @JsonProperty("statementId") int statementId,
         @JsonProperty("parameterValues") List<TypedValue> parameterValues,
-        @JsonProperty("offset") int offset,
+        @JsonProperty("offset") long offset,
         @JsonProperty("fetchMaxRowCount") int fetchMaxRowCount) {
       this.connectionId = connectionId;
       this.statementId = statementId;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c818d50b/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
index f3819fe..d69971d 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
@@ -166,7 +166,7 @@ abstract class CalciteConnectionImpl
   }
 
   <T> CalcitePrepare.CalciteSignature<T> parseQuery(String sql,
-      CalcitePrepare.Context prepareContext, int maxRowCount) {
+      CalcitePrepare.Context prepareContext, long maxRowCount) {
     CalcitePrepare.Dummy.push(prepareContext);
     try {
       final CalcitePrepare prepare = prepareFactory.apply();

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c818d50b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
index cd3df50..9f8ade3 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
@@ -537,7 +537,7 @@ public class CalciteMetaImpl extends MetaImpl {
   }
 
   @Override public StatementHandle prepare(ConnectionHandle ch, String sql,
-      int maxRowCount) {
+      long maxRowCount) {
     final StatementHandle h = createStatement(ch);
     final CalciteConnectionImpl calciteConnection = getConnection();
 
@@ -550,7 +550,7 @@ public class CalciteMetaImpl extends MetaImpl {
   }
 
   @Override public ExecuteResult prepareAndExecute(StatementHandle h,
-      String sql, int maxRowCount, PrepareCallback callback) {
+      String sql, long maxRowCount, PrepareCallback callback) {
     final CalcitePrepare.CalciteSignature<Object> signature;
     try {
       synchronized (callback.getMonitor()) {
@@ -574,7 +574,7 @@ public class CalciteMetaImpl extends MetaImpl {
   }
 
   @Override public Frame fetch(StatementHandle h, List<TypedValue> parameterValues,
-      int offset, int fetchMaxRowCount) {
+      long offset, int fetchMaxRowCount) {
     final CalciteConnectionImpl calciteConnection = getConnection();
     CalciteServerStatement stmt = calciteConnection.server.getStatement(h);
     final Signature signature = stmt.getSignature();
@@ -670,15 +670,15 @@ public class CalciteMetaImpl extends MetaImpl {
    * {@link Iterator}. */
   private static class LimitIterator<E> implements Iterator<E> {
     private final Iterator<E> iterator;
-    private final int limit;
+    private final long limit;
     int i = 0;
 
-    private LimitIterator(Iterator<E> iterator, int limit) {
+    private LimitIterator(Iterator<E> iterator, long limit) {
       this.iterator = iterator;
       this.limit = limit;
     }
 
-    static <E> Iterator<E> of(Iterator<E> iterator, int limit) {
+    static <E> Iterator<E> of(Iterator<E> iterator, long limit) {
       if (limit <= 0) {
         return iterator;
       }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c818d50b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
index c792ed2..2453f98 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
@@ -89,7 +89,7 @@ public interface CalcitePrepare {
       String sql,
       Queryable<T> expression,
       Type elementType,
-      int maxRowCount);
+      long maxRowCount);
 
   <T> CalciteSignature<T> prepareQueryable(
       Context context,
@@ -260,7 +260,7 @@ public interface CalcitePrepare {
    * statement directly, without an explicit prepare step. */
   class CalciteSignature<T> extends Meta.Signature {
     @JsonIgnore public final RelDataType rowType;
-    private final int maxRowCount;
+    private final long maxRowCount;
     private final Bindable<T> bindable;
 
     public CalciteSignature(String sql,
@@ -269,7 +269,7 @@ public interface CalcitePrepare {
         RelDataType rowType,
         List<ColumnMetaData> columns,
         Meta.CursorFactory cursorFactory,
-        int maxRowCount,
+        long maxRowCount,
         Bindable<T> bindable) {
       super(columns, sql, parameterList, internalParameters, cursorFactory);
       this.rowType = rowType;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c818d50b/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 d78f160..674f093 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -535,7 +535,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
       String sql,
       Queryable<T> expression,
       Type elementType,
-      int maxRowCount) {
+      long maxRowCount) {
     return prepare_(context, sql, expression, elementType, maxRowCount);
   }
 
@@ -544,7 +544,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
       String sql,
       Queryable<T> queryable,
       Type elementType,
-      int maxRowCount) {
+      long maxRowCount) {
     if (SIMPLE_SQLS.contains(sql)) {
       return simplePrepare(context, sql);
     }
@@ -612,7 +612,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
       String sql,
       Queryable<T> queryable,
       Type elementType,
-      int maxRowCount,
+      long maxRowCount,
       CalciteCatalogReader catalogReader,
       RelOptPlanner planner) {
     final JavaTypeFactory typeFactory = context.getTypeFactory();
@@ -709,7 +709,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
     }
     //noinspection unchecked
     final Bindable<T> bindable = preparedResult.getBindable();
-    return new CalciteSignature<T>(
+    return new CalciteSignature<>(
         sql,
         parameters,
         preparingStmt.internalParameters,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c818d50b/linq4j/src/main/java/org/apache/calcite/linq4j/EnumerableDefaults.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/EnumerableDefaults.java b/linq4j/src/main/java/org/apache/calcite/linq4j/EnumerableDefaults.java
index e470032..57f9372 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/EnumerableDefaults.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/EnumerableDefaults.java
@@ -694,7 +694,8 @@ public abstract class EnumerableDefaults {
       Function0<TAccumulate> accumulatorInitializer,
       Function2<TAccumulate, TSource, TAccumulate> accumulatorAdder,
       final Function2<TKey, TAccumulate, TResult> resultSelector) {
-    return groupByMultiple_(new HashMap<TKey, TAccumulate>(),
+    return groupByMultiple_(
+        new HashMap<TKey, TAccumulate>(),
         enumerable,
         keySelectors,
         accumulatorInitializer,
@@ -716,8 +717,13 @@ public abstract class EnumerableDefaults {
       Function2<TAccumulate, TSource, TAccumulate> accumulatorAdder,
       Function2<TKey, TAccumulate, TResult> resultSelector,
       EqualityComparer<TKey> comparer) {
-    return groupBy_(new WrapMap<TKey, TAccumulate>(comparer), enumerable,
-        keySelector, accumulatorInitializer, accumulatorAdder, resultSelector);
+    return groupBy_(
+        new WrapMap<TKey, TAccumulate>(comparer),
+        enumerable,
+        keySelector,
+        accumulatorInitializer,
+        accumulatorAdder,
+        resultSelector);
   }
 
   private static <TSource, TKey, TAccumulate, TResult> Enumerable<TResult>
@@ -918,8 +924,15 @@ public abstract class EnumerableDefaults {
       final Function1<TSource, TKey> outerKeySelector,
       final Function1<TInner, TKey> innerKeySelector,
       final Function2<TSource, TInner, TResult> resultSelector) {
-    return join(outer, inner, outerKeySelector, innerKeySelector,
-        resultSelector, null, false, false);
+    return join(
+        outer,
+        inner,
+        outerKeySelector,
+        innerKeySelector,
+        resultSelector,
+        null,
+        false,
+        false);
   }
 
   /**
@@ -933,8 +946,15 @@ public abstract class EnumerableDefaults {
       Function1<TInner, TKey> innerKeySelector,
       Function2<TSource, TInner, TResult> resultSelector,
       EqualityComparer<TKey> comparer) {
-    return join(outer, inner, outerKeySelector, innerKeySelector,
-        resultSelector, comparer, false, false);
+    return join(
+        outer,
+        inner,
+        outerKeySelector,
+        innerKeySelector,
+        resultSelector,
+        comparer,
+        false,
+        false);
   }
 
   /**
@@ -949,8 +969,15 @@ public abstract class EnumerableDefaults {
       Function2<TSource, TInner, TResult> resultSelector,
       EqualityComparer<TKey> comparer, boolean generateNullsOnLeft,
       boolean generateNullsOnRight) {
-    return join_(outer, inner, outerKeySelector, innerKeySelector,
-        resultSelector, comparer, generateNullsOnLeft, generateNullsOnRight);
+    return join_(
+        outer,
+        inner,
+        outerKeySelector,
+        innerKeySelector,
+        resultSelector,
+        comparer,
+        generateNullsOnLeft,
+        generateNullsOnRight);
   }
 
   /** Implementation of join that builds the right input and probes with the
@@ -1985,6 +2012,21 @@ public abstract class EnumerableDefaults {
   }
 
   /**
+   * Returns a specified number of contiguous elements
+   * from the start of a sequence.
+   */
+  public static <TSource> Enumerable<TSource> take(Enumerable<TSource> source,
+      final long count) {
+    return takeWhileLong(
+        source, new Predicate2<TSource, Long>() {
+          public boolean apply(TSource v1, Long v2) {
+            // Count is 1-based
+            return v2 < count;
+          }
+        });
+  }
+
+  /**
    * Returns elements from a sequence as long as a
    * specified condition is true.
    */
@@ -2004,7 +2046,22 @@ public abstract class EnumerableDefaults {
       final Predicate2<TSource, Integer> predicate) {
     return new AbstractEnumerable<TSource>() {
       public Enumerator<TSource> enumerator() {
-        return new TakeWhileEnumerator<TSource>(source.enumerator(), predicate);
+        return new TakeWhileEnumerator<>(source.enumerator(), predicate);
+      }
+    };
+  }
+
+  /**
+   * Returns elements from a sequence as long as a
+   * specified condition is true. The element's index is used in the
+   * logic of the predicate function.
+   */
+  public static <TSource> Enumerable<TSource> takeWhileLong(
+      final Enumerable<TSource> source,
+      final Predicate2<TSource, Long> predicate) {
+    return new AbstractEnumerable<TSource>() {
+      public Enumerator<TSource> enumerator() {
+        return new TakeWhileLongEnumerator<>(source.enumerator(), predicate);
       }
     };
   }
@@ -2392,8 +2449,49 @@ public abstract class EnumerableDefaults {
 
     public boolean moveNext() {
       if (!done) {
-        if (enumerator.moveNext() && predicate.apply(enumerator.current(),
-            ++n)) {
+        if (enumerator.moveNext()
+            && predicate.apply(enumerator.current(), ++n)) {
+          return true;
+        } else {
+          done = true;
+        }
+      }
+      return false;
+    }
+
+    public void reset() {
+      enumerator.reset();
+      done = false;
+      n = -1;
+    }
+
+    public void close() {
+      enumerator.close();
+    }
+  }
+
+  /** Enumerable that implements take-while. */
+  static class TakeWhileLongEnumerator<TSource> implements Enumerator<TSource> {
+    private final Enumerator<TSource> enumerator;
+    private final Predicate2<TSource, Long> predicate;
+
+    boolean done = false;
+    long n = -1;
+
+    public TakeWhileLongEnumerator(Enumerator<TSource> enumerator,
+        Predicate2<TSource, Long> predicate) {
+      this.enumerator = enumerator;
+      this.predicate = predicate;
+    }
+
+    public TSource current() {
+      return enumerator.current();
+    }
+
+    public boolean moveNext() {
+      if (!done) {
+        if (enumerator.moveNext()
+            && predicate.apply(enumerator.current(), ++n)) {
           return true;
         } else {
           done = true;


[16/50] incubator-calcite git commit: [CALCITE-783] Infer collation of Project using monotonicity (Milinda Pathirage)

Posted by jh...@apache.org.
[CALCITE-783] Infer collation of Project using monotonicity (Milinda Pathirage)

Close apache/incubator-calcite#104


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

Branch: refs/heads/branch-release
Commit: c711fed6e2392f296554719a98b2d737da53c9b5
Parents: f7ec3e8
Author: Milinda Pathirage <mi...@gmail.com>
Authored: Thu Jul 9 11:46:58 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Jul 20 20:58:24 2015 -0700

----------------------------------------------------------------------
 .../calcite/rel/logical/LogicalAggregate.java   | 21 ++++++++-
 .../calcite/rel/metadata/RelMdCollation.java    | 45 ++++++++++++++++---
 .../java/org/apache/calcite/rex/RexBuilder.java |  5 ++-
 .../org/apache/calcite/rex/RexCallBinding.java  | 46 ++++++++++++++++----
 .../calcite/sql2rel/SqlToRelConverter.java      |  3 +-
 .../sql2rel/StandardConvertletTable.java        |  3 +-
 6 files changed, 104 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c711fed6/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
index e0bca76..650e8a6 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
@@ -19,6 +19,8 @@ package org.apache.calcite.rel.logical;
 import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelInput;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelShuttle;
@@ -26,6 +28,9 @@ import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.util.ImmutableBitSet;
 
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+
 import java.util.List;
 
 /**
@@ -85,13 +90,25 @@ public final class LogicalAggregate extends Aggregate {
   }
 
   /** Creates a LogicalAggregate. */
-  public static LogicalAggregate create(RelNode input,
+  public static LogicalAggregate create(final RelNode input,
       boolean indicator,
       ImmutableBitSet groupSet,
       List<ImmutableBitSet> groupSets,
       List<AggregateCall> aggCalls) {
     final RelOptCluster cluster = input.getCluster();
-    final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE);
+    final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE).replaceIfs(
+        RelCollationTraitDef.INSTANCE,
+        new Supplier<List<RelCollation>>() {
+          public List<RelCollation> get() {
+            List<RelCollation> collations =
+                input.getTraitSet().getTraits(RelCollationTraitDef.INSTANCE);
+            if (collations != null) {
+              return collations;
+            }
+
+            return ImmutableList.of();
+          }
+        });
     return new LogicalAggregate(cluster, traitSet, input, indicator, groupSet,
         groupSets, aggCalls);
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c711fed6/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
index 52a7c43..cf0614b 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
@@ -55,7 +55,9 @@ import com.google.common.collect.Ordering;
 import com.google.common.collect.Sets;
 
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.SortedSet;
 
 /**
@@ -187,18 +189,16 @@ public class RelMdCollation {
       return ImmutableList.of();
     }
     final Multimap<Integer, Integer> targets = LinkedListMultimap.create();
+    final Map<Integer, SqlMonotonicity> targetsWithMonotonicity =
+        new HashMap<>();
     for (Ord<RexNode> project : Ord.zip(projects)) {
       if (project.e instanceof RexInputRef) {
         targets.put(((RexInputRef) project.e).getIndex(), project.i);
       } else if (project.e instanceof RexCall) {
         final RexCall call = (RexCall) project.e;
         final RexCallBinding binding =
-            RexCallBinding.create(input.getCluster().getTypeFactory(), call);
-        if (false) {
-          final SqlMonotonicity monotonicity =
-              call.getOperator().getMonotonicity(binding);
-          // TODO: do something with this monotonicity
-        }
+            RexCallBinding.create(input.getCluster().getTypeFactory(), call, inputCollations);
+        targetsWithMonotonicity.put(project.i, call.getOperator().getMonotonicity(binding));
       }
     }
     final List<RelFieldCollation> fieldCollations = Lists.newArrayList();
@@ -218,9 +218,42 @@ public class RelMdCollation {
       assert !fieldCollations.isEmpty();
       collations.add(RelCollations.of(fieldCollations));
     }
+
+    final List<RelFieldCollation> fieldCollationsForRexCalls = Lists.newArrayList();
+    for (Map.Entry<Integer, SqlMonotonicity> targetMonotonicity
+        : targetsWithMonotonicity.entrySet()) {
+      if (targetMonotonicity.getValue() != SqlMonotonicity.NOT_MONOTONIC
+          && targetMonotonicity.getValue() != SqlMonotonicity.CONSTANT) {
+        fieldCollationsForRexCalls.add(new RelFieldCollation(targetMonotonicity.getKey(),
+            monotonicityToDirection(targetMonotonicity.getValue())));
+      }
+    }
+
+    if (!fieldCollationsForRexCalls.isEmpty()) {
+      collations.add(RelCollations.of(fieldCollationsForRexCalls));
+    }
+
     return ImmutableList.copyOf(collations);
   }
 
+  private static RelFieldCollation.Direction monotonicityToDirection(SqlMonotonicity monotonicity) {
+    switch (monotonicity) {
+    case INCREASING:
+      return RelFieldCollation.Direction.ASCENDING;
+    case DECREASING:
+      return RelFieldCollation.Direction.DESCENDING;
+    case STRICTLY_INCREASING:
+      return RelFieldCollation.Direction.STRICTLY_ASCENDING;
+    case STRICTLY_DECREASING:
+      return RelFieldCollation.Direction.STRICTLY_DESCENDING;
+    case MONOTONIC:
+      return RelFieldCollation.Direction.CLUSTERED;
+    default:
+      throw new IllegalStateException(
+          String.format("SQL monotonicity of type %s is not allowed at this stage.", monotonicity));
+    }
+  }
+
   /** Helper method to determine a
    * {@link org.apache.calcite.rel.core.Window}'s collation.
    *

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c711fed6/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
index 335293a..2cb47d5 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
@@ -20,6 +20,7 @@ import org.apache.calcite.avatica.util.ByteString;
 import org.apache.calcite.avatica.util.DateTimeUtils;
 import org.apache.calcite.avatica.util.Spaces;
 import org.apache.calcite.avatica.util.TimeUnit;
+import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.rel.type.RelDataType;
@@ -263,7 +264,9 @@ public class RexBuilder {
   public RelDataType deriveReturnType(
       SqlOperator op,
       List<? extends RexNode> exprs) {
-    return op.inferReturnType(new RexCallBinding(typeFactory, op, exprs));
+    return op.inferReturnType(
+        new RexCallBinding(typeFactory, op, exprs,
+            ImmutableList.<RelCollation>of()));
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c711fed6/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java b/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java
index 373b90f..c2828aa 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java
@@ -16,6 +16,8 @@
  */
 package org.apache.calcite.rex;
 
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.runtime.CalciteException;
@@ -40,26 +42,31 @@ public class RexCallBinding extends SqlOperatorBinding {
 
   private final List<RexNode> operands;
 
+  private final List<RelCollation> inputCollations;
+
   //~ Constructors -----------------------------------------------------------
 
   public RexCallBinding(
       RelDataTypeFactory typeFactory,
       SqlOperator sqlOperator,
-      List<? extends RexNode> operands) {
+      List<? extends RexNode> operands,
+      List<RelCollation> inputCollations) {
     super(typeFactory, sqlOperator);
     this.operands = ImmutableList.copyOf(operands);
+    this.inputCollations = ImmutableList.copyOf(inputCollations);
   }
 
   /** Creates a binding of the appropriate type. */
   public static RexCallBinding create(RelDataTypeFactory typeFactory,
-      RexCall call) {
+      RexCall call,
+      List<RelCollation> inputCollations) {
     switch (call.getKind()) {
     case CAST:
       return new RexCastCallBinding(typeFactory, call.getOperator(),
-          call.getOperands(), call.getType());
+          call.getOperands(), call.getType(), inputCollations);
     }
     return new RexCallBinding(typeFactory, call.getOperator(),
-        call.getOperands());
+        call.getOperands(), inputCollations);
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -77,7 +84,28 @@ public class RexCallBinding extends SqlOperatorBinding {
   }
 
   @Override public SqlMonotonicity getOperandMonotonicity(int ordinal) {
-    throw new AssertionError(); // to be completed
+    RexNode operand = operands.get(ordinal);
+
+    if (operand instanceof RexInputRef) {
+      for (RelCollation ic : inputCollations) {
+        if (ic.getFieldCollations().isEmpty()) {
+          continue;
+        }
+
+        for (RelFieldCollation rfc : ic.getFieldCollations()) {
+          if (rfc.getFieldIndex() == ((RexInputRef) operand).getIndex()) {
+            return rfc.direction.monotonicity();
+            // TODO: Is it possible to have more than one RelFieldCollation for a RexInputRef?
+          }
+        }
+      }
+    } else if (operand instanceof RexCall) {
+      final RexCallBinding binding =
+          RexCallBinding.create(typeFactory, (RexCall) operand, inputCollations);
+      ((RexCall) operand).getOperator().getMonotonicity(binding);
+    }
+
+    return SqlMonotonicity.NOT_MONOTONIC;
   }
 
   @Override public boolean isOperandNull(int ordinal, boolean allowCast) {
@@ -104,10 +132,12 @@ public class RexCallBinding extends SqlOperatorBinding {
   private static class RexCastCallBinding extends RexCallBinding {
     private final RelDataType type;
 
-    public RexCastCallBinding(RelDataTypeFactory typeFactory,
+    public RexCastCallBinding(
+        RelDataTypeFactory typeFactory,
         SqlOperator sqlOperator, List<? extends RexNode> operands,
-        RelDataType type) {
-      super(typeFactory, sqlOperator, operands);
+        RelDataType type,
+        List<RelCollation> inputCollations) {
+      super(typeFactory, sqlOperator, operands, inputCollations);
       this.type = type;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c711fed6/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index e733d13..fe16f23 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -4688,7 +4688,8 @@ public class SqlToRelConverter {
             new RexCallBinding(
                 rexBuilder.getTypeFactory(),
                 SqlStdOperatorTable.HISTOGRAM_AGG,
-                exprs);
+                exprs,
+                ImmutableList.<RelCollation>of());
 
         RexNode over =
             rexBuilder.makeOver(

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c711fed6/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
index 8bf28e0..b184982 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
@@ -20,6 +20,7 @@ import org.apache.calcite.avatica.util.DateTimeUtils;
 import org.apache.calcite.avatica.util.TimeUnit;
 import org.apache.calcite.avatica.util.TimeUnitRange;
 import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeFamily;
@@ -718,7 +719,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
     final int groupCount = cx.getGroupCount();
     if (returnType == null) {
       RexCallBinding binding =
-          new RexCallBinding(cx.getTypeFactory(), fun, exprs) {
+          new RexCallBinding(cx.getTypeFactory(), fun, exprs, ImmutableList.<RelCollation>of()) {
             @Override public int getGroupCount() {
               return groupCount;
             }


[02/50] incubator-calcite git commit: [CALCITE-780] HTTP error 413 when sending a long string to the Avatica server

Posted by jh...@apache.org.
[CALCITE-780] HTTP error 413 when sending a long string to the Avatica server


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

Branch: refs/heads/branch-release
Commit: 03111d2b680c4f4eb4886d60cab9beebd1c7bdcb
Parents: 40c55fd
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Jul 7 00:20:48 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jul 7 00:20:48 2015 -0700

----------------------------------------------------------------------
 .../calcite/avatica/server/AvaticaHandler.java  | 13 ++++-
 .../calcite/avatica/remote/RemoteMetaTest.java  | 51 +++++++++++++++++++-
 .../apache/calcite/avatica/AvaticaUtils.java    | 17 +++++++
 .../calcite/avatica/remote/RemoteService.java   | 28 ++++++-----
 4 files changed, 94 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/03111d2b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
index fa0e1ac..2ada444 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.avatica.server;
 
+import org.apache.calcite.avatica.AvaticaUtils;
 import org.apache.calcite.avatica.remote.JsonHandler;
 import org.apache.calcite.avatica.remote.Service;
 
@@ -27,6 +28,7 @@ import org.eclipse.jetty.server.handler.AbstractHandler;
 
 import java.io.IOException;
 import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -48,9 +50,16 @@ public class AvaticaHandler extends AbstractHandler {
     response.setContentType("application/json;charset=utf-8");
     response.setStatus(HttpServletResponse.SC_OK);
     if (request.getMethod().equals("POST")) {
+      // First look for a request in the header, then look in the body.
+      // The latter allows very large requests without hitting HTTP 413.
+      String rawRequest = request.getHeader("request");
+      if (rawRequest == null) {
+        try (ServletInputStream inputStream = request.getInputStream()) {
+          rawRequest = AvaticaUtils.readFully(inputStream);
+        }
+      }
       final String jsonRequest =
-          new String(request.getHeader("request").getBytes("ISO-8859-1"),
-              "UTF-8");
+          new String(rawRequest.getBytes("ISO-8859-1"), "UTF-8");
       if (LOG.isTraceEnabled()) {
         LOG.trace("request: " + jsonRequest);
       }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/03111d2b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
index 2439ac3..27dcfa4 100644
--- a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
+++ b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
@@ -41,8 +41,10 @@ import java.sql.Statement;
 import java.util.List;
 import java.util.Map;
 
+import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 /** Tests covering {@link RemoteMeta}. */
@@ -98,7 +100,7 @@ public class RemoteMetaTest {
     Method m = AvaticaConnection.class.getDeclaredMethod("prepareAndExecuteInternal",
       AvaticaStatement.class, String.class, int.class);
     m.setAccessible(true);
-    return (Meta.ExecuteResult) m.invoke(conn, statement, sql, new Integer(maxRowCount));
+    return (Meta.ExecuteResult) m.invoke(conn, statement, sql, maxRowCount);
   }
 
   private static Connection getConnection(JdbcMeta m, String id) throws Exception {
@@ -128,6 +130,53 @@ public class RemoteMetaTest {
     }
   }
 
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-780">[CALCITE-780]
+   * HTTP error 413 when sending a long string to the Avatica server</a>. */
+  @Test public void testRemoteExecuteVeryLargeQuery() throws Exception {
+    // Before the bug was fixed, a value over 7998 caused an HTTP 413.
+    // 16K bytes, I guess.
+    checkLargeQuery(8);
+    checkLargeQuery(240);
+    checkLargeQuery(8000);
+    checkLargeQuery(240000);
+  }
+
+  private void checkLargeQuery(int n) throws Exception {
+    try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url)) {
+      final AvaticaStatement statement = conn.createStatement();
+      final String frenchDisko = "It said human existence is pointless\n"
+          + "As acts of rebellious solidarity\n"
+          + "Can bring sense in this world\n"
+          + "La resistance!\n";
+      final String sql = "select '"
+          + longString(frenchDisko, n)
+          + "' as s from (values 'x')";
+      prepareAndExecuteInternal(conn, statement, sql, -1);
+      ResultSet rs = statement.getResultSet();
+      int count = 0;
+      while (rs.next()) {
+        count++;
+      }
+      assertThat(count, is(1));
+      rs.close();
+      statement.close();
+      conn.close();
+    }
+  }
+
+  /** Creates a string of exactly {@code length} characters by concatenating
+   * {@code fragment}. */
+  private static String longString(String fragment, int length) {
+    assert fragment.length() > 0;
+    final StringBuilder buf = new StringBuilder();
+    while (buf.length() < length) {
+      buf.append(fragment);
+    }
+    buf.setLength(length);
+    return buf.toString();
+  }
+
   @Test public void testRemoteConnectionProperties() throws Exception {
     try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url)) {
       String id = conn.id;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/03111d2b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
index 5ca5245..0ee030d 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
@@ -16,6 +16,9 @@
  */
 package org.apache.calcite.avatica;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.reflect.Field;
 import java.util.AbstractList;
 import java.util.HashMap;
@@ -165,6 +168,20 @@ public class AvaticaUtils {
           + "' not valid for plugin type " + pluginClass.getName(), e);
     }
   }
+
+  /** Reads the contents of an input stream and returns as a string. */
+  public static String readFully(InputStream inputStream) throws IOException {
+    final byte[] bytes = new byte[4096];
+    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    for (;;) {
+      int count = inputStream.read(bytes, 0, bytes.length);
+      if (count < 0) {
+        break;
+      }
+      baos.write(bytes, 0, count);
+    }
+    return baos.toString();
+  }
 }
 
 // End AvaticaUtils.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/03111d2b/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteService.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteService.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteService.java
index 7cbdcf0..a5896f2 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteService.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteService.java
@@ -16,7 +16,9 @@
  */
 package org.apache.calcite.avatica.remote;
 
-import java.io.ByteArrayOutputStream;
+import org.apache.calcite.avatica.AvaticaUtils;
+
+import java.io.DataOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.HttpURLConnection;
@@ -39,22 +41,24 @@ public class RemoteService extends JsonService {
       final HttpURLConnection connection =
           (HttpURLConnection) url.openConnection();
       connection.setRequestMethod("POST");
-      connection.setRequestProperty("request", request);
+      connection.setDoInput(true);
+      connection.setDoOutput(true);
+      if (request.length() < 256) {
+        connection.setRequestProperty("request", request);
+      } else {
+        try (DataOutputStream wr
+            = new DataOutputStream(connection.getOutputStream())) {
+          wr.writeBytes(request);
+          wr.flush();
+          wr.close();
+        }
+      }
       final int responseCode = connection.getResponseCode();
       if (responseCode != HttpURLConnection.HTTP_OK) {
         throw new RuntimeException("response code " + responseCode);
       }
       final InputStream inputStream = connection.getInputStream();
-      final byte[] bytes = new byte[4096];
-      final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-      for (;;) {
-        int count = inputStream.read(bytes, 0, bytes.length);
-        if (count < 0) {
-          break;
-        }
-        baos.write(bytes, 0, count);
-      }
-      return baos.toString();
+      return AvaticaUtils.readFully(inputStream);
     } catch (IOException e) {
       throw new RuntimeException(e);
     }


[33/50] incubator-calcite git commit: [CALCITE-803] Add MYSQL_ANSI Lexing policy.

Posted by jh...@apache.org.
[CALCITE-803] Add MYSQL_ANSI Lexing policy.


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

Branch: refs/heads/branch-release
Commit: e0a42301e5556685945ecbe2be83f93f10a1869f
Parents: 26a0877
Author: Jacques Nadeau <ja...@apache.org>
Authored: Fri Jul 24 09:53:02 2015 -0700
Committer: Jacques Nadeau <ja...@apache.org>
Committed: Fri Jul 24 18:48:54 2015 -0700

----------------------------------------------------------------------
 .../java/org/apache/calcite/config/Lex.java     |  8 +++++
 .../java/org/apache/calcite/test/JdbcTest.java  | 34 ++++++++++++++++++++
 2 files changed, 42 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e0a42301/core/src/main/java/org/apache/calcite/config/Lex.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/config/Lex.java b/core/src/main/java/org/apache/calcite/config/Lex.java
index c492d1b..d5a50cb 100644
--- a/core/src/main/java/org/apache/calcite/config/Lex.java
+++ b/core/src/main/java/org/apache/calcite/config/Lex.java
@@ -36,6 +36,14 @@ public enum Lex {
    * Back-ticks allow identifiers to contain non-alphanumeric characters. */
   MYSQL(Quoting.BACK_TICK, Casing.UNCHANGED, Casing.UNCHANGED, false),
 
+  /** Lexical policy similar to MySQL with ANSI_QUOTES option enabled. (To be
+   * precise: MySQL on Windows; MySQL on Linux uses case-sensitive matching,
+   * like the Linux file system.) The case of identifiers is preserved whether
+   * or not they quoted; after which, identifiers are matched
+   * case-insensitively. Double quotes allow identifiers to contain
+   * non-alphanumeric characters. */
+  MYSQL_ANSI(Quoting.DOUBLE_QUOTE, Casing.UNCHANGED, Casing.UNCHANGED, false),
+
   /** Lexical policy similar to Microsoft SQL Server.
    * The case of identifiers is preserved whether or not they are quoted;
    * after which, identifiers are matched case-insensitively.

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e0a42301/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index f365ab2..e466f39 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -5909,6 +5909,40 @@ public class JdbcTest {
             });
   }
 
+  /** Tests metadata for the MySQL ANSI lexical scheme. */
+  @Test public void testLexMySQLANSI() throws Exception {
+    CalciteAssert.that()
+        .with(Lex.MYSQL_ANSI)
+        .doWithConnection(
+            new Function<CalciteConnection, Void>() {
+              public Void apply(CalciteConnection connection) {
+                try {
+                  DatabaseMetaData metaData = connection.getMetaData();
+                  assertThat(metaData.getIdentifierQuoteString(), equalTo("\""));
+                  assertThat(metaData.supportsMixedCaseIdentifiers(),
+                      equalTo(false));
+                  assertThat(metaData.storesMixedCaseIdentifiers(),
+                      equalTo(true));
+                  assertThat(metaData.storesUpperCaseIdentifiers(),
+                      equalTo(false));
+                  assertThat(metaData.storesLowerCaseIdentifiers(),
+                      equalTo(false));
+                  assertThat(metaData.supportsMixedCaseQuotedIdentifiers(),
+                      equalTo(false));
+                  assertThat(metaData.storesMixedCaseQuotedIdentifiers(),
+                      equalTo(true));
+                  assertThat(metaData.storesUpperCaseIdentifiers(),
+                      equalTo(false));
+                  assertThat(metaData.storesLowerCaseQuotedIdentifiers(),
+                      equalTo(false));
+                  return null;
+                } catch (SQLException e) {
+                  throw new RuntimeException(e);
+                }
+              }
+            });
+  }
+
   /** Tests metadata for different the "SQL_SERVER" lexical scheme. */
   @Test public void testLexSqlServer() throws Exception {
     CalciteAssert.that()


[20/50] incubator-calcite git commit: [CALCITE-808] Optimize ProjectMergeRule

Posted by jh...@apache.org.
[CALCITE-808] Optimize ProjectMergeRule


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

Branch: refs/heads/branch-release
Commit: b550ff887b41c51348f14c0dc10481fe18aadf0f
Parents: c9fe32b
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Jul 21 11:12:46 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jul 21 12:29:15 2015 -0700

----------------------------------------------------------------------
 .../org/apache/calcite/plan/RelOptUtil.java     | 34 ++++++---
 .../calcite/rel/rules/ProjectMergeRule.java     | 73 +++++---------------
 .../org/apache/calcite/test/RelOptRulesTest.xml | 28 ++++----
 3 files changed, 57 insertions(+), 78 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b550ff88/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
index 6892dfd..d2686a0 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -2379,14 +2379,32 @@ public abstract class RelOptUtil {
    * @param project Project underneath the expression
    * @return converted expression
    */
-  public static RexNode pushPastProject(RexNode node,
-      final Project project) {
-    return node.accept(
-        new RexShuttle() {
-          @Override public RexNode visitInputRef(RexInputRef ref) {
-            return project.getProjects().get(ref.getIndex());
-          }
-        });
+  public static RexNode pushPastProject(RexNode node, Project project) {
+    return node.accept(pushShuttle(project));
+  }
+
+  /**
+   * Converts a list of expressions that are based on the output fields of a
+   * {@link Project} to equivalent expressions on the Project's
+   * input fields.
+   *
+   * @param nodes The expressions to be converted
+   * @param project Project underneath the expression
+   * @return converted expressions
+   */
+  public static List<RexNode> pushPastProject(List<? extends RexNode> nodes,
+      Project project) {
+    final List<RexNode> list = new ArrayList<>();
+    pushShuttle(project).visitList(nodes, list);
+    return list;
+  }
+
+  private static RexShuttle pushShuttle(final Project project) {
+    return new RexShuttle() {
+      @Override public RexNode visitInputRef(RexInputRef ref) {
+        return project.getProjects().get(ref.getIndex());
+      }
+    };
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b550ff88/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java
index cef654e..89ed15f 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java
@@ -23,14 +23,9 @@ import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.core.RelFactories.ProjectFactory;
-import org.apache.calcite.rex.RexBuilder;
-import org.apache.calcite.rex.RexLocalRef;
 import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.rex.RexProgram;
-import org.apache.calcite.rex.RexProgramBuilder;
 import org.apache.calcite.util.Permutation;
 
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -39,7 +34,8 @@ import java.util.List;
  * provided the projects aren't projecting identical sets of input references.
  */
 public class ProjectMergeRule extends RelOptRule {
-  public static final ProjectMergeRule INSTANCE = new ProjectMergeRule();
+  public static final ProjectMergeRule INSTANCE =
+      new ProjectMergeRule(true, RelFactories.DEFAULT_PROJECT_FACTORY);
 
   //~ Instance fields --------------------------------------------------------
 
@@ -51,13 +47,6 @@ public class ProjectMergeRule extends RelOptRule {
   //~ Constructors -----------------------------------------------------------
 
   /**
-   * Creates a ProjectMergeRule.
-   */
-  private ProjectMergeRule() {
-    this(false, RelFactories.DEFAULT_PROJECT_FACTORY);
-  }
-
-  /**
    * Creates a ProjectMergeRule, specifying whether to always merge projects.
    *
    * @param force Whether to always merge projects
@@ -66,7 +55,7 @@ public class ProjectMergeRule extends RelOptRule {
     super(
         operand(Project.class,
             operand(Project.class, any())),
-             "ProjectMergeRule" + (force ? ":force_mode" : ""));
+        "ProjectMergeRule" + (force ? ":force_mode" : ""));
     this.force = force;
     this.projectFactory = projectFactory;
   }
@@ -74,9 +63,8 @@ public class ProjectMergeRule extends RelOptRule {
   //~ Methods ----------------------------------------------------------------
 
   public void onMatch(RelOptRuleCall call) {
-    Project topProject = call.rel(0);
-    Project bottomProject = call.rel(1);
-    RexBuilder rexBuilder = topProject.getCluster().getRexBuilder();
+    final Project topProject = call.rel(0);
+    final Project bottomProject = call.rel(1);
 
     // If one or both projects are permutations, short-circuit the complex logic
     // of building a RexProgram.
@@ -101,48 +89,25 @@ public class ProjectMergeRule extends RelOptRule {
       }
     }
 
-    // if we're not in force mode and the two projects reference identical
-    // inputs, then return and either let FennelRenameRule or
-    // ProjectRemoveRule replace the projects
+    // If we're not in force mode and the two projects reference identical
+    // inputs, then return and let ProjectRemoveRule replace the projects.
     if (!force) {
-      if (RelOptUtil.checkProjAndChildInputs(topProject, false)) {
+      if (ProjectRemoveRule.isIdentity(topProject.getProjects(),
+          topProject.getInput().getRowType())) {
         return;
       }
     }
 
-    // create a RexProgram for the bottom project
-    RexProgram bottomProgram =
-        RexProgram.create(
-            bottomProject.getInput().getRowType(),
-            bottomProject.getProjects(),
-            null,
-            bottomProject.getRowType(),
-            rexBuilder);
-
-    // create a RexProgram for the topmost project
-    final List<RexNode> projects = topProject.getProjects();
-    RexProgram topProgram =
-        RexProgram.create(
-            bottomProject.getRowType(),
-            projects,
-            null,
-            topProject.getRowType(),
-            rexBuilder);
-
-    // combine the two RexPrograms
-    RexProgram mergedProgram =
-        RexProgramBuilder.mergePrograms(
-            topProgram,
-            bottomProgram,
-            rexBuilder);
-
-    // re-expand the topmost projection expressions, now that they
-    // reference the children of the bottom-most project
-    final int projectCount = projects.size();
-    final List<RexNode> newProjects = new ArrayList<>();
-    List<RexLocalRef> projectRefs = mergedProgram.getProjectList();
-    for (int i = 0; i < projectCount; i++) {
-      newProjects.add(mergedProgram.expandLocalRef(projectRefs.get(i)));
+    final List<RexNode> newProjects =
+        RelOptUtil.pushPastProject(topProject.getProjects(), bottomProject);
+    final RelNode input = bottomProject.getInput();
+    if (ProjectRemoveRule.isIdentity(newProjects, input.getRowType())) {
+      if (force
+          || input.getRowType().getFieldNames()
+              .equals(topProject.getRowType().getFieldNames())) {
+        call.transformTo(input);
+        return;
+      }
     }
 
     // replace the two projects with a combined projection

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b550ff88/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index eb9ed66..d01a8d1 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -1636,10 +1636,9 @@ LogicalProject(DEPTNO=[$0], EXPR$1=[$2])
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
-LogicalProject(DEPTNO=[$0], EXPR$1=[$1])
-  LogicalAggregate(group=[{0}], EXPR$1=[MAX($2)])
-    LogicalProject(DEPTNO=[$7], FOUR=[4], MGR=[$3])
-      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+LogicalAggregate(group=[{0}], EXPR$1=[MAX($2)])
+  LogicalProject(DEPTNO=[$7], FOUR=[4], MGR=[$3])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
     </TestCase>
@@ -1660,10 +1659,9 @@ LogicalProject(DEPTNO=[$0], EXPR$1=[$2])
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
-LogicalProject(DEPTNO=[$0], EXPR$1=[$1])
-  LogicalAggregate(group=[{0}], EXPR$1=[MAX($2)])
-    LogicalProject(DEPTNO=[$7], FOUR=[4], ENAME=[$1])
-      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+LogicalAggregate(group=[{0}], EXPR$1=[MAX($2)])
+  LogicalProject(DEPTNO=[$7], FOUR=[4], ENAME=[$1])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
     </TestCase>
@@ -1708,10 +1706,9 @@ LogicalProject(DEPTNO=[$1], EXPR$1=[$2])
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
-LogicalProject(DEPTNO=[$0], EXPR$1=[$1])
-  LogicalAggregate(group=[{0}], EXPR$1=[MAX($2)])
-    LogicalProject(DEPTNO=[$7], FOUR=[4], MGR=[$3])
-      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+LogicalAggregate(group=[{0}], EXPR$1=[MAX($2)])
+  LogicalProject(DEPTNO=[$7], FOUR=[4], MGR=[$3])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
     </TestCase>
@@ -1732,10 +1729,9 @@ LogicalProject(DEPTNO=[$1], EXPR$1=[$2])
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
-LogicalProject(DEPTNO=[$0], EXPR$1=[$1])
-  LogicalAggregate(group=[{0}], EXPR$1=[MAX($2)])
-    LogicalProject(DEPTNO=[$7], $f0=[+(42, 24)], MGR=[$3])
-      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+LogicalAggregate(group=[{0}], EXPR$1=[MAX($2)])
+  LogicalProject(DEPTNO=[$7], $f0=[+(42, 24)], MGR=[$3])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
     </TestCase>


[31/50] incubator-calcite git commit: [CALCITE-814] RexBuilder reverses precision and scale of DECIMAL literal

Posted by jh...@apache.org.
[CALCITE-814] RexBuilder reverses precision and scale of DECIMAL literal


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

Branch: refs/heads/branch-release
Commit: 67ea045ca65083aed9feb803da8d467286c93800
Parents: c818d50
Author: Julian Hyde <jh...@apache.org>
Authored: Fri Jul 24 00:45:50 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Jul 24 01:28:44 2015 -0700

----------------------------------------------------------------------
 .../java/org/apache/calcite/rex/RexBuilder.java |  5 +--
 .../apache/calcite/test/RexTransformerTest.java | 41 ++++++++++++++++++--
 2 files changed, 40 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/67ea045c/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
index ce716c8..872ae7d 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
@@ -842,10 +842,9 @@ public class RexBuilder {
         relType = typeFactory.createSqlType(SqlTypeName.BIGINT);
       }
     } else {
-      int precision = bd.unscaledValue().toString().length();
+      int precision = bd.unscaledValue().abs().toString().length();
       relType =
-          typeFactory.createSqlType(
-              SqlTypeName.DECIMAL, scale, precision);
+          typeFactory.createSqlType(SqlTypeName.DECIMAL, precision, scale);
     }
     return makeExactLiteral(bd, relType);
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/67ea045c/core/src/test/java/org/apache/calcite/test/RexTransformerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RexTransformerTest.java b/core/src/test/java/org/apache/calcite/test/RexTransformerTest.java
index 8f8f799..2242f9c 100644
--- a/core/src/test/java/org/apache/calcite/test/RexTransformerTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexTransformerTest.java
@@ -22,15 +22,21 @@ import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeSystem;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexTransformer;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.type.SqlTypeName;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.math.BigDecimal;
+
+import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -51,8 +57,7 @@ public class RexTransformerTest {
 
   //~ Methods ----------------------------------------------------------------
 
-  @Before
-  public void setUp() {
+  @Before public void setUp() {
     typeFactory = new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
     rexBuilder = new RexBuilder(typeFactory);
     boolRelDataType = typeFactory.createSqlType(SqlTypeName.BOOLEAN);
@@ -70,6 +75,13 @@ public class RexTransformerTest {
     falseRex = rexBuilder.makeLiteral(false);
   }
 
+  @After public void testDown() {
+    typeFactory = null;
+    rexBuilder = null;
+    boolRelDataType = null;
+    x = y = z = trueRex = falseRex = null;
+  }
+
   void check(
       Boolean encapsulateType,
       RexNode node,
@@ -135,7 +147,7 @@ public class RexTransformerTest {
   /**
    * the or operator should pass through unchanged since e.g. x OR y should
    * return true if x=null and y=true if it was transformed into something
-   * like (x ISNOTNULL) AND (y ISNOTNULL) AND (x OR y) an incorrect result
+   * like (x IS NOT NULL) AND (y IS NOT NULL) AND (x OR y) an incorrect result
    * could be produced
    */
   @Test public void testOrUnchanged() {
@@ -317,6 +329,29 @@ public class RexTransformerTest {
         and,
         "AND(AND(AND(IS NOT NULL($0), IS NOT NULL($1)), =($0, $1)), AND(IS NOT NULL($2), >(false, $2)))");
   }
+
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-814">[CALCITE-814]
+   * RexBuilder reverses precision and scale of DECIMAL literal</a>. */
+  @Test public void testExactLiteral() {
+    final RexLiteral literal =
+        rexBuilder.makeExactLiteral(new BigDecimal("-1234.56"));
+    assertThat(literal.getType().getFullTypeString(),
+        is("DECIMAL(6, 2) NOT NULL"));
+    assertThat(literal.getValue().toString(), is("-1234.56"));
+
+    final RexLiteral literal2 =
+        rexBuilder.makeExactLiteral(new BigDecimal("1234.56"));
+    assertThat(literal2.getType().getFullTypeString(),
+        is("DECIMAL(6, 2) NOT NULL"));
+    assertThat(literal2.getValue().toString(), is("1234.56"));
+
+    final RexLiteral literal3 =
+        rexBuilder.makeExactLiteral(new BigDecimal("0.0123456"));
+    assertThat(literal3.getType().getFullTypeString(),
+        is("DECIMAL(6, 7) NOT NULL"));
+    assertThat(literal3.getValue().toString(), is("0.0123456"));
+  }
 }
 
 // End RexTransformerTest.java


[28/50] incubator-calcite git commit: [CALCITE-714] When de-correlating, push join condition into subquery

Posted by jh...@apache.org.
[CALCITE-714] When de-correlating, push join condition into subquery

Decorrelation enhancements to allow pushing Filter past Correlate.

In FilterProjectTransposeRule, check if the filter condition has correlation and
don't push in such cases.

Close apache/incubator-calcite#110


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

Branch: refs/heads/branch-release
Commit: 29030d8c12709525cf874f4c28a13abe165f46aa
Parents: cf7a7a9
Author: Aman Sinha <as...@maprtech.com>
Authored: Tue May 12 13:53:39 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jul 23 14:10:57 2015 -0700

----------------------------------------------------------------------
 .../org/apache/calcite/rel/core/Filter.java     |  28 +++
 .../calcite/rel/rules/FilterCorrelateRule.java  | 138 +++++++++++++
 .../rel/rules/FilterProjectTransposeRule.java   |   7 +
 .../apache/calcite/sql2rel/RelDecorrelator.java |  23 ++-
 .../calcite/test/SqlToRelConverterTest.java     |  39 ++++
 .../org/apache/calcite/test/RelOptRulesTest.xml |  58 +++---
 .../calcite/test/SqlToRelConverterTest.xml      | 200 ++++++++++++++-----
 core/src/test/resources/sql/misc.oq             |   4 +-
 8 files changed, 410 insertions(+), 87 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/29030d8c/core/src/main/java/org/apache/calcite/rel/core/Filter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Filter.java b/core/src/main/java/org/apache/calcite/rel/core/Filter.java
index 0dc3009..4b6ebfa 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Filter.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Filter.java
@@ -26,12 +26,17 @@ import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelWriter;
 import org.apache.calcite.rel.SingleRel;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
+import org.apache.calcite.rex.RexCall;
 import org.apache.calcite.rex.RexChecker;
+import org.apache.calcite.rex.RexCorrelVariable;
 import org.apache.calcite.rex.RexLocalRef;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexProgram;
 import org.apache.calcite.rex.RexShuttle;
 import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.rex.RexVisitor;
+import org.apache.calcite.rex.RexVisitorImpl;
+import org.apache.calcite.util.Util;
 
 import com.google.common.collect.ImmutableList;
 
@@ -110,6 +115,29 @@ public abstract class Filter extends SingleRel {
     return condition;
   }
 
+  /**
+   * Check if any of the operands of the filter contains a
+   * correlation variable
+   */
+  public boolean hasCorrelation() {
+    if (condition instanceof RexCall) {
+      try {
+        RexVisitor<Void> visitor =
+            new RexVisitorImpl<Void>(true) {
+              public Void visitCorrelVariable(RexCorrelVariable var) {
+                throw new Util.FoundOne(var);
+              }
+            };
+        condition.accept(visitor);
+        return false;
+      } catch (Util.FoundOne e) {
+        Util.swallow(e,  null);
+        return true;
+      }
+    }
+    return false;
+  }
+
   @Override public boolean isValid(boolean fail) {
     if (RexUtil.isNullabilityCast(getCluster().getTypeFactory(), condition)) {
       assert !fail : "Cast for just nullability not allowed";

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/29030d8c/core/src/main/java/org/apache/calcite/rel/rules/FilterCorrelateRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterCorrelateRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterCorrelateRule.java
new file mode 100644
index 0000000..f156ec0
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterCorrelateRule.java
@@ -0,0 +1,138 @@
+/*
+ * 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.rel.rules;
+
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Correlate;
+import org.apache.calcite.rel.core.Filter;
+import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.core.RelFactories;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexUtil;
+
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Planner rule that pushes filters above Correlate node into the children of the Correlate.
+ */
+public class FilterCorrelateRule extends RelOptRule {
+
+  public static final FilterCorrelateRule INSTANCE =
+      new FilterCorrelateRule(RelFactories.DEFAULT_FILTER_FACTORY,
+          RelFactories.DEFAULT_PROJECT_FACTORY);
+
+  private final RelFactories.FilterFactory filterFactory;
+
+  private final RelFactories.ProjectFactory projectFactory;
+
+  //~ Constructors -----------------------------------------------------------
+
+  /**
+   * Creates a FilterCorrelateRule with an explicit root operand and
+   * factories.
+   */
+  public FilterCorrelateRule(RelFactories.FilterFactory filterFactory,
+      RelFactories.ProjectFactory projectFactory) {
+    super(
+        operand(Filter.class,
+            operand(Correlate.class, RelOptRule.any())),
+        "FilterCorrelateRule");
+    this.filterFactory = filterFactory;
+    this.projectFactory = projectFactory;
+  }
+
+  //~ Methods ----------------------------------------------------------------
+
+  public void onMatch(RelOptRuleCall call) {
+    Filter filter = call.rel(0);
+    Correlate corr = call.rel(1);
+
+    if (filter == null) {
+      return;
+    }
+
+    final List<RexNode> aboveFilters =
+        filter != null
+            ? RelOptUtil.conjunctions(filter.getCondition())
+            : Lists.<RexNode>newArrayList();
+
+    List<RexNode> leftFilters = new ArrayList<RexNode>();
+    List<RexNode> rightFilters = new ArrayList<RexNode>();
+
+    // Try to push down above filters. These are typically where clause
+    // filters. They can be pushed down if they are not on the NULL
+    // generating side.
+    RelOptUtil.classifyFilters(
+        corr,
+        aboveFilters,
+        JoinRelType.INNER,
+        false,
+        !corr.getJoinType().toJoinType().generatesNullsOnLeft(),
+        !corr.getJoinType().toJoinType().generatesNullsOnRight(),
+        aboveFilters,
+        leftFilters,
+        rightFilters);
+
+    if (leftFilters.isEmpty()
+        && rightFilters.isEmpty()) {
+      // no filters got pushed
+      return;
+    }
+
+    // create FilterRels on top of the children if any filters were
+    // pushed to them
+    final RexBuilder rexBuilder = corr.getCluster().getRexBuilder();
+    RelNode leftRel =
+        RelOptUtil.createFilter(corr.getLeft(), leftFilters, filterFactory);
+    RelNode rightRel =
+        RelOptUtil.createFilter(corr.getRight(), rightFilters, filterFactory);
+
+    // create the new LogicalCorrelate rel
+    List<RelNode> corrInputs = Lists.newArrayList();
+    corrInputs.add(leftRel);
+    corrInputs.add(rightRel);
+
+    RelNode newCorrRel = corr.copy(corr.getTraitSet(), corrInputs);
+
+    call.getPlanner().onCopy(corr, newCorrRel);
+
+    if (!leftFilters.isEmpty()) {
+      call.getPlanner().onCopy(filter, leftRel);
+    }
+    if (!rightFilters.isEmpty()) {
+      call.getPlanner().onCopy(filter, rightRel);
+    }
+
+    // create a LogicalFilter on top of the join if needed
+    RelNode newRel =
+        RelOptUtil.createFilter(newCorrRel,
+            RexUtil.fixUp(rexBuilder, aboveFilters, newCorrRel.getRowType()),
+            filterFactory);
+
+    call.transformTo(newRel);
+  }
+
+}
+
+// End FilterCorrelateRule.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/29030d8c/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
index ff20f5a..ff006a9 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
@@ -86,6 +86,13 @@ public class FilterProjectTransposeRule extends RelOptRule {
       return;
     }
 
+    if (filter.hasCorrelation()) {
+      // If there is a correlation condition anywhere in the filter, don't
+      // push this filter past project since in some cases it can prevent a
+      // Correlate from being decorrelated
+      return;
+    }
+
     // convert the filter to one that references the child of the project
     RexNode newCondition =
         RelOptUtil.pushPastProject(filter.getCondition(), project);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/29030d8c/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
index 627c5b0..80767c2 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
@@ -44,7 +44,11 @@ import org.apache.calcite.rel.logical.LogicalJoin;
 import org.apache.calcite.rel.logical.LogicalProject;
 import org.apache.calcite.rel.logical.LogicalSort;
 import org.apache.calcite.rel.metadata.RelMdUtil;
+import org.apache.calcite.rel.rules.FilterAggregateTransposeRule;
+import org.apache.calcite.rel.rules.FilterCorrelateRule;
 import org.apache.calcite.rel.rules.FilterJoinRule;
+import org.apache.calcite.rel.rules.FilterProjectTransposeRule;
+import org.apache.calcite.rel.rules.ProjectMergeRule;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeField;
@@ -219,6 +223,8 @@ public class RelDecorrelator implements ReflectiveVisitor {
         .addRuleInstance(new AdjustProjectForCountAggregateRule(false))
         .addRuleInstance(new AdjustProjectForCountAggregateRule(true))
         .addRuleInstance(FilterJoinRule.FILTER_ON_JOIN)
+        .addRuleInstance(FilterProjectTransposeRule.INSTANCE)
+        .addRuleInstance(FilterCorrelateRule.INSTANCE)
         .build();
 
     HepPlanner planner = createPlanner(program);
@@ -234,8 +240,21 @@ public class RelDecorrelator implements ReflectiveVisitor {
     decorrelateVisitor.visit(root, 0, null);
 
     if (mapOldToNewRel.containsKey(root)) {
-      // has been rewritten
-      return mapOldToNewRel.get(root);
+      // has been rewritten; apply rules post-decorrelation
+      HepProgram program2 = HepProgram.builder()
+          .addRuleInstance(FilterJoinRule.FILTER_ON_JOIN)
+          .addRuleInstance(FilterJoinRule.JOIN)
+          .build();
+
+      HepPlanner planner2 = createPlanner(program2);
+
+      RelNode newroot = mapOldToNewRel.get(root);
+      // planner.setRoot(newroot);
+      planner2.setRoot(newroot);
+      // newroot = planner.findBestExp();
+      newroot = planner2.findBestExp();
+
+      return newroot;
     } else {
       // not rewritten
       return root;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/29030d8c/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
index 3a08601..cb0310c 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
@@ -1345,6 +1345,45 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
   }
 
   /**
+   * Test case (correlated scalar aggregate subquery) for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-714">[CALCITE-714]
+   * When de-correlating, push join condition into subquery</a>.
+   */
+  @Test public void testCorrelationScalarAggAndFilter() {
+    tester.withDecorrelation(true).assertConvertsTo(
+       "SELECT e1.empno FROM emp e1, dept d1 where e1.deptno = d1.deptno\n"
+       + "and e1.deptno < 10 and d1.deptno < 15\n"
+       + "and e1.sal > (select avg(sal) from emp e2 where e1.empno = e2.empno)",
+       "${plan}");
+  }
+
+  /**
+   * Test case (correlated EXISTS subquery) for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-714">[CALCITE-714]
+   * When de-correlating, push join condition into subquery</a>.
+   */
+  @Test public void testCorrelationExistsAndFilter() {
+    tester.withDecorrelation(true).assertConvertsTo(
+       "SELECT e1.empno FROM emp e1, dept d1 where e1.deptno = d1.deptno\n"
+       + "and e1.deptno < 10 and d1.deptno < 15\n"
+       + "and exists (select * from emp e2 where e1.empno = e2.empno)",
+       "${plan}");
+  }
+
+  /**
+   * Test case (correlated NOT EXISTS subquery) for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-714">[CALCITE-714]
+   * When de-correlating, push join condition into subquery</a>.
+   */
+  @Test public void testCorrelationNotExistsAndFilter() {
+    tester.withDecorrelation(true).assertConvertsTo(
+       "SELECT e1.empno FROM emp e1, dept d1 where e1.deptno = d1.deptno\n"
+       + "and e1.deptno < 10 and d1.deptno < 15\n"
+       + "and not exists (select * from emp e2 where e1.empno = e2.empno)",
+       "${plan}");
+  }
+
+  /**
    * Visitor that checks that every {@link RelNode} in a tree is valid.
    *
    * @see RelNode#isValid(boolean)

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/29030d8c/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index 044b6b2..04d0fe2 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -2791,37 +2791,33 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
         <Resource name="planBefore">
             <![CDATA[
 LogicalProject(DEPTNO=[$0], NAME=[$1])
-  LogicalProject(DEPTNO=[$0], NAME=[$1], $f0=[$3])
-    LogicalFilter(condition=[IS NOT NULL($3)])
-      LogicalJoin(condition=[=($0, $2)], joinType=[left])
-        LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
-        LogicalAggregate(group=[{0}], agg#0=[MIN($1)])
-          LogicalProject(DEPTNO0=[$2], $f0=[true])
-            LogicalFilter(condition=[AND(=($1, $2), >($0, 100))])
-              LogicalJoin(condition=[true], joinType=[inner])
-                LogicalProject(SAL=[$5], DEPTNO=[$7])
-                  LogicalTableScan(table=[[CATALOG, SALES, EMP]])
-                LogicalAggregate(group=[{0}])
-                  LogicalProject(DEPTNO=[$0])
-                    LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+  LogicalJoin(condition=[=($0, $2)], joinType=[inner])
+    LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+    LogicalAggregate(group=[{0}])
+      LogicalProject(DEPTNO0=[$2], $f0=[true])
+        LogicalJoin(condition=[=($1, $2)], joinType=[inner])
+          LogicalProject(SAL=[$5], DEPTNO=[$7])
+            LogicalFilter(condition=[>($5, 100)])
+              LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+          LogicalAggregate(group=[{0}])
+            LogicalProject(DEPTNO=[$0])
+              LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
 ]]>
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
 LogicalProject(DEPTNO=[$0], NAME=[$1])
-  LogicalProject(DEPTNO=[$0], NAME=[$1], $f0=[$3])
-    LogicalProject(DEPTNO=[$0], NAME=[$1], DEPTNO0=[CAST($2):INTEGER], $f1=[CAST($3):BOOLEAN])
-      LogicalJoin(condition=[=($0, $2)], joinType=[inner])
-        LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
-        LogicalAggregate(group=[{0}], agg#0=[MIN($1)])
-          LogicalProject(DEPTNO0=[$2], $f0=[true])
-            LogicalJoin(condition=[=($1, $2)], joinType=[inner])
-              LogicalFilter(condition=[>($0, 100)])
-                LogicalProject(SAL=[$5], DEPTNO=[$7])
-                  LogicalTableScan(table=[[CATALOG, SALES, EMP]])
-              LogicalAggregate(group=[{0}])
-                LogicalProject(DEPTNO=[$0])
-                  LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+  LogicalJoin(condition=[=($0, $2)], joinType=[inner])
+    LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+    LogicalAggregate(group=[{0}])
+      LogicalProject(DEPTNO0=[$2], $f0=[true])
+        LogicalJoin(condition=[=($1, $2)], joinType=[inner])
+          LogicalProject(SAL=[$5], DEPTNO=[$7])
+            LogicalFilter(condition=[>($5, 100)])
+              LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+          LogicalAggregate(group=[{0}])
+            LogicalProject(DEPTNO=[$0])
+              LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
 ]]>
         </Resource>
     </TestCase>
@@ -2837,11 +2833,11 @@ LogicalProject(DEPTNO=[$0], NAME=[$1])
 LogicalProject(DEPTNO=[$0], NAME=[$1])
   LogicalJoin(condition=[=($0, $2)], joinType=[inner])
     LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
-    LogicalAggregate(group=[{0}], agg#0=[MIN($1)])
+    LogicalAggregate(group=[{0}])
       LogicalProject(DEPTNO0=[$2], $f0=[true])
         LogicalJoin(condition=[=($1, $2)], joinType=[inner])
-          LogicalFilter(condition=[>($0, 100)])
-            LogicalProject(SAL=[$5], DEPTNO=[$7])
+          LogicalProject(SAL=[$5], DEPTNO=[$7])
+            LogicalFilter(condition=[>($5, 100)])
               LogicalTableScan(table=[[CATALOG, SALES, EMP]])
           LogicalAggregate(group=[{0}])
             LogicalProject(DEPTNO=[$0])
@@ -2854,8 +2850,8 @@ SemiJoin(condition=[=($0, $2)], joinType=[inner])
   LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
   LogicalProject(DEPTNO0=[$2], $f0=[true])
     LogicalJoin(condition=[=($1, $2)], joinType=[inner])
-      LogicalFilter(condition=[>($0, 100)])
-        LogicalProject(SAL=[$5], DEPTNO=[$7])
+      LogicalProject(SAL=[$5], DEPTNO=[$7])
+        LogicalFilter(condition=[>($5, 100)])
           LogicalTableScan(table=[[CATALOG, SALES, EMP]])
       LogicalAggregate(group=[{0}])
         LogicalProject(DEPTNO=[$0])

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/29030d8c/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
index fc9fe91..a9f7727 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -1367,12 +1367,11 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
   LogicalJoin(condition=[=($7, $11)], joinType=[inner])
     LogicalTableScan(table=[[CATALOG, SALES, EMP]])
     LogicalProject(DEPTNO=[$0], NAME=[$1], DEPTNO0=[$2])
-      LogicalFilter(condition=[=($2, $0)])
-        LogicalJoin(condition=[true], joinType=[inner])
-          LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
-          LogicalAggregate(group=[{0}])
-            LogicalProject(DEPTNO=[$7])
-              LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+      LogicalJoin(condition=[=($2, $0)], joinType=[inner])
+        LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+        LogicalAggregate(group=[{0}])
+          LogicalProject(DEPTNO=[$7])
+            LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
     </TestCase>
@@ -1416,17 +1415,17 @@ LogicalProject(D2=[$0], D3=[$1])
         <Resource name="plan">
             <![CDATA[
 LogicalProject(D2=[$0], D3=[$1])
-  LogicalFilter(condition=[IS NOT NULL($2)])
-    LogicalProject(D2=[$0], D3=[$1], $f0=[$4])
-      LogicalJoin(condition=[AND(=($0, $2), =($1, $3))], joinType=[left])
+  LogicalProject(D2=[$0], D3=[$1], $f0=[$4])
+    LogicalProject(D2=[$0], D3=[$1], D20=[CAST($2):INTEGER], D30=[$3], $f2=[CAST($4):BOOLEAN])
+      LogicalJoin(condition=[AND(=($0, $2), =($1, $3))], joinType=[inner])
         LogicalProject(D2=[+(2, $7)], D3=[+(3, $7)])
           LogicalTableScan(table=[[CATALOG, SALES, EMP]])
         LogicalAggregate(group=[{0, 1}], agg#0=[MIN($2)])
           LogicalProject(D2=[$1], D3=[$2], $f0=[$0])
             LogicalProject($f0=[true], D2=[$1], D3=[$2])
               LogicalProject(EXPR$0=[1], D2=[$3], D3=[$2])
-                LogicalFilter(condition=[AND(=($0, $3), IS NOT NULL($1))])
-                  LogicalJoin(condition=[true], joinType=[inner])
+                LogicalJoin(condition=[=($0, $3)], joinType=[inner])
+                  LogicalFilter(condition=[IS NOT NULL($1)])
                     LogicalProject(D1=[$0], $f0=[$4], D3=[$3])
                       LogicalJoin(condition=[AND(=($0, $1), =($0, $2))], joinType=[left])
                         LogicalProject(D1=[+($0, 1)])
@@ -1435,22 +1434,21 @@ LogicalProject(D2=[$0], D3=[$1])
                           LogicalProject(D1=[$1], D12=[$2], D3=[$3], $f0=[$0])
                             LogicalProject($f0=[true], D1=[$1], D12=[$2], D3=[$3])
                               LogicalProject(EXPR$0=[2], D1=[$3], D12=[$3], D3=[$4])
-                                LogicalFilter(condition=[AND(=($0, $3), =($1, $3), =($2, $4))])
+                                LogicalJoin(condition=[AND(=($0, $3), =($1, $3), =($2, $4))], joinType=[inner])
+                                  LogicalProject(D4=[+($0, 4)], D5=[+($0, 5)], D6=[+($0, 6)])
+                                    LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
                                   LogicalJoin(condition=[true], joinType=[inner])
-                                    LogicalProject(D4=[+($0, 4)], D5=[+($0, 5)], D6=[+($0, 6)])
-                                      LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
-                                    LogicalJoin(condition=[true], joinType=[inner])
-                                      LogicalAggregate(group=[{0}])
-                                        LogicalProject(D1=[+($0, 1)])
-                                          LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
-                                      LogicalAggregate(group=[{0}])
-                                        LogicalProject(D3=[$1])
-                                          LogicalProject(D2=[+(2, $7)], D3=[+(3, $7)])
-                                            LogicalTableScan(table=[[CATALOG, SALES, EMP]])
-                    LogicalAggregate(group=[{0}])
-                      LogicalProject(D2=[$0])
-                        LogicalProject(D2=[+(2, $7)], D3=[+(3, $7)])
-                          LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+                                    LogicalAggregate(group=[{0}])
+                                      LogicalProject(D1=[+($0, 1)])
+                                        LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+                                    LogicalAggregate(group=[{0}])
+                                      LogicalProject(D3=[$1])
+                                        LogicalProject(D2=[+(2, $7)], D3=[+(3, $7)])
+                                          LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+                  LogicalAggregate(group=[{0}])
+                    LogicalProject(D2=[$0])
+                      LogicalProject(D2=[+(2, $7)], D3=[+(3, $7)])
+                        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
     </TestCase>
@@ -1464,26 +1462,24 @@ where exists (
         <Resource name="plan">
             <![CDATA[
 LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
-  LogicalFilter(condition=[IS NOT NULL($9)])
-    LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], $f0=[$11])
-      LogicalJoin(condition=[AND(=($7, $9), =($7, $10))], joinType=[left])
+  LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], $f0=[$11])
+    LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO1=[CAST($9):INTEGER], DEPTNO0=[CAST($10):INTEGER], $f2=[CAST($11):BOOLEAN])
+      LogicalJoin(condition=[AND(=($7, $9), =($7, $10))], joinType=[inner])
         LogicalTableScan(table=[[CATALOG, SALES, EMP]])
         LogicalAggregate(group=[{0, 1}], agg#0=[MIN($2)])
           LogicalProject(DEPTNO1=[$1], DEPTNO0=[$2], $f0=[$0])
             LogicalProject($f0=[true], DEPTNO1=[$1], DEPTNO0=[$2])
               LogicalProject(EXPR$0=[1], DEPTNO1=[$3], DEPTNO0=[$2])
-                LogicalFilter(condition=[<=($0, $3)])
-                  LogicalJoin(condition=[true], joinType=[inner])
-                    LogicalProject(DEPTNO=[$0], NAME=[$1], DEPTNO0=[$2])
-                      LogicalFilter(condition=[>=($0, $2)])
-                        LogicalJoin(condition=[true], joinType=[inner])
-                          LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
-                          LogicalAggregate(group=[{0}])
-                            LogicalProject(DEPTNO=[$7])
-                              LogicalTableScan(table=[[CATALOG, SALES, EMP]])
-                    LogicalAggregate(group=[{0}])
-                      LogicalProject(DEPTNO=[$7])
-                        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+                LogicalJoin(condition=[<=($0, $3)], joinType=[inner])
+                  LogicalProject(DEPTNO=[$0], NAME=[$1], DEPTNO0=[$2])
+                    LogicalJoin(condition=[>=($0, $2)], joinType=[inner])
+                      LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+                      LogicalAggregate(group=[{0}])
+                        LogicalProject(DEPTNO=[$7])
+                          LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+                  LogicalAggregate(group=[{0}])
+                    LogicalProject(DEPTNO=[$7])
+                      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
     </TestCase>
@@ -1494,20 +1490,19 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
         <Resource name="plan">
             <![CDATA[
 LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
-  LogicalFilter(condition=[IS NOT NULL($9)])
-    LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], $f0=[$10])
-      LogicalJoin(condition=[=($7, $9)], joinType=[left])
+  LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], $f0=[$10])
+    LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[CAST($9):INTEGER], $f1=[CAST($10):BOOLEAN])
+      LogicalJoin(condition=[=($7, $9)], joinType=[inner])
         LogicalTableScan(table=[[CATALOG, SALES, EMP]])
         LogicalAggregate(group=[{0}], agg#0=[MIN($1)])
           LogicalProject(DEPTNO0=[$1], $f0=[$0])
             LogicalProject($f0=[true], DEPTNO0=[$1])
               LogicalProject(EXPR$0=[1], DEPTNO0=[$2])
-                LogicalFilter(condition=[=($2, $0)])
-                  LogicalJoin(condition=[true], joinType=[inner])
-                    LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
-                    LogicalAggregate(group=[{0}])
-                      LogicalProject(DEPTNO=[$7])
-                        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+                LogicalJoin(condition=[=($2, $0)], joinType=[inner])
+                  LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+                  LogicalAggregate(group=[{0}])
+                    LogicalProject(DEPTNO=[$7])
+                      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
     </TestCase>
@@ -1539,8 +1534,8 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
         <Resource name="plan">
             <![CDATA[
 LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
-  LogicalFilter(condition=[IS NOT NULL($9)])
-    LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], $f0=[$9])
+  LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], $f0=[$9])
+    LogicalFilter(condition=[IS NOT NULL($9)])
       LogicalCorrelate(correlation=[$cor0], joinType=[LEFT], requiredColumns=[{7}])
         LogicalTableScan(table=[[CATALOG, SALES, EMP]])
         LogicalAggregate(group=[{}], agg#0=[MIN($0)])
@@ -2414,4 +2409,105 @@ LogicalAggregate(group=[{0}], EMPID=[MIN($1)])
 ]]>
         </Resource>
     </TestCase>
+
+    <TestCase name="testCorrelationScalarAggAndFilter">
+        <Resource name="sql">
+            <![CDATA[SELECT e1.empno FROM emp e1, dept d1 where e1.deptno = d1.deptno
+     and e1.deptno < 10 and d1.deptno < 15
+     and e1.sal > (select avg(sal) from emp e2 where e1.empno = e2.empno)]]>
+        </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalProject(EMPNO=[$0])
+  LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$9], NAME=[$10], EXPR$0=[$12])
+    LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$9], NAME=[$10], EMPNO0=[CAST($11):INTEGER], EXPR$0=[CAST($12):INTEGER])
+      LogicalJoin(condition=[AND(=($0, $11), >($5, $12))], joinType=[inner])
+        LogicalJoin(condition=[=($7, $9)], joinType=[inner])
+          LogicalFilter(condition=[<($7, 10)])
+            LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+          LogicalFilter(condition=[<($0, 15)])
+            LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+        LogicalAggregate(group=[{0}], EXPR$0=[AVG($1)])
+          LogicalProject(EMPNO0=[$1], SAL=[$0])
+            LogicalProject(SAL=[$5], EMPNO0=[$9])
+              LogicalJoin(condition=[=($9, $0)], joinType=[inner])
+                LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+                LogicalAggregate(group=[{0}])
+                  LogicalProject(EMPNO=[$0])
+                    LogicalJoin(condition=[=($7, $9)], joinType=[inner])
+                      LogicalFilter(condition=[<($7, 10)])
+                        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+                      LogicalFilter(condition=[<($0, 15)])
+                        LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+        </Resource>
+    </TestCase>
+
+    <TestCase name="testCorrelationExistsAndFilter">
+        <Resource name="sql">
+            <![CDATA[SELECT e1.empno FROM emp e1, dept d1 where e1.deptno = d1.deptno
+     and e1.deptno < 10 and d1.deptno < 15
+     and exists (select * from emp e2 where e1.empno = e2.empno)]]>
+        </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalProject(EMPNO=[$0])
+  LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$9], NAME=[$10], $f0=[$12])
+    LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$9], NAME=[$10], EMPNO0=[CAST($11):INTEGER], $f1=[CAST($12):BOOLEAN])
+      LogicalJoin(condition=[=($0, $11)], joinType=[inner])
+        LogicalJoin(condition=[=($7, $9)], joinType=[inner])
+          LogicalFilter(condition=[<($7, 10)])
+            LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+          LogicalFilter(condition=[<($0, 15)])
+            LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+        LogicalAggregate(group=[{0}], agg#0=[MIN($1)])
+          LogicalProject(EMPNO0=[$1], $f0=[$0])
+            LogicalProject($f0=[true], EMPNO0=[$9])
+              LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], EMPNO0=[$9])
+                LogicalJoin(condition=[=($9, $0)], joinType=[inner])
+                  LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+                  LogicalAggregate(group=[{0}])
+                    LogicalProject(EMPNO=[$0])
+                      LogicalJoin(condition=[=($7, $9)], joinType=[inner])
+                        LogicalFilter(condition=[<($7, 10)])
+                          LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+                        LogicalFilter(condition=[<($0, 15)])
+                          LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+        </Resource>
+    </TestCase>
+
+    <TestCase name="testCorrelationNotExistsAndFilter">
+        <Resource name="sql">
+            <![CDATA[SELECT e1.empno FROM emp e1, dept d1 where e1.deptno = d1.deptno
+     and e1.deptno < 10 and d1.deptno < 15
+     and not exists (select * from emp e2 where e1.empno = e2.empno)]]>
+        </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalProject(EMPNO=[$0])
+  LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$9], NAME=[$10], $f0=[$12])
+    LogicalFilter(condition=[NOT(IS NOT NULL($12))])
+      LogicalJoin(condition=[=($0, $11)], joinType=[left])
+        LogicalJoin(condition=[=($7, $9)], joinType=[inner])
+          LogicalFilter(condition=[<($7, 10)])
+            LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+          LogicalFilter(condition=[<($0, 15)])
+            LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+        LogicalAggregate(group=[{0}], agg#0=[MIN($1)])
+          LogicalProject(EMPNO0=[$1], $f0=[$0])
+            LogicalProject($f0=[true], EMPNO0=[$9])
+              LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], EMPNO0=[$9])
+                LogicalJoin(condition=[=($9, $0)], joinType=[inner])
+                  LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+                  LogicalAggregate(group=[{0}])
+                    LogicalProject(EMPNO=[$0])
+                      LogicalJoin(condition=[=($7, $9)], joinType=[inner])
+                        LogicalFilter(condition=[<($7, 10)])
+                          LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+                        LogicalFilter(condition=[<($0, 15)])
+                          LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+        </Resource>
+    </TestCase>
 </Root>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/29030d8c/core/src/test/resources/sql/misc.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/misc.oq b/core/src/test/resources/sql/misc.oq
index 1d1bd57..9bb8e58 100644
--- a/core/src/test/resources/sql/misc.oq
+++ b/core/src/test/resources/sql/misc.oq
@@ -240,9 +240,9 @@ where exists (
 (3 rows)
 
 !ok
-EnumerableSemiJoin(condition=[=($1, $5)], joinType=[inner])
+EnumerableSemiJoin(condition=[=($1, $6)], joinType=[inner])
   EnumerableTableScan(table=[[hr, emps]])
-  EnumerableCalc(expr#0..4=[{inputs}], expr#5=[true], deptno0=[$t0], $f0=[$t5])
+  EnumerableCalc(expr#0..4=[{inputs}], expr#5=[true], $f0=[$t5], deptno0=[$t0])
     EnumerableJoin(condition=[=($0, $1)], joinType=[inner])
       EnumerableAggregate(group=[{1}])
         EnumerableTableScan(table=[[hr, emps]])



[04/50] incubator-calcite git commit: Re-enable a test; fix some code formatting; fix Windows line endings

Posted by jh...@apache.org.
Re-enable a test; fix some code formatting; fix Windows line endings


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

Branch: refs/heads/branch-release
Commit: 830afef0484e7b59de01331c2305a33c20df152e
Parents: 03111d2
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Jul 7 17:34:58 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jul 9 10:28:40 2015 -0700

----------------------------------------------------------------------
 .../org/apache/calcite/plan/RelOptUtil.java     |  9 ++----
 .../org/apache/calcite/runtime/FlatLists.java   |  4 +--
 .../java/org/apache/calcite/test/JdbcTest.java  | 12 ++++----
 .../org/apache/calcite/test/RelBuilderTest.java |  8 +++---
 .../calcite/adapter/mongodb/MongoTable.java     | 29 +++++++++++---------
 5 files changed, 30 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/830afef0/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
index 5436e20..5aa2177 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -2820,12 +2820,9 @@ public abstract class RelOptUtil {
    *
    * <p>Optimizes if the fields are the identity projection.
    *
-   * @param factory
-   *          ProjectFactory
-   * @param child
-   *          Input relational expression
-   * @param posList
-   *          Source of each projected field
+   * @param factory ProjectFactory
+   * @param child Input relational expression
+   * @param posList Source of each projected field
    * @return Relational expression that projects given fields
    */
   public static RelNode createProject(final RelFactories.ProjectFactory factory,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/830afef0/core/src/main/java/org/apache/calcite/runtime/FlatLists.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/FlatLists.java b/core/src/main/java/org/apache/calcite/runtime/FlatLists.java
index c2c887f..47915e7 100644
--- a/core/src/main/java/org/apache/calcite/runtime/FlatLists.java
+++ b/core/src/main/java/org/apache/calcite/runtime/FlatLists.java
@@ -219,7 +219,7 @@ public class FlatLists {
    *
    * <p>The list is created via {@link FlatLists#of}.
    *
-   * @param <T>
+   * @param <T> Element type
    */
   protected static class Flat2List<T>
       extends AbstractFlatList<T>
@@ -346,7 +346,7 @@ public class FlatLists {
    *
    * <p>The list is created via {@link FlatLists#of(java.util.List)}.
    *
-   * @param <T>
+   * @param <T> Element type
    */
   protected static class Flat3List<T>
       extends AbstractFlatList<T>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/830afef0/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index 9bee267..658619d 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -3379,20 +3379,18 @@ public class JdbcTest {
   }
 
   /** Tests sorting by a column that is already sorted. */
-  @Ignore("fix output for timezone")
   @Test public void testOrderByOnSortedTable2() {
     CalciteAssert.that()
         .with(CalciteAssert.Config.FOODMART_CLONE)
         .query("select \"time_id\", \"the_date\" from \"time_by_day\"\n"
             + "where \"time_id\" < 370\n"
             + "order by \"time_id\"")
-        .returns("time_id=367; the_date=1997-01-01 00:00:00.0\n"
-            + "time_id=368; the_date=1997-01-02 00:00:00.0\n"
-            + "time_id=369; the_date=1997-01-03 00:00:00.0\n")
+        .returns("time_id=367; the_date=1997-01-01 00:00:00\n"
+            + "time_id=368; the_date=1997-01-02 00:00:00\n"
+            + "time_id=369; the_date=1997-01-03 00:00:00\n")
         .explainContains(""
-            + "PLAN=EnumerableSort(sort0=[$0], dir0=[ASC])\n"
-            + "  EnumerableCalc(expr#0..9=[{inputs}], expr#10=[370], expr#11=[<($t0, $t10)], proj#0..1=[{exprs}], $condition=[$t11])\n"
-            + "    EnumerableTableScan(table=[[foodmart2, time_by_day]])\n\n");
+            + "PLAN=EnumerableCalc(expr#0..9=[{inputs}], expr#10=[370], expr#11=[<($t0, $t10)], proj#0..1=[{exprs}], $condition=[$t11])\n"
+            + "  EnumerableTableScan(table=[[foodmart2, time_by_day]])\n\n");
   }
 
   @Test public void testWithInsideWhereExists() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/830afef0/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
index 0474590..abf85bb 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -642,13 +642,13 @@ public class RelBuilderTest {
     final String expected = ""
         + "LogicalSort(sort0=[$7], dir0=[DESC], fetch=[10])\n"
         + "  LogicalTableScan(table=[[scott, EMP]])\n";
-    assertThat(RelOptUtil.toString(root), is(expected));
+    assertThat(str(root), is(expected));
 
     final RelNode root2 =
         builder.scan("EMP")
             .sortLimit(-1, 10, builder.desc(builder.field("DEPTNO")))
             .build();
-    assertThat(RelOptUtil.toString(root2), is(expected));
+    assertThat(str(root2), is(expected));
   }
 
   /** Tests that a sort on an expression followed by a limit gives the same
@@ -668,7 +668,7 @@ public class RelBuilderTest {
         + "  LogicalSort(sort0=[$3], dir0=[DESC], offset=[3], fetch=[10])\n"
         + "    LogicalProject(DEPTNO=[$0], DNAME=[$1], LOC=[$2], $f3=[+($0, 1)])\n"
         + "      LogicalTableScan(table=[[scott, DEPT]])\n";
-    assertThat(RelOptUtil.toString(root), is(expected));
+    assertThat(str(root), is(expected));
 
     final RelNode root2 =
         builder.scan("DEPT")
@@ -677,7 +677,7 @@ public class RelBuilderTest {
                     builder.call(SqlStdOperatorTable.PLUS,
                         builder.field("DEPTNO"), builder.literal(1))))
             .build();
-    assertThat(RelOptUtil.toString(root2), is(expected));
+    assertThat(str(root2), is(expected));
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/830afef0/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoTable.java
----------------------------------------------------------------------
diff --git a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoTable.java b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoTable.java
index 2c362a3..af8d80c 100644
--- a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoTable.java
+++ b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoTable.java
@@ -189,28 +189,31 @@ public class MongoTable extends AbstractQueryableTable
     };
   }
 
-  /** Helper method to strip non-numerics from a string
+  /** Helper method to strip non-numerics from a string.
+   *
    * <p>Currently used to determine mongod versioning numbers
-   * from buildInfo.versionArray for use in aggregate method logic</p>
-   * @param valueString
-   * @return Integer */
+   * from buildInfo.versionArray for use in aggregate method logic. */
   private static Integer parseIntString(String valueString) {
     return Integer.parseInt(valueString.replaceAll("[^0-9]", ""));
   }
 
   /** Executes an "aggregate" operation for pre-2.6 mongo servers.
+   *
    * <p>Return document is limited to 4M or 16M in size depending on
-   * version of mongo <p>Helper method for
-   * {@link org.apache.calcite.adapter.mongodb.MongoTable#aggregate}
-   * </p>
-   * @param dbCollection
-   * @param first the first aggregate action
-   * @param rest the rest of the aggregate actions
-   * @return AggregationOutput */
+   * version of mongo.
+
+   * <p>Helper method for
+   * {@link org.apache.calcite.adapter.mongodb.MongoTable#aggregate}.
+   *
+   * @param dbCollection Collection
+   * @param first First aggregate action
+   * @param rest Rest of the aggregate actions
+   * @return Aggregation output
+   */
   private AggregationOutput aggregateOldWay(DBCollection dbCollection,
        DBObject first, List<DBObject> rest) {
-    return dbCollection.aggregate(first, rest
-          .toArray(new DBObject[rest.size()]));
+    return dbCollection.aggregate(first,
+       rest.toArray(new DBObject[rest.size()]));
   }
 
   /** Implementation of {@link org.apache.calcite.linq4j.Queryable} based on


[09/50] incubator-calcite git commit: [CALCITE-774] When GROUP BY is present, ensure that window function operands only refer to GROUP BY keys (Hsuan-Yi Chu)

Posted by jh...@apache.org.
[CALCITE-774] When GROUP BY is present, ensure that window function operands only refer to GROUP BY keys (Hsuan-Yi Chu)

Close apache/incubator-calcite#101


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

Branch: refs/heads/branch-release
Commit: e51f853f3461a4e3f0a74b8d83cfc01e39b3f5db
Parents: 92f32e8
Author: Hsuan-Yi Chu <hs...@usc.edu>
Authored: Fri Jun 26 08:42:46 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Jul 13 15:48:31 2015 -0700

----------------------------------------------------------------------
 .../org/apache/calcite/sql/validate/AggChecker.java   |  7 +++++++
 .../org/apache/calcite/test/SqlValidatorTest.java     | 14 ++++++++++++++
 2 files changed, 21 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e51f853f/core/src/main/java/org/apache/calcite/sql/validate/AggChecker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/AggChecker.java b/core/src/main/java/org/apache/calcite/sql/validate/AggChecker.java
index f8c2776..39a7f3c 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/AggChecker.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/AggChecker.java
@@ -148,6 +148,13 @@ class AggChecker extends SqlBasicVisitor<Void> {
       call.operand(0).accept(this);
       return null;
     }
+    // Visit the operand in window function
+    if (call.getOperator().getKind() == SqlKind.OVER) {
+      SqlCall windowFunction = (SqlCall) call.operand(0);
+      if (windowFunction.getOperandList().size() != 0) {
+        windowFunction.operand(0).accept(this);
+      }
+    }
     if (isGroupExpr(call)) {
       // This call matches an expression in the GROUP BY clause.
       return null;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e51f853f/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index 811343b..cc8153e 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -3986,6 +3986,20 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
             "RANK or DENSE_RANK functions require ORDER BY clause in window specification");
   }
 
+  @Test public void testInvalidWindowFunctionWithGroupBy() {
+    sql("select max(^empno^) over () from emp\n"
+        + "group by deptno")
+        .fails("Expression 'EMPNO' is not being grouped");
+
+    sql("select max(deptno) over (partition by ^empno^) from emp\n"
+        + "group by deptno")
+        .fails("Expression 'EMPNO' is not being grouped");
+
+    sql("select rank() over (order by ^empno^) from emp\n"
+        + "group by deptno")
+        .fails("Expression 'EMPNO' is not being grouped");
+  }
+
   @Test public void testInlineWinDef() {
     // the <window specification> used by windowed agg functions is
     // fully defined in SQL 03 Std. section 7.1 <window clause>


[41/50] incubator-calcite git commit: [CALCITE-833] RelOptUtil.splitJoinCondition incorrectly splits a join condition (Hsuan-Yi Chu)

Posted by jh...@apache.org.
[CALCITE-833] RelOptUtil.splitJoinCondition incorrectly splits a join condition (Hsuan-Yi Chu)

Close apache/incubator-calcite#119


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

Branch: refs/heads/branch-release
Commit: a61be0db744081af4c375fb0dcbae4a95041ff9d
Parents: e827bf0
Author: Hsuan-Yi Chu <hs...@usc.edu>
Authored: Sun Aug 9 16:44:26 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Aug 10 20:47:36 2015 -0700

----------------------------------------------------------------------
 .../org/apache/calcite/plan/RelOptUtil.java     |  4 +-
 .../apache/calcite/test/RexTransformerTest.java | 42 ++++++++++++++++++++
 2 files changed, 43 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/a61be0db/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
index 04733cf..76af520 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -1111,9 +1111,7 @@ public abstract class RelOptUtil {
 
         boolean foundInput = false;
         for (int i = 0; i < inputs.size() && !foundInput; i++) {
-          final int lowerLimit = inputsRange[i].nextSetBit(0);
-          final int upperLimit = inputsRange[i].length();
-          if (projRefs.nextSetBit(lowerLimit) < upperLimit) {
+          if (inputsRange[i].contains(projRefs)) {
             leftInput = i;
             leftFields = inputs.get(leftInput).getRowType().getFieldList();
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/a61be0db/core/src/test/java/org/apache/calcite/test/RexTransformerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RexTransformerTest.java b/core/src/test/java/org/apache/calcite/test/RexTransformerTest.java
index 2242f9c..b7ea814 100644
--- a/core/src/test/java/org/apache/calcite/test/RexTransformerTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexTransformerTest.java
@@ -17,8 +17,12 @@
 package org.apache.calcite.test;
 
 import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.logical.LogicalJoin;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.rel.type.RelDataTypeSystem;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexInputRef;
@@ -33,6 +37,8 @@ import org.junit.Before;
 import org.junit.Test;
 
 import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertFalse;
@@ -57,6 +63,13 @@ public class RexTransformerTest {
 
   //~ Methods ----------------------------------------------------------------
 
+  /** Converts a SQL string to a relational expression using mock schema. */
+  private static RelNode toRel(String sql) {
+    final SqlToRelTestBase test = new SqlToRelTestBase() {
+    };
+    return test.createTester().convertSqlToRel(sql);
+  }
+
   @Before public void setUp() {
     typeFactory = new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
     rexBuilder = new RexBuilder(typeFactory);
@@ -352,6 +365,35 @@ public class RexTransformerTest {
         is("DECIMAL(6, 7) NOT NULL"));
     assertThat(literal3.getValue().toString(), is("0.0123456"));
   }
+
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-833">[CALCITE-833]
+   * RelOptUtil.splitJoinCondition attempts to split a Join-Condition which
+   * has a remaining condition</a>. */
+  @Test public void testSplitJoinCondition() {
+    final String sql = "select * \n"
+        + "from emp a \n"
+        + "INNER JOIN dept b \n"
+        + "ON CAST(a.empno AS int) <> b.deptno";
+
+    final RelNode relNode = toRel(sql);
+    final LogicalJoin join = (LogicalJoin) relNode.getInput(0);
+    final List<RexNode> leftJoinKeys = new ArrayList<>();
+    final List<RexNode> rightJoinKeys = new ArrayList<>();
+    final ArrayList<RelDataTypeField> sysFieldList = new ArrayList<>();
+    final RexNode remaining = RelOptUtil.splitJoinCondition(sysFieldList,
+        join.getInputs().get(0),
+        join.getInputs().get(1),
+        join.getCondition(),
+        leftJoinKeys,
+        rightJoinKeys,
+        null,
+        null);
+
+    assertThat(remaining.toString(), is("<>(CAST($0):INTEGER NOT NULL, $9)"));
+    assertThat(leftJoinKeys.isEmpty(), is(true));
+    assertThat(rightJoinKeys.isEmpty(), is(true));
+  }
 }
 
 // End RexTransformerTest.java


[10/50] incubator-calcite git commit: [CALCITE-795] Loss of precision when sending a decimal number via the remote JSON service (Lukáš Lalinský)

Posted by jh...@apache.org.
[CALCITE-795] Loss of precision when sending a decimal number via the remote JSON service (Lukáš Lalinský)

Close apache/incubator-calcite#105


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

Branch: refs/heads/branch-release
Commit: efecdade5efa8155ca20a7262a37944829d8f96d
Parents: e51f853
Author: Lukáš Lalinský <lu...@oxygene.sk>
Authored: Sun Jul 12 14:13:44 2015 +0200
Committer: Julian Hyde <jh...@apache.org>
Committed: Wed Jul 15 16:42:14 2015 -0700

----------------------------------------------------------------------
 .../calcite/avatica/remote/JsonService.java     |   2 +
 .../calcite/avatica/test/JsonHandlerTest.java   | 141 +++++++++++++++++++
 2 files changed, 143 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/efecdade/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java
index c2119db..5c81b7b 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java
@@ -20,6 +20,7 @@ import org.apache.calcite.avatica.ColumnMetaData;
 import org.apache.calcite.avatica.Meta;
 
 import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.ObjectMapper;
 
 import java.io.IOException;
@@ -38,6 +39,7 @@ public abstract class JsonService implements Service {
     MAPPER = new ObjectMapper();
     MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
     MAPPER.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
+    MAPPER.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
   }
 
   public JsonService() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/efecdade/avatica/src/test/java/org/apache/calcite/avatica/test/JsonHandlerTest.java
----------------------------------------------------------------------
diff --git a/avatica/src/test/java/org/apache/calcite/avatica/test/JsonHandlerTest.java b/avatica/src/test/java/org/apache/calcite/avatica/test/JsonHandlerTest.java
new file mode 100644
index 0000000..74f440c
--- /dev/null
+++ b/avatica/src/test/java/org/apache/calcite/avatica/test/JsonHandlerTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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.avatica.test;
+
+import org.apache.calcite.avatica.remote.JsonHandler;
+import org.apache.calcite.avatica.remote.JsonService;
+import org.apache.calcite.avatica.remote.LocalJsonService;
+import org.apache.calcite.avatica.remote.Service;
+import org.apache.calcite.avatica.remote.TypedValue;
+
+import org.junit.Test;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests JSON encoding/decoding in the remote service.
+ */
+public class JsonHandlerTest {
+
+  /**
+   * Implementation of {@link org.apache.calcite.avatica.remote.Service}
+   * that does nothing.
+   */
+  public static class NoopService implements Service {
+    @Override public ResultSetResponse apply(CatalogsRequest request) {
+      return null;
+    }
+
+    @Override public ResultSetResponse apply(SchemasRequest request) {
+      return null;
+    }
+
+    @Override public ResultSetResponse apply(TablesRequest request) {
+      return null;
+    }
+
+    @Override public ResultSetResponse apply(TableTypesRequest request) {
+      return null;
+    }
+
+    @Override public ResultSetResponse apply(TypeInfoRequest request) {
+      return null;
+    }
+
+    @Override public ResultSetResponse apply(ColumnsRequest request) {
+      return null;
+    }
+
+    @Override public PrepareResponse apply(PrepareRequest request) {
+      return null;
+    }
+
+    @Override public ExecuteResponse apply(PrepareAndExecuteRequest request) {
+      return null;
+    }
+
+    @Override public FetchResponse apply(FetchRequest request) {
+      return null;
+    }
+
+    @Override public CreateStatementResponse apply(CreateStatementRequest request) {
+      return null;
+    }
+
+    @Override public CloseStatementResponse apply(CloseStatementRequest request) {
+      return null;
+    }
+
+    @Override public CloseConnectionResponse apply(CloseConnectionRequest request) {
+      return null;
+    }
+
+    @Override public ConnectionSyncResponse apply(ConnectionSyncRequest request) {
+      return null;
+    }
+
+    @Override public DatabasePropertyResponse apply(DatabasePropertyRequest request) {
+      return null;
+    }
+  }
+
+
+  /**
+   * Instrumented subclass of {@link org.apache.calcite.avatica.test.JsonHandlerTest.NoopService}
+   * that checks the parameter values passed to the "fetch" request.
+   */
+  public static class ParameterValuesCheckingService extends NoopService {
+
+    final List<TypedValue> expectedParameterValues;
+
+    public ParameterValuesCheckingService(List<TypedValue> epv) {
+      expectedParameterValues = epv;
+    }
+
+    @Override public FetchResponse apply(FetchRequest request) {
+      assertEquals(expectedParameterValues.size(), request.parameterValues.size());
+      for (int i = 0; i < expectedParameterValues.size(); i++) {
+        assertEquals(expectedParameterValues.get(i).type, request.parameterValues.get(i).type);
+        assertEquals(expectedParameterValues.get(i).value, request.parameterValues.get(i).value);
+      }
+      expectedParameterValues.clear();
+      return null;
+    }
+  }
+
+  @Test public void testFetchRequestWithNumberParameter() {
+    final List<TypedValue> expectedParameterValues = new ArrayList<>();
+    final Service service = new ParameterValuesCheckingService(expectedParameterValues);
+    final JsonService jsonService = new LocalJsonService(service);
+    final JsonHandler jsonHandler = new JsonHandler(jsonService);
+
+    expectedParameterValues.add(TypedValue.create("NUMBER", new BigDecimal("333.333")));
+    jsonHandler.apply("{'request':'fetch','parameterValues':[{'type':'NUMBER','value':333.333}]}");
+    assertTrue(expectedParameterValues.isEmpty());
+
+    expectedParameterValues.add(TypedValue.create("NUMBER", new BigDecimal("333")));
+    jsonHandler.apply("{'request':'fetch','parameterValues':[{'type':'NUMBER','value':333}]}");
+    assertTrue(expectedParameterValues.isEmpty());
+  }
+}
+
+// End JsonHandlerTest.java


[29/50] incubator-calcite git commit: Fix up [CALCITE-714]

Posted by jh...@apache.org.
Fix up [CALCITE-714]

Also, forgot to close the pull request for [CALCITE-761] Pre-populated materializations, so:

Close apache/incubator-calcite#98


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

Branch: refs/heads/branch-release
Commit: e03dafcf20c8c5af5fffda88b4813017dca30048
Parents: 29030d8
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Jul 23 14:11:35 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jul 23 14:21:38 2015 -0700

----------------------------------------------------------------------
 .../org/apache/calcite/rel/core/Filter.java     | 28 -------------
 .../calcite/rel/rules/FilterCorrelateRule.java  | 42 ++++++++------------
 .../rel/rules/FilterProjectTransposeRule.java   |  4 +-
 .../java/org/apache/calcite/rex/RexUtil.java    | 24 +++++++++++
 .../apache/calcite/sql2rel/RelDecorrelator.java | 22 ++++------
 5 files changed, 49 insertions(+), 71 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e03dafcf/core/src/main/java/org/apache/calcite/rel/core/Filter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Filter.java b/core/src/main/java/org/apache/calcite/rel/core/Filter.java
index 4b6ebfa..0dc3009 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Filter.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Filter.java
@@ -26,17 +26,12 @@ import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelWriter;
 import org.apache.calcite.rel.SingleRel;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
-import org.apache.calcite.rex.RexCall;
 import org.apache.calcite.rex.RexChecker;
-import org.apache.calcite.rex.RexCorrelVariable;
 import org.apache.calcite.rex.RexLocalRef;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexProgram;
 import org.apache.calcite.rex.RexShuttle;
 import org.apache.calcite.rex.RexUtil;
-import org.apache.calcite.rex.RexVisitor;
-import org.apache.calcite.rex.RexVisitorImpl;
-import org.apache.calcite.util.Util;
 
 import com.google.common.collect.ImmutableList;
 
@@ -115,29 +110,6 @@ public abstract class Filter extends SingleRel {
     return condition;
   }
 
-  /**
-   * Check if any of the operands of the filter contains a
-   * correlation variable
-   */
-  public boolean hasCorrelation() {
-    if (condition instanceof RexCall) {
-      try {
-        RexVisitor<Void> visitor =
-            new RexVisitorImpl<Void>(true) {
-              public Void visitCorrelVariable(RexCorrelVariable var) {
-                throw new Util.FoundOne(var);
-              }
-            };
-        condition.accept(visitor);
-        return false;
-      } catch (Util.FoundOne e) {
-        Util.swallow(e,  null);
-        return true;
-      }
-    }
-    return false;
-  }
-
   @Override public boolean isValid(boolean fail) {
     if (RexUtil.isNullabilityCast(getCluster().getTypeFactory(), condition)) {
       assert !fail : "Cast for just nullability not allowed";

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e03dafcf/core/src/main/java/org/apache/calcite/rel/rules/FilterCorrelateRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterCorrelateRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterCorrelateRule.java
index f156ec0..2b38074 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterCorrelateRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterCorrelateRule.java
@@ -27,14 +27,16 @@ import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.util.Util;
 
-import com.google.common.collect.Lists;
+import com.google.common.collect.ImmutableList;
 
 import java.util.ArrayList;
 import java.util.List;
 
 /**
- * Planner rule that pushes filters above Correlate node into the children of the Correlate.
+ * Planner rule that pushes a {@link Filter} above a {@link Correlate} into the
+ * inputs of the Correlate.
  */
 public class FilterCorrelateRule extends RelOptRule {
 
@@ -44,8 +46,6 @@ public class FilterCorrelateRule extends RelOptRule {
 
   private final RelFactories.FilterFactory filterFactory;
 
-  private final RelFactories.ProjectFactory projectFactory;
-
   //~ Constructors -----------------------------------------------------------
 
   /**
@@ -59,26 +59,20 @@ public class FilterCorrelateRule extends RelOptRule {
             operand(Correlate.class, RelOptRule.any())),
         "FilterCorrelateRule");
     this.filterFactory = filterFactory;
-    this.projectFactory = projectFactory;
+    Util.discard(projectFactory); // for future use
   }
 
   //~ Methods ----------------------------------------------------------------
 
   public void onMatch(RelOptRuleCall call) {
-    Filter filter = call.rel(0);
-    Correlate corr = call.rel(1);
-
-    if (filter == null) {
-      return;
-    }
+    final Filter filter = call.rel(0);
+    final Correlate corr = call.rel(1);
 
     final List<RexNode> aboveFilters =
-        filter != null
-            ? RelOptUtil.conjunctions(filter.getCondition())
-            : Lists.<RexNode>newArrayList();
+        RelOptUtil.conjunctions(filter.getCondition());
 
-    List<RexNode> leftFilters = new ArrayList<RexNode>();
-    List<RexNode> rightFilters = new ArrayList<RexNode>();
+    final List<RexNode> leftFilters = new ArrayList<>();
+    final List<RexNode> rightFilters = new ArrayList<>();
 
     // Try to push down above filters. These are typically where clause
     // filters. They can be pushed down if they are not on the NULL
@@ -100,20 +94,17 @@ public class FilterCorrelateRule extends RelOptRule {
       return;
     }
 
-    // create FilterRels on top of the children if any filters were
-    // pushed to them
+    // Create Filters on top of the children if any filters were
+    // pushed to them.
     final RexBuilder rexBuilder = corr.getCluster().getRexBuilder();
     RelNode leftRel =
         RelOptUtil.createFilter(corr.getLeft(), leftFilters, filterFactory);
     RelNode rightRel =
         RelOptUtil.createFilter(corr.getRight(), rightFilters, filterFactory);
 
-    // create the new LogicalCorrelate rel
-    List<RelNode> corrInputs = Lists.newArrayList();
-    corrInputs.add(leftRel);
-    corrInputs.add(rightRel);
-
-    RelNode newCorrRel = corr.copy(corr.getTraitSet(), corrInputs);
+    // Create the new Correlate
+    RelNode newCorrRel =
+        corr.copy(corr.getTraitSet(), ImmutableList.of(leftRel, rightRel));
 
     call.getPlanner().onCopy(corr, newCorrRel);
 
@@ -124,7 +115,7 @@ public class FilterCorrelateRule extends RelOptRule {
       call.getPlanner().onCopy(filter, rightRel);
     }
 
-    // create a LogicalFilter on top of the join if needed
+    // Create a Filter on top of the join if needed
     RelNode newRel =
         RelOptUtil.createFilter(newCorrRel,
             RexUtil.fixUp(rexBuilder, aboveFilters, newCorrRel.getRowType()),
@@ -132,7 +123,6 @@ public class FilterCorrelateRule extends RelOptRule {
 
     call.transformTo(newRel);
   }
-
 }
 
 // End FilterCorrelateRule.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e03dafcf/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
index ff006a9..a81d595 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
@@ -86,10 +86,10 @@ public class FilterProjectTransposeRule extends RelOptRule {
       return;
     }
 
-    if (filter.hasCorrelation()) {
+    if (RexUtil.containsCorrelation(filter.getCondition())) {
       // If there is a correlation condition anywhere in the filter, don't
       // push this filter past project since in some cases it can prevent a
-      // Correlate from being decorrelated
+      // Correlate from being de-correlated.
       return;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e03dafcf/core/src/main/java/org/apache/calcite/rex/RexUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexUtil.java b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
index 5347855..1cac0f8 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -1459,6 +1459,16 @@ public class RexUtil {
     };
   }
 
+  /** Returns whether an expression contains a {@link RexCorrelVariable}. */
+  public static boolean containsCorrelation(RexNode condition) {
+    try {
+      condition.accept(CorrelationFinder.INSTANCE);
+      return false;
+    } catch (Util.FoundOne e) {
+      return true;
+    }
+  }
+
   //~ Inner Classes ----------------------------------------------------------
 
   /**
@@ -1841,6 +1851,20 @@ public class RexUtil {
       return new RexInputRef(input.getIndex() + offset, input.getType());
     }
   }
+
+  /** Visitor that throws {@link org.apache.calcite.util.Util.FoundOne} if
+   * there an expression contains a {@link RexCorrelVariable}. */
+  private static class CorrelationFinder extends RexVisitorImpl<Void> {
+    static final CorrelationFinder INSTANCE = new CorrelationFinder();
+
+    private CorrelationFinder() {
+      super(true);
+    }
+
+    @Override public Void visitCorrelVariable(RexCorrelVariable var) {
+      throw Util.FoundOne.NULL;
+    }
+  }
 }
 
 // End RexUtil.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e03dafcf/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
index 80767c2..2f1d6b9 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
@@ -44,11 +44,9 @@ import org.apache.calcite.rel.logical.LogicalJoin;
 import org.apache.calcite.rel.logical.LogicalProject;
 import org.apache.calcite.rel.logical.LogicalSort;
 import org.apache.calcite.rel.metadata.RelMdUtil;
-import org.apache.calcite.rel.rules.FilterAggregateTransposeRule;
 import org.apache.calcite.rel.rules.FilterCorrelateRule;
 import org.apache.calcite.rel.rules.FilterJoinRule;
 import org.apache.calcite.rel.rules.FilterProjectTransposeRule;
-import org.apache.calcite.rel.rules.ProjectMergeRule;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeField;
@@ -241,24 +239,18 @@ public class RelDecorrelator implements ReflectiveVisitor {
 
     if (mapOldToNewRel.containsKey(root)) {
       // has been rewritten; apply rules post-decorrelation
-      HepProgram program2 = HepProgram.builder()
+      final HepProgram program2 = HepProgram.builder()
           .addRuleInstance(FilterJoinRule.FILTER_ON_JOIN)
           .addRuleInstance(FilterJoinRule.JOIN)
           .build();
 
-      HepPlanner planner2 = createPlanner(program2);
-
-      RelNode newroot = mapOldToNewRel.get(root);
-      // planner.setRoot(newroot);
-      planner2.setRoot(newroot);
-      // newroot = planner.findBestExp();
-      newroot = planner2.findBestExp();
-
-      return newroot;
-    } else {
-      // not rewritten
-      return root;
+      final HepPlanner planner2 = createPlanner(program2);
+      final RelNode newRoot = mapOldToNewRel.get(root);
+      planner2.setRoot(newRoot);
+      return planner2.findBestExp();
     }
+
+    return root;
   }
 
   private Function2<RelNode, RelNode, Void> createCopyHook() {


[39/50] incubator-calcite git commit: [CALCITE-822] Revert incorrect LogicalAggregate collation inferring logic made in CALCITE-783 (Milinda Pathirage)

Posted by jh...@apache.org.
[CALCITE-822] Revert incorrect LogicalAggregate collation inferring logic made in CALCITE-783 (Milinda Pathirage)


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

Branch: refs/heads/branch-release
Commit: ac934f695db39d88beb5a12c792ba7da68cc386e
Parents: 0357573
Author: Milinda Pathirage <mi...@gmail.com>
Authored: Fri Aug 7 08:24:11 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Aug 7 18:43:05 2015 -0700

----------------------------------------------------------------------
 .../calcite/rel/logical/LogicalAggregate.java    | 19 +------------------
 .../org/apache/calcite/test/LatticeTest.java     |  2 +-
 2 files changed, 2 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/ac934f69/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
index 650e8a6..d6b9e57 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
@@ -19,8 +19,6 @@ package org.apache.calcite.rel.logical;
 import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.rel.RelCollation;
-import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelInput;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelShuttle;
@@ -28,9 +26,6 @@ import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.util.ImmutableBitSet;
 
-import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableList;
-
 import java.util.List;
 
 /**
@@ -96,19 +91,7 @@ public final class LogicalAggregate extends Aggregate {
       List<ImmutableBitSet> groupSets,
       List<AggregateCall> aggCalls) {
     final RelOptCluster cluster = input.getCluster();
-    final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE).replaceIfs(
-        RelCollationTraitDef.INSTANCE,
-        new Supplier<List<RelCollation>>() {
-          public List<RelCollation> get() {
-            List<RelCollation> collations =
-                input.getTraitSet().getTraits(RelCollationTraitDef.INSTANCE);
-            if (collations != null) {
-              return collations;
-            }
-
-            return ImmutableList.of();
-          }
-        });
+    final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE);
     return new LogicalAggregate(cluster, traitSet, input, indicator, groupSet,
         groupSets, aggCalls);
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/ac934f69/core/src/test/java/org/apache/calcite/test/LatticeTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/LatticeTest.java b/core/src/test/java/org/apache/calcite/test/LatticeTest.java
index b1155f0..77e7943 100644
--- a/core/src/test/java/org/apache/calcite/test/LatticeTest.java
+++ b/core/src/test/java/org/apache/calcite/test/LatticeTest.java
@@ -436,7 +436,7 @@ public class LatticeTest {
                 + "GROUP BY \"s\".\"unit_sales\", \"p\".\"recyclable_package\", \"t\".\"the_day\", \"t\".\"the_year\", \"t\".\"quarter\", \"pc\".\"product_family\"")
         .explainContains(
             "JdbcToEnumerableConverter\n"
-                + "  JdbcAggregate(group=[{7, 16, 25, 27, 31, 37}], m0=[COUNT()], m1=[$SUM0($5)], m2=[$SUM0($7)])\n"
+                + "  JdbcAggregate(group=[{7, 16, 25, 27, 31, 37}], m0=[COUNT()], m1=[SUM($5)], m2=[SUM($7)])\n"
                 + "    JdbcJoin(condition=[=($8, $33)], joinType=[inner])\n"
                 + "      JdbcJoin(condition=[=($1, $23)], joinType=[inner])\n"
                 + "        JdbcJoin(condition=[=($0, $9)], joinType=[inner])\n"


[47/50] incubator-calcite git commit: Add Jacques' key to KEYS

Posted by jh...@apache.org.
Add Jacques' key to KEYS


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

Branch: refs/heads/branch-release
Commit: ce2f17a768f9736a32be3382d8bacb67e901d03d
Parents: f8a5427
Author: Jacques Nadeau <ja...@apache.org>
Authored: Sun Aug 23 12:42:55 2015 -0700
Committer: Jacques Nadeau <ja...@apache.org>
Committed: Sun Aug 23 12:43:26 2015 -0700

----------------------------------------------------------------------
 KEYS | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/ce2f17a7/KEYS
----------------------------------------------------------------------
diff --git a/KEYS b/KEYS
index b52616a..3302795 100644
--- a/KEYS
+++ b/KEYS
@@ -72,3 +72,73 @@ Uf2lGPk3WCmS8+NmQm4PePkNUIN1N6BNvLpeA8xUzUorfUHI74949+ppVQ8td5eS
 HFfYzFyXcqX3BhXdDWg/XQ==
 =9tCp
 -----END PGP PUBLIC KEY BLOCK-----
+
+pub   4096R/AB10D143 2013-09-01 [expires: 2017-09-01]
+uid                  Jacques Nadeau <ja...@apache.org>
+sig 3        AB10D143 2013-09-01  Jacques Nadeau <ja...@apache.org>
+sub   4096R/6B5FA695 2013-09-01 [expires: 2017-09-01]
+sig          AB10D143 2013-09-01  Jacques Nadeau <ja...@apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.13 (Darwin)
+
+mQINBFIjwJwBEADtEHGy8BQWARs89O/erynRvY/yeeZNNFvpKvqfZNrwU4E+RIvi
+mh2HaKQ+jFyyQXBhzrdfNC5Vb6uegYFKer0sXxd3tNglnj9LjDz9P/vS/h6IDtiL
+LbbgVSqciW6OdJp86chXwzLjt6fNdPzTIP1w5a4t8JBRsiWUc8GqHQxhcckw4cpu
+FEE2fheC4vABGdSoFQvOHZRnlVKItlitFHgeWZOFyQ0izwIM8uWDkKCa2FatxHBV
+HgFPQdqbBd54xxe4klx1sOU3hJS1Dy9ezK4JgltPGDrVJsbu8+14Zg9mADT5pSz/
+Hp5vQN1l7Mm0qjAaDrbszYuRc4AICMSMZuCgl0QI6ZI+pI7kULjIYYiR/82YBsqr
+IqVyWoW3fcl7Bi5sY53bbZ1ilabyS6LH1fQdOB7jfyu7n4M2m1QioERLIj3FLt1I
+eu18PCVITuRReFRuc9qtwX8CQCx3J3IAIjUvdehiDfdeHR2DNRmNg8+Rx5QkZgDn
+JK0G22DwO6NpjzvdJ2dJ8GvF2VxtnE6tVvFb3Ws373FyjWEGwWcG/SD8PQ1Lv5Qq
+BeKBZ+Z7i0VtRVTj9Q4fiACXKGSIAjffx9j0KFUcKbPS4uDDw+TpqBD0YLwl9QSI
+AcBuAs8O0lBVDKKyEuuy4ogfX5wPu/0TPBLVEzul6haqsjGNoKYnxyvYRQARAQAB
+tCNKYWNxdWVzIE5hZGVhdSA8amFjcXVlc0BhcGFjaGUub3JnPokCPQQTAQoAJwUC
+UiPAnAIbLwUJB4YfgAULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRDfK+AwqxDR
+QznfEACJ6/PHgL/bs+cTjIUazDfHuAA5Vwt3p9UjLsoavfeQyhWetDZlOPv18WQj
+Bs/hqelYEmRMmKFTA6soTBUVTPWcoxh4zHlg5pI6F9+GtBEfn268iGMYPQxTYG80
+eMlfOiMsSwHNNHF0JxNtdsOPTpiK90rilni4INW5GbRTZAWkYTkLD1+gbCSfJfLg
+zd/TJK6nCCH2Wr4fV9REg2hPHpHkq61Chg4psW/qRlMyPRDYAol2aSbMVegjwElK
+saLdn3vEyrydWeC+iB/tLAVFkvKuqXkCFm6u82LJ7dEoJx5Q1o6WcNsH1n5tI4aJ
+RXJP9GZYXPlnVMljlr0ZSyAYRWa81xOa9sYLWEqIuGkQnuBenhLtRBLYYpAA9QIY
+rhCdBuKo/ATDbOC5ejqYFb3SD7SomSS8OsB2qDP1/Hs6vsLgoPHzNYVYp/fZ5YRx
+T4O3NYbptVKCgRUHJKWQJHu/XEKmmrfS5+UpGxEJLwPxj/VkN/z6G8TxwN3zOGv7
+OeWs77+qFDLeEus0pv1inwFvWdTia3Y2XqRi4zDwS5pTQX6Kh21k1ryOEjHYeYJx
+qKRm+BJ7Nldmb14i5m0OqwBhKTsyFI7z36Lm9axlsF72yiWR5MdpJHA9vMZHn4WP
+qyH4ifmqAuCIm9JpsYHJPGaY+1Nkbolg1WypF2lykTlYkbIbHLkCDQRSI8CcARAA
+rB26ik4YAoTdc2cVXXC9SceVdSe48AMxCqkSdr/AtlLkf/NNXHw4yS8xdt8c0DqT
+qxVBqkWIQipZqkGzl6pC1FhXqPw0jujFVrYoOfeGyQbvTXmxZs1T1pRDKwgsNtOX
+QT5gY2kmbRcISPB8dyw3AujahM4UqkZ+Alyu9NyX/4zmTuNMDdhd+hnds8jba2yz
+U/dCHoM45QXgEzdVCoqoQAyqAcL/WN/qAMeb2yyLNgmJx7mHFnI97BB3uZhEaI/A
+TeZ+KuTPzJg/HjLVaRDPNfd2Re9NCNDPgyqDqPp/LPKKwhiZiod5VddtENJ/cc7O
+H/dHtZavIBOQQGcKZZ7y0XBHP7xCwboe8NECVuo2RLC/IjHNMpO3nKI/8PrbwnfS
+X5n+5Sel4xkRMCk1vKNf8FC8JFPaui2jm/BqTJ+//i8Ztgsvm7BrbFYMGmnEW/uG
+c1ECWkk1SLgv+TRF+w2gumQMKP08x03U6B/gTybfMt1/yAVeZKnGt6i6eOc70dQH
+k4znmIJhilHCk+fNT1T6xd8ZPAYtGOEOqWtlL2tRXF7eqAs2DkGtS9EQttUSknRh
+jsr2bd9PKZkShox8BVX5aMtsLe8M1sTBhrYKCYzM8yjDNr4qUc1SDcgahdFdCwVo
+ZUMA8LNrup9PmcxQfdS4nz6OuVCUkpyIjSA16B4bYScAEQEAAYkERAQYAQoADwUC
+UiPAnAIbLgUJB4YfgAIpCRDfK+AwqxDRQ8FdIAQZAQoABgUCUiPAnAAKCRDCxgIq
+a1+mlfd2D/9IhJLbvBqnVb0boUIKgplmtdgrVLbOX11BAcaHzf/oKbtThdtpakEe
+XN8cJc5sjHFH8hC5xreNhm7VfAYMB5cLPc2dklmo4TJuYzvKJmioQM91BhQBzt9j
++ieklbl2hCE1AVYnwetTDP1jVfHc0SKS7Uq6PqSCybsnXy+FWDJO8U4ZC83cYkuo
+5RtADdNnEovxahv6kc8lRtOmnPoG4k4MxlZWqyinjGLRTGjYEKWQlmBlZx0qIVIP
+4V4EDJp15TyZgjq6yV5lMreoJ3R7vl+O1T97xlHWmJr9TDnF6Db30sLevTo0YP+4
+weNTfACBYBBrB6hJ8DrCEfqSZwFFFzpzF2WnPJqiH3JmZNtIdPw3hTP8NIvt6kAU
+gmTqbnaprpaZ5V7gxluWcVUIFGgC8uCRbp9COrp2dmDfuLbj1HEQ+6uDUDLsPZOw
+avdKpABe85DNJhRpcXO+p2Zvvz0vDYJI+PI0XVy7jfgtI6V6h/4qoqfQbKdcBlUX
+5a4B61cDHlRMQ4B9ZI6ZsyK3y35mz9dB2oBBQv8sAhekBYu2v8bmaz/UEioSN7lP
+MkMgJcvhdJ4qQZlllHi0WFDs0tf7SBTzqNvPjsBHBIf0FifAsO+grPadswWvyKUP
+h52IxWvh5AO2Yg08enyA6h+8X0hmZSpyXDLE+Hdnq8Dqn2q7conB3m5KD/9KrZbm
+gU+kMf7bEjPBWChGCmZG6NFVy9Kfjdv9ezKZi5vp/wl4Qfm7OgTonURbv/BM6Qdj
+R8ZnEe2wiKILSICW/mQ8Y5uUu5BIzODQvyh/WN4ylM+dnDSL/T6+Q4gES7/GeYth
+Es1dRpLKWtEfxQifZ1jhYiKNpFTmhf33O+0e1+aejgWwsLXnXBRMtxLem6BDQtA1
+QLRWBH4lysBgnxeH9KQ/eL6Wy2pTwmbpxyHx87HzEXXLS36/othdXhWAokDw5hqJ
+lbPe9lNkJ8KqtKKU/hxowBQDrj2s6AlPNkBBx5ur8ro9Wr+FYS57LPh4cVhMedHO
+P/9WRAgFctvyXVj//F7DlUWisPA6RDeb+Ot09WpdCDpJ+OL953pqKIPOOw6jEP5u
+u0rIBwtHYCMa5mq5E7OT6CQIZEUTkjKcLAlOPIgzkq+6kdincWtjf8tIiM6T9koS
+OfHgPH5T+RwkxjV/EPORahU4K4cwJYhHF79HiHooHtBAFks9Jysy54M8t7mhdPRZ
++hzkWV6r/hnFHwcth1ypK7b1ugYW2a+hZ2DI8kN2mFcVIphoRSWKyLlNEsoBD3yl
+ql6lhZBgdT7euTI6sc0ch1M5a9C35k1yPFjh5bm6ed5VS+7qVZr2n7LWplQHhRQE
+P5iIjn4zOZYYd6Fobkpw3vi03ifusAeOzwpCmw==
+=6NWa
+-----END PGP PUBLIC KEY BLOCK-----


[13/50] incubator-calcite git commit: Fix up previous commit; add some tests for constant reduction

Posted by jh...@apache.org.
Fix up previous commit; add some tests for constant reduction


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

Branch: refs/heads/branch-release
Commit: 5a365609c0d050e5e832449bdadad1e309f0f204
Parents: 4a9b193
Author: Julian Hyde <jh...@apache.org>
Authored: Wed Jul 15 21:48:51 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jul 16 15:03:20 2015 -0700

----------------------------------------------------------------------
 .../adapter/enumerable/EnumerableWindow.java    |   2 +-
 .../MaterializedViewSubstitutionVisitor.java    |  69 +--
 .../org/apache/calcite/plan/RelOptUtil.java     |  17 +-
 .../calcite/plan/RexImplicationChecker.java     | 256 ++++----
 .../calcite/plan/SubstitutionVisitor.java       |  53 +-
 .../apache/calcite/plan/VisitorDataContext.java |  57 +-
 .../rel/rules/AggregateFilterTransposeRule.java |   2 +-
 .../rel/rules/AggregateUnionTransposeRule.java  |   2 +-
 .../rel/rules/FilterAggregateTransposeRule.java |   2 +-
 .../java/org/apache/calcite/sql/SqlKind.java    |  20 +
 .../org/apache/calcite/rex/RexExecutorTest.java | 136 ++--
 .../org/apache/calcite/test/DiffRepository.java |   1 -
 .../calcite/test/RexImplicationCheckerTest.java | 614 ++++++++-----------
 13 files changed, 592 insertions(+), 639 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a365609/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java
index 15f77f5..433c6cd 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java
@@ -746,7 +746,7 @@ public class EnumerableWindow extends Window implements EnumerableRel {
       BlockBuilder builder, final Result result, int windowIdx,
       List<AggImpState> aggs, PhysType outputPhysType,
       List<Expression> outputRow) {
-    for (final AggImpState agg: aggs) {
+    for (final AggImpState agg : aggs) {
       agg.context =
           new WinAggContext() {
             public SqlAggFunction aggregation() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a365609/core/src/main/java/org/apache/calcite/plan/MaterializedViewSubstitutionVisitor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/MaterializedViewSubstitutionVisitor.java b/core/src/main/java/org/apache/calcite/plan/MaterializedViewSubstitutionVisitor.java
index e367f93..5c4ccdd 100644
--- a/core/src/main/java/org/apache/calcite/plan/MaterializedViewSubstitutionVisitor.java
+++ b/core/src/main/java/org/apache/calcite/plan/MaterializedViewSubstitutionVisitor.java
@@ -25,45 +25,19 @@ import org.apache.calcite.rex.RexShuttle;
 import com.google.common.collect.ImmutableList;
 
 import java.util.List;
+
 /**
- * Substitutes part of a tree of relational expressions with another tree.
- *
- * <p>The call {@code new MaterializedSubstitutionVisitor(target, query).go(replacement))}
- * will return {@code query} with every occurrence of {@code target} replaced
- * by {@code replacement}.</p>
- *
- * <p>The following example shows how {@code MaterializedSubstitutionVisitor} can be used
- * for materialized view recognition.</p>
- *
- * <ul>
- * <li>query = SELECT a, c FROM t WHERE x = 5 AND b = 4</li>
- * <li>target = SELECT a, b, c FROM t WHERE x = 5</li>
- * <li>replacement = SELECT * FROM mv</li>
- * <li>result = SELECT a, c FROM mv WHERE b = 4</li>
- * </ul>
- *
- * <p>Note that {@code result} uses the materialized view table {@code mv} and a
- * simplified condition {@code b = 4}.</p>
- *
- * <p>Uses a bottom-up matching algorithm. Nodes do not need to be identical.
- * At each level, returns the residue.</p>
- *
- * <p>The inputs must only include the core relational operators:
- * {@link org.apache.calcite.rel.logical.LogicalTableScan},
- * {@link LogicalFilter},
- * {@link LogicalProject},
- * {@link org.apache.calcite.rel.logical.LogicalJoin},
- * {@link LogicalUnion},
- * {@link LogicalAggregate}.</p>
+ * Extension to {@link SubstitutionVisitor}.
  */
 public class MaterializedViewSubstitutionVisitor extends SubstitutionVisitor {
+  private static final ImmutableList<UnifyRule> EXTENDED_RULES =
+      ImmutableList.<UnifyRule>builder()
+          .addAll(DEFAULT_RULES)
+          .add(ProjectToProjectUnifyRule1.INSTANCE)
+          .build();
 
   public MaterializedViewSubstitutionVisitor(RelNode target_, RelNode query_) {
-    super(target_, query_);
-    ImmutableList.Builder<UnifyRule> builder = new ImmutableList.Builder<UnifyRule>();
-    builder.addAll(this.unifyRules);
-    builder.add(ProjectToProjectUnifyRule1.INSTANCE);
-    this.unifyRules = builder.build();
+    super(target_, query_, EXTENDED_RULES);
   }
 
   public RelNode go(RelNode replacement_) {
@@ -73,7 +47,6 @@ public class MaterializedViewSubstitutionVisitor extends SubstitutionVisitor {
   /**
    * Project to Project Unify rule.
    */
-
   private static class ProjectToProjectUnifyRule1 extends AbstractUnifyRule {
     public static final ProjectToProjectUnifyRule1 INSTANCE =
         new ProjectToProjectUnifyRule1();
@@ -83,12 +56,13 @@ public class MaterializedViewSubstitutionVisitor extends SubstitutionVisitor {
           operand(MutableProject.class, target(0)), 1);
     }
 
-    @Override
-    protected UnifyResult apply(UnifyRuleCall call) {
+    @Override protected UnifyResult apply(UnifyRuleCall call) {
       final MutableProject query = (MutableProject) call.query;
 
-      final List<RelDataTypeField> oldFieldList = query.getInput().getRowType().getFieldList();
-      final List<RelDataTypeField> newFieldList = call.target.getRowType().getFieldList();
+      final List<RelDataTypeField> oldFieldList =
+          query.getInput().getRowType().getFieldList();
+      final List<RelDataTypeField> newFieldList =
+          call.target.getRowType().getFieldList();
       List<RexNode> newProjects;
       try {
         newProjects = transformRex(query.getProjects(), oldFieldList, newFieldList);
@@ -104,9 +78,8 @@ public class MaterializedViewSubstitutionVisitor extends SubstitutionVisitor {
       return call.result(newProject2);
     }
 
-    @Override
-    protected UnifyRuleCall match(SubstitutionVisitor visitor, MutableRel query,
-        MutableRel target) {
+    @Override protected UnifyRuleCall match(SubstitutionVisitor visitor,
+        MutableRel query, MutableRel target) {
       assert query instanceof MutableProject && target instanceof MutableProject;
 
       if (queryOperand.matches(visitor, query)) {
@@ -116,8 +89,8 @@ public class MaterializedViewSubstitutionVisitor extends SubstitutionVisitor {
 
           final MutableProject queryProject = (MutableProject) query;
           if (queryProject.getInput() instanceof MutableFilter) {
-
-            final MutableFilter innerFilter = (MutableFilter) (queryProject.getInput());
+            final MutableFilter innerFilter =
+                (MutableFilter) queryProject.getInput();
             RexNode newCondition;
             try {
               newCondition = transformRex(innerFilter.getCondition(),
@@ -130,18 +103,18 @@ public class MaterializedViewSubstitutionVisitor extends SubstitutionVisitor {
                 newCondition);
 
             return visitor.new UnifyRuleCall(this, query, newFilter,
-                copy(visitor.getSlots(), slotCount));
+                copy(visitor.slots, slotCount));
           }
         }
       }
       return null;
     }
 
-    private RexNode transformRex(
-        RexNode node,
+    private RexNode transformRex(RexNode node,
         final List<RelDataTypeField> oldFields,
         final List<RelDataTypeField> newFields) {
-      List<RexNode> nodes = transformRex(ImmutableList.of(node), oldFields, newFields);
+      List<RexNode> nodes =
+          transformRex(ImmutableList.of(node), oldFields, newFields);
       return nodes.get(0);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a365609/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
index c1f8af5..7a79aeb 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -1158,7 +1158,7 @@ public abstract class RelOptUtil {
             && kind != SqlKind.EQUALS
             && kind != SqlKind.IS_DISTINCT_FROM) {
           if (reverse) {
-            kind = reverse(kind);
+            kind = kind.reverse();
           }
           rangeOp.add(op(kind, call.getOperator()));
         }
@@ -1199,21 +1199,6 @@ public abstract class RelOptUtil {
         false);
   }
 
-  public static SqlKind reverse(SqlKind kind) {
-    switch (kind) {
-    case GREATER_THAN:
-      return SqlKind.LESS_THAN;
-    case GREATER_THAN_OR_EQUAL:
-      return SqlKind.LESS_THAN_OR_EQUAL;
-    case LESS_THAN:
-      return SqlKind.GREATER_THAN;
-    case LESS_THAN_OR_EQUAL:
-      return SqlKind.GREATER_THAN_OR_EQUAL;
-    default:
-      return kind;
-    }
-  }
-
   public static SqlOperator op(SqlKind kind, SqlOperator operator) {
     switch (kind) {
     case EQUALS:

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a365609/core/src/main/java/org/apache/calcite/plan/RexImplicationChecker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RexImplicationChecker.java b/core/src/main/java/org/apache/calcite/plan/RexImplicationChecker.java
index 1eb019d..42c7b43 100644
--- a/core/src/main/java/org/apache/calcite/plan/RexImplicationChecker.java
+++ b/core/src/main/java/org/apache/calcite/plan/RexImplicationChecker.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.calcite.plan;
 
 import org.apache.calcite.DataContext;
@@ -39,40 +38,44 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-
-
-/** Checks if Condition X logically implies Condition Y
+/**
+ * Checks whether one condition logically implies another.
  *
- * <p>(x > 10) implies (x > 5)</p>
+ * <p>If A &rArr; B, whenever A is true, B will be true also.
  *
- * <p>(y = 10) implies (y < 30 AND x > 30)</p>
+ * <p>For example:
+ * <ul>
+ * <li>(x &gt; 10) &rArr; (x &gt; 5)
+ * <li>(y = 10) &rArr; (y &lt; 30 OR x &gt; 30)
+ * </ul>
  */
 public class RexImplicationChecker {
   final RexBuilder builder;
-  final RexExecutorImpl rexImpl;
+  final RexExecutorImpl executor;
   final RelDataType rowType;
 
   public RexImplicationChecker(
       RexBuilder builder,
-      RexExecutorImpl rexImpl,
+      RexExecutorImpl executor,
       RelDataType rowType) {
     this.builder = builder;
-    this.rexImpl = rexImpl;
+    this.executor = executor;
     this.rowType = rowType;
   }
 
   /**
-   * Checks if condition first implies (=>) condition second
-   * This reduces to SAT problem which is NP-Complete
-   * When func says first => second then it is definitely true
-   * It cannot prove if first doesnot imply second.
+   * Checks if condition first implies (&rArr;) condition second.
+   *
+   * <p>This reduces to SAT problem which is NP-Complete.
+   * When this method says first implies second then it is definitely true.
+   * But it cannot prove that first does not imply second.
+   *
    * @param first first condition
    * @param second second condition
-   * @return true if it can prove first => second, otherwise false i.e.,
-   * it doesn't know if implication holds .
+   * @return true if it can prove first &rArr; second; otherwise false i.e.,
+   * it doesn't know if implication holds
    */
   public boolean implies(RexNode first, RexNode second) {
-
     // Validation
     if (!validate(first, second)) {
       return false;
@@ -91,22 +94,26 @@ public class RexImplicationChecker {
       return true;
     }
 
-    /** Decompose DNF into List of Conjunctions
+    /** Decomposes DNF into List of Conjunctions.
      *
-     * (x > 10 AND y > 30) OR (z > 90) will be converted to
+     * <p>For example,
+     * {@code x > 10 AND y > 30) OR (z > 90)}
+     * will be converted to
      * list of 2 conditions:
-     * 1. (x > 10 AND y > 30)
-     * 2. (z > 90)
      *
+     * <ul>
+     *   <li>(x > 10 AND y > 30)</li>
+     *   <li>z > 90</li>
+     * </ul>
      */
     List<RexNode> firstDnfs = RelOptUtil.disjunctions(firstDnf);
     List<RexNode> secondDnfs = RelOptUtil.disjunctions(secondDnf);
 
     for (RexNode f : firstDnfs) {
       if (!f.isAlwaysFalse()) {
-        //Check if f implies atleast
+        // Check if f implies at least
         // one of the conjunctions in list secondDnfs
-        boolean implyOneConjuntion = false;
+        boolean implyOneConjunction = false;
         for (RexNode s : secondDnfs) {
           if (s.isAlwaysFalse()) { // f cannot imply s
             continue;
@@ -115,57 +122,61 @@ public class RexImplicationChecker {
           if (impliesConjunction(f, s)) {
             // Satisfies one of the condition, so lets
             // move to next conjunction in firstDnfs
-            implyOneConjuntion = true;
+            implyOneConjunction = true;
             break;
           }
-        } //end of inner loop
+        }
 
-        // If f couldnot imply even one conjunction in
+        // If f could not imply even one conjunction in
         // secondDnfs, then final implication may be false
-        if (!implyOneConjuntion) {
+        if (!implyOneConjunction) {
           return false;
         }
       }
-    } //end of outer loop
+    }
 
     return true;
   }
 
-  /** Checks if Conjunction first => Conjunction second**/
+  /** Returns whether first implies second (both are conjunctions). */
   private boolean impliesConjunction(RexNode first, RexNode second) {
+    final InputUsageFinder firstUsageFinder = new InputUsageFinder();
+    final InputUsageFinder secondUsageFinder = new InputUsageFinder();
 
-    InputUsageFinder firstUsgFinder = new InputUsageFinder();
-    InputUsageFinder secondUsgFinder = new InputUsageFinder();
-
-    RexUtil.apply(firstUsgFinder, new ArrayList<RexNode>(), first);
-    RexUtil.apply(secondUsgFinder, new ArrayList<RexNode>(), second);
+    RexUtil.apply(firstUsageFinder, new ArrayList<RexNode>(), first);
+    RexUtil.apply(secondUsageFinder, new ArrayList<RexNode>(), second);
 
     // Check Support
-    if (!checkSupport(firstUsgFinder, secondUsgFinder)) {
+    if (!checkSupport(firstUsageFinder, secondUsageFinder)) {
       return false;
     }
 
-    List<Pair<RexInputRef, RexNode>> usgList = new ArrayList<>();
-    for (Map.Entry<RexInputRef, InputRefUsage<SqlOperator,
-        RexNode>> entry: firstUsgFinder.usageMap.entrySet()) {
-      final List<Pair<SqlOperator, RexNode>> list = entry.getValue().getUsageList();
-      usgList.add(Pair.of(entry.getKey(), list.get(0).getValue()));
+    List<Pair<RexInputRef, RexNode>> usageList = new ArrayList<>();
+    for (Map.Entry<RexInputRef, InputRefUsage<SqlOperator, RexNode>> entry
+        : firstUsageFinder.usageMap.entrySet()) {
+      final Pair<SqlOperator, RexNode> pair = entry.getValue().usageList.get(0);
+      usageList.add(Pair.of(entry.getKey(), pair.getValue()));
     }
 
-    /* Get the literals from first conjunction and execute second conjunction using them
-     * E.g., for x >30 => x > 10,
-     * we will replace x by 30 in second expression and execute it i.e., 30>10
-     * If it's true then we infer implication.
-     */
-    final DataContext dataValues = VisitorDataContext.getDataContext(rowType, usgList);
+    // Get the literals from first conjunction and executes second conjunction
+    // using them.
+    //
+    // E.g., for
+    //   x > 30 &rArr; x > 10,
+    // we will replace x by 30 in second expression and execute it i.e.,
+    //   30 > 10
+    //
+    // If it's true then we infer implication.
+    final DataContext dataValues =
+        VisitorDataContext.of(rowType, usageList);
 
     if (dataValues == null) {
       return false;
     }
 
     ImmutableList<RexNode> constExps = ImmutableList.of(second);
-    final RexExecutable exec = rexImpl.getExecutable(builder,
-        constExps, rowType);
+    final RexExecutable exec =
+        executor.getExecutable(builder, constExps, rowType);
 
     Object[] result;
     exec.setDataContext(dataValues);
@@ -176,72 +187,85 @@ public class RexImplicationChecker {
       // Need to monitor it and handle all the cases raising them.
       return false;
     }
-    return result != null && result.length == 1 && result[0] instanceof Boolean
+    return result != null
+        && result.length == 1
+        && result[0] instanceof Boolean
         && (Boolean) result[0];
   }
 
   /**
    * Looks at the usage of variables in first and second conjunction to decide
-   * if this kind of expression is currently supported for proving first => second.
-   * 1. Variables should be used only once in both the conjunction against
-   *    given set of operations only: >,<,<=,>=,=,!=
-   * 2. All the variables used in second condition should be used even in the first.
-   * 3. If operator used for variable in first is op1 and op2 for second, then we support
-   *    these combination for conjunction (op1, op2) then op1, op2 belongs to
-   *    one of the following sets:
-   *    a. (<,<=) X (<,<=) , X represents cartesian product
-   *    b. (>/>=) X (>,>=)
-   *    c. (=) X (>,>=,<,<=,=,!=)
-   *    d. (!=, =)
-   * @return true, if input usage pattern is supported. Otherwise, false.
+   * whether this kind of expression is currently supported for proving first
+   * implies second.
+   *
+   * <ol>
+   * <li>Variables should be used only once in both the conjunction against
+   * given set of operations only: >, <, <=, >=, =, !=
+   *
+   * <li>All the variables used in second condition should be used even in the
+   * first.
+   *
+   * <li>If operator used for variable in first is op1 and op2 for second, then
+   * we support these combination for conjunction (op1, op2) then op1, op2
+   * belongs to one of the following sets:
+   *
+   * <ul>
+   *    <li>(<, <=) X (<, <=)      <i>note: X represents cartesian product</i>
+   *    <li>(> / >=) X (>, >=)
+   *    <li>(=) X (>, >=, <, <=, =, !=)
+   *    <li>(!=, =)
+   * </ul>
+   * </ol>
+   *
+   * @return whether input usage pattern is supported
    */
-  private boolean checkSupport(
-      InputUsageFinder firstUsgFinder,
-      InputUsageFinder secondUsgFinder) {
-    Map<RexInputRef, InputRefUsage<SqlOperator,
-        RexNode>> firstUsgMap = firstUsgFinder.usageMap;
-    Map<RexInputRef, InputRefUsage<SqlOperator,
-        RexNode>> secondUsgMap = secondUsgFinder.usageMap;
-
-    for (Map.Entry<RexInputRef, InputRefUsage<SqlOperator,
-        RexNode>> entry: firstUsgMap.entrySet()) {
+  private boolean checkSupport(InputUsageFinder firstUsageFinder,
+      InputUsageFinder secondUsageFinder) {
+    final Map<RexInputRef, InputRefUsage<SqlOperator, RexNode>> firstUsageMap =
+        firstUsageFinder.usageMap;
+    final Map<RexInputRef, InputRefUsage<SqlOperator, RexNode>> secondUsageMap =
+        secondUsageFinder.usageMap;
+
+    for (Map.Entry<RexInputRef, InputRefUsage<SqlOperator, RexNode>> entry
+        : firstUsageMap.entrySet()) {
       if (entry.getValue().usageCount > 1) {
         return false;
       }
     }
 
-    for (Map.Entry<RexInputRef, InputRefUsage<SqlOperator,
-        RexNode>> entry: secondUsgMap.entrySet()) {
+    for (Map.Entry<RexInputRef, InputRefUsage<SqlOperator, RexNode>> entry
+        : secondUsageMap.entrySet()) {
       final InputRefUsage<SqlOperator, RexNode> secondUsage = entry.getValue();
-      if (secondUsage.getUsageCount() > 1
-          || secondUsage.getUsageList().size() != 1) {
+      if (secondUsage.usageCount > 1
+          || secondUsage.usageList.size() != 1) {
         return false;
       }
 
-      final InputRefUsage<SqlOperator, RexNode> firstUsage = firstUsgMap.get(entry.getKey());
+      final InputRefUsage<SqlOperator, RexNode> firstUsage =
+          firstUsageMap.get(entry.getKey());
       if (firstUsage == null
-          || firstUsage.getUsageList().size() != 1) {
+          || firstUsage.usageList.size() != 1) {
         return false;
       }
 
-      final Pair<SqlOperator, RexNode> fUse = firstUsage.getUsageList().get(0);
-      final Pair<SqlOperator, RexNode> sUse = secondUsage.getUsageList().get(0);
+      final Pair<SqlOperator, RexNode> fUse = firstUsage.usageList.get(0);
+      final Pair<SqlOperator, RexNode> sUse = secondUsage.usageList.get(0);
 
-      final SqlKind fkind = fUse.getKey().getKind();
+      final SqlKind fKind = fUse.getKey().getKind();
 
-      if (fkind != SqlKind.EQUALS) {
+      if (fKind != SqlKind.EQUALS) {
         switch (sUse.getKey().getKind()) {
         case GREATER_THAN:
         case GREATER_THAN_OR_EQUAL:
-          if (!(fkind == SqlKind.GREATER_THAN)
-              && !(fkind == SqlKind.GREATER_THAN_OR_EQUAL)) {
+          if (!(fKind == SqlKind.GREATER_THAN)
+              && !(fKind == SqlKind.GREATER_THAN_OR_EQUAL)) {
             return false;
           }
           break;
         case LESS_THAN:
         case LESS_THAN_OR_EQUAL:
-          if (!(fkind == SqlKind.LESS_THAN)
-              && !(fkind == SqlKind.LESS_THAN_OR_EQUAL)) {
+          if (!(fKind == SqlKind.LESS_THAN)
+              && !(fKind == SqlKind.LESS_THAN_OR_EQUAL)) {
             return false;
           }
           break;
@@ -254,35 +278,29 @@ public class RexImplicationChecker {
   }
 
   private boolean validate(RexNode first, RexNode second) {
-    if (first == null || second == null) {
-      return false;
-    }
-    if (!(first instanceof RexCall)
-        || !(second instanceof RexCall)) {
-      return false;
-    }
-    return true;
+    return first instanceof RexCall && second instanceof RexCall;
   }
 
-
   /**
-   * Visitor which builds a Usage Map of inputs used by an expression.
-   * E.g: for x >10 AND y < 20 AND x =40, Usage Map would look like:
-   * key:x value: {(>,10),(=,40), usageCount = 2}
-   * key:y value: {(>,20),usageCount=1}
+   * Visitor that builds a usage map of inputs used by an expression.
+   *
+   * <p>E.g: for x > 10 AND y < 20 AND x = 40, usage map is as follows:
+   * <ul>
+   * <li>key: x value: {(>, 10),(=, 40), usageCount = 2}
+   * <li>key: y value: {(>, 20), usageCount = 1}
+   * </ul>
    */
   private static class InputUsageFinder extends RexVisitorImpl<Void> {
-    public final Map<RexInputRef, InputRefUsage<SqlOperator,
-        RexNode>> usageMap = new HashMap<>();
+    public final Map<RexInputRef, InputRefUsage<SqlOperator, RexNode>>
+    usageMap = new HashMap<>();
 
     public InputUsageFinder() {
       super(true);
     }
 
     public Void visitInputRef(RexInputRef inputRef) {
-      InputRefUsage<SqlOperator,
-          RexNode> inputRefUse = getUsageMap(inputRef);
-      inputRefUse.incrUsage();
+      InputRefUsage<SqlOperator, RexNode> inputRefUse = getUsageMap(inputRef);
+      inputRefUse.usageCount++;
       return null;
     }
 
@@ -318,8 +336,7 @@ public class RexImplicationChecker {
     }
 
     private SqlOperator reverse(SqlOperator op) {
-      return RelOptUtil.op(
-          RelOptUtil.reverse(op.getKind()), op);
+      return RelOptUtil.op(op.getKind().reverse(), op);
     }
 
     private static RexNode removeCast(RexNode inputRef) {
@@ -333,11 +350,12 @@ public class RexImplicationChecker {
       return inputRef;
     }
 
-    private void updateUsage(SqlOperator op, RexInputRef inputRef, RexNode literal) {
-      InputRefUsage<SqlOperator,
-          RexNode> inputRefUse = getUsageMap(inputRef);
+    private void updateUsage(SqlOperator op, RexInputRef inputRef,
+        RexNode literal) {
+      final InputRefUsage<SqlOperator, RexNode> inputRefUse =
+          getUsageMap(inputRef);
       Pair<SqlOperator, RexNode> use = Pair.of(op, literal);
-      inputRefUse.getUsageList().add(use);
+      inputRefUse.usageList.add(use);
     }
 
     private InputRefUsage<SqlOperator, RexNode> getUsageMap(RexInputRef rex) {
@@ -352,26 +370,12 @@ public class RexImplicationChecker {
   }
 
   /**
-   * DataStructure to store usage of InputRefs in expression
+   * Usage of a {@link RexInputRef} in an expression.
    */
-
   private static class InputRefUsage<T1, T2> {
-    private final List<Pair<T1, T2>> usageList =
-        new ArrayList<Pair<T1, T2>>();
+    private final List<Pair<T1, T2>> usageList = new ArrayList<>();
     private int usageCount = 0;
-
-    public InputRefUsage() {}
-
-    public int getUsageCount() {
-      return usageCount;
-    }
-
-    public void incrUsage() {
-      usageCount++;
-    }
-
-    public List<Pair<T1, T2>> getUsageList() {
-      return usageList;
-    }
   }
 }
+
+// End RexImplicationChecker.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a365609/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
index 62b2d9d..14e836a 100644
--- a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
+++ b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
@@ -145,11 +145,19 @@ public class SubstitutionVisitor {
   private static final Equivalence<List<?>> PAIRWISE_STRING_EQUIVALENCE =
       (Equivalence) STRING_EQUIVALENCE.pairwise();
 
-  protected static List<UnifyRule> unifyRules;
+  protected static final ImmutableList<UnifyRule> DEFAULT_RULES =
+      ImmutableList.<UnifyRule>of(
+//          TrivialRule.INSTANCE,
+          ProjectToProjectUnifyRule.INSTANCE,
+          FilterToProjectUnifyRule.INSTANCE,
+//          ProjectToFilterUnifyRule.INSTANCE,
+          FilterToFilterUnifyRule.INSTANCE,
+          AggregateToAggregateUnifyRule.INSTANCE,
+          AggregateOnProjectToAggregateUnifyRule.INSTANCE);
 
-  private static final Map<Pair<Class, Class>, List<UnifyRule>> RULE_MAP =
+  private final ImmutableList<UnifyRule> rules;
+  private final Map<Pair<Class, Class>, List<UnifyRule>> ruleMap =
       new HashMap<>();
-
   private final RelOptCluster cluster;
   private final Holder query;
   private final MutableRel target;
@@ -174,8 +182,16 @@ public class SubstitutionVisitor {
    * Assumes no rule needs more than 2 slots. */
   protected final MutableRel[] slots = new MutableRel[2];
 
+  /** Creates a SubstitutionVisitor with the default rule set. */
   public SubstitutionVisitor(RelNode target_, RelNode query_) {
+    this(target_, query_, DEFAULT_RULES);
+  }
+
+  /** Creates a SubstitutionVisitor. */
+  public SubstitutionVisitor(RelNode target_, RelNode query_,
+      ImmutableList<UnifyRule> rules) {
     this.cluster = target_.getCluster();
+    this.rules = rules;
     this.query = Holder.of(toMutable(query_));
     this.target = toMutable(target_);
     final Set<MutableRel> parents = Sets.newIdentityHashSet();
@@ -201,28 +217,6 @@ public class SubstitutionVisitor {
     visitor.go(query);
     allNodes.removeAll(parents);
     queryLeaves = ImmutableList.copyOf(allNodes);
-    initUnifyRules();
-    initRuleMap();
-  }
-
-  public void initUnifyRules() {
-    unifyRules =
-            ImmutableList.<UnifyRule>of(
-//          TrivialRule.INSTANCE,
-                    ProjectToProjectUnifyRule.INSTANCE,
-                    FilterToProjectUnifyRule.INSTANCE,
-//          ProjectToFilterUnifyRule.INSTANCE,
-                    FilterToFilterUnifyRule.INSTANCE,
-                    AggregateToAggregateUnifyRule.INSTANCE,
-                    AggregateOnProjectToAggregateUnifyRule.INSTANCE);
-  }
-
-  public void initRuleMap() {
-    this.RULE_MAP.clear();
-  }
-
-  public MutableRel[] getSlots() {
-    return slots;
   }
 
   private static MutableRel toMutable(RelNode rel) {
@@ -619,23 +613,23 @@ public class SubstitutionVisitor {
     return rule.apply(call);
   }
 
-  private static List<UnifyRule> applicableRules(MutableRel query,
+  private List<UnifyRule> applicableRules(MutableRel query,
       MutableRel target) {
     final Class queryClass = query.getClass();
     final Class targetClass = target.getClass();
     final Pair<Class, Class> key = Pair.of(queryClass, targetClass);
-    List<UnifyRule> list = RULE_MAP.get(key);
+    List<UnifyRule> list = ruleMap.get(key);
     if (list == null) {
       final ImmutableList.Builder<UnifyRule> builder =
           ImmutableList.builder();
-      for (UnifyRule rule : unifyRules) {
+      for (UnifyRule rule : rules) {
         //noinspection unchecked
         if (mightMatch(rule, queryClass, targetClass)) {
           builder.add(rule);
         }
       }
       list = builder.build();
-      RULE_MAP.put(key, list);
+      ruleMap.put(key, list);
     }
     return list;
   }
@@ -648,6 +642,7 @@ public class SubstitutionVisitor {
 
   /** Exception thrown to exit a matcher. Not really an error. */
   protected static class MatchFailed extends ControlFlowException {
+    @SuppressWarnings("ThrowableInstanceNeverThrown")
     public static final MatchFailed INSTANCE = new MatchFailed();
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a365609/core/src/main/java/org/apache/calcite/plan/VisitorDataContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/VisitorDataContext.java b/core/src/main/java/org/apache/calcite/plan/VisitorDataContext.java
index a941347..c0fe8a8 100644
--- a/core/src/main/java/org/apache/calcite/plan/VisitorDataContext.java
+++ b/core/src/main/java/org/apache/calcite/plan/VisitorDataContext.java
@@ -67,17 +67,17 @@ public class VisitorDataContext implements DataContext {
       return null;
     }
   }
-  public static DataContext getDataContext(RelNode targetRel, LogicalFilter queryRel) {
-    return getDataContext(targetRel.getRowType(), queryRel.getCondition());
+  public static DataContext of(RelNode targetRel, LogicalFilter queryRel) {
+    return of(targetRel.getRowType(), queryRel.getCondition());
   }
 
-  public static DataContext getDataContext(RelDataType rowType, RexNode rex) {
-    int size = rowType.getFieldList().size();
-    Object[] values = new Object[size];
-    List<RexNode> operands = ((RexCall) rex).getOperands();
+  public static DataContext of(RelDataType rowType, RexNode rex) {
+    final int size = rowType.getFieldList().size();
+    final Object[] values = new Object[size];
+    final List<RexNode> operands = ((RexCall) rex).getOperands();
     final RexNode firstOperand = operands.get(0);
     final RexNode secondOperand = operands.get(1);
-    final Pair<Integer, ? extends Object> value = getValue(firstOperand, secondOperand);
+    final Pair<Integer, ?> value = getValue(firstOperand, secondOperand);
     if (value != null) {
       int index = value.getKey();
       values[index] = value.getValue();
@@ -87,12 +87,12 @@ public class VisitorDataContext implements DataContext {
     }
   }
 
-  public static DataContext getDataContext(RelDataType rowType, List<Pair<RexInputRef,
-      RexNode>> usgList) {
-    int size = rowType.getFieldList().size();
-    Object[] values = new Object[size];
-    for (Pair<RexInputRef, RexNode> elem: usgList) {
-      Pair<Integer, ? extends Object> value = getValue(elem.getKey(), elem.getValue());
+  public static DataContext of(RelDataType rowType,
+      List<Pair<RexInputRef, RexNode>> usageList) {
+    final int size = rowType.getFieldList().size();
+    final Object[] values = new Object[size];
+    for (Pair<RexInputRef, RexNode> elem : usageList) {
+      Pair<Integer, ?> value = getValue(elem.getKey(), elem.getValue());
       if (value == null) {
         return null;
       }
@@ -102,46 +102,40 @@ public class VisitorDataContext implements DataContext {
     return new VisitorDataContext(values);
   }
 
-  public static Pair<Integer, ? extends Object> getValue(RexNode inputRef, RexNode literal) {
+  public static Pair<Integer, ?> getValue(RexNode inputRef, RexNode literal) {
     inputRef = removeCast(inputRef);
     literal = removeCast(literal);
 
     if (inputRef instanceof RexInputRef
         && literal instanceof RexLiteral)  {
-      Integer index = ((RexInputRef) inputRef).getIndex();
+      final int index = ((RexInputRef) inputRef).getIndex();
       Object value = ((RexLiteral) literal).getValue();
       final RelDataType type = inputRef.getType();
 
       switch (type.getSqlTypeName()) {
       case INTEGER:
         if (value instanceof BigDecimal) {
-          final Integer intValue = new Integer(((BigDecimal) value).intValue());
-          return Pair.of(index, intValue);
+          return Pair.of(index, ((BigDecimal) value).intValue());
         }
       case DOUBLE:
         if (value instanceof BigDecimal) {
-          return Pair.of(index,
-              new Double(((BigDecimal) value).doubleValue()));
+          return Pair.of(index, ((BigDecimal) value).doubleValue());
         }
       case REAL:
         if (value instanceof BigDecimal) {
-          return Pair.of(index,
-              new Float(((BigDecimal) value).floatValue()));
+          return Pair.of(index, ((BigDecimal) value).floatValue());
         }
       case BIGINT:
         if (value instanceof BigDecimal) {
-          return Pair.of(index,
-              new Long(((BigDecimal) value).longValue()));
+          return Pair.of(index, ((BigDecimal) value).longValue());
         }
       case SMALLINT:
         if (value instanceof BigDecimal) {
-          return Pair.of(index,
-              new Short(((BigDecimal) value).shortValue()));
+          return Pair.of(index, ((BigDecimal) value).shortValue());
         }
       case TINYINT:
         if (value instanceof BigDecimal) {
-          return Pair.of(index,
-              new Short(((BigDecimal) value).byteValue()));
+          return Pair.of(index, (short) ((BigDecimal) value).byteValue());
         }
       case DECIMAL:
         if (value instanceof BigDecimal) {
@@ -158,13 +152,12 @@ public class VisitorDataContext implements DataContext {
         }
       case CHAR:
         if (value instanceof NlsString) {
-          // TODO: Support coallation. Not supported in {@link #NlsString} compare too.
+          // TODO: Support collation. Not supported in NlsString compare too.
           final NlsString nl = (NlsString) value;
-          Character c = new Character(nl.getValue().charAt(0));
-          return Pair.of(index, c);
+          return Pair.of(index, nl.getValue().charAt(0));
         }
       default:
-        //TODO: Support few more supported cases
+        // TODO: Support few more supported cases
         return Pair.of(index, value);
       }
     }
@@ -184,3 +177,5 @@ public class VisitorDataContext implements DataContext {
     return inputRef;
   }
 }
+
+// End VisitorDataContext.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a365609/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java
index 302a02e..52b5497 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java
@@ -113,7 +113,7 @@ public class AggregateFilterTransposeRule extends RelOptRule {
       if (aggregate.indicator) {
         ImmutableList.Builder<ImmutableBitSet> newGroupingSetsBuilder =
                 ImmutableList.builder();
-        for (ImmutableBitSet groupingSet: aggregate.getGroupSets()) {
+        for (ImmutableBitSet groupingSet : aggregate.getGroupSets()) {
           final ImmutableBitSet.Builder newGroupingSet =
                   ImmutableBitSet.builder();
           for (int c : groupingSet) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a365609/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
index 5f78489..df55f0d 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
@@ -156,7 +156,7 @@ public class AggregateUnionTransposeRule extends RelOptRule {
   private List<AggregateCall> transformAggCalls(RelNode input, int groupCount,
       List<AggregateCall> origCalls) {
     final List<AggregateCall> newCalls = Lists.newArrayList();
-    for (Ord<AggregateCall> ord: Ord.zip(origCalls)) {
+    for (Ord<AggregateCall> ord : Ord.zip(origCalls)) {
       final AggregateCall origCall = ord.e;
       if (origCall.isDistinct()
           || !SUPPORTED_AGGREGATES.containsKey(origCall.getAggregation()

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a365609/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
index 720e33d..b364ef3 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
@@ -131,7 +131,7 @@ public class FilterAggregateTransposeRule extends RelOptRule {
       // If grouping sets are used, the filter can be pushed if
       // the columns referenced in the predicate are present in
       // all the grouping sets.
-      for (ImmutableBitSet groupingSet: aggregate.getGroupSets()) {
+      for (ImmutableBitSet groupingSet : aggregate.getGroupSets()) {
         if (!groupingSet.contains(rCols)) {
           return false;
         }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a365609/core/src/main/java/org/apache/calcite/sql/SqlKind.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlKind.java b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
index 244a241..0bdb82c 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlKind.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
@@ -728,6 +728,26 @@ public enum SqlKind {
           LESS_THAN, GREATER_THAN,
           GREATER_THAN_OR_EQUAL, LESS_THAN_OR_EQUAL);
 
+  /** Returns the kind that corresponds to this operator but in the opposite
+   * direction. Or returns this, if this kind is not reversible.
+   *
+   * <p>For example, {@code GREATER_THAN.reverse()} returns {@link #LESS_THAN}.
+   */
+  public SqlKind reverse() {
+    switch (this) {
+    case GREATER_THAN:
+      return LESS_THAN;
+    case GREATER_THAN_OR_EQUAL:
+      return LESS_THAN_OR_EQUAL;
+    case LESS_THAN:
+      return GREATER_THAN;
+    case LESS_THAN_OR_EQUAL:
+      return GREATER_THAN_OR_EQUAL;
+    default:
+      return this;
+    }
+  }
+
   /**
    * Returns whether this {@code SqlKind} belongs to a given category.
    *

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a365609/core/src/test/java/org/apache/calcite/rex/RexExecutorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/rex/RexExecutorTest.java b/core/src/test/java/org/apache/calcite/rex/RexExecutorTest.java
index b56c928..d4780a6 100644
--- a/core/src/test/java/org/apache/calcite/rex/RexExecutorTest.java
+++ b/core/src/test/java/org/apache/calcite/rex/RexExecutorTest.java
@@ -31,6 +31,7 @@ import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.tools.Frameworks;
 import org.apache.calcite.util.NlsString;
 
+import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
 
 import org.junit.Assert;
@@ -38,6 +39,7 @@ import org.junit.Test;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.List;
 
 import static org.hamcrest.CoreMatchers.equalTo;
@@ -70,48 +72,48 @@ public class RexExecutorTest {
   /** Tests an executor that uses variables stored in a {@link DataContext}.
    * Can change the value of the variable and execute again. */
   @Test public void testVariableExecution() throws Exception {
-    check(new Action() {
-      public void check(RexBuilder rexBuilder, RexExecutorImpl executor) {
-        Object[] values = new Object[1];
-        final DataContext testContext = new TestDataContext(values);
-        final RelDataType varchar = rexBuilder.getTypeFactory().createSqlType(
-            SqlTypeName.VARCHAR);
-        final RelDataType integer = rexBuilder.getTypeFactory().createSqlType(
-            SqlTypeName.INTEGER);
-        // calcite is internally creating the creating the input ref via a
-        // RexRangeRef
-        // which eventually leads to a RexInputRef. So we are good.
-        final RexInputRef input = rexBuilder.makeInputRef(varchar, 0);
-        final RexNode lengthArg = rexBuilder.makeLiteral(3, integer, true);
-        final RexNode substr =
-            rexBuilder.makeCall(SqlStdOperatorTable.SUBSTRING, input,
-                lengthArg);
-        ImmutableList<RexNode> constExps = ImmutableList.of(substr);
-
-        final RelDataTypeFactory typeFactory = rexBuilder.getTypeFactory();
-        final RelDataType rowType = typeFactory.builder()
-            .add("someStr", varchar)
-            .build();
-
-        final RexExecutable exec = executor.getExecutable(rexBuilder,
-            constExps, rowType);
-        exec.setDataContext(testContext);
-        values[0] = "Hello World";
-        Object[] result = exec.execute();
-        assertTrue(result[0] instanceof String);
-        assertThat((String) result[0], equalTo("llo World"));
-        values[0] = "Calcite";
-        result = exec.execute();
-        assertTrue(result[0] instanceof String);
-        assertThat((String) result[0], equalTo("lcite"));
-      }
-    });
+    check(
+        new Action() {
+          public void check(RexBuilder rexBuilder, RexExecutorImpl executor) {
+            Object[] values = new Object[1];
+            final DataContext testContext = new TestDataContext(values);
+            final RelDataTypeFactory typeFactory = rexBuilder.getTypeFactory();
+            final RelDataType varchar =
+                typeFactory.createSqlType(SqlTypeName.VARCHAR);
+            final RelDataType integer =
+                typeFactory.createSqlType(SqlTypeName.INTEGER);
+            // Calcite is internally creating the input ref via a RexRangeRef
+            // which eventually leads to a RexInputRef. So we are good.
+            final RexInputRef input = rexBuilder.makeInputRef(varchar, 0);
+            final RexNode lengthArg = rexBuilder.makeLiteral(3, integer, true);
+            final RexNode substr =
+                rexBuilder.makeCall(SqlStdOperatorTable.SUBSTRING, input,
+                    lengthArg);
+            ImmutableList<RexNode> constExps = ImmutableList.of(substr);
+
+            final RelDataType rowType = typeFactory.builder()
+                .add("someStr", varchar)
+                .build();
+
+            final RexExecutable exec = executor.getExecutable(rexBuilder,
+                constExps, rowType);
+            exec.setDataContext(testContext);
+            values[0] = "Hello World";
+            Object[] result = exec.execute();
+            assertTrue(result[0] instanceof String);
+            assertThat((String) result[0], equalTo("llo World"));
+            values[0] = "Calcite";
+            result = exec.execute();
+            assertTrue(result[0] instanceof String);
+            assertThat((String) result[0], equalTo("lcite"));
+          }
+        });
   }
 
   @Test public void testConstant() throws Exception {
     check(new Action() {
       public void check(RexBuilder rexBuilder, RexExecutorImpl executor) {
-        final List<RexNode> reducedValues = new ArrayList<RexNode>();
+        final List<RexNode> reducedValues = new ArrayList<>();
         final RexLiteral ten = rexBuilder.makeExactLiteral(BigDecimal.TEN);
         executor.reduce(rexBuilder, ImmutableList.<RexNode>of(ten),
             reducedValues);
@@ -123,10 +125,68 @@ public class RexExecutorTest {
     });
   }
 
+  /** Reduces several expressions to constants. */
+  @Test public void testConstant2() throws Exception {
+    // Same as testConstant; 10 -> 10
+    checkConstant(10L,
+        new Function<RexBuilder, RexNode>() {
+          public RexNode apply(RexBuilder rexBuilder) {
+            return rexBuilder.makeExactLiteral(BigDecimal.TEN);
+          }
+        });
+    // 10 + 1 -> 11
+    checkConstant(11L,
+        new Function<RexBuilder, RexNode>() {
+          public RexNode apply(RexBuilder rexBuilder) {
+            return rexBuilder.makeCall(SqlStdOperatorTable.PLUS,
+                rexBuilder.makeExactLiteral(BigDecimal.TEN),
+                rexBuilder.makeExactLiteral(BigDecimal.ONE));
+          }
+        });
+    // date 'today' <= date 'today' -> true
+    checkConstant(true,
+        new Function<RexBuilder, RexNode>() {
+          public RexNode apply(RexBuilder rexBuilder) {
+            Calendar calendar = Calendar.getInstance();
+            return rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN_OR_EQUAL,
+                rexBuilder.makeDateLiteral(calendar),
+                rexBuilder.makeDateLiteral(calendar));
+          }
+        });
+    // date 'today' < date 'today' -> false
+    checkConstant(false,
+        new Function<RexBuilder, RexNode>() {
+          public RexNode apply(RexBuilder rexBuilder) {
+            Calendar calendar = Calendar.getInstance();
+            return rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN,
+                rexBuilder.makeDateLiteral(calendar),
+                rexBuilder.makeDateLiteral(calendar));
+          }
+        });
+  }
+
+  private void checkConstant(final Object operand,
+      final Function<RexBuilder, RexNode> function) throws Exception {
+    check(
+        new Action() {
+          public void check(RexBuilder rexBuilder, RexExecutorImpl executor) {
+            final List<RexNode> reducedValues = new ArrayList<>();
+            final RexNode expression = function.apply(rexBuilder);
+            assert expression != null;
+            executor.reduce(rexBuilder, ImmutableList.of(expression),
+                reducedValues);
+            assertThat(reducedValues.size(), equalTo(1));
+            assertThat(reducedValues.get(0), instanceOf(RexLiteral.class));
+            assertThat(((RexLiteral) reducedValues.get(0)).getValue2(),
+                equalTo(operand));
+          }
+        });
+  }
+
   @Test public void testSubstring() throws Exception {
     check(new Action() {
       public void check(RexBuilder rexBuilder, RexExecutorImpl executor) {
-        final List<RexNode> reducedValues = new ArrayList<RexNode>();
+        final List<RexNode> reducedValues = new ArrayList<>();
         final RexLiteral hello =
             rexBuilder.makeCharLiteral(
                 new NlsString("Hello world!", null, null));

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a365609/core/src/test/java/org/apache/calcite/test/DiffRepository.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/DiffRepository.java b/core/src/test/java/org/apache/calcite/test/DiffRepository.java
index fb6b325..572dde9 100644
--- a/core/src/test/java/org/apache/calcite/test/DiffRepository.java
+++ b/core/src/test/java/org/apache/calcite/test/DiffRepository.java
@@ -435,7 +435,6 @@ public class DiffRepository {
             tag,
             expected2Canonical,
             actualCanonical);
-        amend(expected, actual);
       } catch (ComparisonFailure e) {
         amend(expected, actual);
         throw e;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a365609/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
index 7e693b0..720798e 100644
--- a/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
@@ -27,6 +27,7 @@ import org.apache.calcite.rel.type.RelDataTypeSystem;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexExecutorImpl;
 import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.schema.SchemaPlus;
 import org.apache.calcite.schema.Schemas;
@@ -34,9 +35,9 @@ import org.apache.calcite.server.CalciteServerStatement;
 import org.apache.calcite.sql.SqlCollation;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.tools.Frameworks;
+import org.apache.calcite.util.Holder;
 import org.apache.calcite.util.NlsString;
 
-import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -50,399 +51,320 @@ import java.sql.Timestamp;
 import java.util.Calendar;
 
 /**
- * Tests the RexImplication checker
+ * Unit tests for {@link RexImplicationChecker}.
  */
 public class RexImplicationCheckerTest {
   //~ Instance fields --------------------------------------------------------
 
-  private RexBuilder rexBuilder = null;
-  private RexNode bl;
-  private RexNode i;
-  private RexNode dec;
-  private RexNode lg;
-  private RexNode sh;
-  private RexNode by;
-  private RexNode fl;
-  private RexNode dt;
-  private RexNode ch;
-  private RexNode ts;
-  private RexNode t;
-
-  private RelDataType boolRelDataType;
-  private RelDataType intRelDataType;
-  private RelDataType decRelDataType;
-  private RelDataType longRelDataType;
-  private RelDataType shortDataType;
-  private RelDataType byteDataType;
-  private RelDataType floatDataType;
-  private RelDataType charDataType;
-  private RelDataType dateDataType;
-  private RelDataType timeStampDataType;
-  private RelDataType timeDataType;
-  private RelDataTypeFactory typeFactory;
-  private RexImplicationChecker checker;
-  private RelDataType rowType;
-  private RexExecutorImpl executor;
-
   //~ Methods ----------------------------------------------------------------
 
-  @Before
-  public void setUp() {
-    typeFactory = new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
-    rexBuilder = new RexBuilder(typeFactory);
-    boolRelDataType = typeFactory.createJavaType(Boolean.class);
-    intRelDataType = typeFactory.createJavaType(Integer.class);
-    decRelDataType = typeFactory.createJavaType(Double.class);
-    longRelDataType = typeFactory.createJavaType(Long.class);
-    shortDataType = typeFactory.createJavaType(Short.class);
-    byteDataType = typeFactory.createJavaType(Byte.class);
-    floatDataType = typeFactory.createJavaType(Float.class);
-    charDataType = typeFactory.createJavaType(Character.class);
-    dateDataType = typeFactory.createJavaType(Date.class);
-    timeStampDataType = typeFactory.createJavaType(Timestamp.class);
-    timeDataType = typeFactory.createJavaType(Time.class);
-
-    bl = new RexInputRef(
-        0,
-        typeFactory.createTypeWithNullability(boolRelDataType, true));
-    i = new RexInputRef(
-        1,
-        typeFactory.createTypeWithNullability(intRelDataType, true));
-    dec = new RexInputRef(
-        2,
-        typeFactory.createTypeWithNullability(decRelDataType, true));
-    lg = new RexInputRef(
-        3,
-        typeFactory.createTypeWithNullability(longRelDataType, true));
-    sh = new RexInputRef(
-        4,
-        typeFactory.createTypeWithNullability(shortDataType, true));
-    by = new RexInputRef(
-        5,
-        typeFactory.createTypeWithNullability(byteDataType, true));
-    fl = new RexInputRef(
-        6,
-        typeFactory.createTypeWithNullability(floatDataType, true));
-    ch = new RexInputRef(
-        7,
-        typeFactory.createTypeWithNullability(charDataType, true));
-    dt = new RexInputRef(
-        8,
-        typeFactory.createTypeWithNullability(dateDataType, true));
-    ts = new RexInputRef(
-        9,
-        typeFactory.createTypeWithNullability(timeStampDataType, true));
-    t = new RexInputRef(
-        10,
-        typeFactory.createTypeWithNullability(timeDataType, true));
-
-    rowType =  typeFactory.builder()
-        .add("bool", boolRelDataType)
-        .add("int", intRelDataType)
-        .add("dec", decRelDataType)
-        .add("long", longRelDataType)
-        .add("short", shortDataType)
-        .add("byte", byteDataType)
-        .add("float", floatDataType)
-        .add("char", charDataType)
-        .add("date", dateDataType)
-        .add("timestamp", timeStampDataType)
-        .add("time", timeDataType)
-        .build();
-
-    Frameworks.withPrepare(
-        new Frameworks.PrepareAction<Void>() {
-          public Void apply(RelOptCluster cluster,
-                            RelOptSchema relOptSchema,
-                            SchemaPlus rootSchema,
-                            CalciteServerStatement statement) {
-            DataContext dataContext =
-                Schemas.createDataContext(statement.getConnection());
-            executor = new RexExecutorImpl(dataContext);
-            return null;
-          }
-        });
-
-    checker = new RexImplicationChecker(rexBuilder, executor, rowType);
-  }
-
-  private void checkImplies(RexNode node1, RexNode node2) {
-    assertTrue(node1.toString() + " doesnot imply " + node2.toString()
-        + " when it should.", checker.implies(node1, node2));
-  }
-
-  private void checkNotImplies(RexNode node1, RexNode node2) {
-    assertFalse(node1.toString() + " implies " + node2.toString()
-        + " when it should not", checker.implies(node1, node2));
-  }
-
   // Simple Tests for Operators
   @Test public void testSimpleGreaterCond() {
-    RexNode node1 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.GREATER_THAN,
-            i,
-            rexBuilder.makeExactLiteral(new BigDecimal(10)));
-
-    RexNode node2 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.GREATER_THAN,
-            i,
-            rexBuilder.makeExactLiteral(new BigDecimal(30)));
-
-    RexNode node3 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
-            i,
-            rexBuilder.makeExactLiteral(new BigDecimal(30)));
-
-    RexNode node4 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
-            i,
-            rexBuilder.makeExactLiteral(new BigDecimal(10)));
-
-    RexNode node5 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.EQUALS,
-            i,
-            rexBuilder.makeExactLiteral(new BigDecimal(30)));
-
-    RexNode node6 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.NOT_EQUALS,
-            i,
-            rexBuilder.makeExactLiteral(new BigDecimal(10)));
-
-    checkImplies(node2, node1);
-    checkNotImplies(node1, node2);
-    checkNotImplies(node1, node3);
-    checkImplies(node3, node1);
-    checkImplies(node5, node1);
-    checkNotImplies(node1, node5);
-    checkNotImplies(node1, node6);
-    checkNotImplies(node4, node6);
+    final Fixture f = new Fixture();
+    final RexNode node1 = f.gt(f.i, f.literal(10));
+    final RexNode node2 = f.gt(f.i, f.literal(30));
+    final RexNode node3 = f.ge(f.i, f.literal(30));
+    final RexNode node4 = f.ge(f.i, f.literal(10));
+    final RexNode node5 = f.eq(f.i, f.literal(30));
+    final RexNode node6 = f.ne(f.i, f.literal(10));
+
+    f.checkImplies(node2, node1);
+    f.checkNotImplies(node1, node2);
+    f.checkNotImplies(node1, node3);
+    f.checkImplies(node3, node1);
+    f.checkImplies(node5, node1);
+    f.checkNotImplies(node1, node5);
+    f.checkNotImplies(node1, node6);
+    f.checkNotImplies(node4, node6);
     // TODO: Need to support Identity
-    //checkImplies(node1, node1);
-    //checkImplies(node3, node3);
+    //f.checkImplies(node1, node1);
+    //f.checkImplies(node3, node3);
   }
 
   @Test public void testSimpleLesserCond() {
-    RexNode node1 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.LESS_THAN,
-            i,
-            rexBuilder.makeExactLiteral(new BigDecimal(10)));
-
-    RexNode node2 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.LESS_THAN,
-            i,
-            rexBuilder.makeExactLiteral(new BigDecimal(30)));
-
-    RexNode node3 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.LESS_THAN_OR_EQUAL,
-            i,
-            rexBuilder.makeExactLiteral(new BigDecimal(30)));
-
-    RexNode node4 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.LESS_THAN_OR_EQUAL,
-            i,
-            rexBuilder.makeExactLiteral(new BigDecimal(10)));
-
-    RexNode node5 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.EQUALS,
-            i,
-            rexBuilder.makeExactLiteral(new BigDecimal(10)));
-
-    RexNode node6 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.NOT_EQUALS,
-            i,
-            rexBuilder.makeExactLiteral(new BigDecimal(10)));
-
-    checkImplies(node1, node2);
-    checkNotImplies(node2, node1);
-    checkImplies(node1, node3);
-    checkNotImplies(node3, node1);
-    checkImplies(node5, node2);
-    checkNotImplies(node2, node5);
-    checkNotImplies(node1, node5);
-    checkNotImplies(node1, node6);
-    checkNotImplies(node4, node6);
+    final Fixture f = new Fixture();
+    final RexNode node1 = f.lt(f.i, f.literal(10));
+    final RexNode node2 = f.lt(f.i, f.literal(30));
+    final RexNode node3 = f.le(f.i, f.literal(30));
+    final RexNode node4 = f.le(f.i, f.literal(10));
+    final RexNode node5 = f.eq(f.i, f.literal(10));
+    final RexNode node6 = f.ne(f.i, f.literal(10));
+
+    f.checkImplies(node1, node2);
+    f.checkNotImplies(node2, node1);
+    f.checkImplies(node1, node3);
+    f.checkNotImplies(node3, node1);
+    f.checkImplies(node5, node2);
+    f.checkNotImplies(node2, node5);
+    f.checkNotImplies(node1, node5);
+    f.checkNotImplies(node1, node6);
+    f.checkNotImplies(node4, node6);
     // TODO: Need to support Identity
-    //checkImplies(node1, node1);
-    //checkImplies(node3, node3);
+    //f.checkImplies(node1, node1);
+    //f.checkImplies(node3, node3);
   }
 
   @Test public void testSimpleEq() {
-    RexNode node1 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.EQUALS,
-            i,
-            rexBuilder.makeExactLiteral(new BigDecimal(30)));
-
-    RexNode node2 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.NOT_EQUALS,
-            i,
-            rexBuilder.makeExactLiteral(new BigDecimal(10)));
+    final Fixture f = new Fixture();
+    final RexNode node1 = f.eq(f.i, f.literal(30));
+    final RexNode node2 = f.ne(f.i, f.literal(10));
 
     //Check Identity
-    checkImplies(node1, node1);
+    f.checkImplies(node1, node1);
     //TODO: Support Identity
-    // checkImplies(node2, node2);
-    checkImplies(node1, node2);
-    checkNotImplies(node2, node1);
+    // f.checkImplies(node2, node2);
+    f.checkImplies(node1, node2);
+    f.checkNotImplies(node2, node1);
   }
 
   // Simple Tests for DataTypes
   @Test public void testSimpleDec() {
-    RexNode node1 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.LESS_THAN,
-            dec,
-            rexBuilder.makeApproxLiteral(new BigDecimal(30.9)));
-
-    RexNode node2 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.LESS_THAN,
-            dec,
-            rexBuilder.makeApproxLiteral(new BigDecimal(40.33)));
-
-    checkImplies(node1, node2);
-    checkNotImplies(node2, node1);
+    final Fixture f = new Fixture();
+    final RexNode node1 = f.lt(f.dec, f.floatLiteral(30.9));
+    final RexNode node2 = f.lt(f.dec, f.floatLiteral(40.33));
+
+    f.checkImplies(node1, node2);
+    f.checkNotImplies(node2, node1);
   }
 
   @Test public void testSimpleBoolean() {
-    RexNode node1 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.EQUALS,
-            bl,
-            rexBuilder.makeLiteral(true));
-
-    RexNode node2 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.EQUALS,
-            bl,
-            rexBuilder.makeLiteral(false));
+    final Fixture f = new Fixture();
+    final RexNode node1 = f.eq(f.bl, f.rexBuilder.makeLiteral(true));
+    final RexNode node2 = f.eq(f.bl, f.rexBuilder.makeLiteral(false));
 
     //TODO: Need to support false => true
-    //checkImplies(node2, node1);
-    checkNotImplies(node1, node2);
+    //f.checkImplies(node2, node1);
+    f.checkNotImplies(node1, node2);
   }
 
   @Test public void testSimpleLong() {
-    RexNode node1 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
-            lg,
-            rexBuilder.makeLiteral(new Long(324324L), longRelDataType, true));
-
-    RexNode node2 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.GREATER_THAN,
-            lg,
-            rexBuilder.makeLiteral(new Long(324325L), longRelDataType, true));
-
-    checkImplies(node2, node1);
-    checkNotImplies(node1, node2);
+    final Fixture f = new Fixture();
+    final RexNode node1 = f.ge(f.lg, f.longLiteral(324324L));
+    final RexNode node2 = f.gt(f.lg, f.longLiteral(324325L));
+
+    f.checkImplies(node2, node1);
+    f.checkNotImplies(node1, node2);
   }
 
   @Test public void testSimpleShort() {
-    RexNode node1 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
-            sh,
-            rexBuilder.makeLiteral(new Short((short) 10), shortDataType, true));
-
-    RexNode node2 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
-            sh,
-            rexBuilder.makeLiteral(new Short((short) 11), shortDataType, true));
-
-    checkImplies(node2, node1);
-    checkNotImplies(node1, node2);
+    final Fixture f = new Fixture();
+    final RexNode node1 = f.ge(f.sh, f.shortLiteral((short) 10));
+    final RexNode node2 = f.ge(f.sh, f.shortLiteral((short) 11));
+
+    f.checkImplies(node2, node1);
+    f.checkNotImplies(node1, node2);
   }
 
   @Test public void testSimpleChar() {
-    RexNode node1 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
-            ch,
-            rexBuilder.makeCharLiteral(new NlsString("b", null, SqlCollation.COERCIBLE)));
-
-    RexNode node2 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
-            ch,
-            rexBuilder.makeCharLiteral(new NlsString("a", null, SqlCollation.COERCIBLE)));
-
-    checkImplies(node1, node2);
-    checkNotImplies(node2, node1);
+    final Fixture f = new Fixture();
+    final RexNode node1 = f.ge(f.ch, f.charLiteral("b"));
+    final RexNode node2 = f.ge(f.ch, f.charLiteral("a"));
+
+    f.checkImplies(node1, node2);
+    f.checkNotImplies(node2, node1);
   }
 
+  @Ignore("work in progress")
   @Test public void testSimpleDate() {
-    RexNode node1 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
-            dt,
-            rexBuilder.makeDateLiteral(Calendar.getInstance()));
-
-    RexNode node2 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.EQUALS,
-            dt,
-            rexBuilder.makeDateLiteral(Calendar.getInstance()));
-
-    checkImplies(node2, node1);
-    checkNotImplies(node1, node2);
+    final Fixture f = new Fixture();
+    final Calendar instance = Calendar.getInstance();
+    final RexNode node1 = f.ge(f.dt, f.rexBuilder.makeDateLiteral(instance));
+    final RexNode node2 = f.eq(f.dt, f.rexBuilder.makeDateLiteral(instance));
+
+    f.checkImplies(node2, node1);
+    f.checkNotImplies(node1, node2);
   }
 
   @Ignore("work in progress")
   @Test public void testSimpleTimeStamp() {
-    RexNode node1 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.LESS_THAN_OR_EQUAL,
-            ts,
-            rexBuilder.makeTimestampLiteral(Calendar.getInstance(),
-                timeStampDataType.getPrecision()));
-
-
-    RexNode node2 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.LESS_THAN_OR_EQUAL,
-            ts,
-            rexBuilder.makeTimestampLiteral(Calendar.getInstance(),
-                timeStampDataType.getPrecision()));
-
-    checkImplies(node1, node2);
-    checkNotImplies(node2, node1);
+    final Fixture f = new Fixture();
+    final Calendar calendar = Calendar.getInstance();
+    final RexNode node1 = f.le(f.ts, f.timestampLiteral(calendar));
+    final RexNode node2 = f.le(f.ts, f.timestampLiteral(calendar));
+
+    f.checkImplies(node1, node2);
+    f.checkNotImplies(node2, node1);
   }
 
   @Ignore("work in progress")
   @Test public void testSimpleTime() {
-    RexNode node1 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.LESS_THAN_OR_EQUAL,
-            t,
-            rexBuilder.makeTimeLiteral(Calendar.getInstance(),
-                timeDataType.getPrecision()));
-
-
-    RexNode node2 =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.LESS_THAN_OR_EQUAL,
-            t,
-            rexBuilder.makeTimestampLiteral(Calendar.getInstance(),
-                timeDataType.getPrecision()));
-
-    checkImplies(node1, node2);
-    checkNotImplies(node2, node1);
+    final Fixture f = new Fixture();
+    final Calendar calendar = Calendar.getInstance();
+    final RexNode node1 = f.le(f.ts, f.timeLiteral(calendar));
+    final RexNode node2 = f.le(f.ts, f.timeLiteral(calendar));
+
+    f.checkImplies(node1, node2);
+    f.checkNotImplies(node2, node1);
   }
 
+  /** Contains all the nourishment a test case could possibly need.
+   *
+   * <p>We put the data in here, rather than as fields in the test case, so that
+   * the data can be garbage-collected as soon as the test has executed.
+   */
+  private static class Fixture {
+    private final RexBuilder rexBuilder;
+    private final RexNode bl;
+    private final RexNode i;
+    private final RexNode dec;
+    private final RexNode lg;
+    private final RexNode sh;
+    private final RexNode by;
+    private final RexNode fl;
+    private final RexNode dt;
+    private final RexNode ch;
+    private final RexNode ts;
+    private final RexNode t;
+
+    private final RelDataType boolRelDataType;
+    private final RelDataType intRelDataType;
+    private final RelDataType decRelDataType;
+    private final RelDataType longRelDataType;
+    private final RelDataType shortDataType;
+    private final RelDataType byteDataType;
+    private final RelDataType floatDataType;
+    private final RelDataType charDataType;
+    private final RelDataType dateDataType;
+    private final RelDataType timeStampDataType;
+    private final RelDataType timeDataType;
+    private final RelDataTypeFactory typeFactory;
+    private final RexImplicationChecker checker;
+    private final RelDataType rowType;
+    private final RexExecutorImpl executor;
+
+    public Fixture() {
+      typeFactory = new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
+      rexBuilder = new RexBuilder(typeFactory);
+      boolRelDataType = typeFactory.createJavaType(Boolean.class);
+      intRelDataType = typeFactory.createJavaType(Integer.class);
+      decRelDataType = typeFactory.createJavaType(Double.class);
+      longRelDataType = typeFactory.createJavaType(Long.class);
+      shortDataType = typeFactory.createJavaType(Short.class);
+      byteDataType = typeFactory.createJavaType(Byte.class);
+      floatDataType = typeFactory.createJavaType(Float.class);
+      charDataType = typeFactory.createJavaType(Character.class);
+      dateDataType = typeFactory.createJavaType(Date.class);
+      timeStampDataType = typeFactory.createJavaType(Timestamp.class);
+      timeDataType = typeFactory.createJavaType(Time.class);
+
+      bl = ref(0, this.boolRelDataType);
+      i = ref(1, intRelDataType);
+      dec = ref(2, decRelDataType);
+      lg = ref(3, longRelDataType);
+      sh = ref(4, shortDataType);
+      by = ref(5, byteDataType);
+      fl = ref(6, floatDataType);
+      ch = ref(7, charDataType);
+      dt = ref(8, dateDataType);
+      ts = ref(9, timeStampDataType);
+      t = ref(10, timeDataType);
+
+      rowType = typeFactory.builder()
+          .add("bool", this.boolRelDataType)
+          .add("int", intRelDataType)
+          .add("dec", decRelDataType)
+          .add("long", longRelDataType)
+          .add("short", shortDataType)
+          .add("byte", byteDataType)
+          .add("float", floatDataType)
+          .add("char", charDataType)
+          .add("date", dateDataType)
+          .add("timestamp", timeStampDataType)
+          .add("time", timeDataType)
+          .build();
+
+      final Holder<RexExecutorImpl> holder = Holder.of(null);
+      Frameworks.withPrepare(
+          new Frameworks.PrepareAction<Void>() {
+            public Void apply(RelOptCluster cluster,
+                RelOptSchema relOptSchema,
+                SchemaPlus rootSchema,
+                CalciteServerStatement statement) {
+              DataContext dataContext =
+                  Schemas.createDataContext(statement.getConnection());
+              holder.set(new RexExecutorImpl(dataContext));
+              return null;
+            }
+          });
+
+      executor = holder.get();
+      checker = new RexImplicationChecker(rexBuilder, executor, rowType);
+    }
+
+    RexInputRef ref(int i, RelDataType type) {
+      return new RexInputRef(i,
+          typeFactory.createTypeWithNullability(type, true));
+    }
+
+    RexLiteral literal(int i) {
+      return rexBuilder.makeExactLiteral(new BigDecimal(i));
+    }
+
+    RexNode gt(RexNode node1, RexNode node2) {
+      return rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN, node1, node2);
+    }
+
+    RexNode ge(RexNode node1, RexNode node2) {
+      return rexBuilder.makeCall(
+          SqlStdOperatorTable.GREATER_THAN_OR_EQUAL, node1, node2);
+    }
+
+    RexNode eq(RexNode node1, RexNode node2) {
+      return rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, node1, node2);
+    }
+
+    RexNode ne(RexNode node1, RexNode node2) {
+      return rexBuilder.makeCall(SqlStdOperatorTable.NOT_EQUALS, node1, node2);
+    }
+
+    RexNode lt(RexNode node1, RexNode node2) {
+      return rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN, node1, node2);
+    }
+
+    RexNode le(RexNode node1, RexNode node2) {
+      return rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN_OR_EQUAL, node1,
+          node2);
+    }
+
+    RexNode longLiteral(long value) {
+      return rexBuilder.makeLiteral(value, longRelDataType, true);
+    }
+
+    RexNode shortLiteral(short value) {
+      return rexBuilder.makeLiteral(value, shortDataType, true);
+    }
+
+    RexLiteral floatLiteral(double value) {
+      return rexBuilder.makeApproxLiteral(new BigDecimal(value));
+    }
+
+    RexLiteral charLiteral(String z) {
+      return rexBuilder.makeCharLiteral(
+          new NlsString(z, null, SqlCollation.COERCIBLE));
+    }
+
+    RexNode timestampLiteral(Calendar calendar) {
+      return rexBuilder.makeTimestampLiteral(
+          calendar, timeStampDataType.getPrecision());
+    }
+
+    RexNode timeLiteral(Calendar calendar) {
+      return rexBuilder.makeTimestampLiteral(
+          calendar, timeDataType.getPrecision());
+    }
+
+    void checkImplies(RexNode node1, RexNode node2) {
+      final String message =
+          node1 + " does not imply " + node2 + " when it should";
+      assertTrue(message, checker.implies(node1, node2));
+    }
+
+    void checkNotImplies(RexNode node1, RexNode node2) {
+      final String message =
+          node1 + " does implies " + node2 + " when it should not";
+      assertFalse(message, checker.implies(node1, node2));
+    }
+  }
 }
+
+// End RexImplicationCheckerTest.java


[05/50] incubator-calcite git commit: [CALCITE-789] MetaImpl.MetaCatalog should expose TABLE_CAT instead of TABLE_CATALOG

Posted by jh...@apache.org.
[CALCITE-789] MetaImpl.MetaCatalog should expose TABLE_CAT instead of TABLE_CATALOG


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

Branch: refs/heads/branch-release
Commit: 464fd364a4ed0563645dee3cefdf2cc5195533fa
Parents: fcb6ba5
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Jul 7 12:00:10 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jul 9 10:47:18 2015 -0700

----------------------------------------------------------------------
 .../java/org/apache/calcite/avatica/Meta.java   | 26 ++++++++++++++++++++
 .../org/apache/calcite/avatica/MetaImpl.java    |  7 +++---
 .../apache/calcite/jdbc/CalciteMetaImpl.java    |  3 ++-
 .../calcite/jdbc/CalciteRemoteDriverTest.java   |  4 +--
 .../java/org/apache/calcite/test/JdbcTest.java  | 12 ++++-----
 5 files changed, 40 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/464fd364/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/Meta.java b/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
index 5dd59f0..a15a769 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
@@ -52,11 +52,13 @@ public interface Meta {
    */
   Map<DatabaseProperty, Object> getDatabaseProperties();
 
+  /** Per {@link DatabaseMetaData#getTables(String, String, String, String[])}. */
   MetaResultSet getTables(String catalog,
       Pat schemaPattern,
       Pat tableNamePattern,
       List<String> typeList);
 
+  /** Per {@link DatabaseMetaData#getColumns(String, String, String, String)}. */
   MetaResultSet getColumns(String catalog,
       Pat schemaPattern,
       Pat tableNamePattern,
@@ -64,42 +66,56 @@ public interface Meta {
 
   MetaResultSet getSchemas(String catalog, Pat schemaPattern);
 
+  /** Per {@link DatabaseMetaData#getCatalogs()}. */
   MetaResultSet getCatalogs();
 
+  /** Per {@link DatabaseMetaData#getTableTypes()}. */
   MetaResultSet getTableTypes();
 
+  /** Per {@link DatabaseMetaData#getProcedures(String, String, String)}. */
   MetaResultSet getProcedures(String catalog,
       Pat schemaPattern,
       Pat procedureNamePattern);
 
+  /** Per {@link DatabaseMetaData#getProcedureColumns(String, String, String, String)}. */
   MetaResultSet getProcedureColumns(String catalog,
       Pat schemaPattern,
       Pat procedureNamePattern,
       Pat columnNamePattern);
 
+  /** Per {@link DatabaseMetaData#getColumnPrivileges(String, String, String, String)}. */
   MetaResultSet getColumnPrivileges(String catalog,
       String schema,
       String table,
       Pat columnNamePattern);
 
+  /** Per {@link DatabaseMetaData#getTablePrivileges(String, String, String)}. */
   MetaResultSet getTablePrivileges(String catalog,
       Pat schemaPattern,
       Pat tableNamePattern);
 
+  /** Per
+   * {@link DatabaseMetaData#getBestRowIdentifier(String, String, String, int, boolean)}. */
   MetaResultSet getBestRowIdentifier(String catalog,
       String schema,
       String table,
       int scope,
       boolean nullable);
 
+  /** Per {@link DatabaseMetaData#getVersionColumns(String, String, String)}. */
   MetaResultSet getVersionColumns(String catalog, String schema, String table);
 
+  /** Per {@link DatabaseMetaData#getPrimaryKeys(String, String, String)}. */
   MetaResultSet getPrimaryKeys(String catalog, String schema, String table);
 
+  /** Per {@link DatabaseMetaData#getImportedKeys(String, String, String)}. */
   MetaResultSet getImportedKeys(String catalog, String schema, String table);
 
+  /** Per {@link DatabaseMetaData#getExportedKeys(String, String, String)}. */
   MetaResultSet getExportedKeys(String catalog, String schema, String table);
 
+  /** Per
+   * {@link DatabaseMetaData#getCrossReference(String, String, String, String, String, String)}. */
   MetaResultSet getCrossReference(String parentCatalog,
       String parentSchema,
       String parentTable,
@@ -107,43 +123,53 @@ public interface Meta {
       String foreignSchema,
       String foreignTable);
 
+  /** Per {@link DatabaseMetaData#getTypeInfo()}. */
   MetaResultSet getTypeInfo();
 
+  /** Per {@link DatabaseMetaData#getIndexInfo(String, String, String, boolean, boolean)}. */
   MetaResultSet getIndexInfo(String catalog,
       String schema,
       String table,
       boolean unique,
       boolean approximate);
 
+  /** Per {@link DatabaseMetaData#getUDTs(String, String, String, int[])}. */
   MetaResultSet getUDTs(String catalog,
       Pat schemaPattern,
       Pat typeNamePattern,
       int[] types);
 
+  /** Per {@link DatabaseMetaData#getSuperTypes(String, String, String)}. */
   MetaResultSet getSuperTypes(String catalog,
       Pat schemaPattern,
       Pat typeNamePattern);
 
+  /** Per {@link DatabaseMetaData#getSuperTables(String, String, String)}. */
   MetaResultSet getSuperTables(String catalog,
       Pat schemaPattern,
       Pat tableNamePattern);
 
+  /** Per {@link DatabaseMetaData#getAttributes(String, String, String, String)}. */
   MetaResultSet getAttributes(String catalog,
       Pat schemaPattern,
       Pat typeNamePattern,
       Pat attributeNamePattern);
 
+  /** Per {@link DatabaseMetaData#getClientInfoProperties()}. */
   MetaResultSet getClientInfoProperties();
 
+  /** Per {@link DatabaseMetaData#getFunctions(String, String, String)}. */
   MetaResultSet getFunctions(String catalog,
       Pat schemaPattern,
       Pat functionNamePattern);
 
+  /** Per {@link DatabaseMetaData#getFunctionColumns(String, String, String, String)}. */
   MetaResultSet getFunctionColumns(String catalog,
       Pat schemaPattern,
       Pat functionNamePattern,
       Pat columnNamePattern);
 
+  /** Per {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}. */
   MetaResultSet getPseudoColumns(String catalog,
       Pat schemaPattern,
       Pat tableNamePattern,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/464fd364/avatica/src/main/java/org/apache/calcite/avatica/MetaImpl.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/MetaImpl.java b/avatica/src/main/java/org/apache/calcite/avatica/MetaImpl.java
index 223830d..504c929 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/MetaImpl.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/MetaImpl.java
@@ -286,6 +286,7 @@ public abstract class MetaImpl implements Meta {
     public final int ordinalPosition;
     public final String isNullable;
     public final String scopeCatalog = null;
+    public final String scopeSchema = null;
     public final String scopeTable = null;
     public final String sourceDataType = null;
     public final String isAutoincrement = null;
@@ -374,15 +375,15 @@ public abstract class MetaImpl implements Meta {
 
   /** Metadata describing a catalog. */
   public static class MetaCatalog implements Named {
-    public final String tableCatalog;
+    public final String tableCat;
 
     public MetaCatalog(
         String tableCatalog) {
-      this.tableCatalog = tableCatalog;
+      this.tableCat = tableCatalog;
     }
 
     public String getName() {
-      return tableCatalog;
+      return tableCat;
     }
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/464fd364/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
index d087f9b..cd3df50 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
@@ -344,6 +344,7 @@ public class CalciteMetaImpl extends MetaImpl {
         "ORDINAL_POSITION",
         "IS_NULLABLE",
         "SCOPE_CATALOG",
+        "SCOPE_SCHEMA",
         "SCOPE_TABLE",
         "SOURCE_DATA_TYPE",
         "IS_AUTOINCREMENT",
@@ -514,7 +515,7 @@ public class CalciteMetaImpl extends MetaImpl {
   public MetaResultSet getCatalogs() {
     return createResultSet(catalogs(),
         MetaCatalog.class,
-        "TABLE_CATALOG");
+        "TABLE_CAT");
   }
 
   public MetaResultSet getTableTypes() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/464fd364/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java b/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
index f7aba8c..9491645 100644
--- a/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
+++ b/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
@@ -174,7 +174,7 @@ public class CalciteRemoteDriverTest {
     final ResultSet resultSet = connection.getMetaData().getCatalogs();
     final ResultSetMetaData metaData = resultSet.getMetaData();
     assertEquals(1, metaData.getColumnCount());
-    assertEquals("TABLE_CATALOG", metaData.getColumnName(1));
+    assertEquals("TABLE_CAT", metaData.getColumnName(1));
     assertTrue(resultSet.next());
     assertFalse(resultSet.next());
     resultSet.close();
@@ -241,7 +241,7 @@ public class CalciteRemoteDriverTest {
   @Test public void testRemoteCatalogs() throws Exception {
     CalciteAssert.hr().with(REMOTE_CONNECTION_FACTORY)
         .metaData(GET_CATALOGS)
-        .returns("TABLE_CATALOG=null\n");
+        .returns("TABLE_CAT=null\n");
   }
 
   @Test public void testRemoteSchemas() throws Exception {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/464fd364/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index 658619d..941b88a 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -5071,18 +5071,18 @@ public class JdbcTest {
 
               // columns
               assertEquals(
-                  "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=empid; DATA_TYPE=4; TYPE_NAME=JavaType(int) NOT NULL; COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=0; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=1; IS_NULLABLE=NO; SCOPE_CATALOG=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=null; IS_GENERATEDCOLUMN=null\n"
-                      + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=deptno; DATA_TYPE=4; TYPE_NAME=JavaType(int) NOT NULL; COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=0; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=2; IS_NULLABLE=NO; SCOPE_CATALOG=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=null; IS_GENERATEDCOLUMN=null\n"
-                      + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=name; DATA_TYPE=12; TYPE_NAME=JavaType(class java.lang.String); COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=1; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=3; IS_NULLABLE=YES; SCOPE_CATALOG=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=null; IS_GENERATEDCOLUMN=null\n"
-                      + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=salary; DATA_TYPE=7; TYPE_NAME=JavaType(float) NOT NULL; COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=0; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=4; IS_NULLABLE=NO; SCOPE_CATALOG=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=null; IS_GENERATEDCOLUMN=null\n"
-                      + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=commission; DATA_TYPE=4; TYPE_NAME=JavaType(class java.lang.Integer); COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=1; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=5; IS_NULLABLE=YES; SCOPE_CATALOG=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=null; IS_GENERATEDCOLUMN=null\n",
+                  "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=empid; DATA_TYPE=4; TYPE_NAME=JavaType(int) NOT NULL; COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=0; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=1; IS_NULLABLE=NO; SCOPE_CATALOG=null; SCOPE_SCHEMA=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=null; IS_GENERATEDCOLUMN=null\n"
+                      + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=deptno; DATA_TYPE=4; TYPE_NAME=JavaType(int) NOT NULL; COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=0; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=2; IS_NULLABLE=NO; SCOPE_CATALOG=null; SCOPE_SCHEMA=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=null; IS_GENERATEDCOLUMN=null\n"
+                      + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=name; DATA_TYPE=12; TYPE_NAME=JavaType(class java.lang.String); COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=1; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=3; IS_NULLABLE=YES; SCOPE_CATALOG=null; SCOPE_SCHEMA=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=null; IS_GENERATEDCOLUMN=null\n"
+                      + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=salary; DATA_TYPE=7; TYPE_NAME=JavaType(float) NOT NULL; COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=0; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=4; IS_NULLABLE=NO; SCOPE_CATALOG=null; SCOPE_SCHEMA=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=null; IS_GENERATEDCOLUMN=null\n"
+                      + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=commission; DATA_TYPE=4; TYPE_NAME=JavaType(class java.lang.Integer); COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=1; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=5; IS_NULLABLE=YES; SCOPE_CATALOG=null; SCOPE_SCHEMA=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=null; IS_GENERATEDCOLUMN=null\n",
                   CalciteAssert.toString(
                       metaData.getColumns(
                           null, "adhoc", "V", null)));
 
               // catalog
               assertEquals(
-                  "TABLE_CATALOG=null\n",
+                  "TABLE_CAT=null\n",
                   CalciteAssert.toString(
                       metaData.getCatalogs()));
 


[37/50] incubator-calcite git commit: Site: add news item (XLDB best lighting talk), and some talks

Posted by jh...@apache.org.
Site: add news item (XLDB best lighting talk), and some talks


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

Branch: refs/heads/branch-release
Commit: 17ef59326ce91673ccd0913e3f29f9820d85fb49
Parents: 1580bd0
Author: Julian Hyde <jh...@apache.org>
Authored: Fri Jul 31 14:06:48 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Jul 31 14:06:48 2015 -0700

----------------------------------------------------------------------
 site/Gemfile                                    |  1 +
 site/_plugins/bundler.rb                        | 20 ++++++++++
 .../2015-07-31-xldb-best-lightning-talk.md      | 41 ++++++++++++++++++++
 site/talks/index.md                             | 38 +++++++++++-------
 4 files changed, 87 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/17ef5932/site/Gemfile
----------------------------------------------------------------------
diff --git a/site/Gemfile b/site/Gemfile
index c5179f1..c13c470 100644
--- a/site/Gemfile
+++ b/site/Gemfile
@@ -16,4 +16,5 @@
 source 'https://rubygems.org'
 gem 'github-pages'
 gem 'rouge'
+gem 'jekyll-oembed', :require => 'jekyll_oembed'
 # End Gemfile

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/17ef5932/site/_plugins/bundler.rb
----------------------------------------------------------------------
diff --git a/site/_plugins/bundler.rb b/site/_plugins/bundler.rb
new file mode 100644
index 0000000..1cdec10
--- /dev/null
+++ b/site/_plugins/bundler.rb
@@ -0,0 +1,20 @@
+# 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.
+#
+require "rubygems"
+require "bundler/setup"
+Bundler.require(:default)
+
+# End bundler.rb

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/17ef5932/site/_posts/2015-07-31-xldb-best-lightning-talk.md
----------------------------------------------------------------------
diff --git a/site/_posts/2015-07-31-xldb-best-lightning-talk.md b/site/_posts/2015-07-31-xldb-best-lightning-talk.md
new file mode 100644
index 0000000..b0e1f46
--- /dev/null
+++ b/site/_posts/2015-07-31-xldb-best-lightning-talk.md
@@ -0,0 +1,41 @@
+---
+layout: news_item
+title: "XLDB 2015 best lightning talk"
+date: "2015-07-31 11:53:00 -0800"
+author: jhyde
+categories: ["talks"]
+---
+<!--
+{% comment %}
+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.
+{% endcomment %}
+-->
+
+Julian Hyde's talk Apache Calcite: One planner fits all won
+[Best Lightning Talk](http://www.xldb.org/archives/2015/05/best-lightning-talks-selected/)
+at the XLDB-2015 conference (with Eric Tschetter's talk "Sketchy
+Approximations").
+
+XLDB is an annual conference that brings together experts from
+science, industry and academia to find practical solutions to problems
+involving extremely large data sets.
+
+As a result of winning Best Lightning Talk, Julian will get a 30
+minute keynote speaking slot at XLDB-2016.
+
+The talk is available in
+[slides](http://www.slideshare.net/julianhyde/apache-calcite-one-planner-fits-all)
+and [video](https://www.youtube.com/watch?v=5_MyORYjq3w).

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/17ef5932/site/talks/index.md
----------------------------------------------------------------------
diff --git a/site/talks/index.md b/site/talks/index.md
index 65efb1c..95fdd33 100644
--- a/site/talks/index.md
+++ b/site/talks/index.md
@@ -25,22 +25,34 @@ Want to learn more about Calcite?
 
 Watch some presentations and read through some slide decks about Calcite.
 
-## Slides
+## Apache Calcite: One planner fits all
+ 
+Voted [Best Lightning Talk at XLDB-2015](http://www.xldb.org/archives/2015/05/best-lightning-talks-selected/);
+[[video](https://www.youtube.com/watch?v=5_MyORYjq3w)],
+[[slides](http://www.slideshare.net/julianhyde/apache-calcite-one-planner-fits-all)].
 
-* Apache Calcite overview
+{% oembed https://www.youtube.com/watch?v=5_MyORYjq3w %}
 
-    Julian Hyde at Apache Kylin meetup 2014
+## Why you care about relational algebra (even though you didn't know it)
 
-    <iframe src="//www.slideshare.net/slideshow/embed_code/key/fCGsAedsQiq53V"
-    width="425" height="355" frameborder="0" marginwidth="0" marginheight="0"
-    scrolling="no" style="border:1px solid #CCC; border-width:1px;
-    margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe>
+Washington DC, April 2015;
+[[slides](http://www.slideshare.net/julianhyde/calcite-algebraedw2015)].
 
+<iframe src="//www.slideshare.net/slideshow/embed_code/key/vfVDu6y1mAM5Dl" width="629" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe>
+
+## Apache Calcite overview
+
+Apache Kylin meetup, 2014;
+[[slides](http://www.slideshare.net/julianhyde/apache-calcite-overview)].
+
+<iframe src="//www.slideshare.net/slideshow/embed_code/key/fCGsAedsQiq53V" width="629" height="354" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe>
+
+## More talks
 
-* <a href="http://www.slideshare.net/julianhyde/how-to-integrate-splunk-with-any-data-solution">How to integrate Splunk with any data solution</a> (Splunk User Conference, 2012)
-* <a href="https://github.com/julianhyde/share/blob/master/slides/optiq-drill-user-group-2013.pdf?raw=true">Drill / SQL / Optiq</a> (2013)
-* <a href="https://github.com/julianhyde/share/blob/master/slides/optiq-richrelevance-2013.pdf?raw=true">SQL on Big Data using Optiq</a> (2013)
-* <a href="https://github.com/julianhyde/share/blob/master/slides/optiq-nosql-now-2013.pdf?raw=true">SQL Now!</a> (NoSQL Now! conference, 2013)
-* <a href="https://github.com/julianhyde/share/blob/master/slides/hive-cbo-summit-2014.pdf?raw=true">Cost-based optimization in Hive</a> (<a href="https://www.youtube.com/watch?v=vpG5noIbEFs">video</a>) (Hadoop Summit, 2014)
-* <a href="https://github.com/julianhyde/share/blob/master/slides/dmmq-summit-2014.pdf?raw=true">Discardable, in-memory materialized query for Hadoop</a> (<a href="https://www.youtube.com/watch?v=CziGOa8GXqI">video</a>) (Hadoop Summit, 2014)
 * <a href="https://github.com/julianhyde/share/blob/master/slides/hive-cbo-seattle-2014.pdf?raw=true">Cost-based optimization in Hive 0.14</a> (Seattle, 2014)
+* <a href="https://github.com/julianhyde/share/blob/master/slides/dmmq-summit-2014.pdf?raw=true">Discardable, in-memory materialized query for Hadoop</a> (<a href="https://www.youtube.com/watch?v=CziGOa8GXqI">video</a>) (Hadoop Summit, 2014)
+* <a href="https://github.com/julianhyde/share/blob/master/slides/hive-cbo-summit-2014.pdf?raw=true">Cost-based optimization in Hive</a> (<a href="https://www.youtube.com/watch?v=vpG5noIbEFs">video</a>) (Hadoop Summit, 2014)
+* <a href="https://github.com/julianhyde/share/blob/master/slides/optiq-nosql-now-2013.pdf?raw=true">SQL Now!</a> (NoSQL Now! conference, 2013)
+* <a href="https://github.com/julianhyde/share/blob/master/slides/optiq-richrelevance-2013.pdf?raw=true">SQL on Big Data using Optiq</a> (2013)
+* <a href="https://github.com/julianhyde/share/blob/master/slides/optiq-drill-user-group-2013.pdf?raw=true">Drill / SQL / Optiq</a> (2013)
+* <a href="http://www.slideshare.net/julianhyde/how-to-integrate-splunk-with-any-data-solution">How to integrate Splunk with any data solution</a> (Splunk User Conference, 2012)


[34/50] incubator-calcite git commit: [CALCITE-805] Add support for using an alternative grammar specification for left and right curly braces. Additionally, add support for including addition token manager declarations.

Posted by jh...@apache.org.
[CALCITE-805] Add support for using an alternative grammar specification for left and right curly braces. Additionally, add support for including addition token manager declarations.


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

Branch: refs/heads/branch-release
Commit: 5cb95e644f38da1a13d6def96eeec935b650289c
Parents: e0a4230
Author: Jacques Nadeau <ja...@apache.org>
Authored: Fri Jul 24 16:38:18 2015 -0700
Committer: Jacques Nadeau <ja...@apache.org>
Committed: Fri Jul 24 18:49:36 2015 -0700

----------------------------------------------------------------------
 core/src/main/codegen/config.fmpp         | 2 ++
 core/src/main/codegen/templates/Parser.jj | 8 ++++++++
 2 files changed, 10 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5cb95e64/core/src/main/codegen/config.fmpp
----------------------------------------------------------------------
diff --git a/core/src/main/codegen/config.fmpp b/core/src/main/codegen/config.fmpp
index d480488..80276c4 100644
--- a/core/src/main/codegen/config.fmpp
+++ b/core/src/main/codegen/config.fmpp
@@ -74,6 +74,8 @@ data: {
     ]
 
     includeCompoundIdentifier: true
+    includeBraces: true
+    includeAdditionalDeclarations: false    
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5cb95e64/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 36f9e05..231c03d 100644
--- a/core/src/main/codegen/templates/Parser.jj
+++ b/core/src/main/codegen/templates/Parser.jj
@@ -5382,12 +5382,16 @@ String CommonNonReservedKeyWord() :
 {
     < LPAREN: "(">
     | < RPAREN: ")">
+    <#if parser.includeBraces >
     | < LBRACE_D: "{" (" ")* ["d","D"] >
     | < LBRACE_T: "{" (" ")* ["t","T"] >
     | < LBRACE_TS: "{" (" ")* ["t","T"] ["s","S"] >
     | < LBRACE_FN: "{" (" ")* ["f","F"] ["n","N"] >
     | < LBRACE: "{" >
     | < RBRACE: "}" >
+    <#else>
+      <#include "/@includes/braces.ftl" />
+    </#if>
     | < LBRACKET: "[" >
     | < RBRACKET: "]" >
     | < SEMICOLON: ";" >
@@ -5432,6 +5436,10 @@ TOKEN_MGR_DECLS : {
     void popState() {
       SwitchTo(lexicalStateStack.remove(lexicalStateStack.size() - 1));
     }
+
+    <#if parser.includeAdditionalDeclarations>
+      <#include "/@includes/tokenManagerDeclarations.ftl" />
+    </#if>
 }
 
 /*


[32/50] incubator-calcite git commit: [CALCITE-717] Compare BINARY and VARBINARY on unsigned byte values (Low Chin Wei)

Posted by jh...@apache.org.
[CALCITE-717] Compare BINARY and VARBINARY on unsigned byte values (Low Chin Wei)


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

Branch: refs/heads/branch-release
Commit: 26a08774516c49eba39ccb7690295f87560a43fc
Parents: 67ea045
Author: Julian Hyde <jh...@apache.org>
Authored: Fri Jul 24 09:48:09 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Jul 24 09:48:09 2015 -0700

----------------------------------------------------------------------
 .../java/org/apache/calcite/avatica/util/ByteString.java |  4 ++--
 .../org/apache/calcite/sql/test/SqlOperatorBaseTest.java | 11 +++++++++++
 .../java/org/apache/calcite/test/SqlFunctionsTest.java   | 10 ++++++++++
 3 files changed, 23 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/26a08774/avatica/src/main/java/org/apache/calcite/avatica/util/ByteString.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/util/ByteString.java b/avatica/src/main/java/org/apache/calcite/avatica/util/ByteString.java
index ecd634c..4e606b7 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/util/ByteString.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/util/ByteString.java
@@ -70,8 +70,8 @@ public class ByteString implements Comparable<ByteString>, Serializable {
     final byte[] v2 = that.bytes;
     final int n = Math.min(v1.length, v2.length);
     for (int i = 0; i < n; i++) {
-      byte c1 = v1[i];
-      byte c2 = v2[i];
+      int c1 = v1[i] & 0xff;
+      int c2 = v2[i] & 0xff;
       if (c1 != c2) {
         return c1 - c2;
       }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/26a08774/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
index 2f76859..82041cc 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
@@ -326,6 +326,8 @@ public abstract class SqlOperatorBaseTest {
     tester.checkNull(
         "1 between cast(null as integer) and cast(null as integer)");
     tester.checkNull("1 between cast(null as integer) and 1");
+    tester.checkBoolean("x'0A00015A' between x'0A000130' and x'0A0001B0'", Boolean.TRUE);
+    tester.checkBoolean("x'0A00015A' between x'0A0001A0' and x'0A0001B0'", Boolean.FALSE);
   }
 
   @Test public void testNotBetween() {
@@ -339,6 +341,8 @@ public abstract class SqlOperatorBaseTest {
     tester.checkBoolean("1.2e1 not between 1.1 and 1.3", Boolean.TRUE);
     tester.checkBoolean("1.5e0 not between 2 and 3", Boolean.TRUE);
     tester.checkBoolean("1.5e0 not between 2e0 and 3e0", Boolean.TRUE);
+    tester.checkBoolean("x'0A00015A' not between x'0A000130' and x'0A0001B0'", Boolean.FALSE);
+    tester.checkBoolean("x'0A00015A' not between x'0A0001A0' and x'0A0001B0'", Boolean.TRUE);
   }
 
   private String getCastString(
@@ -1987,6 +1991,8 @@ public abstract class SqlOperatorBaseTest {
         "DATE '2013-02-23' > DATE '1945-02-24'", Boolean.TRUE);
     tester.checkBoolean(
         "DATE '2013-02-23' > CAST(NULL AS DATE)", null);
+
+    tester.checkBoolean("x'0A000130'>x'0A0001B0'", Boolean.FALSE);
   }
 
   @Test public void testGreaterThanOperatorIntervals() {
@@ -2119,6 +2125,8 @@ public abstract class SqlOperatorBaseTest {
     tester.checkBoolean("false>=false", Boolean.TRUE);
     tester.checkBoolean("false>=true", Boolean.FALSE);
     tester.checkNull("cast(null as real)>=999");
+    tester.checkBoolean("x'0A000130'>=x'0A0001B0'", Boolean.FALSE);
+    tester.checkBoolean("x'0A0001B0'>=x'0A0001B0'", Boolean.TRUE);
   }
 
   @Test public void testGreaterThanOrEqualOperatorIntervals() {
@@ -2283,6 +2291,7 @@ public abstract class SqlOperatorBaseTest {
     tester.checkNull("123<cast(null as bigint)");
     tester.checkNull("cast(null as tinyint)<123");
     tester.checkNull("cast(null as integer)<1.32");
+    tester.checkBoolean("x'0A000130'<x'0A0001B0'", Boolean.TRUE);
   }
 
   @Test public void testLessThanOperatorInterval() {
@@ -2341,6 +2350,8 @@ public abstract class SqlOperatorBaseTest {
     tester.checkNull("cast(null as integer)<=3");
     tester.checkNull("3<=cast(null as smallint)");
     tester.checkNull("cast(null as integer)<=1.32");
+    tester.checkBoolean("x'0A000130'<=x'0A0001B0'", Boolean.TRUE);
+    tester.checkBoolean("x'0A0001B0'<=x'0A0001B0'", Boolean.TRUE);
   }
 
   @Test public void testLessThanOrEqualOperatorInterval() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/26a08774/core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java b/core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java
index f3646b4..1fc4c3a 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java
@@ -459,6 +459,16 @@ public class SqlFunctionsTest {
     } catch (IllegalArgumentException e) {
       assertThat(e.getMessage(), equalTo("hex string has odd length"));
     }
+
+    final byte[] bytes4 = {10, 0, 1, -80};
+    final ByteString byteString4 = new ByteString(bytes4);
+    final byte[] bytes5 = {10, 0, 1, 127};
+    final ByteString byteString5 = new ByteString(bytes5);
+    final ByteString byteString6 = new ByteString(bytes4);
+
+    assertThat(byteString4.compareTo(byteString5) > 0, is(true));
+    assertThat(byteString4.compareTo(byteString6) == 0, is(true));
+    assertThat(byteString5.compareTo(byteString4) < 0, is(true));
   }
 
   private void thereAndBack(byte[] bytes) {


[38/50] incubator-calcite git commit: [CALCITE-826] Use ProjectFactory in AggregateJoinTranposeRule and FilterJoinRule

Posted by jh...@apache.org.
[CALCITE-826] Use ProjectFactory in AggregateJoinTranposeRule and FilterJoinRule


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

Branch: refs/heads/branch-release
Commit: 0357573f57346e976baac9828759b0a991bd9597
Parents: 17ef593
Author: Jesus Camacho Rodriguez <jc...@apache.org>
Authored: Fri Aug 7 16:27:43 2015 +0300
Committer: Jesus Camacho Rodriguez <jc...@apache.org>
Committed: Fri Aug 7 16:27:43 2015 +0300

----------------------------------------------------------------------
 .../org/apache/calcite/plan/RelOptUtil.java     | 75 ++++++++++++++++++--
 .../apache/calcite/rel/core/RelFactories.java   |  4 +-
 .../calcite/rel/logical/LogicalProject.java     |  8 ++-
 .../rel/rules/AggregateJoinTransposeRule.java   | 38 ++++++++--
 .../calcite/rel/rules/FilterJoinRule.java       |  2 +-
 5 files changed, 112 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0357573f/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
index d2686a0..04733cf 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -2497,6 +2497,11 @@ public abstract class RelOptUtil {
     return createProject(child, Mappings.asList(mapping.inverse()));
   }
 
+  public static RelNode createProject(RelNode child, Mappings.TargetMapping mapping,
+          RelFactories.ProjectFactory projectFactory) {
+    return createProject(projectFactory, child, Mappings.asList(mapping.inverse()));
+  }
+
   /** Returns whether relational expression {@code target} occurs within a
    * relational expression {@code ancestor}. */
   public static boolean contains(RelNode ancestor, final RelNode target) {
@@ -2629,7 +2634,23 @@ public abstract class RelOptUtil {
       List<Pair<RexNode, String>> projectList,
       boolean optimize) {
     return createProject(child, Pair.left(projectList), Pair.right(projectList),
-        optimize);
+        optimize, RelFactories.DEFAULT_PROJECT_FACTORY);
+  }
+
+  /**
+   * Creates a relational expression which projects a list of (expression, name)
+   * pairs.
+   *
+   * @param child             input relational expression
+   * @param projectList       list of (expression, name) pairs
+   * @param optimize          Whether to optimize
+   * @param projectFactory    Factory to create project operators
+   */
+  public static RelNode createProject(
+      RelNode child, List<Pair<RexNode, String>> projectList,
+      boolean optimize, RelFactories.ProjectFactory projectFactory) {
+    return createProject(child, Pair.left(projectList), Pair.right(projectList),
+        optimize, projectFactory);
   }
 
   /**
@@ -2669,6 +2690,33 @@ public abstract class RelOptUtil {
       List<? extends RexNode> exprs,
       List<String> fieldNames,
       boolean optimize) {
+    return createProject(child, exprs, fieldNames, optimize,
+            RelFactories.DEFAULT_PROJECT_FACTORY);
+  }
+
+  /**
+   * Creates a relational expression which projects an array of expressions,
+   * and optionally optimizes.
+   *
+   * <p>The result may not be a
+   * {@link org.apache.calcite.rel.logical.LogicalProject}. If the
+   * projection is trivial, <code>child</code> is returned directly; and future
+   * versions may return other formulations of expressions, such as
+   * {@link org.apache.calcite.rel.logical.LogicalCalc}.
+   *
+   * @param child          input relational expression
+   * @param exprs          list of expressions for the input columns
+   * @param fieldNames     aliases of the expressions, or null to generate
+   * @param optimize       Whether to return <code>child</code> unchanged if the
+   *                       projections are trivial.
+   * @param projectFactory Factory to create project operators
+   */
+  public static RelNode createProject(
+      RelNode child,
+      List<? extends RexNode> exprs,
+      List<String> fieldNames,
+      boolean optimize,
+      RelFactories.ProjectFactory projectFactory) {
     final RelOptCluster cluster = child.getCluster();
     final List<String> fieldNames2 =
         fieldNames == null
@@ -2690,7 +2738,7 @@ public abstract class RelOptUtil {
       }
       return child;
     }
-    return LogicalProject.create(child, exprs, fieldNames2);
+    return projectFactory.createProject(child, exprs, fieldNames2);
   }
 
   /**
@@ -2945,6 +2993,23 @@ public abstract class RelOptUtil {
    * @param originalJoin Join whose condition is to be pushed down
    */
   public static RelNode pushDownJoinConditions(Join originalJoin) {
+    return pushDownJoinConditions(originalJoin, RelFactories.DEFAULT_PROJECT_FACTORY);
+  }
+
+  /**
+   * Pushes down expressions in "equal" join condition.
+   *
+   * <p>For example, given
+   * "emp JOIN dept ON emp.deptno + 1 = dept.deptno", adds a project above
+   * "emp" that computes the expression
+   * "emp.deptno + 1". The resulting join condition is a simple combination
+   * of AND, equals, and input fields, plus the remaining non-equal conditions.
+   *
+   * @param originalJoin Join whose condition is to be pushed down
+   * @param projectFactory Factory to create project operator
+   */
+  public static RelNode pushDownJoinConditions(Join originalJoin,
+          RelFactories.ProjectFactory projectFactory) {
     RexNode joinCond = originalJoin.getCondition();
     final JoinRelType joinType = originalJoin.getJoinType();
     RelNode leftRel = originalJoin.getLeft();
@@ -2980,7 +3045,7 @@ public abstract class RelOptUtil {
               }
             }
           },
-          true);
+          true, projectFactory);
     }
     if (!extraRightExprs.isEmpty()) {
       final List<RelDataTypeField> fields =
@@ -3008,7 +3073,7 @@ public abstract class RelOptUtil {
               }
             }
           },
-          true);
+          true, projectFactory);
     }
 
     RelNode join = originalJoin.copy(originalJoin.getTraitSet(),
@@ -3021,7 +3086,7 @@ public abstract class RelOptUtil {
                   + rightCount + extraRightExprs.size(),
               0, 0, leftCount,
               leftCount, leftCount + extraLeftExprs.size(), rightCount);
-      return RelOptUtil.createProject(join, mapping);
+      return RelOptUtil.createProject(join, mapping, projectFactory);
     }
     return join;
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0357573f/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java b/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
index 787ab1f..e8cbd3c 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
@@ -20,7 +20,6 @@ package org.apache.calcite.rel.core;
 import org.apache.calcite.plan.Contexts;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptTable;
-import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelNode;
@@ -29,6 +28,7 @@ import org.apache.calcite.rel.logical.LogicalFilter;
 import org.apache.calcite.rel.logical.LogicalIntersect;
 import org.apache.calcite.rel.logical.LogicalJoin;
 import org.apache.calcite.rel.logical.LogicalMinus;
+import org.apache.calcite.rel.logical.LogicalProject;
 import org.apache.calcite.rel.logical.LogicalSort;
 import org.apache.calcite.rel.logical.LogicalTableScan;
 import org.apache.calcite.rel.logical.LogicalUnion;
@@ -113,7 +113,7 @@ public class RelFactories {
   private static class ProjectFactoryImpl implements ProjectFactory {
     public RelNode createProject(RelNode input,
         List<? extends RexNode> childExprs, List<String> fieldNames) {
-      return RelOptUtil.createProject(input, childExprs, fieldNames);
+      return LogicalProject.create(input, childExprs, fieldNames);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0357573f/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java
index 8b46f79..cce5e79 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java
@@ -30,6 +30,7 @@ import org.apache.calcite.rel.metadata.RelMdCollation;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.sql.validate.SqlValidatorUtil;
 import org.apache.calcite.util.Util;
 
 import com.google.common.base.Supplier;
@@ -95,9 +96,14 @@ public final class LogicalProject extends Project {
   public static LogicalProject create(final RelNode input,
       final List<? extends RexNode> projects, List<String> fieldNames) {
     final RelOptCluster cluster = input.getCluster();
+    final List<String> fieldNames2 =
+        fieldNames == null
+            ? null
+            : SqlValidatorUtil.uniquify(fieldNames,
+                SqlValidatorUtil.F_SUGGESTER);
     final RelDataType rowType =
         RexUtil.createStructType(cluster.getTypeFactory(), projects,
-            fieldNames);
+            fieldNames2);
     return create(input, projects, rowType);
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0357573f/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java
index 673d579..8dfe4aa 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java
@@ -63,27 +63,51 @@ public class AggregateJoinTransposeRule extends RelOptRule {
       new AggregateJoinTransposeRule(LogicalAggregate.class,
           RelFactories.DEFAULT_AGGREGATE_FACTORY,
           LogicalJoin.class,
-          RelFactories.DEFAULT_JOIN_FACTORY);
+          RelFactories.DEFAULT_JOIN_FACTORY,
+          RelFactories.DEFAULT_PROJECT_FACTORY);
 
   /** Extended instance of the rule that can push down aggregate functions. */
   public static final AggregateJoinTransposeRule EXTENDED =
       new AggregateJoinTransposeRule(LogicalAggregate.class,
           RelFactories.DEFAULT_AGGREGATE_FACTORY,
           LogicalJoin.class,
-          RelFactories.DEFAULT_JOIN_FACTORY, true);
+          RelFactories.DEFAULT_JOIN_FACTORY,
+          RelFactories.DEFAULT_PROJECT_FACTORY, true);
 
   private final RelFactories.AggregateFactory aggregateFactory;
 
   private final RelFactories.JoinFactory joinFactory;
 
+  private final RelFactories.ProjectFactory projectFactory;
+
   private final boolean allowFunctions;
 
-  /** Creates an AggregateJoinTransposeRule. */
+  @Deprecated
   public AggregateJoinTransposeRule(Class<? extends Aggregate> aggregateClass,
       RelFactories.AggregateFactory aggregateFactory,
       Class<? extends Join> joinClass,
       RelFactories.JoinFactory joinFactory) {
-    this(aggregateClass, aggregateFactory, joinClass, joinFactory, false);
+    this(aggregateClass, aggregateFactory, joinClass, joinFactory,
+            RelFactories.DEFAULT_PROJECT_FACTORY, false);
+  }
+
+  @Deprecated
+  public AggregateJoinTransposeRule(Class<? extends Aggregate> aggregateClass,
+      RelFactories.AggregateFactory aggregateFactory,
+      Class<? extends Join> joinClass,
+      RelFactories.JoinFactory joinFactory,
+      boolean allowFunctions) {
+    this(aggregateClass, aggregateFactory, joinClass, joinFactory,
+            RelFactories.DEFAULT_PROJECT_FACTORY, allowFunctions);
+  }
+
+  /** Creates an AggregateJoinTransposeRule. */
+  public AggregateJoinTransposeRule(Class<? extends Aggregate> aggregateClass,
+      RelFactories.AggregateFactory aggregateFactory,
+      Class<? extends Join> joinClass,
+      RelFactories.JoinFactory joinFactory,
+      RelFactories.ProjectFactory projectFactory) {
+    this(aggregateClass, aggregateFactory, joinClass, joinFactory, projectFactory, false);
   }
 
   /** Creates an AggregateJoinTransposeRule that may push down functions. */
@@ -91,12 +115,14 @@ public class AggregateJoinTransposeRule extends RelOptRule {
       RelFactories.AggregateFactory aggregateFactory,
       Class<? extends Join> joinClass,
       RelFactories.JoinFactory joinFactory,
+      RelFactories.ProjectFactory projectFactory,
       boolean allowFunctions) {
     super(
         operand(aggregateClass, null, Aggregate.IS_SIMPLE,
             operand(joinClass, any())));
     this.aggregateFactory = aggregateFactory;
     this.joinFactory = joinFactory;
+    this.projectFactory = projectFactory;
     this.allowFunctions = allowFunctions;
   }
 
@@ -279,7 +305,7 @@ public class AggregateJoinTransposeRule extends RelOptRule {
     if (allColumnsInAggregate && newAggCalls.isEmpty()) {
       // no need to aggregate
     } else {
-      r = RelOptUtil.createProject(r, projects, null, true);
+      r = RelOptUtil.createProject(r, projects, null, true, projectFactory);
       if (allColumnsInAggregate) {
         // let's see if we can convert
         List<RexNode> projects2 = new ArrayList<>();
@@ -298,7 +324,7 @@ public class AggregateJoinTransposeRule extends RelOptRule {
         if (projects2.size()
             == aggregate.getGroupSet().cardinality() + newAggCalls.size()) {
           // We successfully converted agg calls into projects.
-          r = RelOptUtil.createProject(r, projects2, null, true);
+          r = RelOptUtil.createProject(r, projects2, null, true, projectFactory);
           break b;
         }
       }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0357573f/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
index 12eadb8..844980a 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
@@ -250,7 +250,7 @@ public abstract class FilterJoinRule extends RelOptRule {
     // Push expression in join condition into Project below Join.
     if (newJoinRel instanceof Join) {
       newJoinRel = RelOptUtil.pushDownJoinConditions(
-          (Join) newJoinRel);
+          (Join) newJoinRel, projectFactory);
     }
 
     // create a FilterRel on top of the join if needed


[08/50] incubator-calcite git commit: [CALCITE-799] Incorrect result for "HAVING count(*) > 1"

Posted by jh...@apache.org.
[CALCITE-799] Incorrect result for "HAVING count(*) > 1"

FilterAggregateTransposeRule was mixing up group keys, and as a result would sometimes push down a filter on an aggregate function when it should not have.


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

Branch: refs/heads/branch-release
Commit: 92f32e8d5b0301e91bc31b3b95ae6049824b9ecf
Parents: c57d807
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Jul 13 12:57:46 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Jul 13 12:57:46 2015 -0700

----------------------------------------------------------------------
 .../rel/rules/FilterAggregateTransposeRule.java | 36 +++++++++++-------
 .../apache/calcite/test/RelOptRulesTest.java    |  8 ++++
 .../org/apache/calcite/test/RelOptRulesTest.xml | 23 +++++++++++
 core/src/test/resources/sql/agg.oq              | 40 ++++++++++++++++++++
 4 files changed, 93 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/92f32e8d/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
index d3de47f..720e33d 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
@@ -88,7 +88,6 @@ public class FilterAggregateTransposeRule extends RelOptRule {
 
     final List<RexNode> conditions =
         RelOptUtil.conjunctions(filterRel.getCondition());
-    final ImmutableBitSet groupKeys = aggRel.getGroupSet();
     final RexBuilder rexBuilder = filterRel.getCluster().getRexBuilder();
     final List<RelDataTypeField> origFields =
         aggRel.getRowType().getFieldList();
@@ -98,19 +97,7 @@ public class FilterAggregateTransposeRule extends RelOptRule {
 
     for (RexNode condition : conditions) {
       ImmutableBitSet rCols = RelOptUtil.InputFinder.bits(condition);
-      boolean push = groupKeys.contains(rCols);
-      if (push && aggRel.indicator) {
-        // If grouping sets are used, the filter can be pushed if
-        // the columns referenced in the predicate are present in
-        // all the grouping sets.
-        for (ImmutableBitSet groupingSet: aggRel.getGroupSets()) {
-          if (!groupingSet.contains(rCols)) {
-            push = false;
-            break;
-          }
-        }
-      }
-      if (push) {
+      if (canPush(aggRel, rCols)) {
         pushedConditions.add(
             condition.accept(
                 new RelOptUtil.RexInputConverter(rexBuilder, origFields,
@@ -131,6 +118,27 @@ public class FilterAggregateTransposeRule extends RelOptRule {
     rel = builder.push(rel).filter(remainingConditions).build();
     call.transformTo(rel);
   }
+
+  private boolean canPush(Aggregate aggregate, ImmutableBitSet rCols) {
+    // If the filter references columns not in the group key, we cannot push
+    final ImmutableBitSet groupKeys =
+        ImmutableBitSet.range(0, aggregate.getGroupSet().cardinality());
+    if (!groupKeys.contains(rCols)) {
+      return false;
+    }
+
+    if (aggregate.indicator) {
+      // If grouping sets are used, the filter can be pushed if
+      // the columns referenced in the predicate are present in
+      // all the grouping sets.
+      for (ImmutableBitSet groupingSet: aggregate.getGroupSets()) {
+        if (!groupingSet.contains(rCols)) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
 }
 
 // End FilterAggregateTransposeRule.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/92f32e8d/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index 8a62e89..3739af5 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -250,6 +250,14 @@ public class RelOptRulesTest extends RelOptTestBase {
   }
 
   /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-799">[CALCITE-799],
+   * Incorrect result for {@code HAVING count(*) > 1}</a>. */
+  @Test public void testPushFilterPastAggThree() {
+    checkPlanning(FilterAggregateTransposeRule.INSTANCE,
+        "select deptno from emp group by deptno having count(*) > 1");
+  }
+
+  /** Test case for
    * <a href="https://issues.apache.org/jira/browse/CALCITE-448">[CALCITE-448],
    * FilterIntoJoinRule creates filters containing invalid RexInputRef</a>. */
   @Test public void testPushFilterPastProject() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/92f32e8d/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index 1baaac4..eb9ed66 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -3753,4 +3753,27 @@ LogicalAggregate(group=[{}], EXPR$0=[COUNT()])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testPushFilterPastAggThree">
+        <Resource name="sql">
+            <![CDATA[select deptno from emp group by deptno having count(*) > 1]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(DEPTNO=[$0])
+  LogicalFilter(condition=[>($1, 1)])
+    LogicalAggregate(group=[{0}], agg#0=[COUNT()])
+      LogicalProject(DEPTNO=[$7])
+        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalProject(DEPTNO=[$0])
+  LogicalFilter(condition=[>($1, 1)])
+    LogicalAggregate(group=[{0}], agg#0=[COUNT()])
+      LogicalProject(DEPTNO=[$7])
+        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+    </TestCase>
 </Root>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/92f32e8d/core/src/test/resources/sql/agg.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/agg.oq b/core/src/test/resources/sql/agg.oq
index d81fa9e..aeecc04 100644
--- a/core/src/test/resources/sql/agg.oq
+++ b/core/src/test/resources/sql/agg.oq
@@ -800,4 +800,44 @@ order by 1, 2;
 
 !ok
 
+# [CALCITE-799] Incorrect result for "HAVING count(*) > 1"
+select d.deptno, min(e.empid) as empid
+from (values (100, 'Bill', 1),
+             (200, 'Eric', 1),
+             (150, 'Sebastian', 3)) as e(empid, name, deptno)
+join (values (1, 'LeaderShip'),
+             (2, 'TestGroup'),
+             (3, 'Development')) as d(deptno, name)
+on e.deptno = d.deptno
+group by d.deptno
+having count(*) > 1;
++--------+-------+
+| DEPTNO | EMPID |
++--------+-------+
+|      1 |   100 |
++--------+-------+
+(1 row)
+
+!ok
+
+# Same, using USING (combining [CALCITE-799] and [CALCITE-801])
+select d.deptno, min(e.empid) as empid
+from (values (100, 'Bill', 1),
+             (200, 'Eric', 1),
+             (150, 'Sebastian', 3)) as e(empid, name, deptno)
+join (values (1, 'LeaderShip'),
+             (2, 'TestGroup'),
+             (3, 'Development')) as d(deptno, name)
+using (deptno)
+group by d.deptno
+having count(*) > 1;
++--------+-------+
+| DEPTNO | EMPID |
++--------+-------+
+|      1 |   100 |
++--------+-------+
+(1 row)
+
+!ok
+
 # End agg.oq


[50/50] incubator-calcite git commit: [maven-release-plugin] prepare release calcite-1.4.0-incubating

Posted by jh...@apache.org.
[maven-release-plugin] prepare release calcite-1.4.0-incubating


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

Branch: refs/heads/branch-release
Commit: 0c0c203daec56c05b6c75fa3896c8af19844df68
Parents: 23a00c9
Author: Jacques Nadeau <ja...@apache.org>
Authored: Sun Aug 23 21:52:20 2015 -0700
Committer: Jacques Nadeau <ja...@apache.org>
Committed: Sun Aug 23 21:52:20 2015 -0700

----------------------------------------------------------------------
 avatica-server/pom.xml |  4 ++--
 avatica/pom.xml        |  4 ++--
 core/pom.xml           |  4 ++--
 example/csv/pom.xml    |  4 ++--
 example/pom.xml        |  4 ++--
 linq4j/pom.xml         |  4 ++--
 mongodb/pom.xml        |  4 ++--
 plus/pom.xml           |  4 ++--
 pom.xml                | 16 ++++++++--------
 spark/pom.xml          |  4 ++--
 splunk/pom.xml         |  4 ++--
 ubenchmark/pom.xml     |  2 +-
 12 files changed, 29 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0c0c203d/avatica-server/pom.xml
----------------------------------------------------------------------
diff --git a/avatica-server/pom.xml b/avatica-server/pom.xml
index c8b9ba3..14f8d9d 100644
--- a/avatica-server/pom.xml
+++ b/avatica-server/pom.xml
@@ -20,12 +20,12 @@ limitations under the License.
   <parent>
     <groupId>org.apache.calcite</groupId>
     <artifactId>calcite</artifactId>
-    <version>1.4.0-incubating-SNAPSHOT</version>
+    <version>1.4.0-incubating</version>
   </parent>
 
   <artifactId>calcite-avatica-server</artifactId>
   <packaging>jar</packaging>
-  <version>1.4.0-incubating-SNAPSHOT</version>
+  <version>1.4.0-incubating</version>
   <name>Calcite Avatica Server</name>
   <description>JDBC server.</description>
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0c0c203d/avatica/pom.xml
----------------------------------------------------------------------
diff --git a/avatica/pom.xml b/avatica/pom.xml
index 7d017d2..16b8546 100644
--- a/avatica/pom.xml
+++ b/avatica/pom.xml
@@ -20,12 +20,12 @@ limitations under the License.
   <parent>
     <groupId>org.apache.calcite</groupId>
     <artifactId>calcite</artifactId>
-    <version>1.4.0-incubating-SNAPSHOT</version>
+    <version>1.4.0-incubating</version>
   </parent>
 
   <artifactId>calcite-avatica</artifactId>
   <packaging>jar</packaging>
-  <version>1.4.0-incubating-SNAPSHOT</version>
+  <version>1.4.0-incubating</version>
   <name>Calcite Avatica</name>
   <description>JDBC driver framework.</description>
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0c0c203d/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index e7ee9f5..1362652 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -20,12 +20,12 @@ limitations under the License.
   <parent>
     <groupId>org.apache.calcite</groupId>
     <artifactId>calcite</artifactId>
-    <version>1.4.0-incubating-SNAPSHOT</version>
+    <version>1.4.0-incubating</version>
   </parent>
 
   <artifactId>calcite-core</artifactId>
   <packaging>jar</packaging>
-  <version>1.4.0-incubating-SNAPSHOT</version>
+  <version>1.4.0-incubating</version>
   <name>Calcite Core</name>
   <description>Core Calcite APIs and engine.</description>
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0c0c203d/example/csv/pom.xml
----------------------------------------------------------------------
diff --git a/example/csv/pom.xml b/example/csv/pom.xml
index 20ea2b3..86fa41f 100644
--- a/example/csv/pom.xml
+++ b/example/csv/pom.xml
@@ -20,12 +20,12 @@ limitations under the License.
   <parent>
     <groupId>org.apache.calcite</groupId>
     <artifactId>calcite-example</artifactId>
-    <version>1.4.0-incubating-SNAPSHOT</version>
+    <version>1.4.0-incubating</version>
   </parent>
 
   <artifactId>calcite-example-csv</artifactId>
   <packaging>jar</packaging>
-  <version>1.4.0-incubating-SNAPSHOT</version>
+  <version>1.4.0-incubating</version>
   <name>Calcite Example CSV</name>
   <description>An example Calcite provider that reads CSV files</description>
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0c0c203d/example/pom.xml
----------------------------------------------------------------------
diff --git a/example/pom.xml b/example/pom.xml
index fdf57cb..6c05e60 100644
--- a/example/pom.xml
+++ b/example/pom.xml
@@ -20,13 +20,13 @@ limitations under the License.
   <parent>
     <groupId>org.apache.calcite</groupId>
     <artifactId>calcite</artifactId>
-    <version>1.4.0-incubating-SNAPSHOT</version>
+    <version>1.4.0-incubating</version>
   </parent>
 
   <!-- The basics. -->
   <artifactId>calcite-example</artifactId>
   <packaging>pom</packaging>
-  <version>1.4.0-incubating-SNAPSHOT</version>
+  <version>1.4.0-incubating</version>
   <name>Calcite Examples</name>
   <description>Calcite examples</description>
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0c0c203d/linq4j/pom.xml
----------------------------------------------------------------------
diff --git a/linq4j/pom.xml b/linq4j/pom.xml
index 9da6c24..64f0bd0 100644
--- a/linq4j/pom.xml
+++ b/linq4j/pom.xml
@@ -20,12 +20,12 @@ limitations under the License.
   <parent>
     <groupId>org.apache.calcite</groupId>
     <artifactId>calcite</artifactId>
-    <version>1.4.0-incubating-SNAPSHOT</version>
+    <version>1.4.0-incubating</version>
   </parent>
 
   <artifactId>calcite-linq4j</artifactId>
   <packaging>jar</packaging>
-  <version>1.4.0-incubating-SNAPSHOT</version>
+  <version>1.4.0-incubating</version>
   <name>Calcite Linq4j</name>
   <description>Calcite APIs for LINQ (Language-Integrated Query) in Java</description>
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0c0c203d/mongodb/pom.xml
----------------------------------------------------------------------
diff --git a/mongodb/pom.xml b/mongodb/pom.xml
index e459803..da4a93b 100644
--- a/mongodb/pom.xml
+++ b/mongodb/pom.xml
@@ -20,12 +20,12 @@ limitations under the License.
   <parent>
     <groupId>org.apache.calcite</groupId>
     <artifactId>calcite</artifactId>
-    <version>1.4.0-incubating-SNAPSHOT</version>
+    <version>1.4.0-incubating</version>
   </parent>
 
   <artifactId>calcite-mongodb</artifactId>
   <packaging>jar</packaging>
-  <version>1.4.0-incubating-SNAPSHOT</version>
+  <version>1.4.0-incubating</version>
   <name>Calcite MongoDB</name>
   <description>MongoDB adapter for Calcite</description>
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0c0c203d/plus/pom.xml
----------------------------------------------------------------------
diff --git a/plus/pom.xml b/plus/pom.xml
index 9119709..f918e8f 100644
--- a/plus/pom.xml
+++ b/plus/pom.xml
@@ -20,12 +20,12 @@ limitations under the License.
   <parent>
     <groupId>org.apache.calcite</groupId>
     <artifactId>calcite</artifactId>
-    <version>1.4.0-incubating-SNAPSHOT</version>
+    <version>1.4.0-incubating</version>
   </parent>
 
   <artifactId>calcite-plus</artifactId>
   <packaging>jar</packaging>
-  <version>1.4.0-incubating-SNAPSHOT</version>
+  <version>1.4.0-incubating</version>
   <name>Calcite Plus</name>
   <description>Miscellaneous extras for Calcite</description>
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0c0c203d/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 3dea676..9d51284 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,7 +27,7 @@ limitations under the License.
   <groupId>org.apache.calcite</groupId>
   <artifactId>calcite</artifactId>
   <packaging>pom</packaging>
-  <version>1.4.0-incubating-SNAPSHOT</version>
+  <version>1.4.0-incubating</version>
 
   <!-- More project information. -->
   <name>Calcite</name>
@@ -61,7 +61,7 @@ limitations under the License.
     <connection>scm:git:https://git-wip-us.apache.org/repos/asf/incubator-calcite.git</connection>
     <developerConnection>scm:git:https://git-wip-us.apache.org/repos/asf/incubator-calcite.git</developerConnection>
     <url>https://github.com/apache/incubator-calcite</url>
-    <tag>HEAD</tag>
+    <tag>calcite-1.4.0-incubating</tag>
   </scm>
 
   <modules>
@@ -88,34 +88,34 @@ limitations under the License.
       <dependency>
         <groupId>org.apache.calcite</groupId>
         <artifactId>calcite-avatica</artifactId>
-        <version>1.4.0-incubating-SNAPSHOT</version>
+        <version>1.4.0-incubating</version>
       </dependency>
       <dependency>
         <groupId>org.apache.calcite</groupId>
         <artifactId>calcite-avatica</artifactId>
-        <version>1.4.0-incubating-SNAPSHOT</version>
+        <version>1.4.0-incubating</version>
         <type>test-jar</type>
       </dependency>
       <dependency>
         <groupId>org.apache.calcite</groupId>
         <artifactId>calcite-avatica-server</artifactId>
-        <version>1.4.0-incubating-SNAPSHOT</version>
+        <version>1.4.0-incubating</version>
       </dependency>
       <dependency>
         <groupId>org.apache.calcite</groupId>
         <artifactId>calcite-core</artifactId>
-        <version>1.4.0-incubating-SNAPSHOT</version>
+        <version>1.4.0-incubating</version>
       </dependency>
       <dependency>
         <groupId>org.apache.calcite</groupId>
         <artifactId>calcite-core</artifactId>
         <type>test-jar</type>
-        <version>1.4.0-incubating-SNAPSHOT</version>
+        <version>1.4.0-incubating</version>
       </dependency>
       <dependency>
         <groupId>org.apache.calcite</groupId>
         <artifactId>calcite-linq4j</artifactId>
-        <version>1.4.0-incubating-SNAPSHOT</version>
+        <version>1.4.0-incubating</version>
       </dependency>
 
       <!-- Now third-party dependencies, sorted by groupId and artifactId. -->

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0c0c203d/spark/pom.xml
----------------------------------------------------------------------
diff --git a/spark/pom.xml b/spark/pom.xml
index 6d664f3..e0b4281 100644
--- a/spark/pom.xml
+++ b/spark/pom.xml
@@ -20,12 +20,12 @@ limitations under the License.
   <parent>
     <groupId>org.apache.calcite</groupId>
     <artifactId>calcite</artifactId>
-    <version>1.4.0-incubating-SNAPSHOT</version>
+    <version>1.4.0-incubating</version>
   </parent>
 
   <artifactId>calcite-spark</artifactId>
   <packaging>jar</packaging>
-  <version>1.4.0-incubating-SNAPSHOT</version>
+  <version>1.4.0-incubating</version>
   <name>Calcite Spark</name>
 
   <properties>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0c0c203d/splunk/pom.xml
----------------------------------------------------------------------
diff --git a/splunk/pom.xml b/splunk/pom.xml
index 307aa8e..e5f5cc2 100644
--- a/splunk/pom.xml
+++ b/splunk/pom.xml
@@ -20,12 +20,12 @@ limitations under the License.
   <parent>
     <groupId>org.apache.calcite</groupId>
     <artifactId>calcite</artifactId>
-    <version>1.4.0-incubating-SNAPSHOT</version>
+    <version>1.4.0-incubating</version>
   </parent>
 
   <artifactId>calcite-splunk</artifactId>
   <packaging>jar</packaging>
-  <version>1.4.0-incubating-SNAPSHOT</version>
+  <version>1.4.0-incubating</version>
   <name>Calcite Splunk</name>
   <description>Splunk adapter for Calcite; also a JDBC driver for Splunk</description>
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0c0c203d/ubenchmark/pom.xml
----------------------------------------------------------------------
diff --git a/ubenchmark/pom.xml b/ubenchmark/pom.xml
index 022d096..6278812 100644
--- a/ubenchmark/pom.xml
+++ b/ubenchmark/pom.xml
@@ -20,7 +20,7 @@ limitations under the License.
   <parent>
     <groupId>org.apache.calcite</groupId>
     <artifactId>calcite</artifactId>
-    <version>1.4.0-incubating-SNAPSHOT</version>
+    <version>1.4.0-incubating</version>
   </parent>
 
   <properties>


[46/50] incubator-calcite git commit: [CALCITE-741] Ensure that the source release's DEPENDENCIES file includes all module dependencies.

Posted by jh...@apache.org.
[CALCITE-741] Ensure that the source release's DEPENDENCIES file includes all module dependencies.

Create new separate remote resources instantiations.  The first will be used only on the root module (and thus include all module dependencies).  The second will be executed on all the non-root modules.


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

Branch: refs/heads/branch-release
Commit: f8a542740733070a3be2ef3c4346816ab7eeaa6c
Parents: c09a872
Author: Jacques Nadeau <ja...@apache.org>
Authored: Sun Aug 23 12:32:30 2015 -0700
Committer: Jacques Nadeau <ja...@apache.org>
Committed: Sun Aug 23 12:36:34 2015 -0700

----------------------------------------------------------------------
 avatica-server/pom.xml | 11 +++++++++++
 avatica/pom.xml        | 11 +++++++++++
 core/pom.xml           | 11 +++++++++++
 example/csv/pom.xml    | 11 +++++++++++
 linq4j/pom.xml         | 11 +++++++++++
 mongodb/pom.xml        | 11 +++++++++++
 plus/pom.xml           | 11 +++++++++++
 pom.xml                | 26 ++++++++++++++++++++++++++
 spark/pom.xml          | 11 +++++++++++
 splunk/pom.xml         | 11 +++++++++++
 ubenchmark/pom.xml     | 11 +++++++++++
 11 files changed, 136 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f8a54274/avatica-server/pom.xml
----------------------------------------------------------------------
diff --git a/avatica-server/pom.xml b/avatica-server/pom.xml
index c1413b8..c8b9ba3 100644
--- a/avatica-server/pom.xml
+++ b/avatica-server/pom.xml
@@ -135,6 +135,17 @@ limitations under the License.
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>non-root-resources</id>
+            <goals>
+              <goal>process</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f8a54274/avatica/pom.xml
----------------------------------------------------------------------
diff --git a/avatica/pom.xml b/avatica/pom.xml
index 50b80c7..7d017d2 100644
--- a/avatica/pom.xml
+++ b/avatica/pom.xml
@@ -94,6 +94,17 @@ limitations under the License.
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>non-root-resources</id>
+            <goals>
+              <goal>process</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f8a54274/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index f863efc..e7ee9f5 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -254,6 +254,17 @@ limitations under the License.
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>non-root-resources</id>
+            <goals>
+              <goal>process</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
 
     <resources>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f8a54274/example/csv/pom.xml
----------------------------------------------------------------------
diff --git a/example/csv/pom.xml b/example/csv/pom.xml
index a8f93e7..20ea2b3 100644
--- a/example/csv/pom.xml
+++ b/example/csv/pom.xml
@@ -100,6 +100,17 @@ limitations under the License.
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>non-root-resources</id>
+            <goals>
+              <goal>process</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f8a54274/linq4j/pom.xml
----------------------------------------------------------------------
diff --git a/linq4j/pom.xml b/linq4j/pom.xml
index 508006a..9da6c24 100644
--- a/linq4j/pom.xml
+++ b/linq4j/pom.xml
@@ -80,6 +80,17 @@ limitations under the License.
           </includes>
         </configuration>
       </plugin>
+      <plugin>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>non-root-resources</id>
+            <goals>
+              <goal>process</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f8a54274/mongodb/pom.xml
----------------------------------------------------------------------
diff --git a/mongodb/pom.xml b/mongodb/pom.xml
index bc1ac3d..e459803 100644
--- a/mongodb/pom.xml
+++ b/mongodb/pom.xml
@@ -117,6 +117,17 @@ limitations under the License.
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>non-root-resources</id>
+            <goals>
+              <goal>process</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f8a54274/plus/pom.xml
----------------------------------------------------------------------
diff --git a/plus/pom.xml b/plus/pom.xml
index 57dfcbb..9119709 100644
--- a/plus/pom.xml
+++ b/plus/pom.xml
@@ -134,6 +134,17 @@ limitations under the License.
           </includes>
         </configuration>
       </plugin>
+      <plugin>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>non-root-resources</id>
+            <goals>
+              <goal>process</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f8a54274/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index c9d1e99..eab243c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -329,6 +329,32 @@ limitations under the License.
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>root-resources</id>
+            <goals>
+              <goal>process</goal>
+            </goals>
+            <configuration>
+              <runOnlyAtExecutionRoot>true</runOnlyAtExecutionRoot>
+              <resourceBundles>
+                <resourceBundle>org.apache:apache-jar-resource-bundle:1.4</resourceBundle>
+              </resourceBundles>
+            </configuration>
+          </execution>
+          <execution>
+            <id>non-root-resources</id>
+            <configuration>
+              <resourceBundles>
+                <resourceBundle>org.apache:apache-jar-resource-bundle:1.4</resourceBundle>
+              </resourceBundles>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <configuration>
           <source>1.7</source>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f8a54274/spark/pom.xml
----------------------------------------------------------------------
diff --git a/spark/pom.xml b/spark/pom.xml
index ff3e745..6d664f3 100644
--- a/spark/pom.xml
+++ b/spark/pom.xml
@@ -162,6 +162,17 @@ limitations under the License.
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>non-root-resources</id>
+            <goals>
+              <goal>process</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f8a54274/splunk/pom.xml
----------------------------------------------------------------------
diff --git a/splunk/pom.xml b/splunk/pom.xml
index bf890e3..307aa8e 100644
--- a/splunk/pom.xml
+++ b/splunk/pom.xml
@@ -104,6 +104,17 @@ limitations under the License.
           </includes>
         </configuration>
       </plugin>
+      <plugin>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>non-root-resources</id>
+            <goals>
+              <goal>process</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f8a54274/ubenchmark/pom.xml
----------------------------------------------------------------------
diff --git a/ubenchmark/pom.xml b/ubenchmark/pom.xml
index cbb4413..022d096 100644
--- a/ubenchmark/pom.xml
+++ b/ubenchmark/pom.xml
@@ -125,6 +125,17 @@ limitations under the License.
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>non-root-resources</id>
+            <goals>
+              <goal>process</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 </project>


[24/50] incubator-calcite git commit: [CALCITE-810] Add committers' organizations to the web site

Posted by jh...@apache.org.
[CALCITE-810] Add committers' organizations to the web site


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

Branch: refs/heads/branch-release
Commit: da5d5c2dfc3dfc26fb2e6a8f0dc7ed7dfd5dbc51
Parents: 096d282
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Jul 21 20:49:58 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Wed Jul 22 14:36:24 2015 -0700

----------------------------------------------------------------------
 site/_data/contributors.yml | 14 ++++++++++++++
 site/develop/index.md       |  6 +++---
 2 files changed, 17 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/da5d5c2d/site/_data/contributors.yml
----------------------------------------------------------------------
diff --git a/site/_data/contributors.yml b/site/_data/contributors.yml
index 48f8750..5163b10 100644
--- a/site/_data/contributors.yml
+++ b/site/_data/contributors.yml
@@ -19,59 +19,73 @@
 - name: Alan Gates
   apacheId: gates
   githubId: alanfgates
+  org: Hortonworks
   role: Mentor
 - name: Aman Sinha
   apacheId: amansinha
   githubId: amansinha100
+  org: MapR
   role: Committer
 - name: Ashutosh Chauhan
   apacheId: hashutosh
   githubId: ashutoshc
+  org: Hortonworks
   role: Champion
 - name: Chris Wensel
   apacheId: cwensel
   githubId: cwensel
+  org: Concurrent
   role: PMC
 - name: James R. Taylor
   apacheId: jamestaylor
   githubId: JamesRTaylor
+  org: Salesforce
   role: PMC
 - name: Jacques Nadeau
   apacheId: jacques
   githubId: jacques-n
+  org: Dremio
   role: PMC
 - name: Jesús Camacho Rodríguez
   apacheId: jcamacho
   githubId: jcamachor
+  org: Hortonworks
   role: Committer
 - name: Jinfeng Ni
   apacheId: jni
   githubId: jinfengni
+  org: MapR
   role: Committer
 - name: John Pullokkaran
   apacheId: jpullokk
   githubId: jpullokkaran
+  org: Hortonworks
   role: Committer
 - name: Julian Hyde
   apacheId: jhyde
   githubId: julianhyde
+  org: Hortonworks
   role: PMC
   homepage: http://people.apache.org/~jhyde
 - name: Nick Dimiduk
   apacheId: ndimiduk
   githubId: ndimiduk
+  org: Hortonworks
   role: Committer
 - name: Steven Noels
   apacheId: stevenn
   githubId: stevenn
+  org: NGData
   role: Mentor
 - name: Ted Dunning
   apacheId: tdunning
   githubId: tdunning
+  org: MapR
   role: Mentor
   avatar: https://www.mapr.com/sites/default/files/otherpageimages/ted-circle-80.png
 - name: Vladimir Sitnikov
   apacheId: vladimirsitnikov
   githubId: vlsi
+  org: NetCracker
   role: PMC
 # End contributors.yml

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/da5d5c2d/site/develop/index.md
----------------------------------------------------------------------
diff --git a/site/develop/index.md b/site/develop/index.md
index 5082ce0..84af4a8 100644
--- a/site/develop/index.md
+++ b/site/develop/index.md
@@ -25,9 +25,9 @@ Want to help add a feature or fix a bug?
 
 ## Project Members
 
-Name | Apache Id | Github | Role
-:--- | :-------- | :----- | :---
-{% for c in site.data.contributors %}  {{ c.name }} | <a href="http://people.apache.org/committer-index#{{ c.apacheId }}">{{ c.apacheId }}</a> | <a href="http://github.com/{{ c.githubId }}"><img width="64" src="{% unless c.avatar %}http://github.com/{{ c.githubId }}.png{% else %}{{ c.avatar }}{% endunless %}"></a> | {{ c.role }}
+Name | Apache Id | Github | Organization | Role
+:--- | :-------- | :----- | :---         | :---
+{% for c in site.data.contributors %}  {{ c.name }} | <a href="http://people.apache.org/committer-index#{{ c.apacheId }}">{{ c.apacheId }}</a> | <a href="http://github.com/{{ c.githubId }}"><img width="64" src="{% unless c.avatar %}http://github.com/{{ c.githubId }}.png{% else %}{{ c.avatar }}{% endunless %}"></a> | {{ c.org }} | {{ c.role }}
 {% endfor %}
 
 ## Mailing Lists


[03/50] incubator-calcite git commit: [CALCITE-752] Add back sqlline as a dependency to csv example

Posted by jh...@apache.org.
[CALCITE-752] Add back sqlline as a dependency to csv example


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

Branch: refs/heads/branch-release
Commit: fcb6ba5fa4be7c5eb55f784f5ff74ce4bd993abb
Parents: 830afef
Author: Julian Hyde <jh...@apache.org>
Authored: Wed Jul 8 11:54:23 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jul 9 10:28:40 2015 -0700

----------------------------------------------------------------------
 example/csv/pom.xml | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/fcb6ba5f/example/csv/pom.xml
----------------------------------------------------------------------
diff --git a/example/csv/pom.xml b/example/csv/pom.xml
index c573eca..a8f93e7 100644
--- a/example/csv/pom.xml
+++ b/example/csv/pom.xml
@@ -69,5 +69,37 @@ limitations under the License.
       <groupId>org.apache.commons</groupId>
       <artifactId>commons-lang3</artifactId>
     </dependency>
+    <dependency>
+      <groupId>sqlline</groupId>
+      <artifactId>sqlline</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <version>2.10</version>
+        <!-- configurations do not cascade, so all of the definition from
+             ../pom.xml:build:plugin-management:plugins:plugin must be repeated in child poms -->
+        <executions>
+          <execution>
+            <id>analyze</id>
+            <goals>
+              <goal>analyze-only</goal>
+            </goals>
+            <configuration>
+              <failOnWarning>true</failOnWarning>
+              <!-- ignore "unused but declared" warnings -->
+              <ignoredUnusedDeclaredDependencies>
+                <ignoredUnusedDeclaredDependency>sqlline:sqlline</ignoredUnusedDeclaredDependency>
+              </ignoredUnusedDeclaredDependencies>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
 </project>


[25/50] incubator-calcite git commit: Add RelBuilder.avg

Posted by jh...@apache.org.
Add RelBuilder.avg


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

Branch: refs/heads/branch-release
Commit: e27311ea784bd4c8f3af354a3deebf9def0371ac
Parents: da5d5c2
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Jul 23 12:21:49 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jul 23 12:21:49 2015 -0700

----------------------------------------------------------------------
 core/src/main/java/org/apache/calcite/tools/RelBuilder.java | 5 +++++
 1 file changed, 5 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e27311ea/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
index 13cf96e..79fd482 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -444,6 +444,11 @@ public class RelBuilder {
     return aggregateCall(SqlStdOperatorTable.SUM, distinct, alias, operand);
   }
 
+  /** Creates a call to the AVG aggregate function. */
+  public AggCall avg(boolean distinct, String alias, RexNode operand) {
+    return aggregateCall(SqlStdOperatorTable.AVG, distinct, alias, operand);
+  }
+
   /** Creates a call to the MIN aggregate function. */
   public AggCall min(String alias, RexNode operand) {
     return aggregateCall(SqlStdOperatorTable.MIN, false, alias, operand);


[49/50] incubator-calcite git commit: Add release notes for version 1.4.0

Posted by jh...@apache.org.
Add release notes for version 1.4.0


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

Branch: refs/heads/branch-release
Commit: 23a00c9ed26b8f3d520c148b111c0970fac81f8e
Parents: a3d3fcd
Author: Jacques Nadeau <ja...@apache.org>
Authored: Sun Aug 23 21:49:11 2015 -0700
Committer: Jacques Nadeau <ja...@apache.org>
Committed: Sun Aug 23 21:49:11 2015 -0700

----------------------------------------------------------------------
 site/_docs/history.md | 187 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 187 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/23a00c9e/site/_docs/history.md
----------------------------------------------------------------------
diff --git a/site/_docs/history.md b/site/_docs/history.md
index b809b19..a0bc735 100644
--- a/site/_docs/history.md
+++ b/site/_docs/history.md
@@ -26,6 +26,193 @@ limitations under the License.
 For a full list of releases, see
 <a href="https://github.com/apache/incubator-calcite/releases">github</a>.
 
+## <a href="https://github.com/apache/incubator-calcite/releases/tag/calcite-1.4.0-incubating">1.4.0-incubating</a> / 2015-08-23
+{: #v1-4-0}
+
+In addition to a large number of bug fixes and minor enhancements, this release includes improvements in Lattice Functionality, Materialized Views and the ability to generate relational albegra using a builder.
+
+New features
+
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-748">CALCITE-748</a>]
+      Add `RelBuilder`, builder for expressions in relational algebra
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-758">CALCITE-758</a>]
+      Use more than one lattice in the same query (Rajat Venkatesh)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-761">CALCITE-761</a>]
+      Pre-populated materializations (Maryann Xue)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-786">CALCITE-786</a>]
+      Detect if materialized view can be used to rewrite a query in
+  non-trivial cases (Amogh Margoor)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-732">CALCITE-732</a>]
+      Implement multiple distinct-COUNT using GROUPING SETS
+* Add various `BitSet` and `ImmutableBitSet` utilities
+
+Website Updates
+
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-810">CALCITE-810</a>]
+      Add committers' organizations to the web site
+* Add news item (XLDB best lighting talk), and some talks
+* Fix javadoc links
+* Add license notice for web site
+* Wrap file header in HTML comments
+* How to release
+* Move disclaimer out of every page's footer and into home page and downloads
+  page
+* For web site files, add license headers where possible, apache-rat
+  exclusions otherwise
+* Calcite DOAP
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-355">CALCITE-355</a>]
+      Web site
+
+Bug fixes, API Changes and Minor Enhancements
+
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-741">CALCITE-741</a>]
+      Ensure that the source release's DEPENDENCIES file includes all module
+  dependencies.
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-743">CALCITE-743</a>]
+      Ensure only a single source assembly is executed.
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-850">CALCITE-850</a>]
+      Remove push down expressions from `FilterJoinRule` and create a new rule
+  for it
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-834">CALCITE-834</a>]
+      `StackOverflowError` getting predicates from the metadata provider
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-833">CALCITE-833</a>]
+      RelOptUtil.splitJoinCondition incorrectly splits a join condition
+  (Hsuan-Yi Chu)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-822">CALCITE-822</a>]
+      Add a unit test case to test collation of `LogicalAggregate`
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-822">CALCITE-822</a>]
+      Revert incorrect `LogicalAggregate` collation inferring logic made in
+  CALCITE-783 (Milinda Pathirage)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-826">CALCITE-826</a>]
+      Use `ProjectFactory` in `AggregateJoinTranposeRule` and `FilterJoinRule`
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-821">CALCITE-821</a>]
+      Frameworks gives NPE when `FrameworkConfig` has no default schema
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-811">CALCITE-811</a>]
+      Extend `JoinProjectTransposeRule` with option to support outer joins
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-805">CALCITE-805</a>]
+      Add support for using an alternative grammar specification for left and
+  right curly braces. Additionally, add support for including addition token
+  manager declarations.
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-803">CALCITE-803</a>]
+      Add `MYSQL_ANSI` Lexing policy.
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-717">CALCITE-717</a>]
+      Compare BINARY and VARBINARY on unsigned byte values (Low Chin Wei)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-814">CALCITE-814</a>]
+      `RexBuilder` reverses precision and scale of `DECIMAL` literal
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-813">CALCITE-813</a>]
+      Upgrade `updateCount`, `maxRows` from int to long
+* Fix up [<a
+  href="https://issues.apache.org/jira/browse/CALCITE-714">CALCITE-714</a>]
+  
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-714">CALCITE-714</a>]
+      When de-correlating, push join condition into subquery
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-751">CALCITE-751</a>]
+      Push aggregate with aggregate functions through join
+* Add `RelBuilder.avg`
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-806">CALCITE-806</a>]
+      ROW_NUMBER should emit distinct values
+* Document JSON model, making javadoc consistent with the model reference
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-808">CALCITE-808</a>]
+      Optimize `ProjectMergeRule`
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-791">CALCITE-791</a>]
+      Optimize `RelOptUtil.pushFilterPastProject`
+* Complete [<a
+  href="https://issues.apache.org/jira/browse/CALCITE-783">CALCITE-783</a>]
+      by fixing some planner rules
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-783">CALCITE-783</a>]
+      Infer collation of `Project` using monotonicity (Milinda Pathirage)
+* Change the argument types of `SqlOperator.getMonotonicity` to allow it to be
+  used for `RexNode` as well as `SqlNode`
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-800">CALCITE-800</a>]
+      Window function defined within another window function should be invalid
+  (Hsuan-Yi Chu)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-787">CALCITE-787</a>]
+      Star table wrongly assigned to materialized view (Amogh Margoor)
+* Fix up previous commit; add some tests for constant reduction
+* Remove duplicate resources from XML test reference files
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-795">CALCITE-795</a>]
+      Loss of precision when sending a decimal number via the remote JSON
+  service (Lukáš Lalinský)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-774">CALCITE-774</a>]
+      When GROUP BY is present, ensure that window function operands only
+  refer to GROUP BY keys (Hsuan-Yi Chu)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-799">CALCITE-799</a>]
+      Incorrect result for "HAVING count(*) > 1"
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-801">CALCITE-801</a>]
+      NullPointerException using USING on table alias with column aliases
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-390">CALCITE-390</a>]
+      Infer predicates for semi-join
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-789">CALCITE-789</a>]
+      `MetaImpl.MetaCatalog` should expose TABLE_CAT instead of TABLE_CATALOG
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-752">CALCITE-752</a>]
+      Add back sqlline as a dependency to csv example
+* Re-enable a test; fix some code formatting; fix Windows line endings
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-780">CALCITE-780</a>]
+      HTTP error 413 when sending a long string to the Avatica server
+* In RelBuilder, calling sort then limit has same effect as calling sortLimit
+* Add Ord.reverse
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-788">CALCITE-788</a>]
+      Allow `EnumerableJoin` to be sub-classed (Li Yang)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-280">CALCITE-280</a>]
+      BigDecimal underflow (Li Yang)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-763">CALCITE-763</a>]
+      Missing translation from `Sort` to `MutableSort` (Maryann Xue)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-770">CALCITE-770</a>]
+      Ignore window aggregates and ranking functions when finding aggregate
+  functions
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-765">CALCITE-765</a>]
+      Set Content-Type from the RPC server to application/json (Lukáš Lalinský)
+* Fix Windows line-endings in `RelBuilderTest`
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-727">CALCITE-727</a>]
+      Constant folding involving CASE and NULL
+* Related to [<a
+  href="https://issues.apache.org/jira/browse/CALCITE-758">CALCITE-758</a>]
+     , speed up matching by not considering tiles separately from other
+  materialized views
+* Test case and workaround for [<a
+  href="https://issues.apache.org/jira/browse/CALCITE-760">CALCITE-760</a>]
+      `Aggregate` recommender blows up if row count estimate is too high
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-753">CALCITE-753</a>]
+      `Aggregate` operators may derive row types with duplicate column names
+  Close apache/incubator-calcite#91
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-457">CALCITE-457</a>]
+      Push condition of non-ansi join into join operator
+* Change jsonRequest encoding to UTF-8 (Guitao Ding)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-757">CALCITE-757</a>]
+      Fix expansion of view of another view (Venki Korukanti)
+* Fix coverity warnings
+* Remove deprecated `SqlTypeName` methods
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-754">CALCITE-754</a>]
+      Validator error when resolving OVER clause of JOIN query
+* Test case for [<a
+  href="https://issues.apache.org/jira/browse/CALCITE-754">CALCITE-754</a>]
+      Validator error when resolving OVER clause of JOIN query (Hsuan-Yi Chu)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-429">CALCITE-429</a>]
+      Cardinality provider for use by lattice algorithm
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-740">CALCITE-740</a>]
+      Redundant WHERE clause causes wrong result in MongoDB adapter
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-665">CALCITE-665</a>]
+      ClassCastException in MongoDB adapter
+* Separate `TableFactory` from suggested table name, so one `TableFactory` can be
+  used for several tables
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-749">CALCITE-749</a>]
+      Add `MaterializationService.TableFactory` (Rajat Venkatesh)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-718">CALCITE-718</a>]
+      Enable fetch to work for `Statement.execute()` for Avatica (Xavier Leong)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-712">CALCITE-712</a>]
+      Obey `setMaxRows` for statement execute (Xavier Leong)
+* Add `LoggingLocalJsonService`, to make it easier to test that JDBC requests
+  cause the right RPCs
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-708">CALCITE-708</a>]
+      Implement `DatabaseMetaData.getTypeInfo` (Xavier Leong)
+* Enable Travis CI on new-master branch and bug-fix branches named
+  "NNN-description"
+* Clean up
+* Upgrade tpcds
+* Make `JdbcTest.testVersion` more permissive, so that version.major and
+  version.minor can be set just before a release, rather than just after as at
+  present
+
 ## <a href="https://github.com/apache/incubator-calcite/releases/tag/calcite-1.3.0-incubating">1.3.0-incubating</a> / 2015-05-30
 {: #v1-3-0}
 


[26/50] incubator-calcite git commit: Various BitSet and ImmutableBitSet utilities

Posted by jh...@apache.org.
Various BitSet and ImmutableBitSet utilities

* BitSets.closure does not alter its argument
* Add ImmutableBitSet.union(BitSet)
* Add ImmutableBitSet.shift(int)
* Add Mappings.apply2(Mapping, Iterable<ImmutableBitSet>)


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

Branch: refs/heads/branch-release
Commit: 41541d44d458ec4e4c6067cb40aa68dd1f433bda
Parents: e27311e
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Jul 23 12:30:11 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jul 23 12:30:11 2015 -0700

----------------------------------------------------------------------
 .../java/org/apache/calcite/util/BitSets.java   | 21 +++++++++-
 .../apache/calcite/util/ImmutableBitSet.java    | 44 +++++++++++++++++++-
 .../apache/calcite/util/mapping/Mappings.java   | 20 +++++++++
 .../org/apache/calcite/util/BitSetsTest.java    | 21 +++++++---
 .../calcite/util/ImmutableBitSetTest.java       | 34 +++++++++++++--
 5 files changed, 127 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/41541d44/core/src/main/java/org/apache/calcite/util/BitSets.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/BitSets.java b/core/src/main/java/org/apache/calcite/util/BitSets.java
index bbab792..daa174a 100644
--- a/core/src/main/java/org/apache/calcite/util/BitSets.java
+++ b/core/src/main/java/org/apache/calcite/util/BitSets.java
@@ -16,6 +16,8 @@
  */
 package org.apache.calcite.util;
 
+import com.google.common.collect.ImmutableSortedMap;
+
 import java.util.BitSet;
 import java.util.Iterator;
 import java.util.SortedMap;
@@ -275,6 +277,22 @@ public final class BitSets {
    * <p>Does not modify the input map or its bit sets. */
   public static SortedMap<Integer, BitSet> closure(
       SortedMap<Integer, BitSet> equivalence) {
+    if (equivalence.isEmpty()) {
+      return ImmutableSortedMap.of();
+    }
+    int length = equivalence.lastKey();
+    for (BitSet bitSet : equivalence.values()) {
+      length = Math.max(length, bitSet.length());
+    }
+    if (equivalence.size() < length
+        || equivalence.firstKey() != 0) {
+      SortedMap<Integer, BitSet> old = equivalence;
+      equivalence = new TreeMap<>();
+      for (int i = 0; i < length; i++) {
+        final BitSet bitSet = old.get(i);
+        equivalence.put(i, bitSet == null ? new BitSet() : bitSet);
+      }
+    }
     final Closure closure = new Closure(equivalence);
     return closure.closure;
   }
@@ -305,8 +323,7 @@ public final class BitSets {
    */
   private static class Closure {
     private SortedMap<Integer, BitSet> equivalence;
-    private final SortedMap<Integer, BitSet> closure =
-        new TreeMap<Integer, BitSet>();
+    private final SortedMap<Integer, BitSet> closure = new TreeMap<>();
 
     public Closure(SortedMap<Integer, BitSet> equivalence) {
       this.equivalence = equivalence;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/41541d44/core/src/main/java/org/apache/calcite/util/ImmutableBitSet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/ImmutableBitSet.java b/core/src/main/java/org/apache/calcite/util/ImmutableBitSet.java
index d35a446..5e569e0 100644
--- a/core/src/main/java/org/apache/calcite/util/ImmutableBitSet.java
+++ b/core/src/main/java/org/apache/calcite/util/ImmutableBitSet.java
@@ -21,6 +21,7 @@ import org.apache.calcite.runtime.Utilities;
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSortedMap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
@@ -36,6 +37,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.SortedMap;
+import java.util.TreeMap;
 import javax.annotation.Nonnull;
 
 /**
@@ -347,7 +349,9 @@ public class ImmutableBitSet
   }
 
   /** Returns the number of bits set to {@code true} in this
-   * {@code ImmutableBitSet}. */
+   * {@code ImmutableBitSet}.
+   *
+   * @see #size() */
   public int cardinality() {
     return countBits(words);
   }
@@ -383,6 +387,8 @@ public class ImmutableBitSet
    * The maximum element in the set is the size - 1st element.
    *
    * @return the number of bits currently in this bit set
+   *
+   * @see #cardinality()
    */
   public int size() {
     return words.length * BITS_PER_WORD;
@@ -603,6 +609,13 @@ public class ImmutableBitSet
     return words.length == 0 ? words : words.clone();
   }
 
+  /** Returns the union of this immutable bit set with a {@link BitSet}. */
+  public ImmutableBitSet union(BitSet other) {
+    return builder(this)
+        .addAll(BitSets.toIter(other))
+        .build();
+  }
+
   /** Returns the union of this bit set with another. */
   public ImmutableBitSet union(ImmutableBitSet other) {
     return builder(this)
@@ -678,6 +691,22 @@ public class ImmutableBitSet
    * <p>Does not modify the input map or its bit sets. */
   public static SortedMap<Integer, ImmutableBitSet> closure(
       SortedMap<Integer, ImmutableBitSet> equivalence) {
+    if (equivalence.isEmpty()) {
+      return ImmutableSortedMap.of();
+    }
+    int length = equivalence.lastKey();
+    for (ImmutableBitSet bitSet : equivalence.values()) {
+      length = Math.max(length, bitSet.length());
+    }
+    if (equivalence.size() < length
+        || equivalence.firstKey() != 0) {
+      SortedMap<Integer, ImmutableBitSet> old = equivalence;
+      equivalence = new TreeMap<>();
+      for (int i = 0; i < length; i++) {
+        final ImmutableBitSet bitSet = old.get(i);
+        equivalence.put(i, bitSet == null ? ImmutableBitSet.of() : bitSet);
+      }
+    }
     final Closure closure = new Closure(equivalence);
     return closure.closure;
   }
@@ -788,6 +817,19 @@ public class ImmutableBitSet
         });
   }
 
+  /** Returns a bit set with every bit moved up {@code offset} positions.
+   * Offset may be negative, but throws if any bit ends up negative. */
+  public ImmutableBitSet shift(int offset) {
+    if (offset == 0) {
+      return this;
+    }
+    final Builder builder = builder();
+    for (int i = nextSetBit(0); i >= 0; i = nextSetBit(i + 1)) {
+      builder.set(i + offset);
+    }
+    return builder.build();
+  }
+
   /**
    * Setup equivalence Sets for each position. If i & j are equivalent then
    * they will have the same equivalence Set. The algorithm computes the

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/41541d44/core/src/main/java/org/apache/calcite/util/mapping/Mappings.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/mapping/Mappings.java b/core/src/main/java/org/apache/calcite/util/mapping/Mappings.java
index 556f090..dcacb56 100644
--- a/core/src/main/java/org/apache/calcite/util/mapping/Mappings.java
+++ b/core/src/main/java/org/apache/calcite/util/mapping/Mappings.java
@@ -23,6 +23,8 @@ import org.apache.calcite.util.Permutation;
 import org.apache.calcite.util.Util;
 
 import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
 
 import java.util.AbstractList;
 import java.util.ArrayList;
@@ -208,6 +210,24 @@ public abstract class Mappings {
   }
 
   /**
+   * Applies a mapping to a collection of {@code ImmutableBitSet}s.
+   *
+   * @param mapping Mapping
+   * @param bitSets Collection of bit sets
+   * @return Bit sets with mapping applied
+   */
+  public static ImmutableList<ImmutableBitSet> apply2(final Mapping mapping,
+      Iterable<ImmutableBitSet> bitSets) {
+    return ImmutableList.copyOf(
+        Iterables.transform(bitSets,
+            new Function<ImmutableBitSet, ImmutableBitSet>() {
+              public ImmutableBitSet apply(ImmutableBitSet input1) {
+                return Mappings.apply(mapping, input1);
+              }
+            }));
+  }
+
+  /**
    * Applies a mapping to a list.
    *
    * @param mapping Mapping

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/41541d44/core/src/test/java/org/apache/calcite/util/BitSetsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/util/BitSetsTest.java b/core/src/test/java/org/apache/calcite/util/BitSetsTest.java
index 4e7cdb9..4581e9a 100644
--- a/core/src/test/java/org/apache/calcite/util/BitSetsTest.java
+++ b/core/src/test/java/org/apache/calcite/util/BitSetsTest.java
@@ -195,8 +195,7 @@ public class BitSetsTest {
     final SortedMap<Integer, BitSet> empty = Maps.newTreeMap();
     assertThat(BitSets.closure(empty), equalTo(empty));
 
-    // Currently you need an entry for each position, otherwise you get an NPE.
-    // We should fix that.
+    // Map with an an entry for each position.
     final SortedMap<Integer, BitSet> map = Maps.newTreeMap();
     map.put(0, BitSets.of(3));
     map.put(1, BitSets.of());
@@ -211,11 +210,21 @@ public class BitSetsTest {
     map.put(10, BitSets.of());
     map.put(11, BitSets.of());
     map.put(12, BitSets.of());
-    String original = map.toString();
-    assertThat(BitSets.closure(map).toString(),
-        equalTo(
-            "{0={3, 4, 12}, 1={}, 2={7}, 3={3, 4, 12}, 4={4, 12}, 5={}, 6={}, 7={7}, 8={}, 9={}, 10={}, 11={}, 12={4, 12}}"));
+    final String original = map.toString();
+    final String expected =
+        "{0={3, 4, 12}, 1={}, 2={7}, 3={3, 4, 12}, 4={4, 12}, 5={}, 6={}, 7={7}, 8={}, 9={}, 10={}, 11={}, 12={4, 12}}";
+    assertThat(BitSets.closure(map).toString(), equalTo(expected));
     assertThat("argument modified", map.toString(), equalTo(original));
+
+    // Now a similar map with missing entries. Same result.
+    final SortedMap<Integer, BitSet> map2 = Maps.newTreeMap();
+    map2.put(0, BitSets.of(3));
+    map2.put(2, BitSets.of(7));
+    map2.put(3, BitSets.of(4, 12));
+    map2.put(9, BitSets.of());
+    final String original2 = map2.toString();
+    assertThat(BitSets.closure(map2).toString(), equalTo(expected));
+    assertThat("argument modified", map2.toString(), equalTo(original2));
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/41541d44/core/src/test/java/org/apache/calcite/util/ImmutableBitSetTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/util/ImmutableBitSetTest.java b/core/src/test/java/org/apache/calcite/util/ImmutableBitSetTest.java
index da34dc7..b04c12a 100644
--- a/core/src/test/java/org/apache/calcite/util/ImmutableBitSetTest.java
+++ b/core/src/test/java/org/apache/calcite/util/ImmutableBitSetTest.java
@@ -30,6 +30,7 @@ import java.util.List;
 import java.util.SortedMap;
 
 import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
@@ -374,11 +375,21 @@ public class ImmutableBitSetTest {
     map.put(10, ImmutableBitSet.of());
     map.put(11, ImmutableBitSet.of());
     map.put(12, ImmutableBitSet.of());
-    String original = map.toString();
-    assertThat(ImmutableBitSet.closure(map).toString(),
-        equalTo(
-            "{0={3, 4, 12}, 1={}, 2={7}, 3={3, 4, 12}, 4={4, 12}, 5={}, 6={}, 7={7}, 8={}, 9={}, 10={}, 11={}, 12={4, 12}}"));
+    final String original = map.toString();
+    final String expected =
+        "{0={3, 4, 12}, 1={}, 2={7}, 3={3, 4, 12}, 4={4, 12}, 5={}, 6={}, 7={7}, 8={}, 9={}, 10={}, 11={}, 12={4, 12}}";
+    assertThat(ImmutableBitSet.closure(map).toString(), equalTo(expected));
     assertThat("argument modified", map.toString(), equalTo(original));
+
+    // Now a similar map with missing entries. Same result.
+    final SortedMap<Integer, ImmutableBitSet> map2 = Maps.newTreeMap();
+    map2.put(0, ImmutableBitSet.of(3));
+    map2.put(2, ImmutableBitSet.of(7));
+    map2.put(3, ImmutableBitSet.of(4, 12));
+    map2.put(9, ImmutableBitSet.of());
+    final String original2 = map2.toString();
+    assertThat(ImmutableBitSet.closure(map2).toString(), equalTo(expected));
+    assertThat("argument modified", map2.toString(), equalTo(original2));
   }
 
   @Test public void testPowerSet() {
@@ -446,6 +457,21 @@ public class ImmutableBitSetTest {
     assertThat(bitSet.clearIf(29, false), equalTo(bitSet));
     assertThat(bitSet.clearIf(29, true), equalTo(bitSet2));
   }
+
+  @Test public void testShift() {
+    final ImmutableBitSet bitSet = ImmutableBitSet.of(29, 4, 1969);
+    assertThat(bitSet.shift(0), is(bitSet));
+    assertThat(bitSet.shift(1), is(ImmutableBitSet.of(30, 5, 1970)));
+    assertThat(bitSet.shift(-4), is(ImmutableBitSet.of(25, 0, 1965)));
+    try {
+      final ImmutableBitSet x = bitSet.shift(-5);
+      fail("Expected error, got " + x);
+    } catch (ArrayIndexOutOfBoundsException e) {
+      assertThat(e.getMessage(), is("-1"));
+    }
+    final ImmutableBitSet empty = ImmutableBitSet.of();
+    assertThat(empty.shift(-100), is(empty));
+  }
 }
 
 // End ImmutableBitSetTest.java


[22/50] incubator-calcite git commit: [CALCITE-761] Pre-populated materializations (Maryann Xue)

Posted by jh...@apache.org.
[CALCITE-761] Pre-populated materializations (Maryann Xue)


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

Branch: refs/heads/branch-release
Commit: 4b60b9bf46b88b4dc6af8279013cbb731d98a8d3
Parents: 629a56e
Author: maryannxue <we...@intel.com>
Authored: Fri Jun 26 15:32:02 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jul 21 16:51:15 2015 -0700

----------------------------------------------------------------------
 .../materialize/MaterializationService.java     | 19 +++++--
 .../org/apache/calcite/model/ModelHandler.java  | 17 +++++-
 .../calcite/plan/RelOptMaterialization.java     |  3 +-
 .../schema/impl/MaterializedViewTable.java      | 13 +++--
 .../org/apache/calcite/test/CalciteAssert.java  | 58 ++++++++++----------
 .../calcite/test/MaterializationTest.java       | 39 +++++++++++++
 site/_docs/model.md                             |  7 ++-
 7 files changed, 111 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4b60b9bf/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java b/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
index b594cca..615d185 100644
--- a/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
+++ b/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
@@ -95,15 +95,16 @@ public class MaterializationService {
   /** Defines a new materialization. Returns its key. */
   public MaterializationKey defineMaterialization(final CalciteSchema schema,
       TileKey tileKey, String viewSql, List<String> viewSchemaPath,
-      final String suggestedTableName, boolean create) {
+      final String suggestedTableName, boolean create, boolean existing) {
     return defineMaterialization(schema, tileKey, viewSql, viewSchemaPath,
-        suggestedTableName, tableFactory, create);
+        suggestedTableName, tableFactory, create, existing);
   }
 
   /** Defines a new materialization. Returns its key. */
   public MaterializationKey defineMaterialization(final CalciteSchema schema,
       TileKey tileKey, String viewSql, List<String> viewSchemaPath,
-      String suggestedTableName, TableFactory tableFactory, boolean create) {
+      String suggestedTableName, TableFactory tableFactory, boolean create,
+      boolean existing) {
     final MaterializationActor.QueryKey queryKey =
         new MaterializationActor.QueryKey(viewSql, schema, viewSchemaPath);
     final MaterializationKey existingKey = actor.keyBySql.get(queryKey);
@@ -116,7 +117,15 @@ public class MaterializationService {
 
     final CalciteConnection connection =
         CalciteMetaImpl.connect(schema.root(), null);
-    CalciteSchema.TableEntry tableEntry = schema.getTableBySql(viewSql);
+    CalciteSchema.TableEntry tableEntry;
+    if (existing) {
+      tableEntry = schema.getTable(suggestedTableName, true);
+    } else {
+      tableEntry = null;
+    }
+    if (tableEntry == null) {
+      tableEntry = schema.getTableBySql(viewSql);
+    }
     RelDataType rowType = null;
     if (tableEntry == null) {
       Table table = tableFactory.createTable(schema, viewSql, viewSchemaPath);
@@ -265,7 +274,7 @@ public class MaterializationService {
     final String sql = lattice.sql(groupSet, newTileKey.measures);
     materializationKey =
         defineMaterialization(schema, newTileKey, sql, schema.path(null),
-            suggestedTableName, tableFactory, true);
+            suggestedTableName, tableFactory, true, false);
     if (materializationKey != null) {
       final CalciteSchema.TableEntry tableEntry =
           checkValid(materializationKey);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4b60b9bf/core/src/main/java/org/apache/calcite/model/ModelHandler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/model/ModelHandler.java b/core/src/main/java/org/apache/calcite/model/ModelHandler.java
index 1afaf41..3faf446 100644
--- a/core/src/main/java/org/apache/calcite/model/ModelHandler.java
+++ b/core/src/main/java/org/apache/calcite/model/ModelHandler.java
@@ -265,9 +265,22 @@ public class ModelHandler {
                 + "' is not a SemiMutableSchema");
       }
       CalciteSchema calciteSchema = CalciteSchema.from(schema);
-      schema.add(jsonMaterialization.view,
+
+      final String viewName;
+      final boolean existing;
+      if (jsonMaterialization.view == null) {
+        // If the user did not supply a view name, that means the materialized
+        // view is pre-populated. Generate a synthetic view name.
+        viewName = "$" + schema.getTableNames().size();
+        existing = true;
+      } else {
+        viewName = jsonMaterialization.view;
+        existing = false;
+      }
+      schema.add(viewName,
           MaterializedViewTable.create(calciteSchema,
-              jsonMaterialization.getSql(), null, jsonMaterialization.table));
+              jsonMaterialization.getSql(), null, jsonMaterialization.table,
+              existing));
     } catch (Exception e) {
       throw new RuntimeException("Error instantiating " + jsonMaterialization,
           e);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4b60b9bf/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java b/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java
index f945e65..4108cff 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java
@@ -62,7 +62,8 @@ public class RelOptMaterialization {
    */
   public RelOptMaterialization(RelNode tableRel, RelNode queryRel,
       RelOptTable starRelOptTable) {
-    this.tableRel = tableRel;
+    this.tableRel =
+        RelOptUtil.createCastRel(tableRel, queryRel.getRowType(), false);
     this.starRelOptTable = starRelOptTable;
     if (starRelOptTable == null) {
       this.starTable = null;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4b60b9bf/core/src/main/java/org/apache/calcite/schema/impl/MaterializedViewTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/impl/MaterializedViewTable.java b/core/src/main/java/org/apache/calcite/schema/impl/MaterializedViewTable.java
index 27e873a..8d80465 100644
--- a/core/src/main/java/org/apache/calcite/schema/impl/MaterializedViewTable.java
+++ b/core/src/main/java/org/apache/calcite/schema/impl/MaterializedViewTable.java
@@ -75,11 +75,10 @@ public class MaterializedViewTable extends ViewTable {
 
   /** Table macro that returns a materialized view. */
   public static MaterializedViewTableMacro create(final CalciteSchema schema,
-      final String viewSql,
-      final List<String> viewSchemaPath,
-      final String tableName) {
+      final String viewSql, final List<String> viewSchemaPath,
+      final String suggestedTableName, boolean existing) {
     return new MaterializedViewTableMacro(schema, viewSql, viewSchemaPath,
-        tableName);
+        suggestedTableName, existing);
   }
 
   @Override public RelNode toRel(RelOptTable.ToRelContext context,
@@ -102,11 +101,13 @@ public class MaterializedViewTable extends ViewTable {
     private final MaterializationKey key;
 
     private MaterializedViewTableMacro(CalciteSchema schema, String viewSql,
-        List<String> viewSchemaPath, String suggestedTableName) {
+        List<String> viewSchemaPath, String suggestedTableName,
+        boolean existing) {
       super(schema, viewSql, viewSchemaPath, Boolean.TRUE);
       this.key = Preconditions.checkNotNull(
           MaterializationService.instance().defineMaterialization(
-              schema, null, viewSql, schemaPath, suggestedTableName, true));
+              schema, null, viewSql, schemaPath, suggestedTableName, true,
+              existing));
     }
 
     @Override public TranslatableTable apply(List<Object> arguments) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4b60b9bf/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 39ed982..3d0a0dc 100644
--- a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
+++ b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
@@ -405,7 +405,7 @@ public class CalciteAssert {
 
   private static String typeString(ResultSetMetaData metaData)
       throws SQLException {
-    final List<String> list = new ArrayList<String>();
+    final List<String> list = new ArrayList<>();
     for (int i = 0; i < metaData.getColumnCount(); i++) {
       list.add(
           metaData.getColumnName(i + 1)
@@ -452,13 +452,7 @@ public class CalciteAssert {
           exceptionChecker.apply(null);
           return;
         }
-      } catch (Exception e) {
-        if (exceptionChecker != null) {
-          exceptionChecker.apply(e);
-          return;
-        }
-        throw e;
-      } catch (Error e) {
+      } catch (Exception | Error e) {
         if (exceptionChecker != null) {
           exceptionChecker.apply(e);
           return;
@@ -471,13 +465,11 @@ public class CalciteAssert {
       resultSet.close();
       statement.close();
       connection.close();
-    } catch (Error e) {
+    } catch (Error | RuntimeException e) {
       // We ignore extended message for non-runtime exception, however
       // it does not matter much since it is better to have AssertionError
       // at the very top level of the exception stack.
       throw e;
-    } catch (RuntimeException e) {
-      throw e;
     } catch (Throwable e) {
       throw new RuntimeException(message, e);
     } finally {
@@ -840,21 +832,32 @@ public class CalciteAssert {
 
     /** Adds materializations to the schema. */
     public final AssertThat withMaterializations(String model,
-        String... materializations) {
-      assert materializations.length % 2 == 0;
+        final String... materializations) {
+      return withMaterializations(model,
+          new Function<JsonBuilder, List<Object>>() {
+            public List<Object> apply(JsonBuilder builder) {
+              assert materializations.length % 2 == 0;
+              final List<Object> list = builder.list();
+              for (int i = 0; i < materializations.length; i++) {
+                String table = materializations[i++];
+                final Map<String, Object> map = builder.map();
+                map.put("table", table);
+                map.put("view", table + "v");
+                String sql = materializations[i];
+                final String sql2 = sql.replaceAll("`", "\"");
+                map.put("sql", sql2);
+                list.add(map);
+              }
+              return list;
+            }
+          });
+    }
+
+    /** Adds materializations to the schema. */
+    public final AssertThat withMaterializations(String model,
+        Function<JsonBuilder, List<Object>> materializations) {
       final JsonBuilder builder = new JsonBuilder();
-      final List<Object> list = builder.list();
-      for (int i = 0; i < materializations.length; i++) {
-        String table = materializations[i++];
-        final Map<String, Object> map = builder.map();
-        map.put("table", table);
-        map.put("view", table + "v");
-        String sql = materializations[i];
-        final String sql2 = sql
-            .replaceAll("`", "\"");
-        map.put("sql", sql2);
-        list.add(map);
-      }
+      final List<Object> list = materializations.apply(builder);
       final String buf =
           "materializations: " + builder.toJsonString(list);
       final String model2;
@@ -908,13 +911,10 @@ public class CalciteAssert {
      * and executes a callback. */
     public <T> AssertThat doWithConnection(Function<CalciteConnection, T> fn)
         throws Exception {
-      Connection connection = connectionFactory.createConnection();
-      try {
+      try (Connection connection = connectionFactory.createConnection()) {
         T t = fn.apply((CalciteConnection) connection);
         Util.discard(t);
         return AssertThat.this;
-      } finally {
-        connection.close();
       }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4b60b9bf/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
index ae235ab..f132915 100644
--- a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
+++ b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
@@ -28,14 +28,18 @@ import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.util.JsonBuilder;
 
 import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
 
 import org.junit.Ignore;
 import org.junit.Test;
 
 import java.math.BigDecimal;
 import java.sql.ResultSet;
+import java.util.List;
+import java.util.Map;
 
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.junit.Assert.assertEquals;
@@ -53,6 +57,10 @@ public class MaterializationTest {
       CalciteAssert.checkResultContains(
           "EnumerableTableScan(table=[[hr, m0]])");
 
+  private static final Function<ResultSet, Void> CONTAINS_LOCATIONS =
+      CalciteAssert.checkResultContains(
+          "EnumerableTableScan(table=[[hr, locations]])");
+
   final JavaTypeFactoryImpl typeFactory =
       new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
   final RexBuilder rexBuilder = new RexBuilder(typeFactory);
@@ -749,6 +757,37 @@ public class MaterializationTest {
             + "join \"depts\" using (\"deptno\")";
     checkMaterialize("select * from \"emps\" where \"empid\" < 500", q);
   }
+
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-761">[CALCITE-761]
+   * Pre-populated materializations</a>. */
+  @Test public void testPrePopulated() {
+    String q = "select \"deptno\" from \"emps\"";
+    try {
+      Prepare.THREAD_TRIM.set(true);
+      MaterializationService.setThreadLocal();
+      CalciteAssert.that()
+          .withMaterializations(
+              JdbcTest.HR_MODEL,
+              new Function<JsonBuilder, List<Object>>() {
+                public List<Object> apply(JsonBuilder builder) {
+                  final Map<String, Object> map = builder.map();
+                  map.put("table", "locations");
+                  String sql = "select `deptno` as `empid`, '' as `name`\n"
+                       + "from `emps`";
+                  final String sql2 = sql.replaceAll("`", "\"");
+                  map.put("sql", sql2);
+                  return ImmutableList.<Object>of(map);
+                }
+              })
+          .query(q)
+          .enableMaterializations(true)
+          .explainMatches("", CONTAINS_LOCATIONS)
+          .sameResultWithMaterializationsDisabled();
+    } finally {
+      Prepare.THREAD_TRIM.set(false);
+    }
+  }
 }
 
 // End MaterializationTest.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4b60b9bf/site/_docs/model.md
----------------------------------------------------------------------
diff --git a/site/_docs/model.md b/site/_docs/model.md
index 0f9a548..cb8cc9c 100644
--- a/site/_docs/model.md
+++ b/site/_docs/model.md
@@ -204,9 +204,12 @@ Occurs within `root.schemas.materializations`.
 }
 {% endhighlight %}
 
-`view` (optional string) TODO
+`view` (optional string) is the name of the view; null means that the table
+already exists and is populated with the correct data.
 
-`table` (optional string) TODO
+`table` (required string) is the name of the table that materializes the data in
+the query. If `view` is not null, the table might not exist, and if it does not,
+Calcite will create and populate an in-memory table.
 
 `sql` (optional string, or list of strings that will be concatenated as a
  multi-line string) is the SQL definition of the materialization.


[42/50] incubator-calcite git commit: [CALCITE-834] StackOverflowError getting predicates from the metadata provider

Posted by jh...@apache.org.
[CALCITE-834] StackOverflowError getting predicates from the metadata provider


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

Branch: refs/heads/branch-release
Commit: c9d7233d4e2be531814663f2a2ef3fc5600c4950
Parents: a61be0d
Author: Jesus Camacho Rodriguez <jc...@apache.org>
Authored: Tue Aug 18 19:57:42 2015 +0300
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Aug 18 11:00:33 2015 -0700

----------------------------------------------------------------------
 .../calcite/rel/metadata/RelMdPredicates.java   | 42 ++++++++++++++++----
 .../apache/calcite/test/RelMetadataTest.java    |  2 +-
 2 files changed, 35 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c9d7233d/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
index 5e14ba7..1912087 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
@@ -193,11 +193,21 @@ public class RelMdPredicates {
 
   /** Infers predicates for a {@link org.apache.calcite.rel.core.SemiJoin}. */
   public RelOptPredicateList getPredicates(SemiJoin semiJoin) {
-    final RelNode left = semiJoin.getInput(0);
-    final RelOptPredicateList leftInfo =
+    RexBuilder rB = semiJoin.getCluster().getRexBuilder();
+    RelNode left = semiJoin.getInput(0);
+    RelNode right = semiJoin.getInput(1);
+
+    RelOptPredicateList leftInfo =
         RelMetadataQuery.getPulledUpPredicates(left);
-    return RelOptPredicateList.of(leftInfo.pulledUpPredicates,
-        leftInfo.pulledUpPredicates, ImmutableList.<RexNode>of());
+    RelOptPredicateList rightInfo =
+        RelMetadataQuery.getPulledUpPredicates(right);
+
+    JoinConditionBasedPredicateInference jI =
+        new JoinConditionBasedPredicateInference(semiJoin,
+            RexUtil.composeConjunction(rB, leftInfo.pulledUpPredicates, false),
+            RexUtil.composeConjunction(rB, rightInfo.pulledUpPredicates, false));
+
+    return jI.inferPredicates(false);
   }
 
   /** Infers predicates for a {@link org.apache.calcite.rel.core.Join}. */
@@ -325,6 +335,7 @@ public class RelMdPredicates {
    */
   static class JoinConditionBasedPredicateInference {
     final Join joinRel;
+    final boolean isSemiJoin;
     final int nSysFields;
     final int nFieldsLeft;
     final int nFieldsRight;
@@ -339,9 +350,15 @@ public class RelMdPredicates {
     final RexNode rightChildPredicates;
 
     public JoinConditionBasedPredicateInference(Join joinRel,
+            RexNode lPreds, RexNode rPreds) {
+      this(joinRel, joinRel instanceof SemiJoin, lPreds, rPreds);
+    }
+
+    private JoinConditionBasedPredicateInference(Join joinRel, boolean isSemiJoin,
         RexNode lPreds, RexNode rPreds) {
       super();
       this.joinRel = joinRel;
+      this.isSemiJoin = isSemiJoin;
       nFieldsLeft = joinRel.getLeft().getRowType().getFieldList().size();
       nFieldsRight = joinRel.getRight().getRowType().getFieldList().size();
       nSysFields = joinRel.getSystemFieldList().size();
@@ -453,6 +470,7 @@ public class RelMdPredicates {
           nSysFields + nFieldsLeft, 0, nSysFields, nFieldsLeft);
       final RexPermuteInputsShuttle leftPermute =
           new RexPermuteInputsShuttle(leftMapping, joinRel);
+
       List<RexNode> leftInferredPredicates = new ArrayList<RexNode>();
       List<RexNode> rightInferredPredicates = new ArrayList<RexNode>();
 
@@ -467,12 +485,20 @@ public class RelMdPredicates {
 
       switch (joinType) {
       case INNER:
-        return RelOptPredicateList.of(
-            Iterables.concat(RelOptUtil.conjunctions(leftChildPredicates),
+        Iterable<RexNode> pulledUpPredicates;
+        if (isSemiJoin) {
+          pulledUpPredicates = Iterables.concat(
+                RelOptUtil.conjunctions(leftChildPredicates),
+                leftInferredPredicates);
+        } else {
+          pulledUpPredicates = Iterables.concat(
+                RelOptUtil.conjunctions(leftChildPredicates),
                 RelOptUtil.conjunctions(rightChildPredicates),
                 RelOptUtil.conjunctions(joinRel.getCondition()),
-                inferredPredicates),
-            leftInferredPredicates, rightInferredPredicates);
+                inferredPredicates);
+        }
+        return RelOptPredicateList.of(pulledUpPredicates,
+          leftInferredPredicates, rightInferredPredicates);
       case LEFT:
         return RelOptPredicateList.of(
             RelOptUtil.conjunctions(leftChildPredicates),

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c9d7233d/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
index ddb116f..5ade0c8 100644
--- a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
@@ -1074,7 +1074,7 @@ public class RelMetadataTest extends SqlToRelTestBase {
 
     predicates = RelMetadataQuery.getPulledUpPredicates(semiJoin);
     assertThat(predicates.pulledUpPredicates.toString(), is("[=($0, 1)]"));
-    assertThat(predicates.leftInferredPredicates.toString(), is("[=($0, 1)]"));
+    assertThat(predicates.leftInferredPredicates.toString(), is("[]"));
     assertThat(predicates.rightInferredPredicates.isEmpty(), is(true));
   }
 


[19/50] incubator-calcite git commit: [CALCITE-791] Optimize RelOptUtil.pushFilterPastProject

Posted by jh...@apache.org.
[CALCITE-791] Optimize RelOptUtil.pushFilterPastProject


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

Branch: refs/heads/branch-release
Commit: c9fe32b7d693cff7dc337335029fe94d3a4d5c53
Parents: 9177063
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Jul 20 23:45:41 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Jul 20 23:45:41 2015 -0700

----------------------------------------------------------------------
 .../org/apache/calcite/plan/RelOptUtil.java     | 57 +++++++-------------
 .../rel/metadata/RelMdDistinctRowCount.java     |  2 +-
 .../calcite/rel/metadata/RelMdSelectivity.java  |  2 +-
 .../rel/rules/FilterProjectTransposeRule.java   |  2 +-
 4 files changed, 23 insertions(+), 40 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c9fe32b7/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
index 7a79aeb..6892dfd 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -58,7 +58,6 @@ import org.apache.calcite.rex.RexMultisetUtil;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexOver;
 import org.apache.calcite.rex.RexProgram;
-import org.apache.calcite.rex.RexProgramBuilder;
 import org.apache.calcite.rex.RexShuttle;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.rex.RexVisitorImpl;
@@ -2365,45 +2364,29 @@ public abstract class RelOptUtil {
     return exps;
   }
 
+  @Deprecated // to be removed before 2.0
+  public static RexNode pushFilterPastProject(RexNode filter,
+      final Project projRel) {
+    return pushPastProject(filter, projRel);
+  }
+
   /**
-   * Converts a filter to the new filter that would result if the filter is
-   * pushed past a LogicalProject that it currently is referencing.
+   * Converts an expression that is based on the output fields of a
+   * {@link Project} to an equivalent expression on the Project's
+   * input fields.
    *
-   * @param filter  the filter to be converted
-   * @param projRel project rel underneath the filter
-   * @return converted filter
+   * @param node The expression to be converted
+   * @param project Project underneath the expression
+   * @return converted expression
    */
-  public static RexNode pushFilterPastProject(
-      RexNode filter,
-      Project projRel) {
-    // use RexPrograms to merge the filter and LogicalProject into a
-    // single program so we can convert the LogicalFilter condition to
-    // directly reference the LogicalProject's child
-    RexBuilder rexBuilder = projRel.getCluster().getRexBuilder();
-    RexProgram bottomProgram =
-        RexProgram.create(
-            projRel.getInput().getRowType(),
-            projRel.getProjects(),
-            null,
-            projRel.getRowType(),
-            rexBuilder);
-
-    RexProgramBuilder topProgramBuilder =
-        new RexProgramBuilder(
-            projRel.getRowType(),
-            rexBuilder);
-    topProgramBuilder.addIdentity();
-    topProgramBuilder.addCondition(filter);
-    RexProgram topProgram = topProgramBuilder.getProgram();
-
-    RexProgram mergedProgram =
-        RexProgramBuilder.mergePrograms(
-            topProgram,
-            bottomProgram,
-            rexBuilder);
-
-    return mergedProgram.expandLocalRef(
-        mergedProgram.getCondition());
+  public static RexNode pushPastProject(RexNode node,
+      final Project project) {
+    return node.accept(
+        new RexShuttle() {
+          @Override public RexNode visitInputRef(RexInputRef ref) {
+            return project.getProjects().get(ref.getIndex());
+          }
+        });
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c9fe32b7/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistinctRowCount.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistinctRowCount.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistinctRowCount.java
index de76201..784e131 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistinctRowCount.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistinctRowCount.java
@@ -236,7 +236,7 @@ public class RelMdDistinctRowCount {
     if (childPred == null) {
       modifiedPred = null;
     } else {
-      modifiedPred = RelOptUtil.pushFilterPastProject(childPred, rel);
+      modifiedPred = RelOptUtil.pushPastProject(childPred, rel);
     }
     Double distinctRowCount =
         RelMetadataQuery.getDistinctRowCount(

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c9fe32b7/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java
index 3bffe26..c59a005 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java
@@ -169,7 +169,7 @@ public class RelMdSelectivity {
     if (childPred == null) {
       modifiedPred = null;
     } else {
-      modifiedPred = RelOptUtil.pushFilterPastProject(childPred, rel);
+      modifiedPred = RelOptUtil.pushPastProject(childPred, rel);
     }
     Double selectivity =
         RelMetadataQuery.getSelectivity(

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c9fe32b7/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
index 802cf87..ff20f5a 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
@@ -88,7 +88,7 @@ public class FilterProjectTransposeRule extends RelOptRule {
 
     // convert the filter to one that references the child of the project
     RexNode newCondition =
-        RelOptUtil.pushFilterPastProject(filter.getCondition(), project);
+        RelOptUtil.pushPastProject(filter.getCondition(), project);
 
     // Remove cast of BOOLEAN NOT NULL to BOOLEAN or vice versa. Filter accepts
     // nullable and not-nullable conditions, but a CAST might get in the way of


[40/50] incubator-calcite git commit: [CALCITE-822] Add a unit test case to test collation of LogicalAggregate

Posted by jh...@apache.org.
[CALCITE-822] Add a unit test case to test collation of LogicalAggregate

Close apache/incubator-calcite#118


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

Branch: refs/heads/branch-release
Commit: e827bf0a2e410e5613dcf407778e4f5735e75c1c
Parents: ac934f6
Author: Jinfeng Ni <jn...@apache.org>
Authored: Fri Aug 7 09:28:22 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Aug 7 18:43:53 2015 -0700

----------------------------------------------------------------------
 core/src/test/resources/sql/agg.oq | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e827bf0a/core/src/test/resources/sql/agg.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/agg.oq b/core/src/test/resources/sql/agg.oq
index 771ff86..2fe0cc2 100644
--- a/core/src/test/resources/sql/agg.oq
+++ b/core/src/test/resources/sql/agg.oq
@@ -1092,6 +1092,34 @@ group by m.empno;
 
 !ok
 
+# Collation of LogicalAggregate ([CALCITE-783] and [CALCITE-822])
+select  sum(x) as sum_cnt,
+  count(distinct y) as cnt_dist
+from
+  (
+  select
+    count(*)                as x,
+          t1.job      as y,
+    t1.deptno as z
+  from
+    "scott".emp t1
+  group by t1.job, t1.deptno
+  order by t1.job, t1.deptno
+) sq(x,y,z)
+group by z
+order by sum_cnt;
+
++---------+----------+
+| SUM_CNT | CNT_DIST |
++---------+----------+
+|       3 |        3 |
+|       5 |        3 |
+|       6 |        3 |
++---------+----------+
+(3 rows)
+
+!ok
+
 # [CALCITE-729] IndexOutOfBoundsException in ROLLUP query on JDBC data source
 !use jdbc_scott
 select deptno, job, count(*) as c


[17/50] incubator-calcite git commit: Change the argument types of SqlOperator.getMonotonicity to allow it to be used for RexNode as well as SqlNode

Posted by jh...@apache.org.
Change the argument types of SqlOperator.getMonotonicity to allow it to be used for RexNode as well as SqlNode


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

Branch: refs/heads/branch-release
Commit: f7ec3e847eb3ba82c182a63327fd1da490df648b
Parents: ef5833f
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Jul 6 17:42:16 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Jul 20 20:58:24 2015 -0700

----------------------------------------------------------------------
 .../calcite/rel/metadata/RelMdCollation.java    | 13 +++-
 .../org/apache/calcite/rex/RexCallBinding.java  | 50 ++++++++++++++--
 .../java/org/apache/calcite/rex/RexLiteral.java |  4 ++
 .../org/apache/calcite/sql/SqlAsOperator.java   |  6 +-
 .../apache/calcite/sql/SqlBinaryOperator.java   | 20 +++----
 .../java/org/apache/calcite/sql/SqlCall.java    |  6 +-
 .../org/apache/calcite/sql/SqlCallBinding.java  | 54 +++++++++--------
 .../java/org/apache/calcite/sql/SqlLiteral.java | 61 +++++++++++++++++++
 .../org/apache/calcite/sql/SqlOperator.java     | 16 +++++
 .../apache/calcite/sql/SqlOperatorBinding.java  | 39 ++++++++++++
 .../apache/calcite/sql/SqlPrefixOperator.java   |  9 +--
 .../sql/fun/SqlAbstractTimeFunction.java        |  6 +-
 .../apache/calcite/sql/fun/SqlCastFunction.java | 13 ++--
 .../calcite/sql/fun/SqlCurrentDateFunction.java |  7 +--
 .../sql/fun/SqlDatetimeSubtractionOperator.java |  8 +--
 .../calcite/sql/fun/SqlExtractFunction.java     | 12 ++--
 .../calcite/sql/fun/SqlFloorFunction.java       |  8 +--
 .../sql/fun/SqlMonotonicBinaryOperator.java     | 63 ++++++++++----------
 .../sql/fun/SqlMonotonicUnaryFunction.java      |  9 +--
 .../sql/fun/SqlStringContextVariable.java       |  7 +--
 .../calcite/sql/fun/SqlSubstringFunction.java   | 24 +++-----
 21 files changed, 286 insertions(+), 149 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
index 614c111..52a7c43 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
@@ -35,10 +35,13 @@ import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.core.Values;
 import org.apache.calcite.rel.core.Window;
 import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexCall;
+import org.apache.calcite.rex.RexCallBinding;
 import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexProgram;
+import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.util.BuiltInMethod;
 import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.Pair;
@@ -177,7 +180,6 @@ public class RelMdCollation {
   /** Helper method to determine a {@link Project}'s collation. */
   public static List<RelCollation> project(RelNode input,
       List<? extends RexNode> projects) {
-    // TODO: also monotonic expressions
     final SortedSet<RelCollation> collations = Sets.newTreeSet();
     final List<RelCollation> inputCollations =
         RelMetadataQuery.collations(input);
@@ -188,6 +190,15 @@ public class RelMdCollation {
     for (Ord<RexNode> project : Ord.zip(projects)) {
       if (project.e instanceof RexInputRef) {
         targets.put(((RexInputRef) project.e).getIndex(), project.i);
+      } else if (project.e instanceof RexCall) {
+        final RexCall call = (RexCall) project.e;
+        final RexCallBinding binding =
+            RexCallBinding.create(input.getCluster().getTypeFactory(), call);
+        if (false) {
+          final SqlMonotonicity monotonicity =
+              call.getOperator().getMonotonicity(binding);
+          // TODO: do something with this monotonicity
+        }
       }
     }
     final List<RelFieldCollation> fieldCollations = Lists.newArrayList();

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java b/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java
index fc80c19..373b90f 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java
@@ -24,6 +24,7 @@ import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.SqlUtil;
 import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.sql.validate.SqlValidatorException;
 
 import com.google.common.collect.ImmutableList;
@@ -49,20 +50,37 @@ public class RexCallBinding extends SqlOperatorBinding {
     this.operands = ImmutableList.copyOf(operands);
   }
 
+  /** Creates a binding of the appropriate type. */
+  public static RexCallBinding create(RelDataTypeFactory typeFactory,
+      RexCall call) {
+    switch (call.getKind()) {
+    case CAST:
+      return new RexCastCallBinding(typeFactory, call.getOperator(),
+          call.getOperands(), call.getType());
+    }
+    return new RexCallBinding(typeFactory, call.getOperator(),
+        call.getOperands());
+  }
+
   //~ Methods ----------------------------------------------------------------
 
-  // implement SqlOperatorBinding
-  public String getStringLiteralOperand(int ordinal) {
+  @Override public String getStringLiteralOperand(int ordinal) {
     return RexLiteral.stringValue(operands.get(ordinal));
   }
 
-  // implement SqlOperatorBinding
-  public int getIntLiteralOperand(int ordinal) {
+  @Override public int getIntLiteralOperand(int ordinal) {
     return RexLiteral.intValue(operands.get(ordinal));
   }
 
-  // implement SqlOperatorBinding
-  public boolean isOperandNull(int ordinal, boolean allowCast) {
+  @Override public Comparable getOperandLiteralValue(int ordinal) {
+    return RexLiteral.value(operands.get(ordinal));
+  }
+
+  @Override public SqlMonotonicity getOperandMonotonicity(int ordinal) {
+    throw new AssertionError(); // to be completed
+  }
+
+  @Override public boolean isOperandNull(int ordinal, boolean allowCast) {
     return RexUtil.isNullLiteral(operands.get(ordinal), allowCast);
   }
 
@@ -80,6 +98,26 @@ public class RexCallBinding extends SqlOperatorBinding {
       Resources.ExInst<SqlValidatorException> e) {
     return SqlUtil.newContextException(SqlParserPos.ZERO, e);
   }
+
+  /** To be compatible with {@code SqlCall}, CAST needs to pretend that it
+   * has two arguments, the second of which is the target type. */
+  private static class RexCastCallBinding extends RexCallBinding {
+    private final RelDataType type;
+
+    public RexCastCallBinding(RelDataTypeFactory typeFactory,
+        SqlOperator sqlOperator, List<? extends RexNode> operands,
+        RelDataType type) {
+      super(typeFactory, sqlOperator, operands);
+      this.type = type;
+    }
+
+    @Override public RelDataType getOperandType(int ordinal) {
+      if (ordinal == 1) {
+        return type;
+      }
+      return super.getOperandType(ordinal);
+    }
+  }
 }
 
 // End RexCallBinding.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java b/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
index 767734d..0f8dceb 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
@@ -593,6 +593,10 @@ public class RexLiteral extends RexNode {
     return com.google.common.base.Objects.hashCode(value, type);
   }
 
+  public static Comparable value(RexNode node) {
+    return findValue(node);
+  }
+
   public static int intValue(RexNode node) {
     final Comparable value = findValue(node);
     return ((Number) value).intValue();

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/SqlAsOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlAsOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlAsOperator.java
index 1d260cc..6f4aaf3 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlAsOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlAsOperator.java
@@ -124,10 +124,8 @@ public class SqlAsOperator extends SqlSpecialOperator {
     return validateOperands(validator, scope, call);
   }
 
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
-    return call.getOperandList().get(0).getMonotonicity(scope);
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
+    return call.getOperandMonotonicity(0);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java
index bdcf961..c5f9f66 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java
@@ -180,20 +180,14 @@ public class SqlBinaryOperator extends SqlOperator {
     return type;
   }
 
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
     if (getName().equals("/")) {
-      final SqlNode operand0 = call.operand(0);
-      final SqlNode operand1 = call.operand(1);
-      final SqlMonotonicity mono0 = operand0.getMonotonicity(scope);
-      final SqlMonotonicity mono1 = operand1.getMonotonicity(scope);
+      final SqlMonotonicity mono0 = call.getOperandMonotonicity(0);
+      final SqlMonotonicity mono1 = call.getOperandMonotonicity(1);
       if (mono1 == SqlMonotonicity.CONSTANT) {
-        if (operand1 instanceof SqlLiteral) {
-          SqlLiteral literal = (SqlLiteral) operand1;
-          switch (
-              literal.bigDecimalValue().compareTo(
-                  BigDecimal.ZERO)) {
+        final Object o = call.getOperandLiteralValue(1);
+        if (o instanceof BigDecimal) {
+          switch (((BigDecimal) o).compareTo(BigDecimal.ZERO)) {
           case -1:
 
             // mono / -ve constant --> reverse mono, unstrict
@@ -211,7 +205,7 @@ public class SqlBinaryOperator extends SqlOperator {
       }
     }
 
-    return super.getMonotonicity(call, scope);
+    return super.getMonotonicity(call);
   }
 
   @Override public boolean validRexOperands(int count, boolean fail) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/SqlCall.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlCall.java b/core/src/main/java/org/apache/calcite/sql/SqlCall.java
index 7548e01..41e9eb3 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlCall.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlCall.java
@@ -156,7 +156,7 @@ public abstract class SqlCall extends SqlNode {
   protected String getCallSignature(
       SqlValidator validator,
       SqlValidatorScope scope) {
-    List<String> signatureList = new ArrayList<String>();
+    List<String> signatureList = new ArrayList<>();
     for (final SqlNode operand : getOperandList()) {
       final RelDataType argType = validator.deriveType(scope, operand);
       if (null == argType) {
@@ -169,7 +169,9 @@ public abstract class SqlCall extends SqlNode {
 
   public SqlMonotonicity getMonotonicity(SqlValidatorScope scope) {
     // Delegate to operator.
-    return getOperator().getMonotonicity(this, scope);
+    final SqlCallBinding binding =
+        new SqlCallBinding(scope.getValidator(), scope, this);
+    return getOperator().getMonotonicity(binding);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java b/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
index ceb7b49..aaa8c96 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
@@ -21,13 +21,16 @@ import org.apache.calcite.runtime.CalciteException;
 import org.apache.calcite.runtime.Resources;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.validate.SelectScope;
+import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.sql.validate.SqlValidatorException;
 import org.apache.calcite.sql.validate.SqlValidatorNamespace;
 import org.apache.calcite.sql.validate.SqlValidatorScope;
 import org.apache.calcite.sql.validate.SqlValidatorUtil;
+import org.apache.calcite.util.NlsString;
 import org.apache.calcite.util.Util;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 import static org.apache.calcite.util.Static.RESOURCE;
@@ -109,43 +112,45 @@ public class SqlCallBinding extends SqlOperatorBinding {
     return call;
   }
 
-  // implement SqlOperatorBinding
-  public String getStringLiteralOperand(int ordinal) {
+  public SqlMonotonicity getOperandMonotonicity(int ordinal) {
+    return call.getOperandList().get(ordinal).getMonotonicity(scope);
+  }
+
+  @Override public String getStringLiteralOperand(int ordinal) {
     SqlNode node = call.operand(ordinal);
-    return SqlLiteral.stringValue(node);
+    final Object o = SqlLiteral.value(node);
+    return o instanceof NlsString ? ((NlsString) o).getValue() : null;
   }
 
-  // implement SqlOperatorBinding
-  public int getIntLiteralOperand(int ordinal) {
-    // todo: move this to SqlTypeUtil
+  @Override public int getIntLiteralOperand(int ordinal) {
     SqlNode node = call.operand(ordinal);
-    if (node instanceof SqlLiteral) {
-      SqlLiteral sqlLiteral = (SqlLiteral) node;
-      return sqlLiteral.intValue(true);
-    } else if (node instanceof SqlCall) {
-      final SqlCall c = (SqlCall) node;
-      if (c.getKind() == SqlKind.MINUS_PREFIX) {
-        SqlNode child = c.operand(0);
-        if (child instanceof SqlLiteral) {
-          return -((SqlLiteral) child).intValue(true);
-        }
+    final Object o = SqlLiteral.value(node);
+    if (o instanceof BigDecimal) {
+      BigDecimal bd = (BigDecimal) o;
+      try {
+        return bd.intValueExact();
+      } catch (ArithmeticException e) {
+        throw SqlUtil.newContextException(node.pos,
+            RESOURCE.numberLiteralOutOfRange(bd.toString()));
       }
     }
     throw Util.newInternal("should never come here");
   }
 
-  // implement SqlOperatorBinding
-  public boolean isOperandNull(int ordinal, boolean allowCast) {
+  @Override public Comparable getOperandLiteralValue(int ordinal) {
+    SqlNode node = call.operand(ordinal);
+    return SqlLiteral.value(node);
+  }
+
+  @Override public boolean isOperandNull(int ordinal, boolean allowCast) {
     return SqlUtil.isNullLiteral(call.operand(ordinal), allowCast);
   }
 
-  // implement SqlOperatorBinding
-  public int getOperandCount() {
+  @Override public int getOperandCount() {
     return call.getOperandList().size();
   }
 
-  // implement SqlOperatorBinding
-  public RelDataType getOperandType(int ordinal) {
+  @Override public RelDataType getOperandType(int ordinal) {
     final SqlNode operand = call.operand(ordinal);
     final RelDataType type = validator.deriveType(scope, operand);
     final SqlValidatorNamespace namespace = validator.getNamespace(operand);
@@ -155,7 +160,7 @@ public class SqlCallBinding extends SqlOperatorBinding {
     return type;
   }
 
-  public RelDataType getCursorOperand(int ordinal) {
+  @Override public RelDataType getCursorOperand(int ordinal) {
     final SqlNode operand = call.operand(ordinal);
     if (!SqlUtil.isCallTo(operand, SqlStdOperatorTable.CURSOR)) {
       return null;
@@ -165,8 +170,7 @@ public class SqlCallBinding extends SqlOperatorBinding {
     return validator.deriveType(scope, query);
   }
 
-  // implement SqlOperatorBinding
-  public String getColumnListParamInfo(
+  @Override public String getColumnListParamInfo(
       int ordinal,
       String paramName,
       List<String> columnList) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java b/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
index 3990a8a..b7aa493 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
@@ -259,9 +259,68 @@ public class SqlLiteral extends SqlNode {
   }
 
   /**
+   * Extracts the value from a literal.
+   *
+   * <p>Cases:
+   * <ul>
+   * <li>If the node is a character literal, a chain of string
+   * literals, or a CAST of a character literal, returns the value as a
+   * {@link NlsString}.
+   *
+   * <li>If the node is a numeric literal, or a negated numeric literal,
+   * returns the value as a {@link BigDecimal}.
+   *
+   * <li>If the node is a {@link SqlIntervalQualifier},
+   * returns its {@link TimeUnitRange}.
+   *
+   * <li>Otherwise the behavior is not specified.
+   * </ul>
+   */
+  public static Comparable value(SqlNode node) {
+    if (node instanceof SqlLiteral) {
+      SqlLiteral literal = (SqlLiteral) node;
+      switch (literal.getTypeName().getFamily()) {
+      case CHARACTER:
+        return (NlsString) literal.value;
+      case NUMERIC:
+        return (BigDecimal) literal.value;
+      }
+    }
+    if (SqlUtil.isLiteralChain(node)) {
+      assert node instanceof SqlCall;
+      final SqlLiteral literal =
+          SqlLiteralChainOperator.concatenateOperands((SqlCall) node);
+      assert SqlTypeUtil.inCharFamily(literal.getTypeName());
+      return (NlsString) literal.value;
+    }
+    if (node instanceof SqlIntervalQualifier) {
+      SqlIntervalQualifier qualifier = (SqlIntervalQualifier) node;
+      return qualifier.timeUnitRange;
+    }
+    switch (node.getKind()) {
+    case CAST:
+      assert node instanceof SqlCall;
+      return value(((SqlCall) node).operand(0));
+    case MINUS_PREFIX:
+      assert node instanceof SqlCall;
+      Comparable o = value(((SqlCall) node).operand(0));
+      if (o instanceof BigDecimal) {
+        BigDecimal bigDecimal = (BigDecimal) o;
+        return bigDecimal.negate();
+      }
+      // fall through
+    default:
+      throw Util.newInternal("invalid literal: " + node);
+    }
+  }
+
+  /**
    * Extracts the string value from a string literal, a chain of string
    * literals, or a CAST of a string literal.
+   *
+   * @deprecated Use {@link #value(SqlNode)}
    */
+  @Deprecated // to be removed before 2.0
   public static String stringValue(SqlNode node) {
     if (node instanceof SqlLiteral) {
       SqlLiteral literal = (SqlLiteral) node;
@@ -466,6 +525,7 @@ public class SqlLiteral extends SqlNode {
    *
    * @return -1, 0 or 1
    */
+  @Deprecated // to be removed before 2.0
   public int signum() {
     return bigDecimalValue().compareTo(
         BigDecimal.ZERO);
@@ -484,6 +544,7 @@ public class SqlLiteral extends SqlNode {
     }
   }
 
+  @Deprecated // to be removed before 2.0
   public String getStringValue() {
     return ((NlsString) value).getValue();
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
index e8914b2..ee35b09 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
@@ -723,10 +723,26 @@ public abstract class SqlOperator {
    *
    * @param call  Call to this operator
    * @param scope Scope in which the call occurs
+   *
+   * @deprecated Use {@link #getMonotonicity(SqlOperatorBinding)}
    */
+  @Deprecated // to be removed before 2.0
   public SqlMonotonicity getMonotonicity(
       SqlCall call,
       SqlValidatorScope scope) {
+    return getMonotonicity(
+        new SqlCallBinding(scope.getValidator(), scope, call));
+  }
+
+  /**
+   * Returns whether a call to this operator is monotonic.
+   *
+   * <p>Default implementation returns {@link SqlMonotonicity#NOT_MONOTONIC}.
+   *
+   * @param call Call to this operator with particular arguments and information
+   *             about the monotonicity of the arguments
+   */
+  public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
     return SqlMonotonicity.NOT_MONOTONIC;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/SqlOperatorBinding.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlOperatorBinding.java b/core/src/main/java/org/apache/calcite/sql/SqlOperatorBinding.java
index 3e3b6f6..2ca13f9 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlOperatorBinding.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlOperatorBinding.java
@@ -20,6 +20,7 @@ import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.runtime.CalciteException;
 import org.apache.calcite.runtime.Resources;
+import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.sql.validate.SqlValidatorException;
 
 import java.util.AbstractList;
@@ -94,6 +95,7 @@ public abstract class SqlOperatorBinding {
    * @param ordinal zero-based ordinal of operand of interest
    * @return string value
    */
+  @Deprecated // to be removed before 2.0
   public String getStringLiteralOperand(int ordinal) {
     throw new UnsupportedOperationException();
   }
@@ -104,11 +106,38 @@ public abstract class SqlOperatorBinding {
    * @param ordinal zero-based ordinal of operand of interest
    * @return integer value
    */
+  @Deprecated // to be removed before 2.0
   public int getIntLiteralOperand(int ordinal) {
     throw new UnsupportedOperationException();
   }
 
   /**
+   * Gets the value of a literal operand.
+   *
+   * <p>Cases:
+   * <ul>
+   * <li>If the operand is not a literal, the value is null.
+   *
+   * <li>If the operand is a string literal,
+   * the value will be of type {@link org.apache.calcite.util.NlsString}.
+   *
+   * <li>If the operand is a numeric literal,
+   * the value will be of type {@link java.math.BigDecimal}.
+   *
+   * <li>If the operand is an interval qualifier,
+   * the value will be of type {@link SqlIntervalQualifier}</li>
+   *
+   * <li>Otherwise the type is undefined, and the value may be null.
+   * </ul>
+   *
+   * @param ordinal zero-based ordinal of operand of interest
+   * @return value of operand
+   */
+  public Comparable getOperandLiteralValue(int ordinal) {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
    * Determines whether a bound operand is NULL.
    *
    * <p>This is only relevant for SQL validation.
@@ -136,6 +165,16 @@ public abstract class SqlOperatorBinding {
   public abstract RelDataType getOperandType(int ordinal);
 
   /**
+   * Gets the monotonicity of a bound operand.
+   *
+   * @param ordinal zero-based ordinal of operand of interest
+   * @return monotonicity of operand
+   */
+  public SqlMonotonicity getOperandMonotonicity(int ordinal) {
+    return SqlMonotonicity.NOT_MONOTONIC;
+  }
+
+  /**
    * Collects the types of the bound operands into a list.
    *
    * @return collected list

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java
index b99abf2..8923645 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java
@@ -23,7 +23,6 @@ import org.apache.calcite.sql.type.SqlReturnTypeInference;
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.sql.validate.SqlValidator;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
 import org.apache.calcite.util.Util;
 
 /**
@@ -90,14 +89,12 @@ public class SqlPrefixOperator extends SqlOperator {
     return type;
   }
 
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
     if (getName().equals("-")) {
-      return scope.getMonotonicity(call.operand(0)).reverse();
+      return call.getOperandMonotonicity(0).reverse();
     }
 
-    return super.getMonotonicity(call, scope);
+    return super.getMonotonicity(call);
   }
 
   @Override public boolean validRexOperands(int count, boolean fail) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlAbstractTimeFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlAbstractTimeFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlAbstractTimeFunction.java
index 6469927..82c660e 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlAbstractTimeFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlAbstractTimeFunction.java
@@ -17,7 +17,6 @@
 package org.apache.calcite.sql.fun;
 
 import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlKind;
@@ -28,7 +27,6 @@ import org.apache.calcite.sql.type.SqlOperandTypeChecker;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
 
 import static org.apache.calcite.util.Static.RESOURCE;
 
@@ -81,9 +79,7 @@ public class SqlAbstractTimeFunction extends SqlFunction {
   }
 
   // All of the time functions are increasing. Not strictly increasing.
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
     return SqlMonotonicity.INCREASING;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
index 08bd3b3..f4e933a 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
@@ -37,7 +37,6 @@ import org.apache.calcite.sql.type.SqlOperandCountRanges;
 import org.apache.calcite.sql.type.SqlTypeFamily;
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
 
 import com.google.common.collect.ImmutableSet;
 
@@ -199,15 +198,11 @@ public class SqlCastFunction extends SqlFunction {
     writer.endFunCall(frame);
   }
 
-  @Override public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
-    RelDataTypeFamily castFrom =
-        scope.getValidator().deriveType(scope, call.operand(0)).getFamily();
-    RelDataTypeFamily castTo =
-        scope.getValidator().deriveType(scope, call.operand(1)).getFamily();
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
+    RelDataTypeFamily castFrom = call.getOperandType(0).getFamily();
+    RelDataTypeFamily castTo = call.getOperandType(1).getFamily();
     if (isMonotonicPreservingCast(castFrom, castTo)) {
-      return call.operand(0).getMonotonicity(scope);
+      return call.getOperandMonotonicity(0);
     } else {
       return SqlMonotonicity.NOT_MONOTONIC;
     }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlCurrentDateFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlCurrentDateFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlCurrentDateFunction.java
index cdab873..ceb9b78 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlCurrentDateFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlCurrentDateFunction.java
@@ -16,15 +16,14 @@
  */
 package org.apache.calcite.sql.fun;
 
-import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.SqlSyntax;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
 
 /**
  * The <code>CURRENT_DATE</code> function.
@@ -48,9 +47,7 @@ public class SqlCurrentDateFunction extends SqlFunction {
     return SqlSyntax.FUNCTION_ID;
   }
 
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
     return SqlMonotonicity.INCREASING;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlDatetimeSubtractionOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlDatetimeSubtractionOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlDatetimeSubtractionOperator.java
index 9ff4ee1..f79c366 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlDatetimeSubtractionOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlDatetimeSubtractionOperator.java
@@ -18,6 +18,7 @@ package org.apache.calcite.sql.fun;
 
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.SqlSpecialOperator;
 import org.apache.calcite.sql.SqlSyntax;
 import org.apache.calcite.sql.SqlWriter;
@@ -25,7 +26,6 @@ import org.apache.calcite.sql.type.InferTypes;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
 
 /**
  * A special operator for the subtraction of two DATETIMEs. The format of
@@ -70,10 +70,8 @@ public class SqlDatetimeSubtractionOperator extends SqlSpecialOperator {
     call.operand(2).unparse(writer, leftPrec, rightPrec);
   }
 
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
-    return SqlStdOperatorTable.MINUS.getMonotonicity(call, scope);
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
+    return SqlStdOperatorTable.MINUS.getMonotonicity(call);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlExtractFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlExtractFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlExtractFunction.java
index 86c6893..fd3bad6 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlExtractFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlExtractFunction.java
@@ -16,16 +16,16 @@
  */
 package org.apache.calcite.sql.fun;
 
+import org.apache.calcite.avatica.util.TimeUnitRange;
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
-import org.apache.calcite.sql.SqlIntervalQualifier;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
 import org.apache.calcite.util.Util;
 
 /**
@@ -68,12 +68,10 @@ public class SqlExtractFunction extends SqlFunction {
     writer.endFunCall(frame);
   }
 
-  @Override public SqlMonotonicity getMonotonicity(SqlCall call,
-      SqlValidatorScope scope) {
-    final SqlIntervalQualifier o = call.operand(0);
-    switch (o.timeUnitRange) {
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
+    switch ((TimeUnitRange) call.getOperandLiteralValue(0)) {
     case YEAR:
-      return scope.getMonotonicity(call.operand(1)).unstrict();
+      return call.getOperandMonotonicity(1).unstrict();
     default:
       return SqlMonotonicity.NOT_MONOTONIC;
     }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlFloorFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlFloorFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlFloorFunction.java
index e9d147f..c5986a0 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlFloorFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlFloorFunction.java
@@ -19,11 +19,11 @@ package org.apache.calcite.sql.fun;
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
 
 import com.google.common.base.Preconditions;
 
@@ -48,11 +48,9 @@ public class SqlFloorFunction extends SqlMonotonicUnaryFunction {
 
   //~ Methods ----------------------------------------------------------------
 
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
     // Monotonic iff its first argument is, but not strict.
-    return scope.getMonotonicity(call.operand(0)).unstrict();
+    return call.getOperandMonotonicity(0).unstrict();
   }
 
   @Override public void unparse(SqlWriter writer, SqlCall call, int leftPrec,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicBinaryOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicBinaryOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicBinaryOperator.java
index 42599a1..dc35783 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicBinaryOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicBinaryOperator.java
@@ -17,14 +17,15 @@
 package org.apache.calcite.sql.fun;
 
 import org.apache.calcite.sql.SqlBinaryOperator;
-import org.apache.calcite.sql.SqlCall;
+import org.apache.calcite.sql.SqlIntervalLiteral;
 import org.apache.calcite.sql.SqlKind;
-import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.type.SqlOperandTypeChecker;
 import org.apache.calcite.sql.type.SqlOperandTypeInference;
 import org.apache.calcite.sql.type.SqlReturnTypeInference;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
+
+import java.math.BigDecimal;
 
 /**
  * Base class for binary operators such as addition, subtraction, and
@@ -54,11 +55,9 @@ public class SqlMonotonicBinaryOperator extends SqlBinaryOperator {
 
   //~ Methods ----------------------------------------------------------------
 
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
-    final SqlMonotonicity mono0 = scope.getMonotonicity(call.operand(0));
-    final SqlMonotonicity mono1 = scope.getMonotonicity(call.operand(1));
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
+    final SqlMonotonicity mono0 = call.getOperandMonotonicity(0);
+    final SqlMonotonicity mono1 = call.getOperandMonotonicity(1);
 
     // constant <op> constant --> constant
     if ((mono1 == SqlMonotonicity.CONSTANT)
@@ -75,24 +74,19 @@ public class SqlMonotonicBinaryOperator extends SqlBinaryOperator {
         return mono0;
       }
       assert getName().equals("*");
-      if (call.operand(1) instanceof SqlLiteral) {
-        SqlLiteral literal = call.operand(1);
-        switch (literal.signum()) {
-        case -1:
-
-          // mono0 * negative constant --> reverse mono0
-          return mono0.reverse();
-        case 0:
+      switch (signum(call.getOperandLiteralValue(1))) {
+      case -1:
+        // mono0 * negative constant --> reverse mono0
+        return mono0.reverse();
 
-          // mono0 * 0 --> constant (zero)
-          return SqlMonotonicity.CONSTANT;
-        default:
+      case 0:
+        // mono0 * 0 --> constant (zero)
+        return SqlMonotonicity.CONSTANT;
 
-          // mono0 * positiove constant --> mono0
-          return mono0;
-        }
+      default:
+        // mono0 * positive constant --> mono0
+        return mono0;
       }
-      return mono0;
     }
 
     // constant <op> mono
@@ -106,19 +100,18 @@ public class SqlMonotonicBinaryOperator extends SqlBinaryOperator {
         return mono1;
       }
       assert getName().equals("*");
-      if (call.operand(0) instanceof SqlLiteral) {
-        SqlLiteral literal = call.operand(0);
-        switch (literal.signum()) {
+      final Object v0 = call.getOperandLiteralValue(0);
+      if (v0 != null) {
+        switch (signum(v0)) {
         case -1:
-
           // negative constant * mono1 --> reverse mono1
           return mono1.reverse();
-        case 0:
 
+        case 0:
           // 0 * mono1 --> constant (zero)
           return SqlMonotonicity.CONSTANT;
-        default:
 
+        default:
           // positive constant * mono1 --> mono1
           return mono1;
         }
@@ -156,7 +149,17 @@ public class SqlMonotonicBinaryOperator extends SqlBinaryOperator {
       return SqlMonotonicity.NOT_MONOTONIC;
     }
 
-    return super.getMonotonicity(call, scope);
+    return super.getMonotonicity(call);
+  }
+
+  private int signum(Object o) {
+    if (o instanceof BigDecimal) {
+      return ((BigDecimal) o).signum();
+    } else if (o instanceof SqlIntervalLiteral.IntervalValue) {
+      return ((SqlIntervalLiteral.IntervalValue) o).getSign();
+    } else {
+      return 1;
+    }
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicUnaryFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicUnaryFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicUnaryFunction.java
index d347fbc..2a194ba 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicUnaryFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicUnaryFunction.java
@@ -16,15 +16,14 @@
  */
 package org.apache.calcite.sql.fun;
 
-import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.type.SqlOperandTypeChecker;
 import org.apache.calcite.sql.type.SqlOperandTypeInference;
 import org.apache.calcite.sql.type.SqlReturnTypeInference;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
 
 /**
  * Base class for unary operators such as FLOOR/CEIL which are monotonic for
@@ -51,10 +50,8 @@ public class SqlMonotonicUnaryFunction extends SqlFunction {
 
   //~ Methods ----------------------------------------------------------------
 
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
-    return scope.getMonotonicity(call.operand(0)).unstrict();
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
+    return call.getOperandMonotonicity(0).unstrict();
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlStringContextVariable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlStringContextVariable.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlStringContextVariable.java
index db7057e..caedd64 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStringContextVariable.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStringContextVariable.java
@@ -16,15 +16,14 @@
  */
 package org.apache.calcite.sql.fun;
 
-import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.SqlSyntax;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
 
 /**
  * Base class for functions such as "USER", "CURRENT_ROLE", and "CURRENT_PATH".
@@ -49,9 +48,7 @@ public class SqlStringContextVariable extends SqlFunction {
   }
 
   // All of the string constants are monotonic.
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
     return SqlMonotonicity.CONSTANT;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java
index 5cac08f..73eda82 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java
@@ -23,9 +23,9 @@ import org.apache.calcite.sql.SqlCallBinding;
 import org.apache.calcite.sql.SqlFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlKind;
-import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOperandCountRange;
+import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.SqlUtil;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.type.OperandTypes;
@@ -190,25 +190,19 @@ public class SqlSubstringFunction extends SqlFunction {
     writer.endFunCall(frame);
   }
 
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
     // SUBSTRING(x FROM 0 FOR constant) has same monotonicity as x
-    final List<SqlNode> operands = call.getOperandList();
-    if (operands.size() == 3) {
-      final SqlNode op0 = operands.get(0);
-      final SqlNode op1 = operands.get(1);
-      final SqlNode op2 = operands.get(2);
-      final SqlMonotonicity mono0 = op0.getMonotonicity(scope);
+    if (call.getOperandCount() == 3) {
+      final SqlMonotonicity mono0 = call.getOperandMonotonicity(0);
       if ((mono0 != SqlMonotonicity.NOT_MONOTONIC)
-          && op1.getMonotonicity(scope) == SqlMonotonicity.CONSTANT
-          && op1 instanceof SqlLiteral
-          && ((SqlLiteral) op1).bigDecimalValue().equals(BigDecimal.ZERO)
-          && op2.getMonotonicity(scope) == SqlMonotonicity.CONSTANT) {
+          && call.getOperandMonotonicity(1) == SqlMonotonicity.CONSTANT
+          && call.getOperandLiteralValue(1) instanceof BigDecimal
+          && call.getOperandLiteralValue(1).equals(BigDecimal.ZERO)
+          && call.getOperandMonotonicity(2) == SqlMonotonicity.CONSTANT) {
         return mono0.unstrict();
       }
     }
-    return super.getMonotonicity(call, scope);
+    return super.getMonotonicity(call);
   }
 }
 



[27/50] incubator-calcite git commit: [CALCITE-751] Push aggregate with aggregate functions through join

Posted by jh...@apache.org.
[CALCITE-751] Push aggregate with aggregate functions through join

In this iteration, it is not safe to use the extended rule (that can handle
aggregate functions) in the Volcano planner, only in the Hep planner. The
extended rule requires metadata that can handle cyclic relational expressions
(to be fixed in [CALCITE-794]).


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

Branch: refs/heads/branch-release
Commit: cf7a7a97368d6e72b2a413f9f8857f54c2970e61
Parents: 41541d4
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Jun 4 17:22:28 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jul 23 12:46:58 2015 -0700

----------------------------------------------------------------------
 .../calcite/plan/SubstitutionVisitor.java       |  11 +-
 .../apache/calcite/rel/core/AggregateCall.java  |   5 +-
 .../rel/metadata/RelMdColumnUniqueness.java     |  66 ++++
 .../rel/rules/AggregateJoinTransposeRule.java   | 295 +++++++++++++++--
 .../rel/rules/AggregateReduceFunctionsRule.java |   8 +-
 .../java/org/apache/calcite/rex/RexBuilder.java |  28 +-
 .../org/apache/calcite/sql/SqlAggFunction.java  |   7 +-
 .../calcite/sql/SqlSplittableAggFunction.java   | 267 +++++++++++++++
 .../calcite/sql/fun/SqlCountAggFunction.java    |   8 +
 .../calcite/sql/fun/SqlMinMaxAggFunction.java   |   7 +
 .../calcite/sql/fun/SqlSumAggFunction.java      |   9 +
 .../sql/fun/SqlSumEmptyIsZeroAggFunction.java   |   8 +
 .../apache/calcite/test/RelOptRulesTest.java    | 111 +++++--
 .../org/apache/calcite/test/RelOptRulesTest.xml | 120 ++++++-
 core/src/test/resources/sql/agg.oq              | 323 ++++++++++++++++++-
 core/src/test/resources/sql/join.oq             |  11 +-
 .../apache/calcite/adapter/tpcds/TpcdsTest.java | 103 ++++++
 17 files changed, 1276 insertions(+), 111 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cf7a7a97/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
index 14e836a..28d7b32 100644
--- a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
+++ b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
@@ -69,7 +69,6 @@ import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
 import com.google.common.collect.LinkedHashMultimap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
@@ -1070,16 +1069,10 @@ public class SubstitutionVisitor {
   }
 
   public static MutableAggregate permute(MutableAggregate aggregate,
-      MutableRel input, final Mapping mapping) {
+      MutableRel input, Mapping mapping) {
     ImmutableBitSet groupSet = Mappings.apply(mapping, aggregate.getGroupSet());
     ImmutableList<ImmutableBitSet> groupSets =
-        ImmutableList.copyOf(
-            Iterables.transform(aggregate.getGroupSets(),
-                new Function<ImmutableBitSet, ImmutableBitSet>() {
-                  public ImmutableBitSet apply(ImmutableBitSet input1) {
-                    return Mappings.apply(mapping, input1);
-                  }
-                }));
+        Mappings.apply2(mapping, aggregate.getGroupSets());
     List<AggregateCall> aggregateCalls =
         apply(mapping, aggregate.getAggCallList());
     return MutableAggregate.of(input, aggregate.indicator, groupSet, groupSets,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cf7a7a97/core/src/main/java/org/apache/calcite/rel/core/AggregateCall.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/AggregateCall.java b/core/src/main/java/org/apache/calcite/rel/core/AggregateCall.java
index 2b56522..d35f7e1 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/AggregateCall.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/AggregateCall.java
@@ -21,6 +21,7 @@ import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.type.SqlTypeUtil;
+import org.apache.calcite.util.mapping.Mapping;
 import org.apache.calcite.util.mapping.Mappings;
 
 import com.google.common.base.Objects;
@@ -286,8 +287,8 @@ public class AggregateCall {
   /** Creates a copy of this aggregate call, applying a mapping to its
    * arguments. */
   public AggregateCall transform(Mappings.TargetMapping mapping) {
-    return copy(Mappings.permute(argList, mapping),
-        Mappings.apply(mapping, filterArg));
+    return copy(Mappings.apply2((Mapping) mapping, argList),
+        filterArg < 0 ? -1 : Mappings.apply(mapping, filterArg));
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cf7a7a97/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
index 527ab3f..9e0e0bd 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
@@ -16,6 +16,8 @@
  */
 package org.apache.calcite.rel.metadata;
 
+import org.apache.calcite.plan.hep.HepRelVertex;
+import org.apache.calcite.plan.volcano.RelSubset;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.core.Correlate;
@@ -35,6 +37,8 @@ import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.util.BuiltInMethod;
 import org.apache.calcite.util.ImmutableBitSet;
 
+import com.google.common.base.Predicate;
+
 import java.util.List;
 
 /**
@@ -258,6 +262,68 @@ public class RelMdColumnUniqueness {
     // no information available
     return null;
   }
+
+  public Boolean areColumnsUnique(
+      boolean dummy, // prevent method from being used
+      HepRelVertex rel,
+      ImmutableBitSet columns,
+      boolean ignoreNulls) {
+    return RelMetadataQuery.areColumnsUnique(
+        rel.getCurrentRel(),
+        columns,
+        ignoreNulls);
+  }
+
+  public Boolean areColumnsUnique(
+      boolean dummy, // prevent method from being used
+      RelSubset rel,
+      ImmutableBitSet columns,
+      boolean ignoreNulls) {
+    int nullCount = 0;
+    for (RelNode rel2 : rel.getRels()) {
+      if (rel2 instanceof Aggregate || simplyProjects(rel2, columns)) {
+        final Boolean unique =
+            RelMetadataQuery.areColumnsUnique(rel2, columns, ignoreNulls);
+        if (unique != null) {
+          if (unique) {
+            return true;
+          }
+        } else {
+          ++nullCount;
+        }
+      }
+    }
+    return nullCount == 0 ? false : null;
+  }
+
+  private boolean simplyProjects(RelNode rel, ImmutableBitSet columns) {
+    if (!(rel instanceof Project)) {
+      return false;
+    }
+    Project project = (Project) rel;
+    final List<RexNode> projects = project.getProjects();
+    for (int column : columns) {
+      if (column >= projects.size()) {
+        return false;
+      }
+      if (!(projects.get(column) instanceof RexInputRef)) {
+        return false;
+      }
+      final RexInputRef ref = (RexInputRef) projects.get(column);
+      if (ref.getIndex() != column) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /** Aggregate and Calc are "safe" children of a RelSubset to delve into. */
+  private static final Predicate<RelNode> SAFE_REL =
+      new Predicate<RelNode>() {
+        public boolean apply(RelNode r) {
+          return r instanceof Aggregate || r instanceof Project;
+        }
+      };
 }
 
 // End RelMdColumnUniqueness.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cf7a7a97/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java
index 3d310a5..673d579 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java
@@ -16,25 +16,42 @@
  */
 package org.apache.calcite.rel.rules;
 
+import org.apache.calcite.linq4j.Ord;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Aggregate;
+import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.logical.LogicalAggregate;
 import org.apache.calcite.rel.logical.LogicalJoin;
+import org.apache.calcite.rel.metadata.RelMetadataQuery;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexCall;
+import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.sql.SqlAggFunction;
+import org.apache.calcite.sql.SqlSplittableAggFunction;
 import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.mapping.Mapping;
 import org.apache.calcite.util.mapping.Mappings;
 
 import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
 
 /**
  * Planner rule that pushes an
@@ -48,29 +65,56 @@ public class AggregateJoinTransposeRule extends RelOptRule {
           LogicalJoin.class,
           RelFactories.DEFAULT_JOIN_FACTORY);
 
+  /** Extended instance of the rule that can push down aggregate functions. */
+  public static final AggregateJoinTransposeRule EXTENDED =
+      new AggregateJoinTransposeRule(LogicalAggregate.class,
+          RelFactories.DEFAULT_AGGREGATE_FACTORY,
+          LogicalJoin.class,
+          RelFactories.DEFAULT_JOIN_FACTORY, true);
+
   private final RelFactories.AggregateFactory aggregateFactory;
 
   private final RelFactories.JoinFactory joinFactory;
 
+  private final boolean allowFunctions;
+
   /** Creates an AggregateJoinTransposeRule. */
   public AggregateJoinTransposeRule(Class<? extends Aggregate> aggregateClass,
       RelFactories.AggregateFactory aggregateFactory,
       Class<? extends Join> joinClass,
       RelFactories.JoinFactory joinFactory) {
+    this(aggregateClass, aggregateFactory, joinClass, joinFactory, false);
+  }
+
+  /** Creates an AggregateJoinTransposeRule that may push down functions. */
+  public AggregateJoinTransposeRule(Class<? extends Aggregate> aggregateClass,
+      RelFactories.AggregateFactory aggregateFactory,
+      Class<? extends Join> joinClass,
+      RelFactories.JoinFactory joinFactory,
+      boolean allowFunctions) {
     super(
         operand(aggregateClass, null, Aggregate.IS_SIMPLE,
             operand(joinClass, any())));
     this.aggregateFactory = aggregateFactory;
     this.joinFactory = joinFactory;
+    this.allowFunctions = allowFunctions;
   }
 
   public void onMatch(RelOptRuleCall call) {
-    Aggregate aggregate = call.rel(0);
-    Join join = call.rel(1);
+    final Aggregate aggregate = call.rel(0);
+    final Join join = call.rel(1);
+    final RexBuilder rexBuilder = aggregate.getCluster().getRexBuilder();
 
-    // If aggregate functions are present, we bail out
-    if (!aggregate.getAggCallList().isEmpty()) {
-      return;
+    // If any aggregate functions do not support splitting, bail out
+    // If any aggregate call has a filter, bail out
+    for (AggregateCall aggregateCall : aggregate.getAggCallList()) {
+      if (aggregateCall.getAggregation().unwrap(SqlSplittableAggFunction.class)
+          == null) {
+        return;
+      }
+      if (aggregateCall.filterArg >= 0) {
+        return;
+      }
     }
 
     // If it is not an inner join, we do not push the
@@ -79,14 +123,20 @@ public class AggregateJoinTransposeRule extends RelOptRule {
       return;
     }
 
+    if (!allowFunctions && !aggregate.getAggCallList().isEmpty()) {
+      return;
+    }
+
     // Do the columns used by the join appear in the output of the aggregate?
     final ImmutableBitSet aggregateColumns = aggregate.getGroupSet();
+    final ImmutableBitSet keyColumns = keyColumns(aggregateColumns,
+        RelMetadataQuery.getPulledUpPredicates(join).pulledUpPredicates);
     final ImmutableBitSet joinColumns =
         RelOptUtil.InputFinder.bits(join.getCondition());
-    boolean allColumnsInAggregate = aggregateColumns.contains(joinColumns);
-    if (!allColumnsInAggregate) {
-      return;
-    }
+    final boolean allColumnsInAggregate =
+        keyColumns.contains(joinColumns);
+    final ImmutableBitSet belowAggregateColumns =
+        aggregateColumns.union(joinColumns);
 
     // Split join condition
     final List<Integer> leftKeys = Lists.newArrayList();
@@ -99,32 +149,233 @@ public class AggregateJoinTransposeRule extends RelOptRule {
       return;
     }
 
-    // Create new aggregate operators below join
-    final ImmutableBitSet leftKeysBitSet = ImmutableBitSet.of(leftKeys);
-    RelNode newLeftInput = aggregateFactory.createAggregate(join.getLeft(),
-        false, leftKeysBitSet, null, aggregate.getAggCallList());
-    final ImmutableBitSet rightKeysBitSet = ImmutableBitSet.of(rightKeys);
-    RelNode newRightInput = aggregateFactory.createAggregate(join.getRight(),
-        false, rightKeysBitSet, null, aggregate.getAggCallList());
+    // Push each aggregate function down to each side that contains all of its
+    // arguments. Note that COUNT(*), because it has no arguments, can go to
+    // both sides.
+    final Map<Integer, Integer> map = new HashMap<>();
+    final List<Side> sides = new ArrayList<>();
+    int uniqueCount = 0;
+    int offset = 0;
+    int belowOffset = 0;
+    for (int s = 0; s < 2; s++) {
+      final Side side = new Side();
+      final RelNode joinInput = join.getInput(s);
+      int fieldCount = joinInput.getRowType().getFieldCount();
+      final ImmutableBitSet fieldSet =
+          ImmutableBitSet.range(offset, offset + fieldCount);
+      final ImmutableBitSet belowAggregateKeyNotShifted =
+          belowAggregateColumns.intersect(fieldSet);
+      for (Ord<Integer> c : Ord.zip(belowAggregateKeyNotShifted)) {
+        map.put(c.e, belowOffset + c.i);
+      }
+      final ImmutableBitSet belowAggregateKey =
+          belowAggregateKeyNotShifted.shift(-offset);
+      final boolean unique;
+      if (!allowFunctions) {
+        assert aggregate.getAggCallList().isEmpty();
+        // If there are no functions, it doesn't matter as much whether we
+        // aggregate the inputs before the join, because there will not be
+        // any functions experiencing a cartesian product effect.
+        //
+        // But finding out whether the input is already unique requires a call
+        // to areColumnsUnique that currently (until [CALCITE-794] "Detect
+        // cycles when computing statistics" is fixed) places a heavy load on
+        // the metadata system.
+        //
+        // So we choose to imagine the the input is already unique, which is
+        // untrue but harmless.
+        //
+        unique = true;
+      } else {
+        final Boolean unique0 =
+            RelMetadataQuery.areColumnsUnique(joinInput, belowAggregateKey);
+        unique = unique0 != null && unique0;
+      }
+      if (unique) {
+        ++uniqueCount;
+        side.aggregate = false;
+        side.newInput = joinInput;
+      } else {
+        side.aggregate = true;
+        List<AggregateCall> belowAggCalls = new ArrayList<>();
+        final SqlSplittableAggFunction.Registry<AggregateCall>
+            belowAggCallRegistry = registry(belowAggCalls);
+        final Mappings.TargetMapping mapping =
+            s == 0
+                ? Mappings.createIdentity(fieldCount)
+                : Mappings.createShiftMapping(fieldCount + offset, 0, offset,
+                    fieldCount);
+        for (Ord<AggregateCall> aggCall : Ord.zip(aggregate.getAggCallList())) {
+          final SqlAggFunction aggregation = aggCall.e.getAggregation();
+          final SqlSplittableAggFunction splitter =
+              Preconditions.checkNotNull(
+                  aggregation.unwrap(SqlSplittableAggFunction.class));
+          final AggregateCall call1;
+          if (fieldSet.contains(ImmutableBitSet.of(aggCall.e.getArgList()))) {
+            call1 = splitter.split(aggCall.e, mapping);
+          } else {
+            call1 = splitter.other(rexBuilder.getTypeFactory(), aggCall.e);
+          }
+          if (call1 != null) {
+            side.split.put(aggCall.i,
+                belowAggregateKey.cardinality()
+                    + belowAggCallRegistry.register(call1));
+          }
+        }
+        side.newInput = aggregateFactory.createAggregate(joinInput, false,
+            belowAggregateKey, null, belowAggCalls);
+      }
+      offset += fieldCount;
+      belowOffset += side.newInput.getRowType().getFieldCount();
+      sides.add(side);
+    }
+
+    if (uniqueCount == 2) {
+      // Both inputs to the join are unique. There is nothing to be gained by
+      // this rule. In fact, this aggregate+join may be the result of a previous
+      // invocation of this rule; if we continue we might loop forever.
+      return;
+    }
 
     // Update condition
-    final Mappings.TargetMapping mapping = Mappings.target(
+    final Mapping mapping = (Mapping) Mappings.target(
         new Function<Integer, Integer>() {
           public Integer apply(Integer a0) {
-            return aggregateColumns.indexOf(a0);
+            return map.get(a0);
           }
         },
         join.getRowType().getFieldCount(),
-        aggregateColumns.cardinality());
+        belowOffset);
     final RexNode newCondition =
         RexUtil.apply(mapping, join.getCondition());
 
     // Create new join
-    RelNode newJoin = joinFactory.createJoin(newLeftInput, newRightInput,
-        newCondition, join.getJoinType(),
+    RelNode newJoin = joinFactory.createJoin(sides.get(0).newInput,
+        sides.get(1).newInput, newCondition, join.getJoinType(),
         join.getVariablesStopped(), join.isSemiJoinDone());
 
-    call.transformTo(newJoin);
+    // Aggregate above to sum up the sub-totals
+    final List<AggregateCall> newAggCalls = new ArrayList<>();
+    final int groupIndicatorCount =
+        aggregate.getGroupCount() + aggregate.getIndicatorCount();
+    final int newLeftWidth = sides.get(0).newInput.getRowType().getFieldCount();
+    final List<RexNode> projects =
+        new ArrayList<>(rexBuilder.identityProjects(newJoin.getRowType()));
+    for (Ord<AggregateCall> aggCall : Ord.zip(aggregate.getAggCallList())) {
+      final SqlAggFunction aggregation = aggCall.e.getAggregation();
+      final SqlSplittableAggFunction splitter =
+          Preconditions.checkNotNull(
+              aggregation.unwrap(SqlSplittableAggFunction.class));
+      final Integer leftSubTotal = sides.get(0).split.get(aggCall.i);
+      final Integer rightSubTotal = sides.get(1).split.get(aggCall.i);
+      newAggCalls.add(
+          splitter.topSplit(rexBuilder, registry(projects),
+              groupIndicatorCount, newJoin.getRowType(), aggCall.e,
+              leftSubTotal == null ? -1 : leftSubTotal,
+              rightSubTotal == null ? -1 : rightSubTotal + newLeftWidth));
+    }
+    RelNode r = newJoin;
+  b:
+    if (allColumnsInAggregate && newAggCalls.isEmpty()) {
+      // no need to aggregate
+    } else {
+      r = RelOptUtil.createProject(r, projects, null, true);
+      if (allColumnsInAggregate) {
+        // let's see if we can convert
+        List<RexNode> projects2 = new ArrayList<>();
+        for (int key : Mappings.apply(mapping, aggregate.getGroupSet())) {
+          projects2.add(rexBuilder.makeInputRef(r, key));
+        }
+        for (AggregateCall newAggCall : newAggCalls) {
+          final SqlSplittableAggFunction splitter =
+              newAggCall.getAggregation()
+                  .unwrap(SqlSplittableAggFunction.class);
+          if (splitter != null) {
+            projects2.add(
+                splitter.singleton(rexBuilder, r.getRowType(), newAggCall));
+          }
+        }
+        if (projects2.size()
+            == aggregate.getGroupSet().cardinality() + newAggCalls.size()) {
+          // We successfully converted agg calls into projects.
+          r = RelOptUtil.createProject(r, projects2, null, true);
+          break b;
+        }
+      }
+      r = aggregateFactory.createAggregate(r, aggregate.indicator,
+          Mappings.apply(mapping, aggregate.getGroupSet()),
+          Mappings.apply2(mapping, aggregate.getGroupSets()), newAggCalls);
+    }
+    call.transformTo(r);
+  }
+
+  /** Computes the closure of a set of columns according to a given list of
+   * constraints. Each 'x = y' constraint causes bit y to be set if bit x is
+   * set, and vice versa. */
+  private static ImmutableBitSet keyColumns(ImmutableBitSet aggregateColumns,
+      ImmutableList<RexNode> predicates) {
+    SortedMap<Integer, BitSet> equivalence = new TreeMap<>();
+    for (RexNode pred : predicates) {
+      populateEquivalences(equivalence, pred);
+    }
+    ImmutableBitSet keyColumns = aggregateColumns;
+    for (Integer aggregateColumn : aggregateColumns) {
+      final BitSet bitSet = equivalence.get(aggregateColumn);
+      if (bitSet != null) {
+        keyColumns = keyColumns.union(bitSet);
+      }
+    }
+    return keyColumns;
+  }
+
+  private static void populateEquivalences(Map<Integer, BitSet> equivalence,
+      RexNode predicate) {
+    switch (predicate.getKind()) {
+    case EQUALS:
+      RexCall call = (RexCall) predicate;
+      final List<RexNode> operands = call.getOperands();
+      if (operands.get(0) instanceof RexInputRef) {
+        final RexInputRef ref0 = (RexInputRef) operands.get(0);
+        if (operands.get(1) instanceof RexInputRef) {
+          final RexInputRef ref1 = (RexInputRef) operands.get(1);
+          populateEquivalence(equivalence, ref0.getIndex(), ref1.getIndex());
+          populateEquivalence(equivalence, ref1.getIndex(), ref0.getIndex());
+        }
+      }
+    }
+  }
+
+  private static void populateEquivalence(Map<Integer, BitSet> equivalence,
+      int i0, int i1) {
+    BitSet bitSet = equivalence.get(i0);
+    if (bitSet == null) {
+      bitSet = new BitSet();
+      equivalence.put(i0, bitSet);
+    }
+    bitSet.set(i1);
+  }
+
+  /** Creates a {@link org.apache.calcite.sql.SqlSplittableAggFunction.Registry}
+   * that is a view of a list. */
+  private static <E> SqlSplittableAggFunction.Registry<E>
+  registry(final List<E> list) {
+    return new SqlSplittableAggFunction.Registry<E>() {
+      public int register(E e) {
+        int i = list.indexOf(e);
+        if (i < 0) {
+          i = list.size();
+          list.add(e);
+        }
+        return i;
+      }
+    };
+  }
+
+  /** Work space for an input to a join. */
+  private static class Side {
+    final Map<Integer, Integer> split = new HashMap<>();
+    RelNode newInput;
+    boolean aggregate;
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cf7a7a97/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
index 3a33e16..752c212 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
@@ -153,12 +153,8 @@ public class AggregateReduceFunctionsRule extends RelOptRule {
     // will add an expression to the end, and we will create an extra
     // project.
     RelNode input = oldAggRel.getInput();
-    final List<RexNode> inputExprs = new ArrayList<>();
-    for (RelDataTypeField field : input.getRowType().getFieldList()) {
-      inputExprs.add(
-          rexBuilder.makeInputRef(
-              field.getType(), inputExprs.size()));
-    }
+    final List<RexNode> inputExprs =
+        new ArrayList<>(rexBuilder.identityProjects(input.getRowType()));
 
     // create new agg function calls and rest of project list together
     for (AggregateCall oldCall : oldCalls) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cf7a7a97/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
index 2cb47d5..ce716c8 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
@@ -119,7 +119,7 @@ public class RexBuilder {
 
   /** Creates a list of {@link org.apache.calcite.rex.RexInputRef} expressions,
    * projecting the fields of a given record type. */
-  public List<RexInputRef> identityProjects(final RelDataType rowType) {
+  public List<? extends RexNode> identityProjects(final RelDataType rowType) {
     return Lists.transform(rowType.getFieldList(), TO_INPUT_REF);
   }
 
@@ -533,28 +533,23 @@ public class RexBuilder {
   }
 
   private RexNode makeCastExactToBoolean(RelDataType toType, RexNode exp) {
-    return makeCall(
-        toType,
+    return makeCall(toType,
         SqlStdOperatorTable.NOT_EQUALS,
         ImmutableList.of(exp, makeZeroLiteral(exp.getType())));
   }
 
   private RexNode makeCastBooleanToExact(RelDataType toType, RexNode exp) {
-    final RexNode casted = makeCall(
-        SqlStdOperatorTable.CASE,
+    final RexNode casted = makeCall(SqlStdOperatorTable.CASE,
         exp,
         makeExactLiteral(BigDecimal.ONE, toType),
         makeZeroLiteral(toType));
     if (!exp.getType().isNullable()) {
       return casted;
     }
-    return makeCall(
-        toType,
+    return makeCall(toType,
         SqlStdOperatorTable.CASE,
-        ImmutableList.<RexNode>of(
-            makeCall(SqlStdOperatorTable.IS_NOT_NULL, exp),
-            casted,
-            makeNullLiteral(toType.getSqlTypeName())));
+        ImmutableList.of(makeCall(SqlStdOperatorTable.IS_NOT_NULL, exp),
+            casted, makeNullLiteral(toType.getSqlTypeName())));
   }
 
   private RexNode makeCastIntervalToExact(RelDataType toType, RexNode exp) {
@@ -605,14 +600,12 @@ public class RexBuilder {
     BigDecimal multiplier = BigDecimal.valueOf(endUnit.multiplier)
         .divide(BigDecimal.TEN.pow(scale));
     RelDataType decimalType =
-        getTypeFactory().createSqlType(
-            SqlTypeName.DECIMAL,
+        getTypeFactory().createSqlType(SqlTypeName.DECIMAL,
             scale + intervalType.getPrecision(),
             scale);
     RexNode value = decodeIntervalOrDecimal(ensureType(decimalType, exp, true));
     if (multiplier.longValue() != 1) {
-      value = makeCall(
-          SqlStdOperatorTable.MULTIPLY,
+      value = makeCall(SqlStdOperatorTable.MULTIPLY,
           value, makeExactLiteral(multiplier));
     }
     return encodeIntervalOrDecimal(value, toType, false);
@@ -639,8 +632,7 @@ public class RexBuilder {
       RelDataType type,
       boolean checkOverflow) {
     RelDataType bigintType =
-        typeFactory.createSqlType(
-            SqlTypeName.BIGINT);
+        typeFactory.createSqlType(SqlTypeName.BIGINT);
     RexNode cast = ensureType(bigintType, value, true);
     return makeReinterpretCast(type, cast, makeLiteral(checkOverflow));
   }
@@ -771,6 +763,8 @@ public class RexBuilder {
    * @param input Input relational expression
    * @param i    Ordinal of field
    * @return Reference to field
+   *
+   * @see #identityProjects(RelDataType)
    */
   public RexInputRef makeInputRef(RelNode input, int i) {
     return makeInputRef(input.getRowType().getFieldList().get(i).getType(), i);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cf7a7a97/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java
index 4f51be2..944309a 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.sql;
 
+import org.apache.calcite.plan.Context;
 import org.apache.calcite.sql.type.SqlOperandTypeChecker;
 import org.apache.calcite.sql.type.SqlOperandTypeInference;
 import org.apache.calcite.sql.type.SqlReturnTypeInference;
@@ -26,7 +27,7 @@ import org.apache.calcite.sql.validate.SqlValidatorScope;
  * Abstract base class for the definition of an aggregate function: an operator
  * which aggregates sets of values into a result.
  */
-public abstract class SqlAggFunction extends SqlFunction {
+public abstract class SqlAggFunction extends SqlFunction implements Context {
   //~ Constructors -----------------------------------------------------------
 
   /** Creates a built-in SqlAggFunction. */
@@ -57,6 +58,10 @@ public abstract class SqlAggFunction extends SqlFunction {
 
   //~ Methods ----------------------------------------------------------------
 
+  public <T> T unwrap(Class<T> clazz) {
+    return clazz.isInstance(this) ? clazz.cast(this) : null;
+  }
+
   @Override public boolean isAggregator() {
     return true;
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cf7a7a97/core/src/main/java/org/apache/calcite/sql/SqlSplittableAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlSplittableAggFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlSplittableAggFunction.java
new file mode 100644
index 0000000..465a4d6
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/sql/SqlSplittableAggFunction.java
@@ -0,0 +1,267 @@
+/*
+ * 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.rel.core.AggregateCall;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.util.ImmutableIntList;
+import org.apache.calcite.util.mapping.Mappings;
+
+import com.google.common.collect.ImmutableList;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Aggregate function that can be split into partial aggregates.
+ *
+ * <p>For example, {@code COUNT(x)} can be split into {@code COUNT(x)} on
+ * subsets followed by {@code SUM} to combine those counts.
+ */
+public interface SqlSplittableAggFunction {
+  AggregateCall split(AggregateCall aggregateCall,
+      Mappings.TargetMapping mapping);
+
+  /** Called to generate an aggregate for the other side of the join
+   * than the side aggregate call's arguments come from. Returns null if
+   * no aggregate is required. */
+  AggregateCall other(RelDataTypeFactory typeFactory, AggregateCall e);
+
+  /** Generates an aggregate call to merge sub-totals.
+   *
+   * <p>Most implementations will add a single aggregate call to
+   * {@code aggCalls}, and return a {@link RexInputRef} that points to it.
+   *
+   * @param rexBuilder Rex builder
+   * @param extra Place to define extra input expressions
+   * @param offset Offset due to grouping columns (and indicator columns if
+   *     applicable)
+   * @param inputRowType Input row type
+   * @param aggregateCall Source aggregate call
+   * @param leftSubTotal Ordinal of the sub-total coming from the left side of
+   *     the join, or -1 if there is no such sub-total
+   * @param rightSubTotal Ordinal of the sub-total coming from the right side
+   *     of the join, or -1 if there is no such sub-total
+   *
+   * @return Aggregate call
+   */
+  AggregateCall topSplit(RexBuilder rexBuilder, Registry<RexNode> extra,
+      int offset, RelDataType inputRowType, AggregateCall aggregateCall,
+      int leftSubTotal, int rightSubTotal);
+
+  /** Generates an expression for the value of the aggregate function when
+   * applied to a single row.
+   *
+   * <p>For example, if there is one row:
+   * <ul>
+   *   <li>{@code SUM(x)} is {@code x}
+   *   <li>{@code MIN(x)} is {@code x}
+   *   <li>{@code MAX(x)} is {@code x}
+   *   <li>{@code COUNT(x)} is {@code CASE WHEN x IS NOT NULL THEN 1 ELSE 0 END 1}
+   *   which can be simplified to {@code 1} if {@code x} is never null
+   *   <li>{@code COUNT(*)} is 1
+   * </ul>
+   *
+   * @param rexBuilder Rex builder
+   * @param inputRowType Input row type
+   * @param aggregateCall Aggregate call
+   *
+   * @return Expression for single row
+   */
+  RexNode singleton(RexBuilder rexBuilder, RelDataType inputRowType,
+      AggregateCall aggregateCall);
+
+  /** Collection in which one can register an element. Registering may return
+   * a reference to an existing element. */
+  interface Registry<E> {
+    int register(E e);
+  }
+
+  /** Splitting strategy for {@code COUNT}.
+   *
+   * <p>COUNT splits into itself followed by SUM. (Actually
+   * SUM0, because the total needs to be 0, not null, if there are 0 rows.)
+   * This rule works for any number of arguments to COUNT, including COUNT(*).
+   */
+  class CountSplitter implements SqlSplittableAggFunction {
+    public static final CountSplitter INSTANCE = new CountSplitter();
+
+    public AggregateCall split(AggregateCall aggregateCall,
+        Mappings.TargetMapping mapping) {
+      return aggregateCall.transform(mapping);
+    }
+
+    public AggregateCall other(RelDataTypeFactory typeFactory, AggregateCall e) {
+      return AggregateCall.create(SqlStdOperatorTable.COUNT, false,
+          ImmutableIntList.of(), -1,
+          typeFactory.createSqlType(SqlTypeName.BIGINT), null);
+    }
+
+    public AggregateCall topSplit(RexBuilder rexBuilder,
+        Registry<RexNode> extra, int offset, RelDataType inputRowType,
+        AggregateCall aggregateCall, int leftSubTotal, int rightSubTotal) {
+      final List<RexNode> merges = new ArrayList<>();
+      if (leftSubTotal >= 0) {
+        merges.add(
+            rexBuilder.makeInputRef(aggregateCall.type, leftSubTotal));
+      }
+      if (rightSubTotal >= 0) {
+        merges.add(
+            rexBuilder.makeInputRef(aggregateCall.type, rightSubTotal));
+      }
+      RexNode node;
+      switch (merges.size()) {
+      case 1:
+        node = merges.get(0);
+        break;
+      case 2:
+        node = rexBuilder.makeCall(SqlStdOperatorTable.MULTIPLY, merges);
+        break;
+      default:
+        throw new AssertionError("unexpected count " + merges);
+      }
+      int ordinal = extra.register(node);
+      return AggregateCall.create(SqlStdOperatorTable.SUM0, false,
+          ImmutableList.of(ordinal), -1, aggregateCall.type,
+          aggregateCall.name);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * COUNT(*) and COUNT applied to all NOT NULL arguments become {@code 1};
+     * otherwise {@code CASE WHEN arg0 IS NOT NULL THEN 1 ELSE 0 END}.
+     */
+    public RexNode singleton(RexBuilder rexBuilder, RelDataType inputRowType,
+        AggregateCall aggregateCall) {
+      final List<RexNode> predicates = new ArrayList<>();
+      for (Integer arg : aggregateCall.getArgList()) {
+        final RelDataType type = inputRowType.getFieldList().get(arg).getType();
+        if (type.isNullable()) {
+          predicates.add(
+              rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL,
+                  rexBuilder.makeInputRef(type, arg)));
+        }
+      }
+      final RexNode predicate =
+          RexUtil.composeConjunction(rexBuilder, predicates, true);
+      if (predicate == null) {
+        return rexBuilder.makeExactLiteral(BigDecimal.ONE);
+      } else {
+        return rexBuilder.makeCall(SqlStdOperatorTable.CASE, predicate,
+            rexBuilder.makeExactLiteral(BigDecimal.ONE),
+            rexBuilder.makeExactLiteral(BigDecimal.ZERO));
+      }
+    }
+  }
+
+  /** Aggregate function that splits into two applications of itself.
+   *
+   * <p>Examples are MIN and MAX. */
+  class SelfSplitter implements SqlSplittableAggFunction {
+    public static final SelfSplitter INSTANCE = new SelfSplitter();
+
+    public RexNode singleton(RexBuilder rexBuilder,
+        RelDataType inputRowType, AggregateCall aggregateCall) {
+      final int arg = aggregateCall.getArgList().get(0);
+      final RelDataTypeField field = inputRowType.getFieldList().get(arg);
+      return rexBuilder.makeInputRef(field.getType(), arg);
+    }
+
+    public AggregateCall split(AggregateCall aggregateCall,
+        Mappings.TargetMapping mapping) {
+      return aggregateCall.transform(mapping);
+    }
+
+    public AggregateCall other(RelDataTypeFactory typeFactory, AggregateCall e) {
+      return null; // no aggregate function required on other side
+    }
+
+    public AggregateCall topSplit(RexBuilder rexBuilder,
+        Registry<RexNode> extra, int offset, RelDataType inputRowType,
+        AggregateCall aggregateCall, int leftSubTotal, int rightSubTotal) {
+      assert (leftSubTotal >= 0) != (rightSubTotal >= 0);
+      final int arg = leftSubTotal >= 0 ? leftSubTotal : rightSubTotal;
+      return aggregateCall.copy(ImmutableIntList.of(arg), -1);
+    }
+  }
+
+  /** Splitting strategy for {@code SUM}. */
+  class SumSplitter implements SqlSplittableAggFunction {
+    public static final SumSplitter INSTANCE = new SumSplitter();
+
+    public RexNode singleton(RexBuilder rexBuilder,
+        RelDataType inputRowType, AggregateCall aggregateCall) {
+      final int arg = aggregateCall.getArgList().get(0);
+      final RelDataTypeField field = inputRowType.getFieldList().get(arg);
+      return rexBuilder.makeInputRef(field.getType(), arg);
+    }
+
+    public AggregateCall split(AggregateCall aggregateCall,
+        Mappings.TargetMapping mapping) {
+      return aggregateCall.transform(mapping);
+    }
+
+    public AggregateCall other(RelDataTypeFactory typeFactory, AggregateCall e) {
+      return AggregateCall.create(SqlStdOperatorTable.COUNT, false,
+          ImmutableIntList.of(), -1,
+          typeFactory.createSqlType(SqlTypeName.BIGINT), null);
+    }
+
+    public AggregateCall topSplit(RexBuilder rexBuilder,
+        Registry<RexNode> extra, int offset, RelDataType inputRowType,
+        AggregateCall aggregateCall, int leftSubTotal, int rightSubTotal) {
+      final List<RexNode> merges = new ArrayList<>();
+      final List<RelDataTypeField> fieldList = inputRowType.getFieldList();
+      if (leftSubTotal >= 0) {
+        final RelDataType type = fieldList.get(leftSubTotal).getType();
+        merges.add(rexBuilder.makeInputRef(type, leftSubTotal));
+      }
+      if (rightSubTotal >= 0) {
+        final RelDataType type = fieldList.get(rightSubTotal).getType();
+        merges.add(rexBuilder.makeInputRef(type, rightSubTotal));
+      }
+      RexNode node;
+      switch (merges.size()) {
+      case 1:
+        node = merges.get(0);
+        break;
+      case 2:
+        node = rexBuilder.makeCall(SqlStdOperatorTable.MULTIPLY, merges);
+        node = rexBuilder.makeAbstractCast(aggregateCall.type, node);
+        break;
+      default:
+        throw new AssertionError("unexpected count " + merges);
+      }
+      int ordinal = extra.register(node);
+      return AggregateCall.create(SqlStdOperatorTable.SUM, false,
+          ImmutableList.of(ordinal), -1, aggregateCall.type,
+          aggregateCall.name);
+    }
+  }
+}
+
+// End SqlSplittableAggFunction.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cf7a7a97/core/src/main/java/org/apache/calcite/sql/fun/SqlCountAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlCountAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlCountAggFunction.java
index a08a96e..3feefc2 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlCountAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlCountAggFunction.java
@@ -22,6 +22,7 @@ import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlSplittableAggFunction;
 import org.apache.calcite.sql.SqlSyntax;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
@@ -83,6 +84,13 @@ public class SqlCountAggFunction extends SqlAggFunction {
     }
     return super.deriveType(validator, scope, call);
   }
+
+  @Override public <T> T unwrap(Class<T> clazz) {
+    if (clazz == SqlSplittableAggFunction.class) {
+      return clazz.cast(SqlSplittableAggFunction.CountSplitter.INSTANCE);
+    }
+    return super.unwrap(clazz);
+  }
 }
 
 // End SqlCountAggFunction.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cf7a7a97/core/src/main/java/org/apache/calcite/sql/fun/SqlMinMaxAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlMinMaxAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlMinMaxAggFunction.java
index 74b3c99..2ce8d6f 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlMinMaxAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlMinMaxAggFunction.java
@@ -21,6 +21,7 @@ import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlSplittableAggFunction;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
 import org.apache.calcite.util.Util;
@@ -112,6 +113,12 @@ public class SqlMinMaxAggFunction extends SqlAggFunction {
     }
   }
 
+  @Override public <T> T unwrap(Class<T> clazz) {
+    if (clazz == SqlSplittableAggFunction.class) {
+      return clazz.cast(SqlSplittableAggFunction.SelfSplitter.INSTANCE);
+    }
+    return super.unwrap(clazz);
+  }
 }
 
 // End SqlMinMaxAggFunction.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cf7a7a97/core/src/main/java/org/apache/calcite/sql/fun/SqlSumAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlSumAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlSumAggFunction.java
index 9b2835d..41b9d1d 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlSumAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlSumAggFunction.java
@@ -21,6 +21,7 @@ import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlSplittableAggFunction;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
 
@@ -35,6 +36,7 @@ import java.util.List;
  * is the same type.
  */
 public class SqlSumAggFunction extends SqlAggFunction {
+
   //~ Instance fields --------------------------------------------------------
 
   private final RelDataType type;
@@ -65,6 +67,13 @@ public class SqlSumAggFunction extends SqlAggFunction {
   public RelDataType getReturnType(RelDataTypeFactory typeFactory) {
     return type;
   }
+
+  @Override public <T> T unwrap(Class<T> clazz) {
+    if (clazz == SqlSplittableAggFunction.class) {
+      return clazz.cast(SqlSplittableAggFunction.SumSplitter.INSTANCE);
+    }
+    return super.unwrap(clazz);
+  }
 }
 
 // End SqlSumAggFunction.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cf7a7a97/core/src/main/java/org/apache/calcite/sql/fun/SqlSumEmptyIsZeroAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlSumEmptyIsZeroAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlSumEmptyIsZeroAggFunction.java
index 50fa487..965ae75 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlSumEmptyIsZeroAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlSumEmptyIsZeroAggFunction.java
@@ -21,6 +21,7 @@ import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlSplittableAggFunction;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
 import org.apache.calcite.sql.type.SqlTypeName;
@@ -59,6 +60,13 @@ public class SqlSumEmptyIsZeroAggFunction extends SqlAggFunction {
     return typeFactory.createTypeWithNullability(
         typeFactory.createSqlType(SqlTypeName.ANY), true);
   }
+
+  @Override public <T> T unwrap(Class<T> clazz) {
+    if (clazz == SqlSplittableAggFunction.class) {
+      return clazz.cast(SqlSplittableAggFunction.SumSplitter.INSTANCE);
+    }
+    return super.unwrap(clazz);
+  }
 }
 
 // End SqlSumEmptyIsZeroAggFunction.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cf7a7a97/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index 3739af5..1901f89 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -1563,12 +1563,13 @@ public class RelOptRulesTest extends RelOptTestBase {
   @Test public void testPushFilterWithRank() throws Exception {
     HepProgram program = new HepProgramBuilder().addRuleInstance(
         FilterProjectTransposeRule.INSTANCE).build();
-    checkPlanning(program, "select e1.ename, r\n"
+    final String sql = "select e1.ename, r\n"
         + "from (\n"
         + "  select ename, "
         + "  rank() over(partition by  deptno order by sal) as r "
         + "  from emp) e1\n"
-        + "where r < 2");
+        + "where r < 2";
+    checkPlanning(program, sql);
   }
 
   @Test public void testPushFilterWithRankExpr() throws Exception {
@@ -1587,14 +1588,13 @@ public class RelOptRulesTest extends RelOptTestBase {
         .addRuleInstance(AggregateProjectMergeRule.INSTANCE)
         .build();
     final HepProgram program = new HepProgramBuilder()
-        .addRuleInstance(AggregateJoinTransposeRule.INSTANCE)
+        .addRuleInstance(AggregateJoinTransposeRule.EXTENDED)
         .build();
-    checkPlanning(tester, preProgram,
-        new HepPlanner(program),
-        "select e.empno,d.deptno \n"
-                + "from (select * from sales.emp where empno = 10) as e "
-                + "join sales.dept as d on e.empno = d.deptno "
-                + "group by e.empno,d.deptno");
+    final String sql = "select e.empno,d.deptno \n"
+        + "from (select * from sales.emp where empno = 10) as e "
+        + "join sales.dept as d on e.empno = d.deptno "
+        + "group by e.empno,d.deptno";
+    checkPlanning(tester, preProgram, new HepPlanner(program), sql);
   }
 
   @Test public void testPushAggregateThroughJoin2() throws Exception {
@@ -1602,15 +1602,14 @@ public class RelOptRulesTest extends RelOptTestBase {
         .addRuleInstance(AggregateProjectMergeRule.INSTANCE)
         .build();
     final HepProgram program = new HepProgramBuilder()
-        .addRuleInstance(AggregateJoinTransposeRule.INSTANCE)
+        .addRuleInstance(AggregateJoinTransposeRule.EXTENDED)
         .build();
-    checkPlanning(tester, preProgram,
-        new HepPlanner(program),
-        "select e.empno,d.deptno \n"
-                + "from (select * from sales.emp where empno = 10) as e "
-                + "join sales.dept as d on e.empno = d.deptno "
-                + "and e.deptno + e.empno = d.deptno + 5 "
-                + "group by e.empno,d.deptno");
+    final String sql = "select e.empno,d.deptno \n"
+        + "from (select * from sales.emp where empno = 10) as e "
+        + "join sales.dept as d on e.empno = d.deptno "
+        + "and e.deptno + e.empno = d.deptno + 5 "
+        + "group by e.empno,d.deptno";
+    checkPlanning(tester, preProgram, new HepPlanner(program), sql);
   }
 
   @Test public void testPushAggregateThroughJoin3() throws Exception {
@@ -1618,29 +1617,77 @@ public class RelOptRulesTest extends RelOptTestBase {
         .addRuleInstance(AggregateProjectMergeRule.INSTANCE)
         .build();
     final HepProgram program = new HepProgramBuilder()
-        .addRuleInstance(AggregateJoinTransposeRule.INSTANCE)
+        .addRuleInstance(AggregateJoinTransposeRule.EXTENDED)
         .build();
-    checkPlanning(tester, preProgram,
-        new HepPlanner(program),
-        "select e.empno,d.deptno \n"
-                + "from (select * from sales.emp where empno = 10) as e "
-                + "join sales.dept as d on e.empno < d.deptno "
-                + "group by e.empno,d.deptno");
+    final String sql = "select e.empno,d.deptno \n"
+        + "from (select * from sales.emp where empno = 10) as e "
+        + "join sales.dept as d on e.empno < d.deptno "
+        + "group by e.empno,d.deptno";
+    checkPlanning(tester, preProgram, new HepPlanner(program), sql);
   }
 
-  @Test public void testPushAggregateThroughJoin4() throws Exception {
+  /** SUM is the easiest aggregate function to split. */
+  @Test public void testPushAggregateSumThroughJoin() throws Exception {
     final HepProgram preProgram = new HepProgramBuilder()
         .addRuleInstance(AggregateProjectMergeRule.INSTANCE)
         .build();
     final HepProgram program = new HepProgramBuilder()
-        .addRuleInstance(AggregateJoinTransposeRule.INSTANCE)
+        .addRuleInstance(AggregateJoinTransposeRule.EXTENDED)
         .build();
-    checkPlanning(tester, preProgram,
-        new HepPlanner(program),
-        "select e.empno,sum(sal) \n"
-                + "from (select * from sales.emp where empno = 10) as e "
-                + "join sales.dept as d on e.empno = d.deptno "
-                + "group by e.empno,d.deptno");
+    final String sql = "select e.empno,sum(sal) \n"
+        + "from (select * from sales.emp where empno = 10) as e "
+        + "join sales.dept as d on e.empno = d.deptno "
+        + "group by e.empno,d.deptno";
+    checkPlanning(tester, preProgram, new HepPlanner(program), sql);
+  }
+
+  /** Push a variety of aggregate functions. */
+  @Test public void testPushAggregateFunctionsThroughJoin() throws Exception {
+    final HepProgram preProgram = new HepProgramBuilder()
+        .addRuleInstance(AggregateProjectMergeRule.INSTANCE)
+        .build();
+    final HepProgram program = new HepProgramBuilder()
+        .addRuleInstance(AggregateJoinTransposeRule.EXTENDED)
+        .build();
+    final String sql = "select e.empno,\n"
+        + "  min(sal) as min_sal, min(e.deptno) as min_deptno,\n"
+        + "  sum(sal) + 1 as sum_sal_plus, max(sal) as max_sal,\n"
+        + "  sum(sal) as sum_sal_2, count(sal) as count_sal\n"
+        + "from sales.emp as e\n"
+        + "join sales.dept as d on e.empno = d.deptno\n"
+        + "group by e.empno,d.deptno";
+    checkPlanning(tester, preProgram, new HepPlanner(program), sql);
+  }
+
+  /** Push a aggregate functions into a relation that is unique on the join
+   * key. */
+  @Test public void testPushAggregateThroughJoinDistinct() throws Exception {
+    final HepProgram preProgram = new HepProgramBuilder()
+        .addRuleInstance(AggregateProjectMergeRule.INSTANCE)
+        .build();
+    final HepProgram program = new HepProgramBuilder()
+        .addRuleInstance(AggregateJoinTransposeRule.EXTENDED)
+        .build();
+    final String sql = "select d.deptno,\n"
+        + "  sum(sal) as sum_sal, count(*) as c\n"
+        + "from sales.emp as e\n"
+        + "join (select distinct deptno from sales.dept) as d\n"
+        + "  on e.empno = d.deptno\n"
+        + "group by d.deptno";
+    checkPlanning(tester, preProgram, new HepPlanner(program), sql);
+  }
+
+  /** Push count(*) through join, no GROUP BY. */
+  @Test public void testPushAggregateSumNoGroup() throws Exception {
+    final HepProgram preProgram = new HepProgramBuilder()
+        .addRuleInstance(AggregateProjectMergeRule.INSTANCE)
+        .build();
+    final HepProgram program = new HepProgramBuilder()
+        .addRuleInstance(AggregateJoinTransposeRule.EXTENDED)
+        .build();
+    final String sql =
+        "select count(*) from sales.emp join sales.dept using (deptno)";
+    checkPlanning(tester, preProgram, new HepPlanner(program), sql);
   }
 
   @Test public void testSwapOuterJoin() throws Exception {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cf7a7a97/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index d01a8d1..044b6b2 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -3383,14 +3383,16 @@ LogicalAggregate(group=[{0, 10}])
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
-LogicalAggregate(group=[{0, 10}])
-  LogicalJoin(condition=[AND(=($0, $10), =($9, $12))], joinType=[inner])
-    LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], $f9=[+($7, $0)])
-      LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
-        LogicalFilter(condition=[=($0, 10)])
-          LogicalTableScan(table=[[CATALOG, SALES, EMP]])
-    LogicalProject(DEPTNO=[$0], NAME=[$1], $f2=[+($0, 5)])
-      LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+LogicalAggregate(group=[{0, 2}])
+  LogicalJoin(condition=[AND(=($0, $2), =($1, $3))], joinType=[inner])
+    LogicalAggregate(group=[{0, 9}])
+      LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], $f9=[+($7, $0)])
+        LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+          LogicalFilter(condition=[=($0, 10)])
+            LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+    LogicalAggregate(group=[{0, 2}])
+      LogicalProject(DEPTNO=[$0], NAME=[$1], $f2=[+($0, 5)])
+        LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
 ]]>
         </Resource>
     </TestCase>
@@ -3420,7 +3422,7 @@ LogicalAggregate(group=[{0, 9}])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testPushAggregateThroughJoin4">
+    <TestCase name="testPushAggregateSumThroughJoin">
         <Resource name="sql">
             <![CDATA[select e.empno,sum(sal) 
 from (select * from sales.emp where empno = 10) as e join sales.dept as d on e.empno = d.deptno group by e.empno,d.deptno]]>
@@ -3439,12 +3441,15 @@ LogicalProject(EMPNO=[$0], EXPR$1=[$2])
         <Resource name="planAfter">
             <![CDATA[
 LogicalProject(EMPNO=[$0], EXPR$1=[$2])
-  LogicalAggregate(group=[{0, 9}], EXPR$1=[SUM($5)])
-    LogicalJoin(condition=[=($0, $9)], joinType=[inner])
-      LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
-        LogicalFilter(condition=[=($0, 10)])
-          LogicalTableScan(table=[[CATALOG, SALES, EMP]])
-      LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+  LogicalProject($f0=[$0], $f1=[$2], $f2=[$4])
+    LogicalProject($f0=[$0], $f1=[$1], $f2=[$2], $f3=[$3], $f4=[CAST(*($1, $3)):INTEGER NOT NULL])
+      LogicalJoin(condition=[=($0, $2)], joinType=[inner])
+        LogicalAggregate(group=[{0}], EXPR$1=[SUM($5)])
+          LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+            LogicalFilter(condition=[=($0, 10)])
+              LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+        LogicalAggregate(group=[{0}], agg#0=[COUNT()])
+          LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
 ]]>
         </Resource>
     </TestCase>
@@ -3772,4 +3777,89 @@ LogicalProject(DEPTNO=[$0])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testPushAggregateFunctionsThroughJoin">
+        <Resource name="sql">
+            <![CDATA[select e.empno,
+  min(sal) as min_sal, min(e.deptno) as min_deptno,
+  sum(sal) + 1 as sum_sal_plus, max(sal) as max_sal,
+  sum(sal) as sum_sal_2, count(sal) as count_sal
+from sales.emp as e
+join sales.dept as d on e.empno = d.deptno
+group by e.empno,d.deptno]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(EMPNO=[$0], MIN_SAL=[$2], MIN_DEPTNO=[$3], SUM_SAL_PLUS=[+($4, 1)], MAX_SAL=[$5], SUM_SAL_2=[$4], COUNT_SAL=[$6])
+  LogicalAggregate(group=[{0, 9}], MIN_SAL=[MIN($5)], MIN_DEPTNO=[MIN($7)], SUM_SAL_2=[SUM($5)], MAX_SAL=[MAX($5)], COUNT_SAL=[COUNT()])
+    LogicalJoin(condition=[=($0, $9)], joinType=[inner])
+      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+      LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalProject(EMPNO=[$0], MIN_SAL=[$2], MIN_DEPTNO=[$3], SUM_SAL_PLUS=[+($4, 1)], MAX_SAL=[$5], SUM_SAL_2=[$4], COUNT_SAL=[$6])
+  LogicalProject($f0=[$0], $f1=[$6], $f2=[$1], $f3=[$2], $f4=[$8], $f5=[$4], $f6=[$9])
+    LogicalProject($f0=[$0], $f1=[$1], $f2=[$2], $f3=[$3], $f4=[$4], $f5=[$5], $f6=[$6], $f7=[$7], $f8=[CAST(*($3, $7)):INTEGER NOT NULL], $f9=[*($5, $7)])
+      LogicalJoin(condition=[=($0, $6)], joinType=[inner])
+        LogicalAggregate(group=[{0}], MIN_SAL=[MIN($5)], MIN_DEPTNO=[MIN($7)], SUM_SAL_2=[SUM($5)], MAX_SAL=[MAX($5)], COUNT_SAL=[COUNT()])
+          LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+        LogicalAggregate(group=[{0}], agg#0=[COUNT()])
+          LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+        </Resource>
+    </TestCase>
+    <TestCase name="testPushAggregateSumNoGroup">
+        <Resource name="sql">
+            <![CDATA[select count(*) from sales.emp join sales.dept using (deptno)]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalAggregate(group=[{}], EXPR$0=[COUNT()])
+  LogicalJoin(condition=[=($7, $9)], joinType=[inner])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+    LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalAggregate(group=[{}], EXPR$0=[$SUM0($4)])
+  LogicalProject($f0=[$0], $f1=[$1], $f2=[$2], $f3=[$3], $f4=[*($1, $3)])
+    LogicalJoin(condition=[=($0, $2)], joinType=[inner])
+      LogicalAggregate(group=[{7}], EXPR$0=[COUNT()])
+        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+      LogicalAggregate(group=[{0}], EXPR$0=[COUNT()])
+        LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+        </Resource>
+    </TestCase>
+    <TestCase name="testPushAggregateThroughJoinDistinct">
+        <Resource name="sql">
+            <![CDATA[select d.deptno,
+  sum(sal) as sum_sal, count(*) as c
+from sales.emp as e
+join (select distinct deptno from sales.dept) as d
+  on e.empno = d.deptno
+group by d.deptno]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalAggregate(group=[{9}], SUM_SAL=[SUM($5)], C=[COUNT()])
+  LogicalJoin(condition=[=($0, $9)], joinType=[inner])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+    LogicalAggregate(group=[{0}])
+      LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalProject($f0=[$3], $f1=[$1], $f2=[$2])
+  LogicalJoin(condition=[=($0, $3)], joinType=[inner])
+    LogicalAggregate(group=[{0}], SUM_SAL=[SUM($5)], C=[COUNT()])
+      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+    LogicalAggregate(group=[{0}])
+      LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+        </Resource>
+    </TestCase>
 </Root>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cf7a7a97/core/src/test/resources/sql/agg.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/agg.oq b/core/src/test/resources/sql/agg.oq
index aeecc04..771ff86 100644
--- a/core/src/test/resources/sql/agg.oq
+++ b/core/src/test/resources/sql/agg.oq
@@ -52,7 +52,6 @@ select count(deptno) as c from emp;
 !ok
 
 # composite count
-!if (false) {
 select count(deptno, ename, 1, deptno) as c from emp;
 +---+
 | C |
@@ -62,7 +61,6 @@ select count(deptno, ename, 1, deptno) as c from emp;
 (1 row)
 
 !ok
-!}
 
 select city, gender as c from emps;
 +---------------+---+
@@ -773,6 +771,327 @@ select avg(comm) as a, count(comm) as c from "scott".emp where empno < 7844;
 
 !ok
 
+# [CALCITE-751] Aggregate join transpose
+select count(*)
+from "scott".emp join "scott".dept using (deptno);
++--------+
+| EXPR$0 |
++--------+
+|     14 |
++--------+
+(1 row)
+
+!ok
+EnumerableAggregate(group=[{}], EXPR$0=[COUNT()])
+  EnumerableJoin(condition=[=($0, $2)], joinType=[inner])
+    EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
+      EnumerableTableScan(table=[[scott, DEPT]])
+    EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], DEPTNO=[$t7])
+      EnumerableTableScan(table=[[scott, EMP]])
+!plan
+
+# Push sum: splits into sum * count
+select sum(sal)
+from "scott".emp join "scott".dept using (deptno);
++----------+
+| EXPR$0   |
++----------+
+| 29025.00 |
++----------+
+(1 row)
+
+!ok
+EnumerableAggregate(group=[{}], EXPR$0=[SUM($2)])
+  EnumerableJoin(condition=[=($0, $3)], joinType=[inner])
+    EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
+      EnumerableTableScan(table=[[scott, DEPT]])
+    EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5], DEPTNO=[$t7])
+      EnumerableTableScan(table=[[scott, EMP]])
+!plan
+
+# Push sum; no aggregate needed after join
+select sum(sal)
+from "scott".emp join "scott".dept using (deptno)
+group by emp.deptno, dept.deptno;
++----------+
+| EXPR$0   |
++----------+
+| 10875.00 |
+|  8750.00 |
+|  9400.00 |
++----------+
+(3 rows)
+
+!ok
+EnumerableCalc(expr#0..2=[{inputs}], EXPR$0=[$t2])
+  EnumerableAggregate(group=[{0, 3}], EXPR$0=[SUM($2)])
+    EnumerableJoin(condition=[=($0, $3)], joinType=[inner])
+      EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
+        EnumerableTableScan(table=[[scott, DEPT]])
+      EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5], DEPTNO=[$t7])
+        EnumerableTableScan(table=[[scott, EMP]])
+!plan
+
+# Push sum; group by only one of the join keys
+select sum(sal)
+from "scott".emp join "scott".dept using (deptno)
+group by emp.deptno;
++----------+
+| EXPR$0   |
++----------+
+| 10875.00 |
+|  8750.00 |
+|  9400.00 |
++----------+
+(3 rows)
+
+!ok
+EnumerableCalc(expr#0..1=[{inputs}], EXPR$0=[$t1])
+  EnumerableAggregate(group=[{3}], EXPR$0=[SUM($2)])
+    EnumerableJoin(condition=[=($0, $3)], joinType=[inner])
+      EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
+        EnumerableTableScan(table=[[scott, DEPT]])
+      EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5], DEPTNO=[$t7])
+        EnumerableTableScan(table=[[scott, EMP]])
+!plan
+
+# Push min; Join-Aggregate is optimized to SemiJoin
+select min(sal)
+from "scott".emp join "scott".dept using (deptno)
+group by emp.deptno;
++---------+
+| EXPR$0  |
++---------+
+| 1300.00 |
+|  800.00 |
+|  950.00 |
++---------+
+(3 rows)
+
+!ok
+EnumerableCalc(expr#0..1=[{inputs}], EXPR$0=[$t1])
+  EnumerableAggregate(group=[{3}], EXPR$0=[MIN($2)])
+    EnumerableJoin(condition=[=($0, $3)], joinType=[inner])
+      EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
+        EnumerableTableScan(table=[[scott, DEPT]])
+      EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5], DEPTNO=[$t7])
+        EnumerableTableScan(table=[[scott, EMP]])
+!plan
+
+# Push sum and count
+select count(*) as c, sum(sal) as s
+from "scott".emp join "scott".dept using (deptno);
++----+----------+
+| C  | S        |
++----+----------+
+| 14 | 29025.00 |
++----+----------+
+(1 row)
+
+!ok
+EnumerableAggregate(group=[{}], C=[COUNT()], S=[SUM($2)])
+  EnumerableJoin(condition=[=($0, $3)], joinType=[inner])
+    EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
+      EnumerableTableScan(table=[[scott, DEPT]])
+    EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5], DEPTNO=[$t7])
+      EnumerableTableScan(table=[[scott, EMP]])
+!plan
+
+# Push sum and count, group by join key
+select count(*) as c, sum(sal) as s
+from "scott".emp join "scott".dept using (deptno) group by emp.deptno;
++---+----------+
+| C | S        |
++---+----------+
+| 3 |  8750.00 |
+| 5 | 10875.00 |
+| 6 |  9400.00 |
++---+----------+
+(3 rows)
+
+!ok
+# No aggregate on top, because output of join is unique
+EnumerableCalc(expr#0..2=[{inputs}], C=[$t1], S=[$t2])
+  EnumerableAggregate(group=[{3}], C=[COUNT()], S=[SUM($2)])
+    EnumerableJoin(condition=[=($0, $3)], joinType=[inner])
+      EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
+        EnumerableTableScan(table=[[scott, DEPT]])
+      EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5], DEPTNO=[$t7])
+        EnumerableTableScan(table=[[scott, EMP]])
+!plan
+
+# Push sum and count, group by join key plus another column
+select count(*) as c, sum(sal) as s
+from "scott".emp join "scott".dept using (deptno) group by emp.job, dept.deptno;
++---+---------+
+| C | S       |
++---+---------+
+| 1 | 1300.00 |
+| 1 | 2450.00 |
+| 1 | 2850.00 |
+| 1 | 2975.00 |
+| 1 | 5000.00 |
+| 1 |  950.00 |
+| 2 | 1900.00 |
+| 2 | 6000.00 |
+| 4 | 5600.00 |
++---+---------+
+(9 rows)
+
+!ok
+EnumerableCalc(expr#0..3=[{inputs}], C=[$t2], S=[$t3])
+  EnumerableAggregate(group=[{0, 2}], C=[COUNT()], S=[SUM($3)])
+    EnumerableJoin(condition=[=($0, $4)], joinType=[inner])
+      EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
+        EnumerableTableScan(table=[[scott, DEPT]])
+      EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], JOB=[$t2], SAL=[$t5], DEPTNO=[$t7])
+        EnumerableTableScan(table=[[scott, EMP]])
+!plan
+
+# Push sum and count, group by non-join column
+select count(*) as c, sum(sal) as s
+from "scott".emp join "scott".dept using (deptno) group by emp.job;
++---+---------+
+| C | S       |
++---+---------+
+| 1 | 5000.00 |
+| 2 | 6000.00 |
+| 3 | 8275.00 |
+| 4 | 4150.00 |
+| 4 | 5600.00 |
++---+---------+
+(5 rows)
+
+!ok
+EnumerableCalc(expr#0..2=[{inputs}], C=[$t1], S=[$t2])
+  EnumerableAggregate(group=[{2}], C=[COUNT()], S=[SUM($3)])
+    EnumerableJoin(condition=[=($0, $4)], joinType=[inner])
+      EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
+        EnumerableTableScan(table=[[scott, DEPT]])
+      EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], JOB=[$t2], SAL=[$t5], DEPTNO=[$t7])
+        EnumerableTableScan(table=[[scott, EMP]])
+!plan
+
+# Push count and sum, group by superset of join key
+select count(*) as c, sum(sal) as s
+from "scott".emp join "scott".dept using (deptno) group by emp.job, dept.deptno;
++---+---------+
+| C | S       |
++---+---------+
+| 1 | 5000.00 |
+| 2 | 6000.00 |
+| 4 | 5600.00 |
+| 1 | 1300.00 |
+| 1 | 2450.00 |
+| 1 | 2850.00 |
+| 1 | 2975.00 |
+| 1 |  950.00 |
+| 2 | 1900.00 |
++---+---------+
+(9 rows)
+
+!ok
+EnumerableCalc(expr#0..3=[{inputs}], C=[$t2], S=[$t3])
+  EnumerableAggregate(group=[{0, 2}], C=[COUNT()], S=[SUM($3)])
+    EnumerableJoin(condition=[=($0, $4)], joinType=[inner])
+      EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
+        EnumerableTableScan(table=[[scott, DEPT]])
+      EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], JOB=[$t2], SAL=[$t5], DEPTNO=[$t7])
+        EnumerableTableScan(table=[[scott, EMP]])
+!plan
+
+# Push count and sum, group by a column being aggregated
+select count(*) as c, sum(sal) as s
+from "scott".emp join "scott".dept using (deptno) group by emp.sal;
++---+---------+
+| C | S       |
++---+---------+
+| 1 | 5000.00 |
+| 2 | 6000.00 |
+| 1 | 1100.00 |
+| 1 | 1300.00 |
+| 1 | 1500.00 |
+| 1 | 1600.00 |
+| 1 | 2450.00 |
+| 1 | 2850.00 |
+| 1 | 2975.00 |
+| 1 |  800.00 |
+| 1 |  950.00 |
+| 2 | 2500.00 |
++---+---------+
+(12 rows)
+
+!ok
+EnumerableCalc(expr#0..2=[{inputs}], C=[$t1], S=[$t2])
+  EnumerableAggregate(group=[{2}], C=[COUNT()], S=[SUM($2)])
+    EnumerableJoin(condition=[=($0, $3)], joinType=[inner])
+      EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
+        EnumerableTableScan(table=[[scott, DEPT]])
+      EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5], DEPTNO=[$t7])
+        EnumerableTableScan(table=[[scott, EMP]])
+!plan
+
+# Push sum, self-join, returning one row with a null value
+select sum(e.sal) as s
+from "scott".emp e join "scott".emp m on e.mgr = e.empno;
++---+
+| S |
++---+
+|   |
++---+
+(1 row)
+
+!ok
+
+# Push sum, self-join
+select sum(e.sal) as s
+from "scott".emp e join "scott".emp m on e.mgr = m.empno;
++----------+
+| S        |
++----------+
+| 24025.00 |
++----------+
+(1 row)
+
+!ok
+
+# Push sum, self-join, aggregate by column on "many" side
+select sum(e.sal) as s
+from "scott".emp e join "scott".emp m on e.mgr = m.empno
+group by m.empno;
++---------+
+| S       |
++---------+
+| 1100.00 |
+| 1300.00 |
+| 6000.00 |
+| 6550.00 |
+|  800.00 |
+| 8275.00 |
++---------+
+(6 rows)
+
+!ok
+
+# Push sum, self-join, aggregate by column on "one" side.
+# Note inflated totals due to cartesian product.
+select sum(m.sal) as s
+from "scott".emp e join "scott".emp m on e.mgr = m.empno
+group by m.empno;
++----------+
+| S        |
++----------+
+| 14250.00 |
+| 15000.00 |
+|  2450.00 |
+|  3000.00 |
+|  3000.00 |
+|  5950.00 |
++----------+
+(6 rows)
+
+!ok
+
 # [CALCITE-729] IndexOutOfBoundsException in ROLLUP query on JDBC data source
 !use jdbc_scott
 select deptno, job, count(*) as c

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cf7a7a97/core/src/test/resources/sql/join.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/join.oq b/core/src/test/resources/sql/join.oq
index bb273dc..0c69e2a 100644
--- a/core/src/test/resources/sql/join.oq
+++ b/core/src/test/resources/sql/join.oq
@@ -122,11 +122,12 @@ from "scott".emp join "scott".dept using (deptno);
 (3 rows)
 
 !ok
-EnumerableJoin(condition=[=($0, $1)], joinType=[inner])
-  EnumerableAggregate(group=[{0}])
-    EnumerableTableScan(table=[[scott, DEPT]])
-  EnumerableAggregate(group=[{7}])
-    EnumerableTableScan(table=[[scott, EMP]])
+EnumerableAggregate(group=[{0, 2}])
+  EnumerableJoin(condition=[=($0, $2)], joinType=[inner])
+    EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
+      EnumerableTableScan(table=[[scott, DEPT]])
+    EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], DEPTNO=[$t7])
+      EnumerableTableScan(table=[[scott, EMP]])
 !plan
 
 select distinct dept.deptno

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cf7a7a97/plus/src/test/java/org/apache/calcite/adapter/tpcds/TpcdsTest.java
----------------------------------------------------------------------
diff --git a/plus/src/test/java/org/apache/calcite/adapter/tpcds/TpcdsTest.java b/plus/src/test/java/org/apache/calcite/adapter/tpcds/TpcdsTest.java
index 9f855f2..15fc496 100644
--- a/plus/src/test/java/org/apache/calcite/adapter/tpcds/TpcdsTest.java
+++ b/plus/src/test/java/org/apache/calcite/adapter/tpcds/TpcdsTest.java
@@ -16,11 +16,21 @@
  */
 package org.apache.calcite.adapter.tpcds;
 
+import org.apache.calcite.jdbc.CalciteConnection;
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.plan.RelTraitDef;
 import org.apache.calcite.prepare.Prepare;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.calcite.runtime.Hook;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.parser.SqlParser;
 import org.apache.calcite.test.CalciteAssert;
+import org.apache.calcite.tools.Frameworks;
 import org.apache.calcite.tools.Program;
 import org.apache.calcite.tools.Programs;
+import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.util.Bug;
 import org.apache.calcite.util.Holder;
 import org.apache.calcite.util.Pair;
@@ -141,6 +151,10 @@ public class TpcdsTest {
                 + "                EnumerableTableAccessRel(table=[[TPCDS, CATALOG_SALES]]): rowcount = 1441548.0, cumulative cost = {1441548.0 rows, 1441549.0 cpu, 0.0 io}\n"));
   }
 
+  @Test public void testQuery27() {
+    checkQuery(27).runs();
+  }
+
   @Test public void testQuery58() {
     checkQuery(58).explainContains("PLAN").runs();
   }
@@ -189,6 +203,95 @@ public class TpcdsTest {
     return with()
         .query(sql.replaceAll("tpcds\\.", "tpcds_01."));
   }
+
+  public Frameworks.ConfigBuilder config() throws Exception {
+    final Holder<SchemaPlus> root = Holder.of(null);
+    CalciteAssert.model(TPCDS_MODEL)
+        .doWithConnection(
+            new Function<CalciteConnection, Object>() {
+              public Object apply(CalciteConnection input) {
+                root.set(input.getRootSchema().getSubSchema("TPCDS"));
+                return null;
+              }
+            });
+    return Frameworks.newConfigBuilder()
+        .parserConfig(SqlParser.Config.DEFAULT)
+        .defaultSchema(root.get())
+        .traitDefs((List<RelTraitDef>) null)
+        .programs(Programs.heuristicJoinOrder(Programs.RULE_SET, true, 2));
+  }
+
+  /**
+   * Builder query 27 using {@link RelBuilder}.
+   *
+   * <blockquote><pre>
+   *   select  i_item_id,
+   *         s_state, grouping(s_state) g_state,
+   *         avg(ss_quantity) agg1,
+   *         avg(ss_list_price) agg2,
+   *         avg(ss_coupon_amt) agg3,
+   *         avg(ss_sales_price) agg4
+   * from store_sales, customer_demographics, date_dim, store, item
+   * where ss_sold_date_sk = d_date_sk and
+   *        ss_item_sk = i_item_sk and
+   *        ss_store_sk = s_store_sk and
+   *        ss_cdemo_sk = cd_demo_sk and
+   *        cd_gender = 'dist(gender, 1, 1)' and
+   *        cd_marital_status = 'dist(marital_status, 1, 1)' and
+   *        cd_education_status = 'dist(education, 1, 1)' and
+   *        d_year = 1998 and
+   *        s_state in ('distmember(fips_county,[STATENUMBER.1], 3)',
+   *              'distmember(fips_county,[STATENUMBER.2], 3)',
+   *              'distmember(fips_county,[STATENUMBER.3], 3)',
+   *              'distmember(fips_county,[STATENUMBER.4], 3)',
+   *              'distmember(fips_county,[STATENUMBER.5], 3)',
+   *              'distmember(fips_county,[STATENUMBER.6], 3)')
+   *  group by rollup (i_item_id, s_state)
+   *  order by i_item_id
+   *          ,s_state
+   *  LIMIT 100
+   * </pre></blockquote>
+   */
+  @Test public void testQuery27Builder() throws Exception {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    final RelNode root =
+        builder.scan("STORE_SALES")
+            .scan("CUSTOMER_DEMOGRAPHICS")
+            .scan("DATE_DIM")
+            .scan("STORE")
+            .scan("ITEM")
+            .join(JoinRelType.INNER)
+            .join(JoinRelType.INNER)
+            .join(JoinRelType.INNER)
+            .join(JoinRelType.INNER)
+            .filter(
+                builder.equals(builder.field("SS_SOLD_DATE_SK"), builder.field("D_DATE_SK")),
+                builder.equals(builder.field("SS_ITEM_SK"), builder.field("I_ITEM_SK")),
+                builder.equals(builder.field("SS_STORE_SK"), builder.field("S_STORE_SK")),
+                builder.equals(builder.field("SS_CDEMO_SK"), builder.field("CD_DEMO_SK")),
+                builder.equals(builder.field("CD_GENDER"), builder.literal("M")),
+                builder.equals(builder.field("CD_MARITAL_STATUS"), builder.literal("S")),
+                builder.equals(builder.field("CD_EDUCATION_STATUS"),
+                    builder.literal("HIGH SCHOOL")),
+                builder.equals(builder.field("D_YEAR"), builder.literal(1998)),
+                builder.call(SqlStdOperatorTable.IN,
+                    builder.field("S_STATE"),
+                    builder.call(SqlStdOperatorTable.ARRAY_VALUE_CONSTRUCTOR,
+                        builder.literal("CA"),
+                        builder.literal("OR"),
+                        builder.literal("WA"),
+                        builder.literal("TX"),
+                        builder.literal("OK"),
+                        builder.literal("MD"))))
+            .aggregate(builder.groupKey("I_ITEM_ID", "S_STATE"),
+                builder.avg(false, "AGG1", builder.field("SS_QUANTITY")),
+                builder.avg(false, "AGG2", builder.field("SS_LIST_PRICE")),
+                builder.avg(false, "AGG3", builder.field("SS_COUPON_AMT")),
+                builder.avg(false, "AGG4", builder.field("SS_SALES_PRICE")))
+            .sortLimit(0, 100, builder.field("I_ITEM_ID"), builder.field("S_STATE"))
+            .build();
+    System.out.println(RelOptUtil.toString(root));
+  }
 }
 
 // End TpcdsTest.java


[18/50] incubator-calcite git commit: Complete [CALCITE-783] by fixing some planner rules

Posted by jh...@apache.org.
Complete [CALCITE-783] by fixing some planner rules


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

Branch: refs/heads/branch-release
Commit: 9177063b5217ba01a7a34f85a0bf8e8753adeb20
Parents: c711fed
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Jul 9 15:36:03 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Jul 20 21:20:05 2015 -0700

----------------------------------------------------------------------
 .../enumerable/EnumerableAggregateRule.java     |  2 +-
 .../enumerable/EnumerableProjectRule.java       | 12 ++++++
 .../apache/calcite/adapter/jdbc/JdbcRules.java  |  2 +-
 .../apache/calcite/prepare/RelOptTableImpl.java | 22 +----------
 .../apache/calcite/rel/RelFieldCollation.java   | 39 ++++++++++++++++++++
 .../calcite/rel/metadata/RelMdCollation.java    | 38 +++++++------------
 .../rel/rules/AggregateReduceFunctionsRule.java |  2 +-
 .../calcite/rel/rules/AggregateRemoveRule.java  |  2 +-
 .../apache/calcite/sql2rel/RelFieldTrimmer.java |  2 +-
 .../java/org/apache/calcite/test/JdbcTest.java  |  2 +-
 .../org/apache/calcite/test/LatticeTest.java    |  2 +-
 core/src/test/resources/sql/join.oq             | 10 ++---
 .../calcite/adapter/mongodb/MongoRules.java     |  2 +-
 13 files changed, 79 insertions(+), 58 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregateRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregateRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregateRule.java
index 340801f..aec578a 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregateRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregateRule.java
@@ -41,7 +41,7 @@ class EnumerableAggregateRule extends ConverterRule {
       return new EnumerableAggregate(
           rel.getCluster(),
           traitSet,
-          convert(agg.getInput(), traitSet),
+          convert(agg.getInput(), EnumerableConvention.INSTANCE),
           agg.indicator,
           agg.getGroupSet(),
           agg.getGroupSets(),

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
index b7dcc69..459e025 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
@@ -18,6 +18,8 @@ package org.apache.calcite.adapter.enumerable;
 
 import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.rel.RelCollationTraitDef;
+import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.convert.ConverterRule;
 import org.apache.calcite.rel.logical.LogicalProject;
@@ -34,6 +36,16 @@ class EnumerableProjectRule extends ConverterRule {
 
   public RelNode convert(RelNode rel) {
     final LogicalProject project = (LogicalProject) rel;
+    if (rel.getTraitSet().getTrait(RelCollationTraitDef.INSTANCE)
+        != RelCollations.PRESERVE) {
+      return EnumerableProject.create(
+          convert(project.getInput(),
+              project.getInput().getTraitSet()
+                  .replace(EnumerableConvention.INSTANCE)),
+          project.getProjects(),
+          project.getRowType());
+    }
+    // Special case for PRESERVE, to hand-create collation.
     return new EnumerableProject(rel.getCluster(),
         rel.getTraitSet().replace(EnumerableConvention.INSTANCE),
         convert(project.getInput(),

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
index f48f675..c52d7f3 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
@@ -680,7 +680,7 @@ public class JdbcRules {
           agg.getTraitSet().replace(out);
       try {
         return new JdbcAggregate(rel.getCluster(), traitSet,
-            convert(agg.getInput(), traitSet), agg.indicator, agg.getGroupSet(),
+            convert(agg.getInput(), out), agg.indicator, agg.getGroupSet(),
             agg.getGroupSets(), agg.getAggCallList());
       } catch (InvalidRelException e) {
         LOGGER.fine(e.toString());

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
index 9919cec..3a77256 100644
--- a/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
@@ -290,33 +290,13 @@ public class RelOptTableImpl implements Prepare.PreparingTable {
         final RelFieldCollation fieldCollation =
             collation.getFieldCollations().get(0);
         if (fieldCollation.getFieldIndex() == i) {
-          return monotonicity(fieldCollation.direction);
+          return fieldCollation.direction.monotonicity();
         }
       }
     }
     return SqlMonotonicity.NOT_MONOTONIC;
   }
 
-  /** Converts a {@link org.apache.calcite.rel.RelFieldCollation.Direction}
-   * value to a {@link org.apache.calcite.sql.validate.SqlMonotonicity}. */
-  private static SqlMonotonicity
-  monotonicity(RelFieldCollation.Direction direction) {
-    switch (direction) {
-    case ASCENDING:
-      return SqlMonotonicity.INCREASING;
-    case STRICTLY_ASCENDING:
-      return SqlMonotonicity.STRICTLY_INCREASING;
-    case DESCENDING:
-      return SqlMonotonicity.DECREASING;
-    case STRICTLY_DESCENDING:
-      return SqlMonotonicity.STRICTLY_DECREASING;
-    case CLUSTERED:
-      return SqlMonotonicity.MONOTONIC;
-    default:
-      throw new AssertionError("unknown: " + direction);
-    }
-  }
-
   public SqlAccessType getAllowedAccess() {
     return SqlAccessType.ALL;
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/main/java/org/apache/calcite/rel/RelFieldCollation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/RelFieldCollation.java b/core/src/main/java/org/apache/calcite/rel/RelFieldCollation.java
index fb54412..7fa2274 100644
--- a/core/src/main/java/org/apache/calcite/rel/RelFieldCollation.java
+++ b/core/src/main/java/org/apache/calcite/rel/RelFieldCollation.java
@@ -16,6 +16,8 @@
  */
 package org.apache.calcite.rel;
 
+import org.apache.calcite.sql.validate.SqlMonotonicity;
+
 /**
  * Definition of the ordering of one field of a {@link RelNode} whose
  * output is to be sorted.
@@ -81,6 +83,43 @@ public class RelFieldCollation {
     Direction(String shortString) {
       this.shortString = shortString;
     }
+
+    /** Converts thie direction to a
+     * {@link org.apache.calcite.sql.validate.SqlMonotonicity}. */
+    public SqlMonotonicity monotonicity() {
+      switch (this) {
+      case ASCENDING:
+        return SqlMonotonicity.INCREASING;
+      case STRICTLY_ASCENDING:
+        return SqlMonotonicity.STRICTLY_INCREASING;
+      case DESCENDING:
+        return SqlMonotonicity.DECREASING;
+      case STRICTLY_DESCENDING:
+        return SqlMonotonicity.STRICTLY_DECREASING;
+      case CLUSTERED:
+        return SqlMonotonicity.MONOTONIC;
+      default:
+        throw new AssertionError("unknown: " + this);
+      }
+    }
+
+    /** Converts a {@link SqlMonotonicity} to a direction. */
+    public static Direction of(SqlMonotonicity monotonicity) {
+      switch (monotonicity) {
+      case INCREASING:
+        return ASCENDING;
+      case DECREASING:
+        return DESCENDING;
+      case STRICTLY_INCREASING:
+        return STRICTLY_ASCENDING;
+      case STRICTLY_DECREASING:
+        return STRICTLY_DESCENDING;
+      case MONOTONIC:
+        return CLUSTERED;
+      default:
+        throw new AssertionError("unknown: " + monotonicity);
+      }
+    }
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
index cf0614b..37ce6da 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
@@ -54,6 +54,7 @@ import com.google.common.collect.Multimap;
 import com.google.common.collect.Ordering;
 import com.google.common.collect.Sets;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
@@ -219,13 +220,20 @@ public class RelMdCollation {
       collations.add(RelCollations.of(fieldCollations));
     }
 
-    final List<RelFieldCollation> fieldCollationsForRexCalls = Lists.newArrayList();
-    for (Map.Entry<Integer, SqlMonotonicity> targetMonotonicity
+    final List<RelFieldCollation> fieldCollationsForRexCalls =
+        new ArrayList<>();
+    for (Map.Entry<Integer, SqlMonotonicity> entry
         : targetsWithMonotonicity.entrySet()) {
-      if (targetMonotonicity.getValue() != SqlMonotonicity.NOT_MONOTONIC
-          && targetMonotonicity.getValue() != SqlMonotonicity.CONSTANT) {
-        fieldCollationsForRexCalls.add(new RelFieldCollation(targetMonotonicity.getKey(),
-            monotonicityToDirection(targetMonotonicity.getValue())));
+      final SqlMonotonicity value = entry.getValue();
+      switch (value) {
+      case NOT_MONOTONIC:
+      case CONSTANT:
+        break;
+      default:
+        fieldCollationsForRexCalls.add(
+            new RelFieldCollation(entry.getKey(),
+                RelFieldCollation.Direction.of(value)));
+        break;
       }
     }
 
@@ -236,24 +244,6 @@ public class RelMdCollation {
     return ImmutableList.copyOf(collations);
   }
 
-  private static RelFieldCollation.Direction monotonicityToDirection(SqlMonotonicity monotonicity) {
-    switch (monotonicity) {
-    case INCREASING:
-      return RelFieldCollation.Direction.ASCENDING;
-    case DECREASING:
-      return RelFieldCollation.Direction.DESCENDING;
-    case STRICTLY_INCREASING:
-      return RelFieldCollation.Direction.STRICTLY_ASCENDING;
-    case STRICTLY_DECREASING:
-      return RelFieldCollation.Direction.STRICTLY_DESCENDING;
-    case MONOTONIC:
-      return RelFieldCollation.Direction.CLUSTERED;
-    default:
-      throw new IllegalStateException(
-          String.format("SQL monotonicity of type %s is not allowed at this stage.", monotonicity));
-    }
-  }
-
   /** Helper method to determine a
    * {@link org.apache.calcite.rel.core.Window}'s collation.
    *

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
index 2a79f14..3a33e16 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
@@ -340,7 +340,7 @@ public class AggregateReduceFunctionsRule extends RelOptRule {
             argType, argType.isNullable());
     final AggregateCall sumZeroCall =
         AggregateCall.create(SqlStdOperatorTable.SUM0, oldCall.isDistinct(),
-            oldCall.getArgList(), oldCall.filterArg, sumType, null);
+            oldCall.getArgList(), oldCall.filterArg, sumType, oldCall.name);
     final AggregateCall countCall =
         AggregateCall.create(
             SqlStdOperatorTable.COUNT,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java
index 6031717..12f735c 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java
@@ -63,7 +63,7 @@ public class AggregateRemoveRule extends RelOptRule {
     // Distinct is "GROUP BY c1, c2" (where c1, c2 are a set of columns on
     // which the input is unique, i.e. contain a key) and has no aggregate
     // functions. It can be removed.
-    final RelNode newInput = convert(input, aggregate.getTraitSet());
+    final RelNode newInput = convert(input, aggregate.getTraitSet().simplify());
 
     // If aggregate was projecting a subset of columns, add a project for the
     // same effect.

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
index 5e9e333..9e17837 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
@@ -200,7 +200,7 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
       fieldsUsed = ImmutableBitSet.range(input.getRowType().getFieldCount());
     }
     final ImmutableList<RelCollation> collations =
-        RelMetadataQuery.collations(rel);
+        RelMetadataQuery.collations(input);
     for (RelCollation collation : collations) {
       for (RelFieldCollation fieldCollation : collation.getFieldCollations()) {
         fieldsUsed = fieldsUsed.set(fieldCollation.getFieldIndex());

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index 941b88a..a037a23 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -3332,7 +3332,7 @@ public class JdbcTest {
             + "where \"deptno\" < 0")
         .explainContains(""
             + "PLAN=EnumerableCalc(expr#0..1=[{inputs}], expr#2=[0], expr#3=[=($t0, $t2)], expr#4=[null], expr#5=[CASE($t3, $t4, $t1)], expr#6=[/($t5, $t0)], expr#7=[CAST($t6):JavaType(class java.lang.Integer)], CS=[$t0], C=[$t0], S=[$t5], A=[$t7])\n"
-            + "  EnumerableAggregate(group=[{}], CS=[COUNT()], agg#1=[$SUM0($1)])\n"
+            + "  EnumerableAggregate(group=[{}], CS=[COUNT()], S=[$SUM0($1)])\n"
             + "    EnumerableCalc(expr#0..4=[{inputs}], expr#5=[0], expr#6=[<($t1, $t5)], proj#0..4=[{exprs}], $condition=[$t6])\n"
             + "      EnumerableTableScan(table=[[hr, emps]])\n")
         .returns("CS=0; C=0; S=null; A=null\n");

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/test/java/org/apache/calcite/test/LatticeTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/LatticeTest.java b/core/src/test/java/org/apache/calcite/test/LatticeTest.java
index 77e7943..b1155f0 100644
--- a/core/src/test/java/org/apache/calcite/test/LatticeTest.java
+++ b/core/src/test/java/org/apache/calcite/test/LatticeTest.java
@@ -436,7 +436,7 @@ public class LatticeTest {
                 + "GROUP BY \"s\".\"unit_sales\", \"p\".\"recyclable_package\", \"t\".\"the_day\", \"t\".\"the_year\", \"t\".\"quarter\", \"pc\".\"product_family\"")
         .explainContains(
             "JdbcToEnumerableConverter\n"
-                + "  JdbcAggregate(group=[{7, 16, 25, 27, 31, 37}], m0=[COUNT()], m1=[SUM($5)], m2=[SUM($7)])\n"
+                + "  JdbcAggregate(group=[{7, 16, 25, 27, 31, 37}], m0=[COUNT()], m1=[$SUM0($5)], m2=[$SUM0($7)])\n"
                 + "    JdbcJoin(condition=[=($8, $33)], joinType=[inner])\n"
                 + "      JdbcJoin(condition=[=($1, $23)], joinType=[inner])\n"
                 + "        JdbcJoin(condition=[=($0, $9)], joinType=[inner])\n"

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/test/resources/sql/join.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/join.oq b/core/src/test/resources/sql/join.oq
index 83cfb7c..bb273dc 100644
--- a/core/src/test/resources/sql/join.oq
+++ b/core/src/test/resources/sql/join.oq
@@ -142,10 +142,10 @@ from "scott".emp join "scott".dept using (deptno);
 
 !ok
 EnumerableAggregate(group=[{0}])
-  EnumerableJoin(condition=[=($0, $1)], joinType=[inner])
+  EnumerableJoin(condition=[=($0, $2)], joinType=[inner])
     EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
       EnumerableTableScan(table=[[scott, DEPT]])
-    EnumerableCalc(expr#0..7=[{inputs}], DEPTNO=[$t7])
+    EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], DEPTNO=[$t7])
       EnumerableTableScan(table=[[scott, EMP]])
 !plan
 
@@ -227,11 +227,11 @@ where e.deptno + 10 = d.deptno * 2;
 (9 rows)
 
 !ok
-EnumerableCalc(expr#0..3=[{inputs}], DEPTNO=[$t2], DEPTNO0=[$t0])
-  EnumerableJoin(condition=[=($1, $3)], joinType=[inner])
+EnumerableCalc(expr#0..4=[{inputs}], DEPTNO=[$t3], DEPTNO0=[$t0])
+  EnumerableJoin(condition=[=($1, $4)], joinType=[inner])
     EnumerableCalc(expr#0..2=[{inputs}], expr#3=[2], expr#4=[*($t0, $t3)], DEPTNO=[$t0], $f1=[$t4])
       EnumerableTableScan(table=[[scott, DEPT]])
-    EnumerableCalc(expr#0..7=[{inputs}], expr#8=[10], expr#9=[+($t7, $t8)], DEPTNO=[$t7], $f1=[$t9])
+    EnumerableCalc(expr#0..7=[{inputs}], expr#8=[10], expr#9=[+($t7, $t8)], EMPNO=[$t0], DEPTNO=[$t7], $f2=[$t9])
       EnumerableTableScan(table=[[scott, EMP]])
 !plan
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
----------------------------------------------------------------------
diff --git a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
index e7596b3..50478ee 100644
--- a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
+++ b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
@@ -512,7 +512,7 @@ public class MongoRules {
         return new MongoAggregate(
             rel.getCluster(),
             traitSet,
-            convert(agg.getInput(), traitSet),
+            convert(agg.getInput(), traitSet.simplify()),
             agg.indicator,
             agg.getGroupSet(),
             agg.getGroupSets(),


[12/50] incubator-calcite git commit: [CALCITE-786] Detect if materialized view can be used to rewrite a query in non-trivial cases (Amogh Margoor)

Posted by jh...@apache.org.
[CALCITE-786] Detect if materialized view can be used to rewrite a query in non-trivial cases (Amogh Margoor)

Close apache/incubator-calcite#102


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

Branch: refs/heads/branch-release
Commit: 4a9b19390b2f9ab5a6d3bc2340c323d3a39cfa80
Parents: 220a085
Author: Amogh Margoor <am...@qubole.com>
Authored: Thu Jun 11 15:18:52 2015 +0530
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jul 16 13:22:39 2015 -0700

----------------------------------------------------------------------
 .../MaterializedViewSubstitutionVisitor.java    | 170 +++++++
 .../org/apache/calcite/plan/RelOptUtil.java     |   4 +-
 .../calcite/plan/RexImplicationChecker.java     | 377 ++++++++++++++++
 .../calcite/plan/SubstitutionVisitor.java       | 183 +++++---
 .../apache/calcite/plan/VisitorDataContext.java | 186 ++++++++
 .../calcite/plan/volcano/VolcanoPlanner.java    |   9 +-
 .../java/org/apache/calcite/rex/RexUtil.java    | 105 +++++
 .../org/apache/calcite/test/CalciteSuite.java   |   1 +
 .../calcite/test/MaterializationTest.java       | 140 +++++-
 .../calcite/test/RexImplicationCheckerTest.java | 448 +++++++++++++++++++
 10 files changed, 1558 insertions(+), 65 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4a9b1939/core/src/main/java/org/apache/calcite/plan/MaterializedViewSubstitutionVisitor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/MaterializedViewSubstitutionVisitor.java b/core/src/main/java/org/apache/calcite/plan/MaterializedViewSubstitutionVisitor.java
new file mode 100644
index 0000000..e367f93
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/plan/MaterializedViewSubstitutionVisitor.java
@@ -0,0 +1,170 @@
+/*
+ * 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.plan;
+
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexShuttle;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+/**
+ * Substitutes part of a tree of relational expressions with another tree.
+ *
+ * <p>The call {@code new MaterializedSubstitutionVisitor(target, query).go(replacement))}
+ * will return {@code query} with every occurrence of {@code target} replaced
+ * by {@code replacement}.</p>
+ *
+ * <p>The following example shows how {@code MaterializedSubstitutionVisitor} can be used
+ * for materialized view recognition.</p>
+ *
+ * <ul>
+ * <li>query = SELECT a, c FROM t WHERE x = 5 AND b = 4</li>
+ * <li>target = SELECT a, b, c FROM t WHERE x = 5</li>
+ * <li>replacement = SELECT * FROM mv</li>
+ * <li>result = SELECT a, c FROM mv WHERE b = 4</li>
+ * </ul>
+ *
+ * <p>Note that {@code result} uses the materialized view table {@code mv} and a
+ * simplified condition {@code b = 4}.</p>
+ *
+ * <p>Uses a bottom-up matching algorithm. Nodes do not need to be identical.
+ * At each level, returns the residue.</p>
+ *
+ * <p>The inputs must only include the core relational operators:
+ * {@link org.apache.calcite.rel.logical.LogicalTableScan},
+ * {@link LogicalFilter},
+ * {@link LogicalProject},
+ * {@link org.apache.calcite.rel.logical.LogicalJoin},
+ * {@link LogicalUnion},
+ * {@link LogicalAggregate}.</p>
+ */
+public class MaterializedViewSubstitutionVisitor extends SubstitutionVisitor {
+
+  public MaterializedViewSubstitutionVisitor(RelNode target_, RelNode query_) {
+    super(target_, query_);
+    ImmutableList.Builder<UnifyRule> builder = new ImmutableList.Builder<UnifyRule>();
+    builder.addAll(this.unifyRules);
+    builder.add(ProjectToProjectUnifyRule1.INSTANCE);
+    this.unifyRules = builder.build();
+  }
+
+  public RelNode go(RelNode replacement_) {
+    return super.go(replacement_);
+  }
+
+  /**
+   * Project to Project Unify rule.
+   */
+
+  private static class ProjectToProjectUnifyRule1 extends AbstractUnifyRule {
+    public static final ProjectToProjectUnifyRule1 INSTANCE =
+        new ProjectToProjectUnifyRule1();
+
+    private ProjectToProjectUnifyRule1() {
+      super(operand(MutableProject.class, query(0)),
+          operand(MutableProject.class, target(0)), 1);
+    }
+
+    @Override
+    protected UnifyResult apply(UnifyRuleCall call) {
+      final MutableProject query = (MutableProject) call.query;
+
+      final List<RelDataTypeField> oldFieldList = query.getInput().getRowType().getFieldList();
+      final List<RelDataTypeField> newFieldList = call.target.getRowType().getFieldList();
+      List<RexNode> newProjects;
+      try {
+        newProjects = transformRex(query.getProjects(), oldFieldList, newFieldList);
+      } catch (MatchFailed e) {
+        return null;
+      }
+
+      final MutableProject newProject =
+          MutableProject.of(
+              query.getRowType(), call.target, newProjects);
+
+      final MutableRel newProject2 = MutableRels.strip(newProject);
+      return call.result(newProject2);
+    }
+
+    @Override
+    protected UnifyRuleCall match(SubstitutionVisitor visitor, MutableRel query,
+        MutableRel target) {
+      assert query instanceof MutableProject && target instanceof MutableProject;
+
+      if (queryOperand.matches(visitor, query)) {
+        if (targetOperand.matches(visitor, target)) {
+          return null;
+        } else if (targetOperand.isWeaker(visitor, target)) {
+
+          final MutableProject queryProject = (MutableProject) query;
+          if (queryProject.getInput() instanceof MutableFilter) {
+
+            final MutableFilter innerFilter = (MutableFilter) (queryProject.getInput());
+            RexNode newCondition;
+            try {
+              newCondition = transformRex(innerFilter.getCondition(),
+                  innerFilter.getInput().getRowType().getFieldList(),
+                  target.getRowType().getFieldList());
+            } catch (MatchFailed e) {
+              return null;
+            }
+            final MutableFilter newFilter = MutableFilter.of(target,
+                newCondition);
+
+            return visitor.new UnifyRuleCall(this, query, newFilter,
+                copy(visitor.getSlots(), slotCount));
+          }
+        }
+      }
+      return null;
+    }
+
+    private RexNode transformRex(
+        RexNode node,
+        final List<RelDataTypeField> oldFields,
+        final List<RelDataTypeField> newFields) {
+      List<RexNode> nodes = transformRex(ImmutableList.of(node), oldFields, newFields);
+      return nodes.get(0);
+    }
+
+    private List<RexNode> transformRex(
+        List<RexNode> nodes,
+        final List<RelDataTypeField> oldFields,
+        final List<RelDataTypeField> newFields) {
+      RexShuttle shuttle = new RexShuttle() {
+        @Override public RexNode visitInputRef(RexInputRef ref) {
+          RelDataTypeField f = oldFields.get(ref.getIndex());
+          for (int index = 0; index < newFields.size(); index++) {
+            RelDataTypeField newf = newFields.get(index);
+            if (f.getKey().equals(newf.getKey())
+                && f.getValue() == newf.getValue()) {
+              return new RexInputRef(index, f.getValue());
+            }
+          }
+          throw MatchFailed.INSTANCE;
+        }
+      };
+      return shuttle.apply(nodes);
+    }
+  }
+}
+
+// End MaterializedViewSubstitutionVisitor.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4a9b1939/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
index 5aa2177..c1f8af5 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -1199,7 +1199,7 @@ public abstract class RelOptUtil {
         false);
   }
 
-  private static SqlKind reverse(SqlKind kind) {
+  public static SqlKind reverse(SqlKind kind) {
     switch (kind) {
     case GREATER_THAN:
       return SqlKind.LESS_THAN;
@@ -1214,7 +1214,7 @@ public abstract class RelOptUtil {
     }
   }
 
-  private static SqlOperator op(SqlKind kind, SqlOperator operator) {
+  public static SqlOperator op(SqlKind kind, SqlOperator operator) {
     switch (kind) {
     case EQUALS:
       return SqlStdOperatorTable.EQUALS;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4a9b1939/core/src/main/java/org/apache/calcite/plan/RexImplicationChecker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RexImplicationChecker.java b/core/src/main/java/org/apache/calcite/plan/RexImplicationChecker.java
new file mode 100644
index 0000000..1eb019d
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/plan/RexImplicationChecker.java
@@ -0,0 +1,377 @@
+/*
+ * 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.plan;
+
+import org.apache.calcite.DataContext;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexCall;
+import org.apache.calcite.rex.RexExecutable;
+import org.apache.calcite.rex.RexExecutorImpl;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.rex.RexVisitorImpl;
+import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlOperator;
+import org.apache.calcite.sql.fun.SqlCastFunction;
+import org.apache.calcite.util.Pair;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+
+/** Checks if Condition X logically implies Condition Y
+ *
+ * <p>(x > 10) implies (x > 5)</p>
+ *
+ * <p>(y = 10) implies (y < 30 AND x > 30)</p>
+ */
+public class RexImplicationChecker {
+  final RexBuilder builder;
+  final RexExecutorImpl rexImpl;
+  final RelDataType rowType;
+
+  public RexImplicationChecker(
+      RexBuilder builder,
+      RexExecutorImpl rexImpl,
+      RelDataType rowType) {
+    this.builder = builder;
+    this.rexImpl = rexImpl;
+    this.rowType = rowType;
+  }
+
+  /**
+   * Checks if condition first implies (=>) condition second
+   * This reduces to SAT problem which is NP-Complete
+   * When func says first => second then it is definitely true
+   * It cannot prove if first doesnot imply second.
+   * @param first first condition
+   * @param second second condition
+   * @return true if it can prove first => second, otherwise false i.e.,
+   * it doesn't know if implication holds .
+   */
+  public boolean implies(RexNode first, RexNode second) {
+
+    // Validation
+    if (!validate(first, second)) {
+      return false;
+    }
+
+    RexCall firstCond = (RexCall) first;
+    RexCall secondCond = (RexCall) second;
+
+    // Get DNF
+    RexNode firstDnf = RexUtil.toDnf(builder, first);
+    RexNode secondDnf = RexUtil.toDnf(builder, second);
+
+    // Check Trivial Cases
+    if (firstDnf.isAlwaysFalse()
+        || secondDnf.isAlwaysTrue()) {
+      return true;
+    }
+
+    /** Decompose DNF into List of Conjunctions
+     *
+     * (x > 10 AND y > 30) OR (z > 90) will be converted to
+     * list of 2 conditions:
+     * 1. (x > 10 AND y > 30)
+     * 2. (z > 90)
+     *
+     */
+    List<RexNode> firstDnfs = RelOptUtil.disjunctions(firstDnf);
+    List<RexNode> secondDnfs = RelOptUtil.disjunctions(secondDnf);
+
+    for (RexNode f : firstDnfs) {
+      if (!f.isAlwaysFalse()) {
+        //Check if f implies atleast
+        // one of the conjunctions in list secondDnfs
+        boolean implyOneConjuntion = false;
+        for (RexNode s : secondDnfs) {
+          if (s.isAlwaysFalse()) { // f cannot imply s
+            continue;
+          }
+
+          if (impliesConjunction(f, s)) {
+            // Satisfies one of the condition, so lets
+            // move to next conjunction in firstDnfs
+            implyOneConjuntion = true;
+            break;
+          }
+        } //end of inner loop
+
+        // If f couldnot imply even one conjunction in
+        // secondDnfs, then final implication may be false
+        if (!implyOneConjuntion) {
+          return false;
+        }
+      }
+    } //end of outer loop
+
+    return true;
+  }
+
+  /** Checks if Conjunction first => Conjunction second**/
+  private boolean impliesConjunction(RexNode first, RexNode second) {
+
+    InputUsageFinder firstUsgFinder = new InputUsageFinder();
+    InputUsageFinder secondUsgFinder = new InputUsageFinder();
+
+    RexUtil.apply(firstUsgFinder, new ArrayList<RexNode>(), first);
+    RexUtil.apply(secondUsgFinder, new ArrayList<RexNode>(), second);
+
+    // Check Support
+    if (!checkSupport(firstUsgFinder, secondUsgFinder)) {
+      return false;
+    }
+
+    List<Pair<RexInputRef, RexNode>> usgList = new ArrayList<>();
+    for (Map.Entry<RexInputRef, InputRefUsage<SqlOperator,
+        RexNode>> entry: firstUsgFinder.usageMap.entrySet()) {
+      final List<Pair<SqlOperator, RexNode>> list = entry.getValue().getUsageList();
+      usgList.add(Pair.of(entry.getKey(), list.get(0).getValue()));
+    }
+
+    /* Get the literals from first conjunction and execute second conjunction using them
+     * E.g., for x >30 => x > 10,
+     * we will replace x by 30 in second expression and execute it i.e., 30>10
+     * If it's true then we infer implication.
+     */
+    final DataContext dataValues = VisitorDataContext.getDataContext(rowType, usgList);
+
+    if (dataValues == null) {
+      return false;
+    }
+
+    ImmutableList<RexNode> constExps = ImmutableList.of(second);
+    final RexExecutable exec = rexImpl.getExecutable(builder,
+        constExps, rowType);
+
+    Object[] result;
+    exec.setDataContext(dataValues);
+    try {
+      result = exec.execute();
+    } catch (Exception e) {
+      // TODO: CheckSupport should not allow this exception to be thrown
+      // Need to monitor it and handle all the cases raising them.
+      return false;
+    }
+    return result != null && result.length == 1 && result[0] instanceof Boolean
+        && (Boolean) result[0];
+  }
+
+  /**
+   * Looks at the usage of variables in first and second conjunction to decide
+   * if this kind of expression is currently supported for proving first => second.
+   * 1. Variables should be used only once in both the conjunction against
+   *    given set of operations only: >,<,<=,>=,=,!=
+   * 2. All the variables used in second condition should be used even in the first.
+   * 3. If operator used for variable in first is op1 and op2 for second, then we support
+   *    these combination for conjunction (op1, op2) then op1, op2 belongs to
+   *    one of the following sets:
+   *    a. (<,<=) X (<,<=) , X represents cartesian product
+   *    b. (>/>=) X (>,>=)
+   *    c. (=) X (>,>=,<,<=,=,!=)
+   *    d. (!=, =)
+   * @return true, if input usage pattern is supported. Otherwise, false.
+   */
+  private boolean checkSupport(
+      InputUsageFinder firstUsgFinder,
+      InputUsageFinder secondUsgFinder) {
+    Map<RexInputRef, InputRefUsage<SqlOperator,
+        RexNode>> firstUsgMap = firstUsgFinder.usageMap;
+    Map<RexInputRef, InputRefUsage<SqlOperator,
+        RexNode>> secondUsgMap = secondUsgFinder.usageMap;
+
+    for (Map.Entry<RexInputRef, InputRefUsage<SqlOperator,
+        RexNode>> entry: firstUsgMap.entrySet()) {
+      if (entry.getValue().usageCount > 1) {
+        return false;
+      }
+    }
+
+    for (Map.Entry<RexInputRef, InputRefUsage<SqlOperator,
+        RexNode>> entry: secondUsgMap.entrySet()) {
+      final InputRefUsage<SqlOperator, RexNode> secondUsage = entry.getValue();
+      if (secondUsage.getUsageCount() > 1
+          || secondUsage.getUsageList().size() != 1) {
+        return false;
+      }
+
+      final InputRefUsage<SqlOperator, RexNode> firstUsage = firstUsgMap.get(entry.getKey());
+      if (firstUsage == null
+          || firstUsage.getUsageList().size() != 1) {
+        return false;
+      }
+
+      final Pair<SqlOperator, RexNode> fUse = firstUsage.getUsageList().get(0);
+      final Pair<SqlOperator, RexNode> sUse = secondUsage.getUsageList().get(0);
+
+      final SqlKind fkind = fUse.getKey().getKind();
+
+      if (fkind != SqlKind.EQUALS) {
+        switch (sUse.getKey().getKind()) {
+        case GREATER_THAN:
+        case GREATER_THAN_OR_EQUAL:
+          if (!(fkind == SqlKind.GREATER_THAN)
+              && !(fkind == SqlKind.GREATER_THAN_OR_EQUAL)) {
+            return false;
+          }
+          break;
+        case LESS_THAN:
+        case LESS_THAN_OR_EQUAL:
+          if (!(fkind == SqlKind.LESS_THAN)
+              && !(fkind == SqlKind.LESS_THAN_OR_EQUAL)) {
+            return false;
+          }
+          break;
+        default:
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+  private boolean validate(RexNode first, RexNode second) {
+    if (first == null || second == null) {
+      return false;
+    }
+    if (!(first instanceof RexCall)
+        || !(second instanceof RexCall)) {
+      return false;
+    }
+    return true;
+  }
+
+
+  /**
+   * Visitor which builds a Usage Map of inputs used by an expression.
+   * E.g: for x >10 AND y < 20 AND x =40, Usage Map would look like:
+   * key:x value: {(>,10),(=,40), usageCount = 2}
+   * key:y value: {(>,20),usageCount=1}
+   */
+  private static class InputUsageFinder extends RexVisitorImpl<Void> {
+    public final Map<RexInputRef, InputRefUsage<SqlOperator,
+        RexNode>> usageMap = new HashMap<>();
+
+    public InputUsageFinder() {
+      super(true);
+    }
+
+    public Void visitInputRef(RexInputRef inputRef) {
+      InputRefUsage<SqlOperator,
+          RexNode> inputRefUse = getUsageMap(inputRef);
+      inputRefUse.incrUsage();
+      return null;
+    }
+
+    @Override public Void visitCall(RexCall call) {
+      switch (call.getOperator().getKind()) {
+      case GREATER_THAN:
+      case GREATER_THAN_OR_EQUAL:
+      case LESS_THAN:
+      case LESS_THAN_OR_EQUAL:
+      case EQUALS:
+      case NOT_EQUALS:
+        updateUsage(call);
+        break;
+      default:
+      }
+      return super.visitCall(call);
+    }
+
+    private void updateUsage(RexCall call) {
+      final List<RexNode> operands = call.getOperands();
+      RexNode first = removeCast(operands.get(0));
+      RexNode second = removeCast(operands.get(1));
+
+      if (first.isA(SqlKind.INPUT_REF)
+          && second.isA(SqlKind.LITERAL)) {
+        updateUsage(call.getOperator(), (RexInputRef) first, second);
+      }
+
+      if (first.isA(SqlKind.LITERAL)
+          && second.isA(SqlKind.INPUT_REF)) {
+        updateUsage(reverse(call.getOperator()), (RexInputRef) second, first);
+      }
+    }
+
+    private SqlOperator reverse(SqlOperator op) {
+      return RelOptUtil.op(
+          RelOptUtil.reverse(op.getKind()), op);
+    }
+
+    private static RexNode removeCast(RexNode inputRef) {
+      if (inputRef instanceof RexCall) {
+        final RexCall castedRef = (RexCall) inputRef;
+        final SqlOperator operator = castedRef.getOperator();
+        if (operator instanceof SqlCastFunction) {
+          inputRef = castedRef.getOperands().get(0);
+        }
+      }
+      return inputRef;
+    }
+
+    private void updateUsage(SqlOperator op, RexInputRef inputRef, RexNode literal) {
+      InputRefUsage<SqlOperator,
+          RexNode> inputRefUse = getUsageMap(inputRef);
+      Pair<SqlOperator, RexNode> use = Pair.of(op, literal);
+      inputRefUse.getUsageList().add(use);
+    }
+
+    private InputRefUsage<SqlOperator, RexNode> getUsageMap(RexInputRef rex) {
+      InputRefUsage<SqlOperator, RexNode> inputRefUse = usageMap.get(rex);
+      if (inputRefUse == null) {
+        inputRefUse = new InputRefUsage<>();
+        usageMap.put(rex, inputRefUse);
+      }
+
+      return inputRefUse;
+    }
+  }
+
+  /**
+   * DataStructure to store usage of InputRefs in expression
+   */
+
+  private static class InputRefUsage<T1, T2> {
+    private final List<Pair<T1, T2>> usageList =
+        new ArrayList<Pair<T1, T2>>();
+    private int usageCount = 0;
+
+    public InputRefUsage() {}
+
+    public int getUsageCount() {
+      return usageCount;
+    }
+
+    public void incrUsage() {
+      usageCount++;
+    }
+
+    public List<Pair<T1, T2>> getUsageList() {
+      return usageList;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4a9b1939/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
index b1c89e6..62b2d9d 100644
--- a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
+++ b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
@@ -42,6 +42,7 @@ import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexCall;
+import org.apache.calcite.rex.RexExecutorImpl;
 import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
@@ -144,15 +145,7 @@ public class SubstitutionVisitor {
   private static final Equivalence<List<?>> PAIRWISE_STRING_EQUIVALENCE =
       (Equivalence) STRING_EQUIVALENCE.pairwise();
 
-  private static final List<UnifyRule> RULES =
-      ImmutableList.<UnifyRule>of(
-//          TrivialRule.INSTANCE,
-          ProjectToProjectUnifyRule.INSTANCE,
-          FilterToProjectUnifyRule.INSTANCE,
-//          ProjectToFilterUnifyRule.INSTANCE,
-          FilterToFilterUnifyRule.INSTANCE,
-          AggregateToAggregateUnifyRule.INSTANCE,
-          AggregateOnProjectToAggregateUnifyRule.INSTANCE);
+  protected static List<UnifyRule> unifyRules;
 
   private static final Map<Pair<Class, Class>, List<UnifyRule>> RULE_MAP =
       new HashMap<>();
@@ -208,6 +201,28 @@ public class SubstitutionVisitor {
     visitor.go(query);
     allNodes.removeAll(parents);
     queryLeaves = ImmutableList.copyOf(allNodes);
+    initUnifyRules();
+    initRuleMap();
+  }
+
+  public void initUnifyRules() {
+    unifyRules =
+            ImmutableList.<UnifyRule>of(
+//          TrivialRule.INSTANCE,
+                    ProjectToProjectUnifyRule.INSTANCE,
+                    FilterToProjectUnifyRule.INSTANCE,
+//          ProjectToFilterUnifyRule.INSTANCE,
+                    FilterToFilterUnifyRule.INSTANCE,
+                    AggregateToAggregateUnifyRule.INSTANCE,
+                    AggregateOnProjectToAggregateUnifyRule.INSTANCE);
+  }
+
+  public void initRuleMap() {
+    this.RULE_MAP.clear();
+  }
+
+  public MutableRel[] getSlots() {
+    return slots;
   }
 
   private static MutableRel toMutable(RelNode rel) {
@@ -457,7 +472,8 @@ public class SubstitutionVisitor {
               final UnifyResult result = rule.apply(call);
               if (result != null) {
                 ++count;
-                result.call.query.replaceInParent(result.result);
+                MutableRel parent = result.call.query.replaceInParent(result.result);
+
                 // Replace previous equivalents with new equivalents, higher up
                 // the tree.
                 for (int i = 0; i < rule.slotCount; i++) {
@@ -612,7 +628,7 @@ public class SubstitutionVisitor {
     if (list == null) {
       final ImmutableList.Builder<UnifyRule> builder =
           ImmutableList.builder();
-      for (UnifyRule rule : RULES) {
+      for (UnifyRule rule : unifyRules) {
         //noinspection unchecked
         if (mightMatch(rule, queryClass, targetClass)) {
           builder.add(rule);
@@ -631,8 +647,8 @@ public class SubstitutionVisitor {
   }
 
   /** Exception thrown to exit a matcher. Not really an error. */
-  private static class MatchFailed extends ControlFlowException {
-    static final MatchFailed INSTANCE = new MatchFailed();
+  protected static class MatchFailed extends ControlFlowException {
+    public static final MatchFailed INSTANCE = new MatchFailed();
   }
 
   /** Rule that attempts to match a query relational expression
@@ -641,7 +657,7 @@ public class SubstitutionVisitor {
    * <p>The rule declares the query and target types; this allows the
    * engine to fire only a few rules in a given context.</p>
    */
-  private abstract static class UnifyRule {
+  protected abstract static class UnifyRule {
     protected final int slotCount;
     protected final Operand queryOperand;
     protected final Operand targetOperand;
@@ -679,9 +695,9 @@ public class SubstitutionVisitor {
      *
      * @param call Input parameters
      */
-    abstract UnifyResult apply(UnifyRuleCall call);
+    protected abstract UnifyResult apply(UnifyRuleCall call);
 
-    UnifyRuleCall match(SubstitutionVisitor visitor, MutableRel query,
+    protected UnifyRuleCall match(SubstitutionVisitor visitor, MutableRel query,
         MutableRel target) {
       if (queryOperand.matches(visitor, query)) {
         if (targetOperand.matches(visitor, target)) {
@@ -692,7 +708,7 @@ public class SubstitutionVisitor {
       return null;
     }
 
-    private <E> ImmutableList<E> copy(E[] slots, int slotCount) {
+    protected <E> ImmutableList<E> copy(E[] slots, int slotCount) {
       // Optimize if there are 0 or 1 slots.
       switch (slotCount) {
       case 0:
@@ -708,11 +724,11 @@ public class SubstitutionVisitor {
   /**
    * Arguments to an application of a {@link UnifyRule}.
    */
-  private class UnifyRuleCall {
-    final UnifyRule rule;
-    final MutableRel query;
-    final MutableRel target;
-    final ImmutableList<MutableRel> slots;
+  protected class UnifyRuleCall {
+    protected final UnifyRule rule;
+    public final MutableRel query;
+    public final MutableRel target;
+    protected final ImmutableList<MutableRel> slots;
 
     public UnifyRuleCall(UnifyRule rule, MutableRel query, MutableRel target,
         ImmutableList<MutableRel> slots) {
@@ -722,7 +738,7 @@ public class SubstitutionVisitor {
       this.slots = Preconditions.checkNotNull(slots);
     }
 
-    UnifyResult result(MutableRel result) {
+    public UnifyResult result(MutableRel result) {
       assert MutableRels.contains(result, target);
       assert MutableRels.equalType("result", result, "query", query, true);
       MutableRel replace = replacementMap.get(target);
@@ -753,7 +769,7 @@ public class SubstitutionVisitor {
    * generated a {@code result} that is equivalent to {@code query} and
    * contains {@code target}.
    */
-  private static class UnifyResult {
+  protected static class UnifyResult {
     private final UnifyRuleCall call;
     // equivalent to "query", contains "result"
     private final MutableRel result;
@@ -766,7 +782,7 @@ public class SubstitutionVisitor {
   }
 
   /** Abstract base class for implementing {@link UnifyRule}. */
-  private abstract static class AbstractUnifyRule extends UnifyRule {
+  protected abstract static class AbstractUnifyRule extends UnifyRule {
     public AbstractUnifyRule(Operand queryOperand, Operand targetOperand,
         int slotCount) {
       super(slotCount, queryOperand, targetOperand);
@@ -787,24 +803,24 @@ public class SubstitutionVisitor {
     }
 
     /** Creates an operand with given inputs. */
-    static Operand operand(Class<? extends MutableRel> clazz,
+    protected static Operand operand(Class<? extends MutableRel> clazz,
         Operand... inputOperands) {
       return new InternalOperand(clazz, ImmutableList.copyOf(inputOperands));
     }
 
     /** Creates an operand that doesn't check inputs. */
-    static Operand any(Class<? extends MutableRel> clazz) {
+    protected static Operand any(Class<? extends MutableRel> clazz) {
       return new AnyOperand(clazz);
     }
 
     /** Creates an operand that matches a relational expression in the query. */
-    static Operand query(int ordinal) {
+    protected static Operand query(int ordinal) {
       return new QueryOperand(ordinal);
     }
 
     /** Creates an operand that matches a relational expression in the
      * target. */
-    static Operand target(int ordinal) {
+    protected static Operand target(int ordinal) {
       return new TargetOperand(ordinal);
     }
   }
@@ -860,6 +876,7 @@ public class SubstitutionVisitor {
     }
   }
 
+
   /** Implementation of {@link UnifyRule} that matches a {@link MutableFilter}
    * to a {@link MutableProject}. */
   private static class FilterToProjectUnifyRule extends AbstractUnifyRule {
@@ -899,7 +916,7 @@ public class SubstitutionVisitor {
       }
     }
 
-    private MutableRel invert(List<Pair<RexNode, String>> namedProjects,
+    protected MutableRel invert(List<Pair<RexNode, String>> namedProjects,
         MutableRel input,
         RexShuttle shuttle) {
       if (LOGGER.isLoggable(Level.FINER)) {
@@ -924,7 +941,7 @@ public class SubstitutionVisitor {
       return MutableProject.of(input, exprList, Pair.right(namedProjects));
     }
 
-    private MutableRel invert(MutableRel model, MutableRel input,
+    protected MutableRel invert(MutableRel model, MutableRel input,
         MutableProject project) {
       if (LOGGER.isLoggable(Level.FINER)) {
         LOGGER.finer("SubstitutionVisitor: invert:\n"
@@ -1194,7 +1211,7 @@ public class SubstitutionVisitor {
 
   /** Builds a shuttle that stores a list of expressions, and can map incoming
    * expressions to references to them. */
-  private static RexShuttle getRexShuttle(MutableProject target) {
+  protected static RexShuttle getRexShuttle(MutableProject target) {
     final Map<String, Integer> map = new HashMap<>();
     for (RexNode e : target.getProjects()) {
       map.put(e.toString(), map.size());
@@ -1258,7 +1275,7 @@ public class SubstitutionVisitor {
    * For this reason, you should use {@code MutableRel} for short-lived
    * operations, and transcribe back to {@code RelNode} when you are done.</p>
    */
-  private abstract static class MutableRel {
+  protected abstract static class MutableRel {
     MutableRel parent;
     int ordinalInParent;
     public final RelOptCluster cluster;
@@ -1317,6 +1334,8 @@ public class SubstitutionVisitor {
     @Override public final String toString() {
       return deep();
     }
+
+    public MutableRel getParent() { return parent; }
   }
 
   /** Implementation of {@link MutableRel} whose only purpose is to have a
@@ -1337,7 +1356,7 @@ public class SubstitutionVisitor {
 
    /** Abstract base class for implementations of {@link MutableRel} that have
    * no inputs. */
-  private abstract static class MutableLeafRel extends MutableRel {
+  protected abstract static class MutableLeafRel extends MutableRel {
     protected final RelNode rel;
 
     MutableLeafRel(MutableRelType type, RelNode rel) {
@@ -1359,7 +1378,7 @@ public class SubstitutionVisitor {
   }
 
   /** Mutable equivalent of {@link SingleRel}. */
-  private abstract static class MutableSingleRel extends MutableRel {
+  protected abstract static class MutableSingleRel extends MutableRel {
     protected MutableRel input;
 
     MutableSingleRel(MutableRelType type, RelDataType rowType,
@@ -1396,7 +1415,7 @@ public class SubstitutionVisitor {
 
   /** Mutable equivalent of
    * {@link org.apache.calcite.rel.logical.LogicalTableScan}. */
-  private static class MutableScan extends MutableLeafRel {
+  protected static class MutableScan extends MutableLeafRel {
     private MutableScan(TableScan rel) {
       super(MutableRelType.SCAN, rel);
     }
@@ -1422,7 +1441,7 @@ public class SubstitutionVisitor {
   }
 
   /** Mutable equivalent of {@link org.apache.calcite.rel.core.Values}. */
-  private static class MutableValues extends MutableLeafRel {
+  protected static class MutableValues extends MutableLeafRel {
     private MutableValues(Values rel) {
       super(MutableRelType.VALUES, rel);
     }
@@ -1449,7 +1468,7 @@ public class SubstitutionVisitor {
 
   /** Mutable equivalent of
    * {@link org.apache.calcite.rel.logical.LogicalProject}. */
-  private static class MutableProject extends MutableSingleRel {
+  protected static class MutableProject extends MutableSingleRel {
     private final List<RexNode> projects;
 
     private MutableProject(RelDataType rowType, MutableRel input,
@@ -1459,7 +1478,7 @@ public class SubstitutionVisitor {
       assert RexUtil.compatibleTypes(projects, rowType, true);
     }
 
-    static MutableProject of(RelDataType rowType, MutableRel input,
+    public static MutableProject of(RelDataType rowType, MutableRel input,
         List<RexNode> projects) {
       return new MutableProject(rowType, input, projects);
     }
@@ -1467,7 +1486,7 @@ public class SubstitutionVisitor {
     /** Equivalent to
      * {@link RelOptUtil#createProject(org.apache.calcite.rel.RelNode, java.util.List, java.util.List)}
      * for {@link MutableRel}. */
-    static MutableRel of(MutableRel child, List<RexNode> exprList,
+    public static MutableRel of(MutableRel child, List<RexNode> exprList,
         List<String> fieldNameList) {
       final RelDataType rowType =
           RexUtil.createStructType(child.cluster.getTypeFactory(), exprList,
@@ -1512,7 +1531,7 @@ public class SubstitutionVisitor {
 
   /** Mutable equivalent of
    * {@link org.apache.calcite.rel.logical.LogicalFilter}. */
-  private static class MutableFilter extends MutableSingleRel {
+  protected static class MutableFilter extends MutableSingleRel {
     private final RexNode condition;
 
     private MutableFilter(MutableRel input, RexNode condition) {
@@ -1520,7 +1539,7 @@ public class SubstitutionVisitor {
       this.condition = condition;
     }
 
-    static MutableFilter of(MutableRel input, RexNode condition) {
+    public static MutableFilter of(MutableRel input, RexNode condition) {
       return new MutableFilter(input, condition);
     }
 
@@ -1547,7 +1566,7 @@ public class SubstitutionVisitor {
 
   /** Mutable equivalent of
    * {@link org.apache.calcite.rel.logical.LogicalAggregate}. */
-  private static class MutableAggregate extends MutableSingleRel {
+  protected static class MutableAggregate extends MutableSingleRel {
     public final boolean indicator;
     private final ImmutableBitSet groupSet;
     private final ImmutableList<ImmutableBitSet> groupSets;
@@ -1611,7 +1630,7 @@ public class SubstitutionVisitor {
   }
 
   /** Mutable equivalent of {@link org.apache.calcite.rel.core.Sort}. */
-  private static class MutableSort extends MutableSingleRel {
+  protected static class MutableSort extends MutableSingleRel {
     private final RelCollation collation;
     private final RexNode offset;
     private final RexNode fetch;
@@ -1655,7 +1674,7 @@ public class SubstitutionVisitor {
   }
 
   /** Base class for set-operations. */
-  private abstract static class MutableSetOp extends MutableRel {
+  protected abstract static class MutableSetOp extends MutableRel {
     protected final List<MutableRel> inputs;
 
     private MutableSetOp(RelOptCluster cluster, RelDataType rowType,
@@ -1681,7 +1700,7 @@ public class SubstitutionVisitor {
 
   /** Mutable equivalent of
    * {@link org.apache.calcite.rel.logical.LogicalUnion}. */
-  private static class MutableUnion extends MutableSetOp {
+  protected static class MutableUnion extends MutableSetOp {
     public boolean all;
 
     private MutableUnion(RelOptCluster cluster, RelDataType rowType,
@@ -1820,7 +1839,7 @@ public class SubstitutionVisitor {
   }
 
   /** Utilities for dealing with {@link MutableRel}s. */
-  private static class MutableRels {
+  protected static class MutableRels {
     public static boolean contains(MutableRel ancestor,
         final MutableRel target) {
       if (ancestor.equals(target)) {
@@ -1951,7 +1970,7 @@ public class SubstitutionVisitor {
   }
 
   /** Visitor that prints an indented tree of {@link MutableRel}s. */
-  private static class MutableRelDumper extends MutableRelVisitor {
+  protected static class MutableRelDumper extends MutableRelVisitor {
     private final StringBuilder buf = new StringBuilder();
     private int level;
 
@@ -1975,14 +1994,18 @@ public class SubstitutionVisitor {
   }
 
   /** Operand to a {@link UnifyRule}. */
-  private abstract static class Operand {
+  protected abstract static class Operand {
     protected final Class<? extends MutableRel> clazz;
 
     protected Operand(Class<? extends MutableRel> clazz) {
       this.clazz = clazz;
     }
 
-    abstract boolean matches(SubstitutionVisitor visitor, MutableRel rel);
+    public abstract boolean matches(SubstitutionVisitor visitor, MutableRel rel);
+
+    public boolean isWeaker(SubstitutionVisitor visitor, MutableRel rel) {
+      return false;
+    }
   }
 
   /** Operand to a {@link UnifyRule} that matches a relational expression of a
@@ -1995,11 +2018,15 @@ public class SubstitutionVisitor {
       this.inputs = inputs;
     }
 
-    @Override boolean matches(SubstitutionVisitor visitor, MutableRel rel) {
+    @Override public boolean matches(SubstitutionVisitor visitor, MutableRel rel) {
       return clazz.isInstance(rel)
           && allMatch(visitor, inputs, rel.getInputs());
     }
 
+    @Override public boolean isWeaker(SubstitutionVisitor visitor, MutableRel rel) {
+      return clazz.isInstance(rel)
+          && allWeaker(visitor, inputs, rel.getInputs());
+    }
     private static boolean allMatch(SubstitutionVisitor visitor,
         List<Operand> operands, List<MutableRel> rels) {
       if (operands.size() != rels.size()) {
@@ -2012,6 +2039,20 @@ public class SubstitutionVisitor {
       }
       return true;
     }
+
+    private static boolean allWeaker(
+        SubstitutionVisitor visitor,
+        List<Operand> operands, List<MutableRel> rels) {
+      if (operands.size() != rels.size()) {
+        return false;
+      }
+      for (Pair<Operand, MutableRel> pair : Pair.zip(operands, rels)) {
+        if (!pair.left.isWeaker(visitor, pair.right)) {
+          return false;
+        }
+      }
+      return true;
+    }
   }
 
   /** Operand to a {@link UnifyRule} that matches a relational expression of a
@@ -2021,7 +2062,7 @@ public class SubstitutionVisitor {
       super(clazz);
     }
 
-    @Override boolean matches(SubstitutionVisitor visitor, MutableRel rel) {
+    @Override public boolean matches(SubstitutionVisitor visitor, MutableRel rel) {
       return clazz.isInstance(rel);
     }
   }
@@ -2042,7 +2083,7 @@ public class SubstitutionVisitor {
       this.ordinal = ordinal;
     }
 
-    @Override boolean matches(SubstitutionVisitor visitor, MutableRel rel) {
+    @Override public boolean matches(SubstitutionVisitor visitor, MutableRel rel) {
       visitor.slots[ordinal] = rel;
       return true;
     }
@@ -2058,11 +2099,45 @@ public class SubstitutionVisitor {
       this.ordinal = ordinal;
     }
 
-    @Override boolean matches(SubstitutionVisitor visitor, MutableRel rel) {
+    @Override public boolean matches(SubstitutionVisitor visitor, MutableRel rel) {
       final MutableRel rel0 = visitor.slots[ordinal];
       assert rel0 != null : "QueryOperand should have been called first";
       return rel0 == rel || visitor.equivalents.get(rel0).contains(rel);
     }
+
+    @Override public boolean isWeaker(SubstitutionVisitor visitor, MutableRel rel) {
+      final MutableRel rel0 = visitor.slots[ordinal];
+      assert rel0 != null : "QueryOperand should have been called first";
+
+      if (rel0 == rel || visitor.equivalents.get(rel0).contains(rel)) {
+        return false;
+      }
+
+      if (!(rel0 instanceof MutableFilter)
+          || !(rel instanceof MutableFilter)) {
+        return false;
+      }
+
+      if (!rel.getRowType().equals(rel0.getRowType())) {
+        return false;
+      }
+
+      final MutableRel rel0input = ((MutableFilter) rel0).getInput();
+      final MutableRel relinput = ((MutableFilter) rel).getInput();
+      if (rel0input != relinput
+          && !visitor.equivalents.get(rel0input).contains(relinput)) {
+        return false;
+      }
+
+      RexExecutorImpl rexImpl =
+          (RexExecutorImpl) (rel.cluster.getPlanner().getExecutor());
+      RexImplicationChecker rexImplicationChecker = new RexImplicationChecker(
+          rel.cluster.getRexBuilder(),
+          rexImpl, rel.getRowType());
+
+      return rexImplicationChecker.implies(((MutableFilter) rel0).getCondition(),
+          ((MutableFilter) rel).getCondition());
+    }
   }
 
   /** Visitor that counts how many {@link QueryOperand} and

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4a9b1939/core/src/main/java/org/apache/calcite/plan/VisitorDataContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/VisitorDataContext.java b/core/src/main/java/org/apache/calcite/plan/VisitorDataContext.java
new file mode 100644
index 0000000..a941347
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/plan/VisitorDataContext.java
@@ -0,0 +1,186 @@
+/*
+ * 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.plan;
+
+import org.apache.calcite.DataContext;
+import org.apache.calcite.adapter.java.JavaTypeFactory;
+import org.apache.calcite.linq4j.QueryProvider;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.logical.LogicalFilter;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexCall;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexLiteral;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.sql.SqlOperator;
+import org.apache.calcite.sql.fun.SqlCastFunction;
+import org.apache.calcite.util.NlsString;
+import org.apache.calcite.util.Pair;
+
+import java.math.BigDecimal;
+import java.sql.Date;
+import java.util.Calendar;
+import java.util.List;
+
+/**
+ * DataContext for evaluating an RexExpression
+ */
+public class VisitorDataContext implements DataContext {
+  private final Object[] values;
+
+  public VisitorDataContext(Object[] values) {
+    this.values = values;
+  }
+
+  public SchemaPlus getRootSchema() {
+    throw new RuntimeException("Unsupported");
+  }
+
+  public JavaTypeFactory getTypeFactory() {
+    throw new RuntimeException("Unsupported");
+  }
+
+  public QueryProvider getQueryProvider() {
+    throw new RuntimeException("Unsupported");
+  }
+
+  public Object get(String name) {
+    if (name.equals("inputRecord")) {
+      return values;
+    } else {
+      return null;
+    }
+  }
+  public static DataContext getDataContext(RelNode targetRel, LogicalFilter queryRel) {
+    return getDataContext(targetRel.getRowType(), queryRel.getCondition());
+  }
+
+  public static DataContext getDataContext(RelDataType rowType, RexNode rex) {
+    int size = rowType.getFieldList().size();
+    Object[] values = new Object[size];
+    List<RexNode> operands = ((RexCall) rex).getOperands();
+    final RexNode firstOperand = operands.get(0);
+    final RexNode secondOperand = operands.get(1);
+    final Pair<Integer, ? extends Object> value = getValue(firstOperand, secondOperand);
+    if (value != null) {
+      int index = value.getKey();
+      values[index] = value.getValue();
+      return new VisitorDataContext(values);
+    } else {
+      return null;
+    }
+  }
+
+  public static DataContext getDataContext(RelDataType rowType, List<Pair<RexInputRef,
+      RexNode>> usgList) {
+    int size = rowType.getFieldList().size();
+    Object[] values = new Object[size];
+    for (Pair<RexInputRef, RexNode> elem: usgList) {
+      Pair<Integer, ? extends Object> value = getValue(elem.getKey(), elem.getValue());
+      if (value == null) {
+        return null;
+      }
+      int index = value.getKey();
+      values[index] = value.getValue();
+    }
+    return new VisitorDataContext(values);
+  }
+
+  public static Pair<Integer, ? extends Object> getValue(RexNode inputRef, RexNode literal) {
+    inputRef = removeCast(inputRef);
+    literal = removeCast(literal);
+
+    if (inputRef instanceof RexInputRef
+        && literal instanceof RexLiteral)  {
+      Integer index = ((RexInputRef) inputRef).getIndex();
+      Object value = ((RexLiteral) literal).getValue();
+      final RelDataType type = inputRef.getType();
+
+      switch (type.getSqlTypeName()) {
+      case INTEGER:
+        if (value instanceof BigDecimal) {
+          final Integer intValue = new Integer(((BigDecimal) value).intValue());
+          return Pair.of(index, intValue);
+        }
+      case DOUBLE:
+        if (value instanceof BigDecimal) {
+          return Pair.of(index,
+              new Double(((BigDecimal) value).doubleValue()));
+        }
+      case REAL:
+        if (value instanceof BigDecimal) {
+          return Pair.of(index,
+              new Float(((BigDecimal) value).floatValue()));
+        }
+      case BIGINT:
+        if (value instanceof BigDecimal) {
+          return Pair.of(index,
+              new Long(((BigDecimal) value).longValue()));
+        }
+      case SMALLINT:
+        if (value instanceof BigDecimal) {
+          return Pair.of(index,
+              new Short(((BigDecimal) value).shortValue()));
+        }
+      case TINYINT:
+        if (value instanceof BigDecimal) {
+          return Pair.of(index,
+              new Short(((BigDecimal) value).byteValue()));
+        }
+      case DECIMAL:
+        if (value instanceof BigDecimal) {
+          return Pair.of(index, value);
+        }
+      case DATE:
+        if (value instanceof NlsString) {
+          value = ((RexLiteral) literal).getValue2();
+          final Date dateValue = Date.valueOf((String) value);
+          return Pair.of(index, dateValue);
+        } else if (value instanceof Calendar) {
+          final long timeInMillis = ((Calendar) value).getTimeInMillis();
+          return Pair.of(index, new Date(timeInMillis));
+        }
+      case CHAR:
+        if (value instanceof NlsString) {
+          // TODO: Support coallation. Not supported in {@link #NlsString} compare too.
+          final NlsString nl = (NlsString) value;
+          Character c = new Character(nl.getValue().charAt(0));
+          return Pair.of(index, c);
+        }
+      default:
+        //TODO: Support few more supported cases
+        return Pair.of(index, value);
+      }
+    }
+
+    //Unsupported Arguments
+    return null;
+  }
+
+  private static RexNode removeCast(RexNode inputRef) {
+    if (inputRef instanceof RexCall) {
+      final RexCall castedRef = (RexCall) inputRef;
+      final SqlOperator operator = castedRef.getOperator();
+      if (operator instanceof SqlCastFunction) {
+        inputRef = castedRef.getOperands().get(0);
+      }
+    }
+    return inputRef;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4a9b1939/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
index 3bb3a16..6634cf3 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
@@ -23,6 +23,7 @@ import org.apache.calcite.plan.AbstractRelOptPlanner;
 import org.apache.calcite.plan.Context;
 import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.ConventionTraitDef;
+import org.apache.calcite.plan.MaterializedViewSubstitutionVisitor;
 import org.apache.calcite.plan.RelOptCost;
 import org.apache.calcite.plan.RelOptCostFactory;
 import org.apache.calcite.plan.RelOptLattice;
@@ -38,7 +39,6 @@ import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.plan.RelTrait;
 import org.apache.calcite.plan.RelTraitDef;
 import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.plan.SubstitutionVisitor;
 import org.apache.calcite.plan.hep.HepPlanner;
 import org.apache.calcite.plan.hep.HepProgram;
 import org.apache.calcite.plan.hep.HepProgramBuilder;
@@ -365,6 +365,9 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
     // query. If that is possible, register the remnant query as equivalent
     // to the root.
     //
+
+    // This call modifies originalRoot. Doesn't look like originalRoot should be mutable though.
+    // Need to check.
     RelNode sub = substitute(originalRoot, materialization);
     if (sub != null) {
       // TODO: try to substitute other materializations in the remnant.
@@ -407,8 +410,8 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
     hepPlanner.setRoot(root);
     root = hepPlanner.findBestExp();
 
-    return new SubstitutionVisitor(target, root)
-        .go(materialization.tableRel);
+    return new MaterializedViewSubstitutionVisitor(target, root)
+            .go(materialization.tableRel);
   }
 
   private void useApplicableMaterializations() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4a9b1939/core/src/main/java/org/apache/calcite/rex/RexUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexUtil.java b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
index ee384e1..5347855 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -1024,6 +1024,38 @@ public class RexUtil {
     return new CnfHelper(rexBuilder).toCnf(rex);
   }
 
+  /** Converts an expression to disjunctive normal form (DNF).
+   *
+   * <p>DNF: It is a form of logical formula which is disjunction of conjunctive clauses</p>
+   *
+   * <p>All logicl formulas can be converted into DNF.</p>
+   *
+   * <p>The following expression is in DNF:
+   *
+   * <blockquote>(a AND b) OR (c AND d)</blockquote>
+   *
+   * <p>The following expression is not in CNF:
+   *
+   * <blockquote>(a OR b) AND c</blockquote>
+   *
+   * but can be converted to DNF:
+   *
+   * <blockquote>(a AND c) OR (b AND c)</blockquote>
+   *
+   * <p>The following expression is not in CNF:
+   *
+   * <blockquote>NOT (a OR NOT b)</blockquote>
+   *
+   * but can be converted to DNF by applying de Morgan's theorem:
+   *
+   * <blockquote>NOT a AND b</blockquote>
+   *
+   * <p>Expressions not involving AND, OR or NOT at the top level are in DNF.
+   */
+  public static RexNode toDnf(RexBuilder rexBuilder, RexNode rex) {
+    return new DnfHelper(rexBuilder).toDnf(rex);
+  }
+
   /**
    * Returns whether an operator is associative. AND is associative,
    * which means that "(x AND y) and z" is equivalent to "x AND (y AND z)".
@@ -1723,6 +1755,79 @@ public class RexUtil {
     }
   }
 
+  /** Helps {@link org.apache.calcite.rex.RexUtil#toDnf}. */
+  private static class DnfHelper {
+    final RexBuilder rexBuilder;
+
+    private DnfHelper(RexBuilder rexBuilder) {
+      this.rexBuilder = rexBuilder;
+    }
+
+    public RexNode toDnf(RexNode rex) {
+      final List<RexNode> operands;
+      switch (rex.getKind()) {
+      case AND:
+        operands = flattenAnd(((RexCall) rex).getOperands());
+        final RexNode head = operands.get(0);
+        final RexNode headDnf = toDnf(head);
+        final List<RexNode> headDnfs = RelOptUtil.disjunctions(headDnf);
+        final RexNode tail = and(Util.skip(operands));
+        final RexNode tailDnf = toDnf(tail);
+        final List<RexNode> tailDnfs = RelOptUtil.disjunctions(tailDnf);
+        final List<RexNode> list = Lists.newArrayList();
+        for (RexNode h : headDnfs) {
+          for (RexNode t : tailDnfs) {
+            list.add(and(ImmutableList.of(h, t)));
+          }
+        }
+        return or(list);
+      case OR:
+        operands = flattenOr(((RexCall) rex).getOperands());
+        return or(toDnfs(operands));
+      case NOT:
+        final RexNode arg = ((RexCall) rex).getOperands().get(0);
+        switch (arg.getKind()) {
+        case NOT:
+          return toDnf(((RexCall) arg).getOperands().get(0));
+        case OR:
+          operands = ((RexCall) arg).getOperands();
+          return toDnf(and(Lists.transform(flattenOr(operands), ADD_NOT)));
+        case AND:
+          operands = ((RexCall) arg).getOperands();
+          return toDnf(or(Lists.transform(flattenAnd(operands), ADD_NOT)));
+        default:
+          return rex;
+        }
+      default:
+        return rex;
+      }
+    }
+
+    private List<RexNode> toDnfs(List<RexNode> nodes) {
+      final List<RexNode> list = Lists.newArrayList();
+      for (RexNode node : nodes) {
+        RexNode dnf = toDnf(node);
+        switch (dnf.getKind()) {
+        case OR:
+          list.addAll(((RexCall) dnf).getOperands());
+          break;
+        default:
+          list.add(dnf);
+        }
+      }
+      return list;
+    }
+
+    private RexNode and(Iterable<? extends RexNode> nodes) {
+      return composeConjunction(rexBuilder, nodes, false);
+    }
+
+    private RexNode or(Iterable<? extends RexNode> nodes) {
+      return composeDisjunction(rexBuilder, nodes, false);
+    }
+  }
+
+
   /** Shuttle that adds {@code offset} to each {@link RexInputRef} in an
    * expression. */
   private static class RexShiftShuttle extends RexShuttle {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4a9b1939/core/src/test/java/org/apache/calcite/test/CalciteSuite.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/CalciteSuite.java b/core/src/test/java/org/apache/calcite/test/CalciteSuite.java
index 5a87733..0621a73 100644
--- a/core/src/test/java/org/apache/calcite/test/CalciteSuite.java
+++ b/core/src/test/java/org/apache/calcite/test/CalciteSuite.java
@@ -114,6 +114,7 @@ import org.junit.runners.Suite;
     // slow tests (above 1s)
     PlannerTest.class,
     RelBuilderTest.class,
+    RexImplicationCheckerTest.class,
     MaterializationTest.class,
     JdbcAdapterTest.class,
     LinqFrontJdbcBackTest.class,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4a9b1939/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
index f0fb54b..ae235ab 100644
--- a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
+++ b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
@@ -179,7 +179,8 @@ public class MaterializationTest {
         + "from \"emps\" where \"deptno\" - 10 = 2",
         JdbcTest.HR_MODEL,
         CalciteAssert.checkResultContains(
-            "EnumerableCalc(expr#0..2=[{inputs}], expr#3=[2], expr#4=[=($t0, $t3)], name=[$t2], E=[$t1], $condition=[$t4])\n"
+            "EnumerableCalc(expr#0..2=[{inputs}], expr#3=[2], "
+                + "expr#4=[=($t0, $t3)], name=[$t2], E=[$t1], $condition=[$t4])\n"
                 + "  EnumerableTableScan(table=[[hr, m0]]"));
   }
 
@@ -212,7 +213,8 @@ public class MaterializationTest {
   @Test public void testFilterQueryOnFilterView2() {
     checkMaterialize(
         "select \"deptno\", \"empid\", \"name\" from \"emps\" where \"deptno\" = 10",
-        "select \"empid\" + 1 as x, \"name\" from \"emps\" where \"deptno\" = 10 and \"empid\" < 150");
+        "select \"empid\" + 1 as x, \"name\" from \"emps\" "
+            + "where \"deptno\" = 10 and \"empid\" < 150");
   }
 
   /** As {@link #testFilterQueryOnFilterView()} but condition is weaker in
@@ -220,14 +222,131 @@ public class MaterializationTest {
   @Ignore("not implemented")
   @Test public void testFilterQueryOnFilterView3() {
     checkMaterialize(
-        "select \"deptno\", \"empid\", \"name\" from \"emps\" where \"deptno\" = 10 or \"deptno\" = 20 or \"empid\" < 160",
+        "select \"deptno\", \"empid\", \"name\" from \"emps\" "
+            + "where \"deptno\" = 10 or \"deptno\" = 20 or \"empid\" < 160",
         "select \"empid\" + 1 as x, \"name\" from \"emps\" where \"deptno\" = 10",
         JdbcTest.HR_MODEL,
         CalciteAssert.checkResultContains(
-            "EnumerableCalcRel(expr#0..2=[{inputs}], expr#3=[1], expr#4=[+($t1, $t3)], X=[$t4], name=[$t2], condition=?)\n"
+            "EnumerableCalcRel(expr#0..2=[{inputs}], expr#3=[1], "
+                + "expr#4=[+($t1, $t3)], X=[$t4], name=[$t2], condition=?)\n"
                 + "  EnumerableTableScan(table=[[hr, m0]])"));
   }
 
+  /** As {@link #testFilterQueryOnFilterView()} but condition is stronger in
+   * query. */
+  @Test public void testFilterQueryOnFilterView4() {
+    checkMaterialize(
+            "select * from \"emps\" where \"deptno\" > 10",
+            "select \"name\" from \"emps\" where \"deptno\" > 30");
+  }
+
+  /** As {@link #testFilterQueryOnFilterView()} but condition is stronger in
+   * query and columns selected are subset of columns in materialized view */
+  @Test public void testFilterQueryOnFilterView5() {
+    checkMaterialize(
+            "select \"name\", \"deptno\" from \"emps\" where \"deptno\" > 10",
+            "select \"name\" from \"emps\" where \"deptno\" > 30");
+  }
+
+  /** As {@link #testFilterQueryOnFilterView()} but condition is stronger in
+   * query and columns selected are subset of columns in materialized view */
+  @Test public void testFilterQueryOnFilterView6() {
+    checkMaterialize(
+            "select \"name\", \"deptno\", \"salary\" from \"emps\" "
+                + "where \"salary\" > 2000.5",
+            "select \"name\" from \"emps\" where \"deptno\" > 30 and \"salary\" > 3000");
+  }
+
+  /** As {@link #testFilterQueryOnFilterView()} but condition is stronger in
+   * query and columns selected are subset of columns in materialized view
+   * Condition here is complex*/
+  @Test public void testFilterQueryOnFilterView7() {
+    checkMaterialize(
+            "select * from \"emps\" where "
+                + "((\"salary\" < 1111.9 and \"deptno\" > 10)"
+                + "or (\"empid\" > 400 and \"salary\" > 5000) "
+                + "or \"salary\" > 500)",
+            "select \"name\" from \"emps\" where (\"salary\" > 1000 "
+                + "or (\"deptno\" >= 30 and \"salary\" <= 500))");
+  }
+
+  /** As {@link #testFilterQueryOnFilterView()} but condition is stronger in
+   * query. However, columns selected are not present in columns of materialized view,
+   * hence should not use materialized view*/
+  @Test public void testFilterQueryOnFilterView8() {
+    checkNoMaterialize(
+            "select \"name\", \"deptno\" from \"emps\" where \"deptno\" > 10",
+            "select \"name\", \"empid\" from \"emps\" where \"deptno\" > 30",
+            JdbcTest.HR_MODEL);
+  }
+
+  /** As {@link #testFilterQueryOnFilterView()} but condition is weaker in
+   * query.*/
+  @Test public void testFilterQueryOnFilterView9() {
+    checkNoMaterialize(
+            "select \"name\", \"deptno\" from \"emps\" where \"deptno\" > 10",
+            "select \"name\", \"empid\" from \"emps\" "
+                + "where \"deptno\" > 30 or \"empid\" > 10",
+            JdbcTest.HR_MODEL);
+  }
+  /** As {@link #testFilterQueryOnFilterView()} but condition currently
+   * has unsupported type being checked on query.
+   */
+  @Test public void testFilterQueryOnFilterView10() {
+    checkNoMaterialize(
+            "select \"name\", \"deptno\" from \"emps\" where \"deptno\" > 10 "
+                    + "and \"name\" = \'calcite\'",
+            "select \"name\", \"empid\" from \"emps\" where \"deptno\" > 30 "
+                    + "or \"empid\" > 10",
+            JdbcTest.HR_MODEL);
+  }
+
+  /** As {@link #testFilterQueryOnFilterView()} but condition is weaker in
+   * query and columns selected are subset of columns in materialized view
+   * Condition here is complex*/
+  @Test public void testFilterQueryOnFilterView11() {
+    checkNoMaterialize(
+            "select \"name\", \"deptno\" from \"emps\" where "
+                    + "(\"salary\" < 1111.9 and \"deptno\" > 10)"
+                    + "or (\"empid\" > 400 and \"salary\" > 5000)",
+            "select \"name\" from \"emps\" where \"deptno\" > 30 and \"salary\" > 3000",
+            JdbcTest.HR_MODEL);
+  }
+
+  /** As {@link #testFilterQueryOnFilterView()} but condition of
+   * query is stronger but is on the column not present in MV (salary).
+   */
+  @Test public void testFilterQueryOnFilterView12() {
+    checkNoMaterialize(
+            "select \"name\", \"deptno\" from \"emps\" where \"salary\" > 2000.5",
+            "select \"name\" from \"emps\" where \"deptno\" > 30 and \"salary\" > 3000",
+            JdbcTest.HR_MODEL);
+  }
+
+  /** As {@link #testFilterQueryOnFilterView()} but condition is weaker in
+   * query and columns selected are subset of columns in materialized view
+   * Condition here is complex*/
+  @Test public void testFilterQueryOnFilterView13() {
+    checkNoMaterialize(
+            "select * from \"emps\" where "
+                    + "(\"salary\" < 1111.9 and \"deptno\" > 10)"
+                    + "or (\"empid\" > 400 and \"salary\" > 5000)",
+            "select \"name\" from \"emps\" where \"salary\" > 1000 "
+                    + "or (\"deptno\" > 30 and \"salary\" > 3000)",
+            JdbcTest.HR_MODEL);
+  }
+
+  /** As {@link #testFilterQueryOnFilterView13()} but using alias
+   * and condition of query is stronger*/
+  @Test public void testAlias() {
+    checkMaterialize(
+            "select * from \"emps\" as em where "
+                    + "(em.\"salary\" < 1111.9 and em.\"deptno\" > 10)"
+                    + "or (em.\"empid\" > 400 and em.\"salary\" > 5000)",
+            "select \"name\" as n from \"emps\" as e where "
+                    + "(e.\"empid\" > 500 and e.\"salary\" > 6000)");
+  }
+
   /** Aggregation query at same level of aggregation as aggregation
    * materialization. */
   @Test public void testAggregate() {
@@ -241,11 +360,13 @@ public class MaterializationTest {
    * COUNT is rolled up using SUM. */
   @Test public void testAggregateRollUp() {
     checkMaterialize(
-        "select \"empid\", \"deptno\", count(*) as c, sum(\"empid\") as s from \"emps\" group by \"empid\", \"deptno\"",
+        "select \"empid\", \"deptno\", count(*) as c, sum(\"empid\") as s from \"emps\" "
+            + "group by \"empid\", \"deptno\"",
         "select count(*) + 1 as c, \"deptno\" from \"emps\" group by \"deptno\"",
         JdbcTest.HR_MODEL,
         CalciteAssert.checkResultContains(
-            "EnumerableCalc(expr#0..1=[{inputs}], expr#2=[1], expr#3=[+($t1, $t2)], C=[$t3], deptno=[$t0])\n"
+            "EnumerableCalc(expr#0..1=[{inputs}], expr#2=[1], "
+                + "expr#3=[+($t1, $t2)], C=[$t3], deptno=[$t0])\n"
                 + "  EnumerableAggregate(group=[{1}], agg#0=[$SUM0($2)])\n"
                 + "    EnumerableTableScan(table=[[hr, m0]])"));
   }
@@ -621,6 +742,13 @@ public class MaterializationTest {
         + "join \"depts\" using (\"deptno\")";
     checkNoMaterialize(q, q, JdbcTest.HR_MODEL);
   }
+
+  @Test public void testJoinMaterialization() {
+    String q = "select *\n"
+            + "from (select * from \"emps\" where \"empid\" < 300)\n"
+            + "join \"depts\" using (\"deptno\")";
+    checkMaterialize("select * from \"emps\" where \"empid\" < 500", q);
+  }
 }
 
 // End MaterializationTest.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4a9b1939/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
new file mode 100644
index 0000000..7e693b0
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
@@ -0,0 +1,448 @@
+/*
+ * 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.test;
+
+import org.apache.calcite.DataContext;
+import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptSchema;
+import org.apache.calcite.plan.RexImplicationChecker;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeSystem;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexExecutorImpl;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.schema.Schemas;
+import org.apache.calcite.server.CalciteServerStatement;
+import org.apache.calcite.sql.SqlCollation;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.tools.Frameworks;
+import org.apache.calcite.util.NlsString;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.math.BigDecimal;
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Calendar;
+
+/**
+ * Tests the RexImplication checker
+ */
+public class RexImplicationCheckerTest {
+  //~ Instance fields --------------------------------------------------------
+
+  private RexBuilder rexBuilder = null;
+  private RexNode bl;
+  private RexNode i;
+  private RexNode dec;
+  private RexNode lg;
+  private RexNode sh;
+  private RexNode by;
+  private RexNode fl;
+  private RexNode dt;
+  private RexNode ch;
+  private RexNode ts;
+  private RexNode t;
+
+  private RelDataType boolRelDataType;
+  private RelDataType intRelDataType;
+  private RelDataType decRelDataType;
+  private RelDataType longRelDataType;
+  private RelDataType shortDataType;
+  private RelDataType byteDataType;
+  private RelDataType floatDataType;
+  private RelDataType charDataType;
+  private RelDataType dateDataType;
+  private RelDataType timeStampDataType;
+  private RelDataType timeDataType;
+  private RelDataTypeFactory typeFactory;
+  private RexImplicationChecker checker;
+  private RelDataType rowType;
+  private RexExecutorImpl executor;
+
+  //~ Methods ----------------------------------------------------------------
+
+  @Before
+  public void setUp() {
+    typeFactory = new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
+    rexBuilder = new RexBuilder(typeFactory);
+    boolRelDataType = typeFactory.createJavaType(Boolean.class);
+    intRelDataType = typeFactory.createJavaType(Integer.class);
+    decRelDataType = typeFactory.createJavaType(Double.class);
+    longRelDataType = typeFactory.createJavaType(Long.class);
+    shortDataType = typeFactory.createJavaType(Short.class);
+    byteDataType = typeFactory.createJavaType(Byte.class);
+    floatDataType = typeFactory.createJavaType(Float.class);
+    charDataType = typeFactory.createJavaType(Character.class);
+    dateDataType = typeFactory.createJavaType(Date.class);
+    timeStampDataType = typeFactory.createJavaType(Timestamp.class);
+    timeDataType = typeFactory.createJavaType(Time.class);
+
+    bl = new RexInputRef(
+        0,
+        typeFactory.createTypeWithNullability(boolRelDataType, true));
+    i = new RexInputRef(
+        1,
+        typeFactory.createTypeWithNullability(intRelDataType, true));
+    dec = new RexInputRef(
+        2,
+        typeFactory.createTypeWithNullability(decRelDataType, true));
+    lg = new RexInputRef(
+        3,
+        typeFactory.createTypeWithNullability(longRelDataType, true));
+    sh = new RexInputRef(
+        4,
+        typeFactory.createTypeWithNullability(shortDataType, true));
+    by = new RexInputRef(
+        5,
+        typeFactory.createTypeWithNullability(byteDataType, true));
+    fl = new RexInputRef(
+        6,
+        typeFactory.createTypeWithNullability(floatDataType, true));
+    ch = new RexInputRef(
+        7,
+        typeFactory.createTypeWithNullability(charDataType, true));
+    dt = new RexInputRef(
+        8,
+        typeFactory.createTypeWithNullability(dateDataType, true));
+    ts = new RexInputRef(
+        9,
+        typeFactory.createTypeWithNullability(timeStampDataType, true));
+    t = new RexInputRef(
+        10,
+        typeFactory.createTypeWithNullability(timeDataType, true));
+
+    rowType =  typeFactory.builder()
+        .add("bool", boolRelDataType)
+        .add("int", intRelDataType)
+        .add("dec", decRelDataType)
+        .add("long", longRelDataType)
+        .add("short", shortDataType)
+        .add("byte", byteDataType)
+        .add("float", floatDataType)
+        .add("char", charDataType)
+        .add("date", dateDataType)
+        .add("timestamp", timeStampDataType)
+        .add("time", timeDataType)
+        .build();
+
+    Frameworks.withPrepare(
+        new Frameworks.PrepareAction<Void>() {
+          public Void apply(RelOptCluster cluster,
+                            RelOptSchema relOptSchema,
+                            SchemaPlus rootSchema,
+                            CalciteServerStatement statement) {
+            DataContext dataContext =
+                Schemas.createDataContext(statement.getConnection());
+            executor = new RexExecutorImpl(dataContext);
+            return null;
+          }
+        });
+
+    checker = new RexImplicationChecker(rexBuilder, executor, rowType);
+  }
+
+  private void checkImplies(RexNode node1, RexNode node2) {
+    assertTrue(node1.toString() + " doesnot imply " + node2.toString()
+        + " when it should.", checker.implies(node1, node2));
+  }
+
+  private void checkNotImplies(RexNode node1, RexNode node2) {
+    assertFalse(node1.toString() + " implies " + node2.toString()
+        + " when it should not", checker.implies(node1, node2));
+  }
+
+  // Simple Tests for Operators
+  @Test public void testSimpleGreaterCond() {
+    RexNode node1 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.GREATER_THAN,
+            i,
+            rexBuilder.makeExactLiteral(new BigDecimal(10)));
+
+    RexNode node2 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.GREATER_THAN,
+            i,
+            rexBuilder.makeExactLiteral(new BigDecimal(30)));
+
+    RexNode node3 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
+            i,
+            rexBuilder.makeExactLiteral(new BigDecimal(30)));
+
+    RexNode node4 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
+            i,
+            rexBuilder.makeExactLiteral(new BigDecimal(10)));
+
+    RexNode node5 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.EQUALS,
+            i,
+            rexBuilder.makeExactLiteral(new BigDecimal(30)));
+
+    RexNode node6 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.NOT_EQUALS,
+            i,
+            rexBuilder.makeExactLiteral(new BigDecimal(10)));
+
+    checkImplies(node2, node1);
+    checkNotImplies(node1, node2);
+    checkNotImplies(node1, node3);
+    checkImplies(node3, node1);
+    checkImplies(node5, node1);
+    checkNotImplies(node1, node5);
+    checkNotImplies(node1, node6);
+    checkNotImplies(node4, node6);
+    // TODO: Need to support Identity
+    //checkImplies(node1, node1);
+    //checkImplies(node3, node3);
+  }
+
+  @Test public void testSimpleLesserCond() {
+    RexNode node1 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.LESS_THAN,
+            i,
+            rexBuilder.makeExactLiteral(new BigDecimal(10)));
+
+    RexNode node2 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.LESS_THAN,
+            i,
+            rexBuilder.makeExactLiteral(new BigDecimal(30)));
+
+    RexNode node3 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.LESS_THAN_OR_EQUAL,
+            i,
+            rexBuilder.makeExactLiteral(new BigDecimal(30)));
+
+    RexNode node4 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.LESS_THAN_OR_EQUAL,
+            i,
+            rexBuilder.makeExactLiteral(new BigDecimal(10)));
+
+    RexNode node5 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.EQUALS,
+            i,
+            rexBuilder.makeExactLiteral(new BigDecimal(10)));
+
+    RexNode node6 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.NOT_EQUALS,
+            i,
+            rexBuilder.makeExactLiteral(new BigDecimal(10)));
+
+    checkImplies(node1, node2);
+    checkNotImplies(node2, node1);
+    checkImplies(node1, node3);
+    checkNotImplies(node3, node1);
+    checkImplies(node5, node2);
+    checkNotImplies(node2, node5);
+    checkNotImplies(node1, node5);
+    checkNotImplies(node1, node6);
+    checkNotImplies(node4, node6);
+    // TODO: Need to support Identity
+    //checkImplies(node1, node1);
+    //checkImplies(node3, node3);
+  }
+
+  @Test public void testSimpleEq() {
+    RexNode node1 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.EQUALS,
+            i,
+            rexBuilder.makeExactLiteral(new BigDecimal(30)));
+
+    RexNode node2 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.NOT_EQUALS,
+            i,
+            rexBuilder.makeExactLiteral(new BigDecimal(10)));
+
+    //Check Identity
+    checkImplies(node1, node1);
+    //TODO: Support Identity
+    // checkImplies(node2, node2);
+    checkImplies(node1, node2);
+    checkNotImplies(node2, node1);
+  }
+
+  // Simple Tests for DataTypes
+  @Test public void testSimpleDec() {
+    RexNode node1 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.LESS_THAN,
+            dec,
+            rexBuilder.makeApproxLiteral(new BigDecimal(30.9)));
+
+    RexNode node2 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.LESS_THAN,
+            dec,
+            rexBuilder.makeApproxLiteral(new BigDecimal(40.33)));
+
+    checkImplies(node1, node2);
+    checkNotImplies(node2, node1);
+  }
+
+  @Test public void testSimpleBoolean() {
+    RexNode node1 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.EQUALS,
+            bl,
+            rexBuilder.makeLiteral(true));
+
+    RexNode node2 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.EQUALS,
+            bl,
+            rexBuilder.makeLiteral(false));
+
+    //TODO: Need to support false => true
+    //checkImplies(node2, node1);
+    checkNotImplies(node1, node2);
+  }
+
+  @Test public void testSimpleLong() {
+    RexNode node1 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
+            lg,
+            rexBuilder.makeLiteral(new Long(324324L), longRelDataType, true));
+
+    RexNode node2 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.GREATER_THAN,
+            lg,
+            rexBuilder.makeLiteral(new Long(324325L), longRelDataType, true));
+
+    checkImplies(node2, node1);
+    checkNotImplies(node1, node2);
+  }
+
+  @Test public void testSimpleShort() {
+    RexNode node1 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
+            sh,
+            rexBuilder.makeLiteral(new Short((short) 10), shortDataType, true));
+
+    RexNode node2 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
+            sh,
+            rexBuilder.makeLiteral(new Short((short) 11), shortDataType, true));
+
+    checkImplies(node2, node1);
+    checkNotImplies(node1, node2);
+  }
+
+  @Test public void testSimpleChar() {
+    RexNode node1 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
+            ch,
+            rexBuilder.makeCharLiteral(new NlsString("b", null, SqlCollation.COERCIBLE)));
+
+    RexNode node2 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
+            ch,
+            rexBuilder.makeCharLiteral(new NlsString("a", null, SqlCollation.COERCIBLE)));
+
+    checkImplies(node1, node2);
+    checkNotImplies(node2, node1);
+  }
+
+  @Test public void testSimpleDate() {
+    RexNode node1 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
+            dt,
+            rexBuilder.makeDateLiteral(Calendar.getInstance()));
+
+    RexNode node2 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.EQUALS,
+            dt,
+            rexBuilder.makeDateLiteral(Calendar.getInstance()));
+
+    checkImplies(node2, node1);
+    checkNotImplies(node1, node2);
+  }
+
+  @Ignore("work in progress")
+  @Test public void testSimpleTimeStamp() {
+    RexNode node1 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.LESS_THAN_OR_EQUAL,
+            ts,
+            rexBuilder.makeTimestampLiteral(Calendar.getInstance(),
+                timeStampDataType.getPrecision()));
+
+
+    RexNode node2 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.LESS_THAN_OR_EQUAL,
+            ts,
+            rexBuilder.makeTimestampLiteral(Calendar.getInstance(),
+                timeStampDataType.getPrecision()));
+
+    checkImplies(node1, node2);
+    checkNotImplies(node2, node1);
+  }
+
+  @Ignore("work in progress")
+  @Test public void testSimpleTime() {
+    RexNode node1 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.LESS_THAN_OR_EQUAL,
+            t,
+            rexBuilder.makeTimeLiteral(Calendar.getInstance(),
+                timeDataType.getPrecision()));
+
+
+    RexNode node2 =
+        rexBuilder.makeCall(
+            SqlStdOperatorTable.LESS_THAN_OR_EQUAL,
+            t,
+            rexBuilder.makeTimestampLiteral(Calendar.getInstance(),
+                timeDataType.getPrecision()));
+
+    checkImplies(node1, node2);
+    checkNotImplies(node2, node1);
+  }
+
+}


[06/50] incubator-calcite git commit: [CALCITE-390] Infer predicates for semi-join

Posted by jh...@apache.org.
[CALCITE-390] Infer predicates for semi-join


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

Branch: refs/heads/branch-release
Commit: 23396f0637724205ae35a89972bb61bc60d3e946
Parents: 464fd36
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Jul 9 21:23:00 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jul 9 21:26:49 2015 -0700

----------------------------------------------------------------------
 .../calcite/rel/metadata/RelMdPredicates.java   |  8 ++-
 .../apache/calcite/test/RelMetadataTest.java    | 67 ++++++++++++++++++++
 2 files changed, 72 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/23396f06/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
index 05e6b4f..5e14ba7 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
@@ -193,9 +193,11 @@ public class RelMdPredicates {
 
   /** Infers predicates for a {@link org.apache.calcite.rel.core.SemiJoin}. */
   public RelOptPredicateList getPredicates(SemiJoin semiJoin) {
-    // Workaround, pending [CALCITE-390] "Transitive inference (RelMdPredicate)
-    // doesn't handle semi-join"
-    return RelOptPredicateList.EMPTY;
+    final RelNode left = semiJoin.getInput(0);
+    final RelOptPredicateList leftInfo =
+        RelMetadataQuery.getPulledUpPredicates(left);
+    return RelOptPredicateList.of(leftInfo.pulledUpPredicates,
+        leftInfo.pulledUpPredicates, ImmutableList.<RexNode>of());
   }
 
   /** Infers predicates for a {@link org.apache.calcite.rel.core.Join}. */

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/23396f06/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
index 2c46a9f..ddb116f 100644
--- a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
@@ -19,6 +19,7 @@ package org.apache.calcite.test;
 import org.apache.calcite.adapter.enumerable.EnumerableMergeJoin;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelOptPredicateList;
 import org.apache.calcite.plan.RelOptSchema;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.rel.InvalidRelException;
@@ -32,6 +33,7 @@ import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.calcite.rel.core.Project;
+import org.apache.calcite.rel.core.SemiJoin;
 import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.logical.LogicalAggregate;
 import org.apache.calcite.rel.logical.LogicalFilter;
@@ -51,6 +53,7 @@ import org.apache.calcite.rel.metadata.RelMdCollation;
 import org.apache.calcite.rel.metadata.RelMetadataProvider;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
@@ -1011,6 +1014,70 @@ public class RelMetadataTest extends SqlToRelTestBase {
     assertThat(RelMetadataQuery.splitCount(aggregate), is(1));
   }
 
+  /** Unit test for
+   * {@link org.apache.calcite.rel.metadata.RelMdPredicates#getPredicates(SemiJoin)}. */
+  @Test public void testPredicates() {
+    final Project rel = (Project) convertSql("select * from emp, dept");
+    final Join join = (Join) rel.getInput();
+    final RelOptTable empTable = join.getInput(0).getTable();
+    final RelOptTable deptTable = join.getInput(1).getTable();
+    Frameworks.withPlanner(
+        new Frameworks.PlannerAction<Void>() {
+          public Void apply(RelOptCluster cluster,
+              RelOptSchema relOptSchema,
+              SchemaPlus rootSchema) {
+            checkPredicates(cluster, empTable, deptTable);
+            return null;
+          }
+        });
+  }
+
+  private void checkPredicates(RelOptCluster cluster, RelOptTable empTable,
+      RelOptTable deptTable) {
+    final RexBuilder rexBuilder = cluster.getRexBuilder();
+    final LogicalTableScan empScan = LogicalTableScan.create(cluster, empTable);
+
+    RelOptPredicateList predicates =
+        RelMetadataQuery.getPulledUpPredicates(empScan);
+    assertThat(predicates.pulledUpPredicates.isEmpty(), is(true));
+
+    final LogicalFilter filter =
+        LogicalFilter.create(empScan,
+            rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
+                rexBuilder.makeInputRef(empScan,
+                    empScan.getRowType().getFieldNames().indexOf("EMPNO")),
+                rexBuilder.makeExactLiteral(BigDecimal.ONE)));
+
+    predicates = RelMetadataQuery.getPulledUpPredicates(filter);
+    assertThat(predicates.pulledUpPredicates.toString(), is("[=($0, 1)]"));
+
+    final LogicalTableScan deptScan =
+        LogicalTableScan.create(cluster, deptTable);
+
+    final RelDataTypeField leftDeptnoField =
+        empScan.getRowType().getFieldList().get(
+            empScan.getRowType().getFieldNames().indexOf("DEPTNO"));
+    final RelDataTypeField rightDeptnoField =
+        deptScan.getRowType().getFieldList().get(
+            deptScan.getRowType().getFieldNames().indexOf("DEPTNO"));
+    final SemiJoin semiJoin =
+        SemiJoin.create(filter, deptScan,
+            rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
+                rexBuilder.makeInputRef(leftDeptnoField.getType(),
+                    leftDeptnoField.getIndex()),
+                rexBuilder.makeInputRef(rightDeptnoField.getType(),
+                    rightDeptnoField.getIndex()
+                        + empScan.getRowType().getFieldCount())),
+            ImmutableIntList.of(leftDeptnoField.getIndex()),
+            ImmutableIntList.of(rightDeptnoField.getIndex()
+                    + empScan.getRowType().getFieldCount()));
+
+    predicates = RelMetadataQuery.getPulledUpPredicates(semiJoin);
+    assertThat(predicates.pulledUpPredicates.toString(), is("[=($0, 1)]"));
+    assertThat(predicates.leftInferredPredicates.toString(), is("[=($0, 1)]"));
+    assertThat(predicates.rightInferredPredicates.isEmpty(), is(true));
+  }
+
   /** Custom metadata interface. */
   public interface ColType extends Metadata {
     String getColType(int column);


[43/50] incubator-calcite git commit: Fix javadoc links

Posted by jh...@apache.org.
Fix javadoc links


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

Branch: refs/heads/branch-release
Commit: 6bc8efc4318ef919e7a3a4a42afc574e8f5845f5
Parents: c9d7233
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Aug 18 12:27:00 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Aug 18 12:27:00 2015 -0700

----------------------------------------------------------------------
 .../src/main/java/org/apache/calcite/avatica/server/Main.java   | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6bc8efc4/avatica-server/src/main/java/org/apache/calcite/avatica/server/Main.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/Main.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/Main.java
index f8416d6..7876e1c 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/server/Main.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/Main.java
@@ -40,9 +40,10 @@ public class Main {
    *
    * <p>Arguments are as follows:
    * <ul>
-   *   <li>args[0]: the {@link Meta.Factory} class name
+   *   <li>args[0]: the {@link org.apache.calcite.avatica.Meta.Factory} class
+   *       name
    *   <li>args[1+]: arguments passed along to
-   *   {@link Meta.Factory#create(java.util.List)}
+   *   {@link org.apache.calcite.avatica.Meta.Factory#create(java.util.List)}
    * </ul>
    *
    * @param args Command-line arguments


[36/50] incubator-calcite git commit: [CALCITE-821] Frameworks gives NPE when FrameworkConfig has no default schema

Posted by jh...@apache.org.
[CALCITE-821] Frameworks gives NPE when FrameworkConfig has no default schema


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

Branch: refs/heads/branch-release
Commit: 1580bd0fec62d836c9870edc339b0ab99d909cad
Parents: 2376ae4
Author: Julian Hyde <jh...@apache.org>
Authored: Wed Jul 29 12:55:57 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Wed Jul 29 12:56:47 2015 -0700

----------------------------------------------------------------------
 core/src/main/java/org/apache/calcite/tools/Frameworks.java | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/1580bd0f/core/src/main/java/org/apache/calcite/tools/Frameworks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/Frameworks.java b/core/src/main/java/org/apache/calcite/tools/Frameworks.java
index c73a1e2..f3ebe12 100644
--- a/core/src/main/java/org/apache/calcite/tools/Frameworks.java
+++ b/core/src/main/java/org/apache/calcite/tools/Frameworks.java
@@ -33,6 +33,7 @@ import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.parser.SqlParser;
 import org.apache.calcite.sql2rel.SqlRexConvertletTable;
 import org.apache.calcite.sql2rel.StandardConvertletTable;
+import org.apache.calcite.util.Util;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -107,7 +108,8 @@ public class Frameworks {
           public R apply(RelOptCluster cluster, RelOptSchema relOptSchema,
               SchemaPlus rootSchema, CalciteServerStatement statement) {
             final CalciteSchema schema =
-                CalciteSchema.from(config.getDefaultSchema());
+                CalciteSchema.from(
+                    Util.first(config.getDefaultSchema(), rootSchema));
             return action.apply(cluster, relOptSchema, schema.root().plus());
           }
         });


[45/50] incubator-calcite git commit: [CALCITE-743] Ensure only a single source assembly is executed.

Posted by jh...@apache.org.
[CALCITE-743] Ensure only a single source assembly is executed.

Since Calcite has its own assembly, we need to disable the Apache Parent POM assembly since they conflicting instructions.


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

Branch: refs/heads/branch-release
Commit: c09a872fd481082af1d7f3bb760c68c2c91ff145
Parents: 9f1f73d
Author: Jacques Nadeau <ja...@apache.org>
Authored: Sun Aug 23 12:31:03 2015 -0700
Committer: Jacques Nadeau <ja...@apache.org>
Committed: Sun Aug 23 12:31:03 2015 -0700

----------------------------------------------------------------------
 pom.xml | 4 ++++
 1 file changed, 4 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c09a872f/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index c48cc52..c9d1e99 100644
--- a/pom.xml
+++ b/pom.xml
@@ -670,6 +670,10 @@ limitations under the License.
             <executions>
               <execution>
                 <id>source-release-assembly</id>
+                <phase>none</phase>
+              </execution>
+              <execution>
+                <id>source-release-assembly-calcite</id>
                 <phase>package</phase>
                 <goals>
                   <goal>single</goal>


[14/50] incubator-calcite git commit: [CALCITE-787] Star table wrongly assigned to materialized view (Amogh Margoor)

Posted by jh...@apache.org.
[CALCITE-787] Star table wrongly assigned to materialized view (Amogh Margoor)

Close apache/incubator-calcite#103


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

Branch: refs/heads/branch-release
Commit: d38e6b1b92497c0e4e43847c4ab756e888dac1f3
Parents: 5a36560
Author: Amogh Margoor <am...@qubole.com>
Authored: Mon Jul 6 08:26:18 2015 -0400
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jul 16 15:22:15 2015 -0700

----------------------------------------------------------------------
 .../calcite/plan/RelOptMaterialization.java     |  9 +++-
 .../calcite/plan/volcano/VolcanoPlanner.java    |  7 ++-
 .../org/apache/calcite/test/LatticeTest.java    | 56 ++++++++++++++++++++
 3 files changed, 68 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d38e6b1b/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java b/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java
index 8c9eaae..f945e65 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java
@@ -77,8 +77,12 @@ public class RelOptMaterialization {
   /**
    * Converts a relational expression to one that uses a
    * {@link org.apache.calcite.schema.impl.StarTable}.
-   * The relational expression is already in leaf-join-form, per
+   *
+   * <p>The relational expression is already in leaf-join-form, per
    * {@link #toLeafJoinForm(org.apache.calcite.rel.RelNode)}.
+   *
+   * @return Rewritten expression, or null if expression cannot be rewritten
+   * to use the star
    */
   public static RelNode tryUseStar(RelNode rel,
       final RelOptTable starRelOptTable) {
@@ -191,7 +195,8 @@ public class RelOptMaterialization {
           }
         });
     if (rel2 == rel) {
-      return rel;
+      // No rewrite happened.
+      return null;
     }
     final Program program = Programs.hep(
         ImmutableList.of(ProjectFilterTransposeRule.INSTANCE,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d38e6b1b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
index 6634cf3..e57a760 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
@@ -391,8 +391,11 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
     // First, if the materialization is in terms of a star table, rewrite
     // the query in terms of the star table.
     if (materialization.starTable != null) {
-      root = RelOptMaterialization.tryUseStar(
-          root, materialization.starRelOptTable);
+      RelNode newRoot = RelOptMaterialization.tryUseStar(root,
+          materialization.starRelOptTable);
+      if (newRoot != null) {
+        root = newRoot;
+      }
     }
 
     // Push filters to the bottom, and combine projects on top.

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d38e6b1b/core/src/test/java/org/apache/calcite/test/LatticeTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/LatticeTest.java b/core/src/test/java/org/apache/calcite/test/LatticeTest.java
index 92d121b..77e7943 100644
--- a/core/src/test/java/org/apache/calcite/test/LatticeTest.java
+++ b/core/src/test/java/org/apache/calcite/test/LatticeTest.java
@@ -624,6 +624,62 @@ public class LatticeTest {
   }
 
   /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-787">[CALCITE-787]
+   * Star table wrongly assigned to materialized view</a>. */
+  @Test public void testOneLatticeOneMV() {
+    final AtomicInteger counter = new AtomicInteger();
+    final Class<JdbcTest.EmpDeptTableFactory> clazz =
+        JdbcTest.EmpDeptTableFactory.class;
+
+    final String mv = "       materializations: [\n"
+        + "         {\n"
+        + "           table: \"m0\",\n"
+        + "           view: \"m0v\",\n"
+        + "           sql: \"select * from \\\"foodmart\\\".\\\"sales_fact_1997\\\" "
+        + "where \\\"product_id\\\" = 10\" "
+        + "         }\n"
+        + "       ]\n";
+
+    final String model = ""
+        + "{\n"
+        + "  version: '1.0',\n"
+        + "   schemas: [\n"
+        + JdbcTest.FOODMART_SCHEMA
+        + ",\n"
+        + "     {\n"
+        + "       name: 'adhoc',\n"
+        + "       tables: [\n"
+        + "         {\n"
+        + "           name: 'EMPLOYEES',\n"
+        + "           type: 'custom',\n"
+        + "           factory: '"
+        + clazz.getName()
+        + "',\n"
+        + "           operand: {'foo': true, 'bar': 345}\n"
+        + "         }\n"
+        + "       ],\n"
+        + "       lattices: " + "[" + INVENTORY_LATTICE
+        + "       ]\n"
+        + "     },\n"
+        + "     {\n"
+        + "       name: 'mat',\n"
+        + mv
+        + "     }\n"
+        + "   ]\n"
+        + "}";
+
+    CalciteAssert.model(model)
+        .withDefaultSchema("foodmart")
+        .query("select * from \"foodmart\".\"sales_fact_1997\" where \"product_id\" = 10")
+        .enableMaterializations(true)
+        .substitutionMatches(
+            CalciteAssert.checkRel(
+                "EnumerableTableScan(table=[[mat, m0]])\n",
+                counter));
+    assertThat(counter.intValue(), equalTo(1));
+  }
+
+  /** Test case for
    * <a href="https://issues.apache.org/jira/browse/CALCITE-760">[CALCITE-760]
    * Aggregate recommender blows up if row count estimate is too high</a>. */
   @Ignore


[23/50] incubator-calcite git commit: [CALCITE-806] ROW_NUMBER should emit distinct values

Posted by jh...@apache.org.
[CALCITE-806] ROW_NUMBER should emit distinct values

Close apache/incubator-calcite#107


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

Branch: refs/heads/branch-release
Commit: 096d2820b6a3c48e0fa9e5f7d5489a25aeff10a5
Parents: 4b60b9b
Author: Julian Hyde <jh...@apache.org>
Authored: Sun Jul 19 02:56:28 2015 +0300
Committer: Vladimir Sitnikov <si...@gmail.com>
Committed: Wed Jul 22 23:41:27 2015 +0300

----------------------------------------------------------------------
 .../apache/calcite/runtime/CalciteResource.java |  2 +-
 .../java/org/apache/calcite/sql/SqlWindow.java  |  4 ++
 .../calcite/sql2rel/SqlToRelConverter.java      |  6 +++
 .../calcite/runtime/CalciteResource.properties  |  2 +-
 .../java/org/apache/calcite/test/JdbcTest.java  | 22 +++++---
 .../apache/calcite/test/SqlValidatorTest.java   | 19 ++++---
 core/src/test/resources/sql/winagg.oq           | 54 ++++++++++++++++++--
 pom.xml                                         |  2 +-
 8 files changed, 91 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/096d2820/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
index 007a410..a511143 100644
--- a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
+++ b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
@@ -365,7 +365,7 @@ public interface CalciteResource {
   @BaseMessage("Duplicate window specification not allowed in the same window clause")
   ExInst<SqlValidatorException> dupWindowSpec();
 
-  @BaseMessage("ROW/RANGE not allowed with RANK or DENSE_RANK functions")
+  @BaseMessage("ROW/RANGE not allowed with RANK, DENSE_RANK or ROW_NUMBER functions")
   ExInst<SqlValidatorException> rankWithFrame();
 
   @BaseMessage("RANK or DENSE_RANK functions require ORDER BY clause in window specification")

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/096d2820/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlWindow.java b/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
index 40ba4ee..b54b349 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
@@ -247,6 +247,10 @@ public class SqlWindow extends SqlCall {
     return false;
   }
 
+  public void setRows(SqlLiteral isRows) {
+    this.isRows = isRows;
+  }
+
   public boolean isRows() {
     return isRows.booleanValue();
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/096d2820/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index fe16f23..40e6ed2 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -1747,6 +1747,12 @@ public class SqlToRelConverter {
     SqlNode windowOrRef = call.operand(1);
     final SqlWindow window =
         validator.resolveWindow(windowOrRef, bb.scope, true);
+    // ROW_NUMBER() expects specific kind of framing.
+    if (aggCall.getOperator() == SqlStdOperatorTable.ROW_NUMBER) {
+      window.setLowerBound(SqlWindow.createUnboundedPreceding(SqlParserPos.ZERO));
+      window.setUpperBound(SqlWindow.createCurrentRow(SqlParserPos.ZERO));
+      window.setRows(SqlLiteral.createBoolean(true, SqlParserPos.ZERO));
+    }
     final SqlNodeList partitionList = window.getPartitionList();
     final ImmutableList.Builder<RexNode> partitionKeys =
         ImmutableList.builder();

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/096d2820/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
----------------------------------------------------------------------
diff --git a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
index 3aec262..5ab24cc 100644
--- a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
+++ b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
@@ -124,7 +124,7 @@ WindowNameMustBeSimple=Window name must be a simple identifier
 DuplicateWindowName=Duplicate window names not allowed
 EmptyWindowSpec=Empty window specification not allowed
 DupWindowSpec=Duplicate window specification not allowed in the same window clause
-RankWithFrame=ROW/RANGE not allowed with RANK or DENSE_RANK functions
+RankWithFrame=ROW/RANGE not allowed with RANK, DENSE_RANK or ROW_NUMBER functions
 FuncNeedsOrderBy=RANK or DENSE_RANK functions require ORDER BY clause in window specification
 PartitionNotAllowed=PARTITION BY not allowed with existing window reference
 OrderByOverlap=ORDER BY not allowed in both base and referenced windows

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/096d2820/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index a037a23..f365ab2 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -4022,18 +4022,19 @@ public class JdbcTest {
         .query("select \"deptno\",\n"
             + " \"empid\",\n"
             + " \"commission\",\n"
+            + " row_number() over (partition by \"deptno\") as r,\n"
             + " row_number() over (partition by \"deptno\" order by \"commission\" desc nulls first) as rcnf,\n"
             + " row_number() over (partition by \"deptno\" order by \"commission\" desc nulls last) as rcnl,\n"
             + " row_number() over (partition by \"deptno\" order by \"empid\") as r,\n"
             + " row_number() over (partition by \"deptno\" order by \"empid\" desc) as rd\n"
             + "from \"hr\".\"emps\"")
         .typeIs(
-            "[deptno INTEGER NOT NULL, empid INTEGER NOT NULL, commission INTEGER, RCNF INTEGER NOT NULL, RCNL INTEGER NOT NULL, R INTEGER NOT NULL, RD INTEGER NOT NULL]")
+            "[deptno INTEGER NOT NULL, empid INTEGER NOT NULL, commission INTEGER, R INTEGER NOT NULL, RCNF INTEGER NOT NULL, RCNL INTEGER NOT NULL, R INTEGER NOT NULL, RD INTEGER NOT NULL]")
         .returnsUnordered(
-            "deptno=10; empid=100; commission=1000; RCNF=2; RCNL=1; R=1; RD=3",
-            "deptno=10; empid=110; commission=250; RCNF=3; RCNL=2; R=2; RD=2",
-            "deptno=10; empid=150; commission=null; RCNF=1; RCNL=3; R=3; RD=1",
-            "deptno=20; empid=200; commission=500; RCNF=1; RCNL=1; R=1; RD=1");
+            "deptno=10; empid=100; commission=1000; R=1; RCNF=2; RCNL=1; R=1; RD=3",
+            "deptno=10; empid=110; commission=250; R=3; RCNF=3; RCNL=2; R=2; RD=2",
+            "deptno=10; empid=150; commission=null; R=2; RCNF=1; RCNL=3; R=3; RD=1",
+            "deptno=20; empid=200; commission=500; R=1; RCNF=1; RCNL=1; R=1; RD=1");
   }
 
   /** Tests UNBOUNDED PRECEDING clause. */
@@ -4595,7 +4596,16 @@ public class JdbcTest {
     final FileReader fileReader = new FileReader(inFile);
     final BufferedReader bufferedReader = new BufferedReader(fileReader);
     final FileWriter writer = new FileWriter(outFile);
-    final Quidem quidem = new Quidem(bufferedReader, writer);
+    final Function<String, Object> env =
+        new Function<String, Object>() {
+          public Object apply(String varName) {
+            if (varName.equals("jdk18")) {
+              return System.getProperty("java.version").startsWith("1.8");
+            }
+            return null;
+          }
+        };
+    final Quidem quidem = new Quidem(bufferedReader, writer, env);
     quidem.execute(
         new Quidem.ConnectionFactory() {
           public Connection connect(String name) throws Exception {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/096d2820/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index 76413ec..106ad92 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -107,6 +107,9 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
   private static final String STR_SET_OP_INCONSISTENT =
       "Set operator cannot combine streaming and non-streaming inputs";
 
+  private static final String ROW_RANGE_NOT_ALLOWED_WITH_RANK =
+      "ROW/RANGE not allowed with RANK, DENSE_RANK or ROW_NUMBER functions";
+
   //~ Constructors -----------------------------------------------------------
 
   public SqlValidatorTest() {
@@ -3891,9 +3894,9 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
     winExp("row_number() over (partition by deptno)").ok();
     winExp("row_number() over ()").ok();
     winExp("row_number() over (order by deptno ^rows^ 2 preceding)")
-        .fails("ROW/RANGE not allowed with RANK or DENSE_RANK functions");
+        .fails(ROW_RANGE_NOT_ALLOWED_WITH_RANK);
     winExp("row_number() over (order by deptno ^range^ 2 preceding)")
-        .fails("ROW/RANGE not allowed with RANK or DENSE_RANK functions");
+        .fails(ROW_RANGE_NOT_ALLOWED_WITH_RANK);
 
     // rank function type
     if (defined.contains("DENSE_RANK")) {
@@ -3928,10 +3931,10 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
     // window framing defined in window clause
     winSql(
         "select rank() over w from emp window w as (order by empno ^rows^ 2 preceding )")
-        .fails("ROW/RANGE not allowed with RANK or DENSE_RANK functions");
+        .fails(ROW_RANGE_NOT_ALLOWED_WITH_RANK);
     winSql(
         "select dense_rank() over w from emp window w as (order by empno ^rows^ 2 preceding)")
-        .fails("ROW/RANGE not allowed with RANK or DENSE_RANK functions");
+        .fails(ROW_RANGE_NOT_ALLOWED_WITH_RANK);
     if (defined.contains("PERCENT_RANK")) {
       winSql("select percent_rank() over w from emp\n"
           + "window w as (order by empno)")
@@ -3939,7 +3942,7 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
       winSql(
           "select percent_rank() over w from emp\n"
           + "window w as (order by empno ^rows^ 2 preceding)")
-          .fails("ROW/RANGE not allowed with RANK or DENSE_RANK functions");
+          .fails(ROW_RANGE_NOT_ALLOWED_WITH_RANK);
       winSql(
           "select percent_rank() over w from emp\n"
           + "window w as ^(partition by empno)^")
@@ -3957,7 +3960,7 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
               "RANK or DENSE_RANK functions require ORDER BY clause in window specification");
       winSql(
           "select cume_dist() over w from emp window w as (order by empno ^rows^ 2 preceding)")
-          .fails("ROW/RANGE not allowed with RANK or DENSE_RANK functions");
+          .fails(ROW_RANGE_NOT_ALLOWED_WITH_RANK);
       winSql(
           "select cume_dist() over w from emp window w as (order by empno)")
           .ok();
@@ -3969,10 +3972,10 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
     }
     // window framing defined in in-line window
     winSql("select rank() over (order by empno ^range^ 2 preceding ) from emp ")
-        .fails("ROW/RANGE not allowed with RANK or DENSE_RANK functions");
+        .fails(ROW_RANGE_NOT_ALLOWED_WITH_RANK);
     winSql(
         "select dense_rank() over (order by empno ^rows^ 2 preceding ) from emp ")
-        .fails("ROW/RANGE not allowed with RANK or DENSE_RANK functions");
+        .fails(ROW_RANGE_NOT_ALLOWED_WITH_RANK);
     if (defined.contains("PERCENT_RANK")) {
       winSql("select percent_rank() over (order by empno) from emp").ok();
     }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/096d2820/core/src/test/resources/sql/winagg.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/winagg.oq b/core/src/test/resources/sql/winagg.oq
index d3c4b69..590af75 100644
--- a/core/src/test/resources/sql/winagg.oq
+++ b/core/src/test/resources/sql/winagg.oq
@@ -145,6 +145,7 @@ select *, rank() over (order by deptno) as c from emp;
 (9 rows)
 
 !ok
+
 # Calcite does not yet generate tied ranks
 select *, dense_rank() over (order by deptno) as c from emp;
  ENAME | DEPTNO | GENDER | C
@@ -161,6 +162,54 @@ select *, dense_rank() over (order by deptno) as c from emp;
 (9 rows)
 
 !ok
+
+# [CALCITE-806] ROW_NUMBER should emit distinct values
+#
+# We only run this test under JDK 1.8 because the results are
+# non-deterministic and are different (but still correct) on
+# JDK 1.7 and other platforms.
+!if (jdk18) {
+select *,
+  row_number() over (order by deptno) as r1,
+  row_number() over (partition by deptno order by gender desc) as r2,
+  row_number() over (partition by deptno order by gender) as r3,
+  row_number() over (partition by gender) as r4,
+  row_number() over () as r
+from emp;
+ ENAME | DEPTNO | GENDER | R1 | R2 | R3 | R4 | R
+-------+--------+--------+----+----+----+----+---
+ Wilma |        | F      |  9 |  1 |  1 |  1 | 1
+ Eve   |     50 | F      |  7 |  2 |  1 |  2 | 2
+ Jane  |     10 | F      |  1 |  2 |  1 |  3 | 3
+ Grace |     60 | F      |  8 |  1 |  1 |  4 | 4
+ Susan |     30 | F      |  4 |  1 |  1 |  5 | 5
+ Alice |     30 | F      |  5 |  2 |  2 |  6 | 6
+ Adam  |     50 | M      |  6 |  1 |  2 |  1 | 7
+ Eric  |     20 | M      |  3 |  1 |  1 |  2 | 8
+ Bob   |     10 | M      |  2 |  1 |  2 |  3 | 9
+(9 rows)
+
+!ok
+!}
+
+# As above, ROW_NUMBER without explicit ORDER BY
+select deptno,
+  ename,
+  row_number() over (partition by deptno) as r
+from emp
+where gender = 'F';
+ DEPTNO | ENAME | R
+--------+-------+---
+     10 | Jane  | 1
+     30 | Alice | 2
+     30 | Susan | 1
+     50 | Eve   | 1
+     60 | Grace | 1
+        | Wilma | 1
+(6 rows)
+
+!ok
+
 !if (false) {
 select *, count(*) over (order by deptno), first_value(ename) over (order by deptno rows 2 following) from emp;
  ERROR:  frame starting from following row cannot end with current row
@@ -184,6 +233,7 @@ select *, count(*) over (partition by deptno) as c from emp;
 (9 rows)
 
 !ok
+
 # No ORDER BY, windows defined in WINDOW clause.
 select deptno, gender, min(gender) over w1 as a, min(gender) over w2 as d
 from emp
@@ -224,13 +274,11 @@ window w1 as ();
 !ok
 
 # Window Aggregate and group-by.
-# (ORDER BY is necessary to work around [QUIDEM-7].)
 !set outputformat mysql
 select min(deptno) as x, rank() over (order by ename) as y,
   max(ename) over (partition by deptno) as z
 from emp
-group by deptno, ename
-order by ename;
+group by deptno, ename;
 
 +----+---+-------+
 | X  | Y | Z     |

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/096d2820/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index b44db5b..c48cc52 100644
--- a/pom.xml
+++ b/pom.xml
@@ -200,7 +200,7 @@ limitations under the License.
       <dependency>
         <groupId>net.hydromatic</groupId>
         <artifactId>quidem</artifactId>
-        <version>0.5</version>
+        <version>0.6</version>
       </dependency>
       <dependency>
         <groupId>net.hydromatic</groupId>


[44/50] incubator-calcite git commit: [CALCITE-850] Remove push down expressions from FilterJoinRule and create a new rule for it

Posted by jh...@apache.org.
[CALCITE-850] Remove push down expressions from FilterJoinRule and create a new rule for it

Close apache/incubator-calcite#122


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

Branch: refs/heads/branch-release
Commit: 9f1f73d392fbff4f0ac2b29cc9462cf388be645d
Parents: 6bc8efc
Author: Jesus Camacho Rodriguez <jc...@apache.org>
Authored: Thu Aug 20 13:03:49 2015 +0300
Committer: Jesus Camacho Rodriguez <jc...@apache.org>
Committed: Fri Aug 21 14:02:29 2015 +0300

----------------------------------------------------------------------
 .../calcite/prepare/CalcitePrepareImpl.java     |   2 +
 .../calcite/rel/rules/FilterJoinRule.java       |   6 --
 .../rel/rules/JoinPushExpressionsRule.java      |  67 ++++++++++++
 .../apache/calcite/test/JdbcAdapterTest.java    | 101 +++++++++----------
 .../java/org/apache/calcite/test/JdbcTest.java  |   2 +-
 .../apache/calcite/test/RelOptRulesTest.java    |   7 +-
 .../enumerable/EnumerableCorrelateTest.java     |   4 +-
 core/src/test/resources/sql/misc.oq             |   4 +-
 8 files changed, 130 insertions(+), 63 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9f1f73d3/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 674f093..144755a 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -76,6 +76,7 @@ import org.apache.calcite.rel.rules.FilterProjectTransposeRule;
 import org.apache.calcite.rel.rules.FilterTableScanRule;
 import org.apache.calcite.rel.rules.JoinAssociateRule;
 import org.apache.calcite.rel.rules.JoinCommuteRule;
+import org.apache.calcite.rel.rules.JoinPushExpressionsRule;
 import org.apache.calcite.rel.rules.JoinPushThroughJoinRule;
 import org.apache.calcite.rel.rules.ProjectFilterTransposeRule;
 import org.apache.calcite.rel.rules.ProjectMergeRule;
@@ -209,6 +210,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
           ProjectFilterTransposeRule.INSTANCE,
           FilterProjectTransposeRule.INSTANCE,
           FilterJoinRule.FILTER_ON_JOIN,
+          JoinPushExpressionsRule.INSTANCE,
           AggregateExpandDistinctAggregatesRule.INSTANCE,
           AggregateReduceFunctionsRule.INSTANCE,
           FilterAggregateTransposeRule.INSTANCE,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9f1f73d3/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
index 844980a..f393ffd 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
@@ -247,12 +247,6 @@ public abstract class FilterJoinRule extends RelOptRule {
     newJoinRel = RelOptUtil.createCastRel(newJoinRel, join.getRowType(),
         false, projectFactory);
 
-    // Push expression in join condition into Project below Join.
-    if (newJoinRel instanceof Join) {
-      newJoinRel = RelOptUtil.pushDownJoinConditions(
-          (Join) newJoinRel, projectFactory);
-    }
-
     // create a FilterRel on top of the join if needed
     RelNode newRel =
         RelOptUtil.createFilter(newJoinRel,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9f1f73d3/core/src/main/java/org/apache/calcite/rel/rules/JoinPushExpressionsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinPushExpressionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinPushExpressionsRule.java
new file mode 100644
index 0000000..3e9ec97
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinPushExpressionsRule.java
@@ -0,0 +1,67 @@
+/*
+ * 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.rel.rules;
+
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Join;
+import org.apache.calcite.rel.core.RelFactories;
+import org.apache.calcite.rex.RexNode;
+
+/**
+ * Planner rule that pushes down expressions in "equal" join condition.
+ *
+ * <p>For example, given
+ * "emp JOIN dept ON emp.deptno + 1 = dept.deptno", adds a project above
+ * "emp" that computes the expression
+ * "emp.deptno + 1". The resulting join condition is a simple combination
+ * of AND, equals, and input fields, plus the remaining non-equal conditions.
+ */
+public class JoinPushExpressionsRule extends RelOptRule {
+
+  public static final JoinPushExpressionsRule INSTANCE = new JoinPushExpressionsRule(
+          Join.class, RelFactories.DEFAULT_PROJECT_FACTORY);
+
+  private final RelFactories.ProjectFactory projectFactory;
+
+
+  public JoinPushExpressionsRule(Class<? extends Join> clazz,
+      RelFactories.ProjectFactory projectFactory) {
+    super(operand(clazz, any()));
+    this.projectFactory = projectFactory;
+  }
+
+  @Override public void onMatch(RelOptRuleCall call) {
+    Join join = call.rel(0);
+
+    // Push expression in join condition into Project below Join.
+    RelNode newJoin = RelOptUtil.pushDownJoinConditions(join, projectFactory);
+
+    // If the join is the same, we bail out
+    if (newJoin instanceof Join) {
+      final RexNode newCondition = ((Join) newJoin).getCondition();
+      if (join.getCondition().toString().equals(newCondition.toString())) {
+        return;
+      }
+    }
+
+    call.transformTo(newJoin);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9f1f73d3/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
index 1ba17d3..ea69cae 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
@@ -95,20 +95,20 @@ public class JdbcAdapterTest {
             + "from scott.emp e inner join scott.dept d \n"
             + "on e.deptno = d.deptno")
         .explainContains("PLAN=JdbcToEnumerableConverter\n"
-            + "  JdbcProject(EMPNO=[$2], ENAME=[$3], DEPTNO=[$4], DNAME=[$1])\n"
-            + "    JdbcJoin(condition=[=($4, $0)], joinType=[inner])\n"
-            + "      JdbcProject(DEPTNO=[$0], DNAME=[$1])\n"
-            + "        JdbcTableScan(table=[[SCOTT, DEPT]])\n"
+            + "  JdbcProject(EMPNO=[$0], ENAME=[$1], DEPTNO=[$2], DNAME=[$4])\n"
+            + "    JdbcJoin(condition=[=($2, $3)], joinType=[inner])\n"
             + "      JdbcProject(EMPNO=[$0], ENAME=[$1], DEPTNO=[$7])\n"
-            + "        JdbcTableScan(table=[[SCOTT, EMP]])")
+            + "        JdbcTableScan(table=[[SCOTT, EMP]])\n"
+            + "      JdbcProject(DEPTNO=[$0], DNAME=[$1])\n"
+            + "        JdbcTableScan(table=[[SCOTT, DEPT]])")
         .runs()
         .enable(CalciteAssert.DB == CalciteAssert.DatabaseInstance.HSQLDB)
-        .planHasSql("SELECT \"t0\".\"EMPNO\", \"t0\".\"ENAME\", "
-            + "\"t0\".\"DEPTNO\", \"t\".\"DNAME\"\n"
-            + "FROM (SELECT \"DEPTNO\", \"DNAME\"\n"
-            + "FROM \"SCOTT\".\"DEPT\") AS \"t\"\n"
-            + "INNER JOIN (SELECT \"EMPNO\", \"ENAME\", \"DEPTNO\"\n"
-            + "FROM \"SCOTT\".\"EMP\") AS \"t0\" "
+        .planHasSql("SELECT \"t\".\"EMPNO\", \"t\".\"ENAME\", "
+            + "\"t\".\"DEPTNO\", \"t0\".\"DNAME\"\n"
+            + "FROM (SELECT \"EMPNO\", \"ENAME\", \"DEPTNO\"\n"
+            + "FROM \"SCOTT\".\"EMP\") AS \"t\"\n"
+            + "INNER JOIN (SELECT \"DEPTNO\", \"DNAME\"\n"
+            + "FROM \"SCOTT\".\"DEPT\") AS \"t0\" "
             + "ON \"t\".\"DEPTNO\" = \"t0\".\"DEPTNO\"");
   }
 
@@ -121,18 +121,17 @@ public class JdbcAdapterTest {
             + "from scott.emp e inner join scott.salgrade s \n"
             + "on e.sal > s.losal and e.sal < s.hisal")
         .explainContains("PLAN=JdbcToEnumerableConverter\n"
-            + "  JdbcProject(EMPNO=[$3], ENAME=[$4], GRADE=[$0])\n"
-            + "    JdbcJoin(condition=[AND(>($5, $1), <($5, $2))], joinType=[inner])\n"
-            + "      JdbcTableScan(table=[[SCOTT, SALGRADE]])\n"
+            + "  JdbcProject(EMPNO=[$0], ENAME=[$1], GRADE=[$3])\n"
+            + "    JdbcJoin(condition=[AND(>($2, $4), <($2, $5))], joinType=[inner])\n"
             + "      JdbcProject(EMPNO=[$0], ENAME=[$1], SAL=[$5])\n"
-            + "        JdbcTableScan(table=[[SCOTT, EMP]])")
+            + "        JdbcTableScan(table=[[SCOTT, EMP]])\n"
+            + "      JdbcTableScan(table=[[SCOTT, SALGRADE]])")
         .runs()
         .enable(CalciteAssert.DB == CalciteAssert.DatabaseInstance.HSQLDB)
         .planHasSql("SELECT \"t\".\"EMPNO\", \"t\".\"ENAME\", "
             + "\"SALGRADE\".\"GRADE\"\n"
-            + "FROM \"SCOTT\".\"SALGRADE\"\n"
-            + "INNER JOIN (SELECT \"EMPNO\", \"ENAME\", \"SAL\"\n"
-            + "FROM \"SCOTT\".\"EMP\") AS \"t\" ON \"SALGRADE\".\"LOSAL\" < \"t\".\"SAL\" AND \"SALGRADE\".\"HISAL\" > \"t\".\"SAL\"");
+            + "FROM (SELECT \"EMPNO\", \"ENAME\", \"SAL\"\nFROM \"SCOTT\".\"EMP\") AS \"t\"\n"
+            + "INNER JOIN \"SCOTT\".\"SALGRADE\" ON \"t\".\"SAL\" > \"SALGRADE\".\"LOSAL\" AND \"t\".\"SAL\" < \"SALGRADE\".\"HISAL\"");
   }
 
   @Test public void testNonEquiJoinReverseConditionPlan() {
@@ -141,18 +140,18 @@ public class JdbcAdapterTest {
             + "from scott.emp e inner join scott.salgrade s \n"
             + "on s.losal <= e.sal and s.hisal >= e.sal")
         .explainContains("PLAN=JdbcToEnumerableConverter\n"
-            + "  JdbcProject(EMPNO=[$3], ENAME=[$4], GRADE=[$0])\n"
-            + "    JdbcJoin(condition=[AND(<=($1, $5), >=($2, $5))], joinType=[inner])\n"
-            + "      JdbcTableScan(table=[[SCOTT, SALGRADE]])\n"
+            + "  JdbcProject(EMPNO=[$0], ENAME=[$1], GRADE=[$3])\n"
+            + "    JdbcJoin(condition=[AND(<=($4, $2), >=($5, $2))], joinType=[inner])\n"
             + "      JdbcProject(EMPNO=[$0], ENAME=[$1], SAL=[$5])\n"
-            + "        JdbcTableScan(table=[[SCOTT, EMP]])")
+            + "        JdbcTableScan(table=[[SCOTT, EMP]])\n"
+            + "      JdbcTableScan(table=[[SCOTT, SALGRADE]])")
         .runs()
         .enable(CalciteAssert.DB == CalciteAssert.DatabaseInstance.HSQLDB)
         .planHasSql("SELECT \"t\".\"EMPNO\", \"t\".\"ENAME\", "
             + "\"SALGRADE\".\"GRADE\"\n"
-            + "FROM \"SCOTT\".\"SALGRADE\"\n"
-            + "INNER JOIN (SELECT \"EMPNO\", \"ENAME\", \"SAL\"\n"
-            + "FROM \"SCOTT\".\"EMP\") AS \"t\" ON \"SALGRADE\".\"LOSAL\" <= \"t\".\"SAL\" AND \"SALGRADE\".\"HISAL\" >= \"t\".\"SAL\"");
+            + "FROM (SELECT \"EMPNO\", \"ENAME\", \"SAL\"\n"
+            + "FROM \"SCOTT\".\"EMP\") AS \"t\"\n"
+            + "INNER JOIN \"SCOTT\".\"SALGRADE\" ON \"t\".\"SAL\" >= \"SALGRADE\".\"LOSAL\" AND \"t\".\"SAL\" <= \"SALGRADE\".\"HISAL\"");
   }
 
   @Test public void testMixedJoinPlan() {
@@ -161,20 +160,20 @@ public class JdbcAdapterTest {
             + "from scott.emp e inner join scott.emp m on  \n"
             + "e.mgr = m.empno and e.sal > m.sal")
         .explainContains("PLAN=JdbcToEnumerableConverter\n"
-            + "  JdbcProject(EMPNO=[$2], ENAME=[$3], EMPNO0=[$2], ENAME0=[$3])\n"
-            + "    JdbcJoin(condition=[AND(=($4, $0), >($5, $1))], joinType=[inner])\n"
-            + "      JdbcProject(EMPNO=[$0], SAL=[$5])\n"
-            + "        JdbcTableScan(table=[[SCOTT, EMP]])\n"
+            + "  JdbcProject(EMPNO=[$0], ENAME=[$1], EMPNO0=[$0], ENAME0=[$1])\n"
+            + "    JdbcJoin(condition=[AND(=($2, $4), >($3, $5))], joinType=[inner])\n"
             + "      JdbcProject(EMPNO=[$0], ENAME=[$1], MGR=[$3], SAL=[$5])\n"
+            + "        JdbcTableScan(table=[[SCOTT, EMP]])\n"
+            + "      JdbcProject(EMPNO=[$0], SAL=[$5])\n"
             + "        JdbcTableScan(table=[[SCOTT, EMP]])")
         .runs()
         .enable(CalciteAssert.DB == CalciteAssert.DatabaseInstance.HSQLDB)
-        .planHasSql("SELECT \"t0\".\"EMPNO\", \"t0\".\"ENAME\", "
-            + "\"t0\".\"EMPNO\" AS \"EMPNO0\", \"t0\".\"ENAME\" AS \"ENAME0\"\n"
-            + "FROM (SELECT \"EMPNO\", \"SAL\"\n"
+        .planHasSql("SELECT \"t\".\"EMPNO\", \"t\".\"ENAME\", "
+            + "\"t\".\"EMPNO\" AS \"EMPNO0\", \"t\".\"ENAME\" AS \"ENAME0\"\n"
+            + "FROM (SELECT \"EMPNO\", \"ENAME\", \"MGR\", \"SAL\"\n"
             + "FROM \"SCOTT\".\"EMP\") AS \"t\"\n"
-            + "INNER JOIN (SELECT \"EMPNO\", \"ENAME\", \"MGR\", \"SAL\"\n"
-            + "FROM \"SCOTT\".\"EMP\") AS \"t0\" ON \"t\".\"EMPNO\" = \"t0\".\"MGR\" AND \"t\".\"SAL\" < \"t0\".\"SAL\"");
+            + "INNER JOIN (SELECT \"EMPNO\", \"SAL\"\n"
+            + "FROM \"SCOTT\".\"EMP\") AS \"t0\" ON \"t\".\"MGR\" = \"t0\".\"EMPNO\" AND \"t\".\"SAL\" > \"t0\".\"SAL\"");
   }
 
   @Test public void testMixedJoinWithOrPlan() {
@@ -183,20 +182,20 @@ public class JdbcAdapterTest {
             + "from scott.emp e inner join scott.emp m on  \n"
             + "e.mgr = m.empno and (e.sal > m.sal or m.hiredate > e.hiredate)")
         .explainContains("PLAN=JdbcToEnumerableConverter\n"
-            + "  JdbcProject(EMPNO=[$3], ENAME=[$4], EMPNO0=[$3], ENAME0=[$4])\n"
-            + "    JdbcJoin(condition=[AND(=($5, $0), OR(>($7, $2), >($1, $6)))], joinType=[inner])\n"
-            + "      JdbcProject(EMPNO=[$0], HIREDATE=[$4], SAL=[$5])\n"
-            + "        JdbcTableScan(table=[[SCOTT, EMP]])\n"
+            + "  JdbcProject(EMPNO=[$0], ENAME=[$1], EMPNO0=[$0], ENAME0=[$1])\n"
+            + "    JdbcJoin(condition=[AND(=($2, $5), OR(>($4, $7), >($6, $3)))], joinType=[inner])\n"
             + "      JdbcProject(EMPNO=[$0], ENAME=[$1], MGR=[$3], HIREDATE=[$4], SAL=[$5])\n"
+            + "        JdbcTableScan(table=[[SCOTT, EMP]])\n"
+            + "      JdbcProject(EMPNO=[$0], HIREDATE=[$4], SAL=[$5])\n"
             + "        JdbcTableScan(table=[[SCOTT, EMP]])")
         .runs()
         .enable(CalciteAssert.DB == CalciteAssert.DatabaseInstance.HSQLDB)
-        .planHasSql("SELECT \"t0\".\"EMPNO\", \"t0\".\"ENAME\", "
-            + "\"t0\".\"EMPNO\" AS \"EMPNO0\", \"t0\".\"ENAME\" AS \"ENAME0\"\n"
-            + "FROM (SELECT \"EMPNO\", \"HIREDATE\", \"SAL\"\n"
+        .planHasSql("SELECT \"t\".\"EMPNO\", \"t\".\"ENAME\", "
+            + "\"t\".\"EMPNO\" AS \"EMPNO0\", \"t\".\"ENAME\" AS \"ENAME0\"\n"
+            + "FROM (SELECT \"EMPNO\", \"ENAME\", \"MGR\", \"HIREDATE\", \"SAL\"\n"
             + "FROM \"SCOTT\".\"EMP\") AS \"t\"\n"
-            + "INNER JOIN (SELECT \"EMPNO\", \"ENAME\", \"MGR\", \"HIREDATE\", \"SAL\"\n"
-            + "FROM \"SCOTT\".\"EMP\") AS \"t0\" ON \"t\".\"EMPNO\" = \"t0\".\"MGR\" AND (\"t\".\"SAL\" < \"t0\".\"SAL\" OR \"t\".\"HIREDATE\" > \"t0\".\"HIREDATE\")");
+            + "INNER JOIN (SELECT \"EMPNO\", \"HIREDATE\", \"SAL\"\n"
+            + "FROM \"SCOTT\".\"EMP\") AS \"t0\" ON \"t\".\"MGR\" = \"t0\".\"EMPNO\" AND (\"t\".\"SAL\" > \"t0\".\"SAL\" OR \"t\".\"HIREDATE\" < \"t0\".\"HIREDATE\")");
   }
 
   @Test public void tesJoin3TablesPlan() {
@@ -207,19 +206,19 @@ public class JdbcAdapterTest {
             + "inner join scott.salgrade s \n"
             + "on e.sal > s.losal and e.sal < s.hisal")
         .explainContains("PLAN=JdbcToEnumerableConverter\n"
-            + "  JdbcProject(EMPNO=[$0], ENAME=[$1], DNAME=[$12], GRADE=[$8])\n"
-            + "    JdbcJoin(condition=[=($7, $11)], joinType=[inner])\n"
-            + "      JdbcJoin(condition=[AND(>($5, $9), <($5, $10))], joinType=[inner])\n"
+            + "  JdbcProject(EMPNO=[$3], ENAME=[$4], DNAME=[$12], GRADE=[$0])\n"
+            + "    JdbcJoin(condition=[AND(>($8, $1), <($8, $2))], joinType=[inner])\n"
+            + "      JdbcTableScan(table=[[SCOTT, SALGRADE]])\n"
+            + "      JdbcJoin(condition=[=($7, $8)], joinType=[inner])\n"
             + "        JdbcTableScan(table=[[SCOTT, EMP]])\n"
-            + "        JdbcTableScan(table=[[SCOTT, SALGRADE]])\n"
-            + "      JdbcTableScan(table=[[SCOTT, DEPT]])")
+            + "        JdbcTableScan(table=[[SCOTT, DEPT]])")
         .runs()
         .enable(CalciteAssert.DB == CalciteAssert.DatabaseInstance.HSQLDB)
         .planHasSql("SELECT \"EMP\".\"EMPNO\", \"EMP\".\"ENAME\", "
             + "\"DEPT\".\"DNAME\", \"SALGRADE\".\"GRADE\"\n"
-            + "FROM \"SCOTT\".\"EMP\"\n"
-            + "INNER JOIN \"SCOTT\".\"SALGRADE\" ON \"EMP\".\"SAL\" > \"SALGRADE\".\"LOSAL\" AND \"EMP\".\"SAL\" < \"SALGRADE\".\"HISAL\"\n"
-            + "INNER JOIN \"SCOTT\".\"DEPT\" ON \"EMP\".\"DEPTNO\" = \"DEPT\".\"DEPTNO\"");
+            + "FROM \"SCOTT\".\"SALGRADE\"\n"
+            + "INNER JOIN (\"SCOTT\".\"EMP\" INNER JOIN \"SCOTT\".\"DEPT\" ON \"EMP\".\"DEPTNO\" = \"DEPT\".\"DEPTNO\") "
+            + "ON \"SALGRADE\".\"LOSAL\" < \"EMP\".\"SAL\" AND \"SALGRADE\".\"HISAL\" > \"EMP\".\"SAL\"");
   }
 
   @Test public void testCrossJoinWithJoinKeyPlan() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9f1f73d3/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index e466f39..475ff51 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -2650,7 +2650,7 @@ public class JdbcTest {
         .query("select empno, desc from sales.emps,\n"
             + "  (SELECT * FROM (VALUES (10, 'SameName')) AS t (id, desc)) as sn\n"
             + "where emps.deptno = sn.id and sn.desc = 'SameName' group by empno, desc")
-        .explainContains("EnumerableCalc(expr#0..1=[{inputs}], EMPNO=[$t1], EXPR$1=[$t0])\n"
+        .explainContains("EnumerableCalc(expr#0..1=[{inputs}], EMPNO=[$t1], DESC=[$t0])\n"
             + "  EnumerableAggregate(group=[{1, 2}])\n"
             + "    EnumerableCalc(expr#0..3=[{inputs}], expr#4=[CAST($t3):INTEGER NOT NULL], expr#5=[=($t4, $t0)], expr#6=['SameName'], expr#7=[=($t1, $t6)], expr#8=[AND($t5, $t7)], proj#0..3=[{exprs}], $condition=[$t8])\n"
             + "      EnumerableJoin(condition=[true], joinType=[inner])\n"

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9f1f73d3/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index 013405c..d32c02d 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -52,6 +52,7 @@ import org.apache.calcite.rel.rules.JoinAddRedundantSemiJoinRule;
 import org.apache.calcite.rel.rules.JoinCommuteRule;
 import org.apache.calcite.rel.rules.JoinExtractFilterRule;
 import org.apache.calcite.rel.rules.JoinProjectTransposeRule;
+import org.apache.calcite.rel.rules.JoinPushExpressionsRule;
 import org.apache.calcite.rel.rules.JoinPushTransitivePredicatesRule;
 import org.apache.calcite.rel.rules.JoinToMultiJoinRule;
 import org.apache.calcite.rel.rules.JoinUnionTransposeRule;
@@ -1726,7 +1727,11 @@ public class RelOptRulesTest extends RelOptTestBase {
 
 
   @Test public void testPushJoinCondDownToProject() {
-    checkPlanning(FilterJoinRule.FILTER_ON_JOIN,
+    final HepProgram program = new HepProgramBuilder()
+        .addRuleInstance(FilterJoinRule.FILTER_ON_JOIN)
+        .addRuleInstance(JoinPushExpressionsRule.INSTANCE)
+        .build();
+    checkPlanning(program,
         "select d.deptno, e.deptno from sales.dept d, sales.emp e"
             + " where d.deptno + 10 = e.deptno * 2");
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9f1f73d3/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCorrelateTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCorrelateTest.java b/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCorrelateTest.java
index e4ae781..bfb1e75 100644
--- a/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCorrelateTest.java
+++ b/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCorrelateTest.java
@@ -33,9 +33,9 @@ public class EnumerableCorrelateTest {
             "select empid, name from emps e where exists (select 1 from depts d where d.deptno=e.deptno)")
         .explainContains(
             "EnumerableCalc(expr#0..4=[{inputs}], empid=[$t0], name=[$t2])\n"
-            + "  EnumerableSemiJoin(condition=[=($1, $6)], joinType=[inner])\n"
+            + "  EnumerableSemiJoin(condition=[=($1, $5)], joinType=[inner])\n"
             + "    EnumerableTableScan(table=[[s, emps]])\n"
-            + "    EnumerableCalc(expr#0..4=[{inputs}], expr#5=[true], $f0=[$t5], deptno0=[$t0])\n"
+            + "    EnumerableCalc(expr#0..4=[{inputs}], expr#5=[true], deptno0=[$t0], $f0=[$t5])\n"
             + "      EnumerableJoin(condition=[=($0, $1)], joinType=[inner])\n"
             + "        EnumerableAggregate(group=[{1}])\n"
             + "          EnumerableTableScan(table=[[s, emps]])\n"

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9f1f73d3/core/src/test/resources/sql/misc.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/misc.oq b/core/src/test/resources/sql/misc.oq
index 9bb8e58..1d1bd57 100644
--- a/core/src/test/resources/sql/misc.oq
+++ b/core/src/test/resources/sql/misc.oq
@@ -240,9 +240,9 @@ where exists (
 (3 rows)
 
 !ok
-EnumerableSemiJoin(condition=[=($1, $6)], joinType=[inner])
+EnumerableSemiJoin(condition=[=($1, $5)], joinType=[inner])
   EnumerableTableScan(table=[[hr, emps]])
-  EnumerableCalc(expr#0..4=[{inputs}], expr#5=[true], $f0=[$t5], deptno0=[$t0])
+  EnumerableCalc(expr#0..4=[{inputs}], expr#5=[true], deptno0=[$t0], $f0=[$t5])
     EnumerableJoin(condition=[=($0, $1)], joinType=[inner])
       EnumerableAggregate(group=[{1}])
         EnumerableTableScan(table=[[hr, emps]])