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/04 09:34:59 UTC

[01/10] incubator-calcite git commit: [CALCITE-868] Add API to execute queries expressed as RelNode

Repository: incubator-calcite
Updated Branches:
  refs/heads/master 3e4d2b5c7 -> ba789deb4


[CALCITE-868] Add API to execute queries expressed as RelNode


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

Branch: refs/heads/master
Commit: 2a215df30d26f4363e6a7fe2d27be0ee7db9357f
Parents: 3e4d2b5
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Aug 31 17:19:27 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 1 23:25:59 2015 -0700

----------------------------------------------------------------------
 .../calcite/jdbc/CalciteConnectionImpl.java     | 45 +++++++++--
 .../apache/calcite/jdbc/CalciteMetaImpl.java    |  6 +-
 .../org/apache/calcite/jdbc/CalcitePrepare.java | 34 ++++++++-
 .../apache/calcite/jdbc/CalciteStatement.java   |  3 +-
 .../calcite/prepare/CalcitePrepareImpl.java     | 79 +++++++++++++-------
 .../java/org/apache/calcite/schema/Schemas.java |  3 +-
 .../org/apache/calcite/tools/RelRunner.java     | 35 +++++++++
 .../org/apache/calcite/tools/RelRunners.java    | 43 +++++++++++
 .../org/apache/calcite/test/RelBuilderTest.java | 44 +++++++++++
 9 files changed, 252 insertions(+), 40 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2a215df3/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 d69971d..f563174 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
@@ -41,6 +41,7 @@ import org.apache.calcite.linq4j.tree.Expressions;
 import org.apache.calcite.materialize.Lattice;
 import org.apache.calcite.materialize.MaterializationService;
 import org.apache.calcite.prepare.CalciteCatalogReader;
+import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.type.RelDataTypeSystem;
 import org.apache.calcite.runtime.Hook;
 import org.apache.calcite.schema.SchemaPlus;
@@ -53,16 +54,20 @@ import org.apache.calcite.sql.advise.SqlAdvisorValidator;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.validate.SqlConformance;
 import org.apache.calcite.sql.validate.SqlValidatorWithHints;
+import org.apache.calcite.tools.RelRunner;
 import org.apache.calcite.util.BuiltInMethod;
 import org.apache.calcite.util.Holder;
 
 import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 
 import java.io.Serializable;
 import java.lang.reflect.Type;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.Iterator;
 import java.util.List;
@@ -143,6 +148,24 @@ abstract class CalciteConnectionImpl
     }
   }
 
+  @Override public <T> T unwrap(Class<T> iface) throws SQLException {
+    if (iface == RelRunner.class) {
+      return iface.cast(
+          new RelRunner() {
+            public PreparedStatement prepare(RelNode rel) {
+              try {
+                return prepareStatement_(CalcitePrepare.Query.of(rel),
+                    ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
+                    getHoldability());
+              } catch (SQLException e) {
+                throw Throwables.propagate(e);
+              }
+            }
+          });
+    }
+    return super.unwrap(iface);
+  }
+
   @Override public CalciteStatement createStatement(int resultSetType,
       int resultSetConcurrency, int resultSetHoldability) throws SQLException {
     return (CalciteStatement) super.createStatement(resultSetType,
@@ -154,23 +177,34 @@ abstract class CalciteConnectionImpl
       int resultSetType,
       int resultSetConcurrency,
       int resultSetHoldability) throws SQLException {
+    final CalcitePrepare.Query<Object> query = CalcitePrepare.Query.of(sql);
+    return prepareStatement_(query, resultSetType, resultSetConcurrency,
+        resultSetHoldability);
+  }
+
+  private CalcitePreparedStatement prepareStatement_(
+      CalcitePrepare.Query<?> query,
+      int resultSetType,
+      int resultSetConcurrency,
+      int resultSetHoldability) throws SQLException {
     try {
-      Meta.Signature signature =
-          parseQuery(sql, new ContextImpl(this), -1);
+      final Meta.Signature signature =
+          parseQuery(query, new ContextImpl(this), -1);
       return (CalcitePreparedStatement) factory.newPreparedStatement(this, null,
           signature, resultSetType, resultSetConcurrency, resultSetHoldability);
     } catch (Exception e) {
       throw Helper.INSTANCE.createException(
-          "Error while preparing statement [" + sql + "]", e);
+          "Error while preparing statement [" + query.sql + "]", e);
     }
   }
 
-  <T> CalcitePrepare.CalciteSignature<T> parseQuery(String sql,
+  <T> CalcitePrepare.CalciteSignature<T>
+  parseQuery(CalcitePrepare.Query<T> query,
       CalcitePrepare.Context prepareContext, long maxRowCount) {
     CalcitePrepare.Dummy.push(prepareContext);
     try {
       final CalcitePrepare prepare = prepareFactory.apply();
-      return prepare.prepareSql(prepareContext, sql, null, Object[].class,
+      return prepare.prepareSql(prepareContext, query, Object[].class,
           maxRowCount);
     } finally {
       CalcitePrepare.Dummy.pop(prepareContext);
@@ -468,6 +502,7 @@ abstract class CalciteConnectionImpl
       this.iterator = iterator;
     }
   }
+
 }
 
 // End CalciteConnectionImpl.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2a215df3/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 fabaf26..49a65d7 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
@@ -545,8 +545,8 @@ public class CalciteMetaImpl extends MetaImpl {
 
     CalciteServerStatement statement = calciteConnection.server.getStatement(h);
     h.signature =
-        calciteConnection.parseQuery(sql, statement.createPrepareContext(),
-            maxRowCount);
+        calciteConnection.parseQuery(CalcitePrepare.Query.of(sql),
+            statement.createPrepareContext(), maxRowCount);
     statement.setSignature(h.signature);
     return h;
   }
@@ -560,7 +560,7 @@ public class CalciteMetaImpl extends MetaImpl {
         final CalciteConnectionImpl calciteConnection = getConnection();
         CalciteServerStatement statement =
             calciteConnection.server.getStatement(h);
-        signature = calciteConnection.parseQuery(sql,
+        signature = calciteConnection.parseQuery(CalcitePrepare.Query.of(sql),
             statement.createPrepareContext(), maxRowCount);
         statement.setSignature(signature);
         callback.assign(signature, null, -1);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2a215df3/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 b2c1821..197deb4 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
@@ -95,8 +95,7 @@ public interface CalcitePrepare {
 
   <T> CalciteSignature<T> prepareSql(
       Context context,
-      String sql,
-      Queryable<T> expression,
+      Query<T> query,
       Type elementType,
       long maxRowCount);
 
@@ -319,6 +318,37 @@ public interface CalcitePrepare {
       return collationList;
     }
   }
+
+  /** A union type of the three possible ways of expressing a query: as a SQL
+   * string, a {@link Queryable} or a {@link RelNode}. Exactly one must be
+   * provided. */
+  class Query<T> {
+    public final String sql;
+    public final Queryable<T> queryable;
+    public final RelNode rel;
+
+    private Query(String sql, Queryable<T> queryable, RelNode rel) {
+      this.sql = sql;
+      this.queryable = queryable;
+      this.rel = rel;
+
+      assert (sql == null ? 0 : 1)
+          + (queryable == null ? 0 : 1)
+          + (rel == null ? 0 : 1) == 1;
+    }
+
+    public static <T> Query<T> of(String sql) {
+      return new Query<>(sql, null, null);
+    }
+
+    public static <T> Query<T> of(Queryable<T> queryable) {
+      return new Query<>(null, queryable, null);
+    }
+
+    public static <T> Query<T> of(RelNode rel) {
+      return new Query<>(null, null, rel);
+    }
+  }
 }
 
 // End CalcitePrepare.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2a215df3/core/src/main/java/org/apache/calcite/jdbc/CalciteStatement.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteStatement.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteStatement.java
index fa875e4..298b56c 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteStatement.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteStatement.java
@@ -48,8 +48,7 @@ public abstract class CalciteStatement extends AvaticaStatement {
 
   @Override public <T> T unwrap(Class<T> iface) throws SQLException {
     if (iface == CalciteServerStatement.class) {
-      //noinspection unchecked
-      return (T) getConnection().server.getStatement(handle);
+      return iface.cast(getConnection().server.getStatement(handle));
     }
     return super.unwrap(iface);
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2a215df3/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 b787a0f..87bd09f 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -70,6 +70,7 @@ import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.core.Filter;
 import org.apache.calcite.rel.core.Project;
+import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.rules.AggregateExpandDistinctAggregatesRule;
 import org.apache.calcite.rel.rules.AggregateReduceFunctionsRule;
@@ -124,6 +125,7 @@ import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
+import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
@@ -540,26 +542,25 @@ public class CalcitePrepareImpl implements CalcitePrepare {
   public <T> CalciteSignature<T> prepareQueryable(
       Context context,
       Queryable<T> queryable) {
-    return prepare_(context, null, queryable, queryable.getElementType(), -1);
+    return prepare_(context, Query.of(queryable), queryable.getElementType(),
+        -1);
   }
 
   public <T> CalciteSignature<T> prepareSql(
       Context context,
-      String sql,
-      Queryable<T> expression,
+      Query<T> query,
       Type elementType,
       long maxRowCount) {
-    return prepare_(context, sql, expression, elementType, maxRowCount);
+    return prepare_(context, query, elementType, maxRowCount);
   }
 
   <T> CalciteSignature<T> prepare_(
       Context context,
-      String sql,
-      Queryable<T> queryable,
+      Query<T> query,
       Type elementType,
       long maxRowCount) {
-    if (SIMPLE_SQLS.contains(sql)) {
-      return simplePrepare(context, sql);
+    if (SIMPLE_SQLS.contains(query.sql)) {
+      return simplePrepare(context, query.sql);
     }
     final JavaTypeFactory typeFactory = context.getTypeFactory();
     CalciteCatalogReader catalogReader =
@@ -580,7 +581,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
         throw new AssertionError("factory returned null planner");
       }
       try {
-        return prepare2_(context, sql, queryable, elementType, maxRowCount,
+        return prepare2_(context, query, elementType, maxRowCount,
             catalogReader, planner);
       } catch (RelOptPlanner.CannotPlanException e) {
         exception = e;
@@ -623,8 +624,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
 
   <T> CalciteSignature<T> prepare2_(
       Context context,
-      String sql,
-      Queryable<T> queryable,
+      Query<T> query,
       Type elementType,
       long maxRowCount,
       CalciteCatalogReader catalogReader,
@@ -645,10 +645,9 @@ public class CalcitePrepareImpl implements CalcitePrepare {
 
     final RelDataType x;
     final Prepare.PreparedResult preparedResult;
-    if (sql != null) {
-      assert queryable == null;
+    if (query.sql != null) {
       final CalciteConnectionConfig config = context.config();
-      SqlParser parser = createParser(sql,
+      SqlParser parser = createParser(query.sql,
           createParserConfig()
               .setQuotedCasing(config.quotedCasing())
               .setUnquotedCasing(config.unquotedCasing())
@@ -661,7 +660,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
             "parse failed: " + e.getMessage(), e);
       }
 
-      Hook.PARSE_TREE.run(new Object[] {sql, sqlNode});
+      Hook.PARSE_TREE.run(new Object[] {query.sql, sqlNode});
 
       if (sqlNode.getKind().belongsTo(SqlKind.DDL)) {
         executeDdl(context, sqlNode);
@@ -672,7 +671,8 @@ public class CalcitePrepareImpl implements CalcitePrepare {
             return Linq4j.emptyEnumerable();
           }
         };
-        return new CalciteSignature<>(sql, ImmutableList.<AvaticaParameter>of(),
+        return new CalciteSignature<>(query.sql,
+            ImmutableList.<AvaticaParameter>of(),
             ImmutableMap.<String, Object>of(), null,
             ImmutableList.<ColumnMetaData>of(), Meta.CursorFactory.OBJECT,
             ImmutableList.<RelCollation>of(), -1, bindable);
@@ -706,11 +706,14 @@ public class CalcitePrepareImpl implements CalcitePrepare {
       default:
         x = validator.getValidatedNodeType(sqlNode);
       }
-    } else {
-      assert queryable != null;
+    } else if (query.queryable != null) {
       x = context.getTypeFactory().createType(elementType);
       preparedResult =
-          preparingStmt.prepareQueryable(queryable, x);
+          preparingStmt.prepareQueryable(query.queryable, x);
+    } else {
+      assert query.rel != null;
+      x = query.rel.getRowType();
+      preparedResult = preparingStmt.prepareRel(query.rel);
     }
 
     final List<AvaticaParameter> parameters = new ArrayList<>();
@@ -739,7 +742,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
     //noinspection unchecked
     final Bindable<T> bindable = preparedResult.getBindable();
     return new CalciteSignature<>(
-        sql,
+        query.sql,
         parameters,
         preparingStmt.internalParameters,
         jdbcType,
@@ -948,23 +951,45 @@ public class CalcitePrepareImpl implements CalcitePrepare {
     }
 
     public PreparedResult prepareQueryable(
-        Queryable queryable,
+        final Queryable queryable,
+        RelDataType resultType) {
+      return prepare_(
+          new Supplier<RelNode>() {
+            public RelNode get() {
+              final RelOptCluster cluster =
+                  prepare.createCluster(planner, rexBuilder);
+              return new LixToRelTranslator(cluster, CalcitePreparingStmt.this)
+                  .translate(queryable);
+            }
+          }, resultType);
+    }
+
+    public PreparedResult prepareRel(final RelNode rel) {
+      return prepare_(
+          new Supplier<RelNode>() {
+            public RelNode get() {
+              return rel;
+            }
+          }, rel.getRowType());
+    }
+
+    private PreparedResult prepare_(Supplier<RelNode> fn,
         RelDataType resultType) {
       queryString = null;
       Class runtimeContextClass = Object.class;
       init(runtimeContextClass);
 
-      final RelOptCluster cluster = prepare.createCluster(planner, rexBuilder);
-
-      final RelNode rel =
-          new LixToRelTranslator(cluster, CalcitePreparingStmt.this)
-              .translate(queryable);
+      final RelNode rel = fn.get();
       final RelDataType rowType = rel.getRowType();
       final List<Pair<Integer, String>> fields =
           Pair.zip(ImmutableIntList.identity(rowType.getFieldCount()),
               rowType.getFieldNames());
+      final RelCollation collation =
+          rel instanceof Sort
+              ? ((Sort) rel).collation
+              : RelCollations.EMPTY;
       RelRoot root = new RelRoot(rel, resultType, SqlKind.SELECT, fields,
-          RelCollations.EMPTY);
+          collation);
 
       if (timingTracer != null) {
         timingTracer.traceTime("end sql2rel");

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2a215df3/core/src/main/java/org/apache/calcite/schema/Schemas.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/Schemas.java b/core/src/main/java/org/apache/calcite/schema/Schemas.java
index aa53419..639e852 100644
--- a/core/src/main/java/org/apache/calcite/schema/Schemas.java
+++ b/core/src/main/java/org/apache/calcite/schema/Schemas.java
@@ -343,7 +343,8 @@ public final class Schemas {
         makeContext(connection, schema, schemaPath, map);
     CalcitePrepare.Dummy.push(context);
     try {
-      return prepare.prepareSql(context, sql, null, Object[].class, -1);
+      return prepare.prepareSql(context, CalcitePrepare.Query.of(sql),
+          Object[].class, -1);
     } finally {
       CalcitePrepare.Dummy.pop(context);
     }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2a215df3/core/src/main/java/org/apache/calcite/tools/RelRunner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/RelRunner.java b/core/src/main/java/org/apache/calcite/tools/RelRunner.java
new file mode 100644
index 0000000..d29db9c
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/tools/RelRunner.java
@@ -0,0 +1,35 @@
+/*
+ * 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.tools;
+
+import org.apache.calcite.rel.RelNode;
+
+import java.sql.PreparedStatement;
+
+/**
+ * Runs a relational expression.
+ *
+ * <p>Experimental.
+ *
+ * @see RelRunners
+ */
+public interface RelRunner {
+  /** Runs a relational expression. */
+  PreparedStatement prepare(RelNode rel);
+}
+
+// End RelRunner.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2a215df3/core/src/main/java/org/apache/calcite/tools/RelRunners.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/RelRunners.java b/core/src/main/java/org/apache/calcite/tools/RelRunners.java
new file mode 100644
index 0000000..9db8e7c
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/tools/RelRunners.java
@@ -0,0 +1,43 @@
+/*
+ * 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.tools;
+
+import org.apache.calcite.rel.RelNode;
+
+import com.google.common.base.Throwables;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+/** Implementations of {@link RelRunner}. */
+public class RelRunners {
+  private RelRunners() {}
+
+  /** Runs a relational expression by creating a JDBC connection. */
+  public static PreparedStatement run(RelNode rel) {
+    try (Connection connection = DriverManager.getConnection("jdbc:calcite:")) {
+      final RelRunner runner = connection.unwrap(RelRunner.class);
+      return runner.prepare(rel);
+    } catch (SQLException e) {
+      throw Throwables.propagate(e);
+    }
+  }
+}
+
+// End RelRunners.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2a215df3/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 cafd61e..2aa0d50 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -37,10 +37,12 @@ import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.tools.Frameworks;
 import org.apache.calcite.tools.Programs;
 import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelRunners;
 import org.apache.calcite.util.Util;
 
 import org.junit.Test;
 
+import java.sql.PreparedStatement;
 import java.util.List;
 
 import static org.hamcrest.CoreMatchers.is;
@@ -738,6 +740,48 @@ public class RelBuilderTest {
             .build();
     assertThat(str(root2), is(expected));
   }
+
+  /** Tests {@link org.apache.calcite.tools.RelRunner} for a VALUES query. */
+  @Test public void testRunValues() throws Exception {
+    // Equivalent SQL:
+    //   VALUES (true, 1), (false, -50) AS t(a, b)
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.values(new String[]{"a", "b"}, true, 1, false, -50)
+            .build();
+    try (final PreparedStatement preparedStatement = RelRunners.run(root)) {
+      String s = CalciteAssert.toString(preparedStatement.executeQuery());
+      final String result = "a=true; b=1\n"
+          + "a=false; b=-50\n";
+      assertThat(s, is(result));
+    }
+  }
+
+  /** Tests {@link org.apache.calcite.tools.RelRunner} for a table scan + filter
+   * query. */
+  @Test public void testRun() throws Exception {
+    // Equivalent SQL:
+    //   SELECT * FROM EMP WHERE DEPTNO = 20
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .filter(
+                builder.equals(builder.field("DEPTNO"), builder.literal(20)))
+            .build();
+
+    // Note that because the table has been resolved in the RelNode tree
+    // we do not need to supply a "schema" as context to the runner.
+    try (final PreparedStatement preparedStatement = RelRunners.run(root)) {
+      String s = CalciteAssert.toString(preparedStatement.executeQuery());
+      final String result = ""
+          + "EMPNO=7369; ENAME=SMITH; JOB=CLERK; MGR=7902; HIREDATE=1980-12-17; SAL=800.00; COMM=null; DEPTNO=20\n"
+          + "EMPNO=7566; ENAME=JONES; JOB=MANAGER; MGR=7839; HIREDATE=1981-02-04; SAL=2975.00; COMM=null; DEPTNO=20\n"
+          + "EMPNO=7788; ENAME=SCOTT; JOB=ANALYST; MGR=7566; HIREDATE=1987-04-19; SAL=3000.00; COMM=null; DEPTNO=20\n"
+          + "EMPNO=7876; ENAME=ADAMS; JOB=CLERK; MGR=7788; HIREDATE=1987-05-23; SAL=1100.00; COMM=null; DEPTNO=20\n"
+          + "EMPNO=7902; ENAME=FORD; JOB=ANALYST; MGR=7566; HIREDATE=1981-12-03; SAL=3000.00; COMM=null; DEPTNO=20\n";
+      assertThat(s, is(result));
+    }
+  }
 }
 
 // End RelBuilderTest.java


[06/10] incubator-calcite git commit: Add ImmutableBitSet.get(int, int)

Posted by jh...@apache.org.
Add ImmutableBitSet.get(int, int)


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

Branch: refs/heads/master
Commit: f73c730f67f01369cd16570b6f7f3fdb02cf4015
Parents: c1fb829
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Sep 3 18:01:35 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Sep 3 18:17:38 2015 -0700

----------------------------------------------------------------------
 .../apache/calcite/util/ImmutableBitSet.java    | 39 ++++++++++++++++++++
 .../calcite/util/ImmutableBitSetTest.java       | 23 ++++++++++++
 2 files changed, 62 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f73c730f/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 5e569e0..e6da5c8 100644
--- a/core/src/main/java/org/apache/calcite/util/ImmutableBitSet.java
+++ b/core/src/main/java/org/apache/calcite/util/ImmutableBitSet.java
@@ -287,6 +287,45 @@ public class ImmutableBitSet
   }
 
   /**
+   * Returns a new {@code ImmutableBitSet}
+   * composed of bits from this {@code ImmutableBitSet}
+   * from {@code fromIndex} (inclusive) to {@code toIndex} (exclusive).
+   *
+   * @param  fromIndex index of the first bit to include
+   * @param  toIndex index after the last bit to include
+   * @return a new {@code ImmutableBitSet} from a range of
+   *         this {@code ImmutableBitSet}
+   * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+   *         or {@code toIndex} is negative, or {@code fromIndex} is
+   *         larger than {@code toIndex}
+   */
+  public ImmutableBitSet get(int fromIndex, int toIndex) {
+    checkRange(fromIndex, toIndex);
+    final Builder builder = builder();
+    for (int i = nextSetBit(fromIndex); i >= 0 && i < toIndex;
+         i = nextSetBit(i + 1)) {
+      builder.set(i);
+    }
+    return builder.build();
+  }
+
+  /**
+   * Checks that fromIndex ... toIndex is a valid range of bit indices.
+   */
+  private static void checkRange(int fromIndex, int toIndex) {
+    if (fromIndex < 0) {
+      throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
+    }
+    if (toIndex < 0) {
+      throw new IndexOutOfBoundsException("toIndex < 0: " + toIndex);
+    }
+    if (fromIndex > toIndex) {
+      throw new IndexOutOfBoundsException("fromIndex: " + fromIndex
+          + " > toIndex: " + toIndex);
+    }
+  }
+
+  /**
    * Returns a string representation of this bit set. For every index
    * for which this {@code BitSet} contains a bit in the set
    * state, the decimal representation of that index is included in

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f73c730f/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 b04c12a..a496fd9 100644
--- a/core/src/test/java/org/apache/calcite/util/ImmutableBitSetTest.java
+++ b/core/src/test/java/org/apache/calcite/util/ImmutableBitSetTest.java
@@ -472,6 +472,29 @@ public class ImmutableBitSetTest {
     final ImmutableBitSet empty = ImmutableBitSet.of();
     assertThat(empty.shift(-100), is(empty));
   }
+
+  @Test public void testGet2() {
+    final ImmutableBitSet bitSet = ImmutableBitSet.of(29, 4, 1969);
+    assertThat(bitSet.get(0, 8), is(ImmutableBitSet.of(4)));
+    assertThat(bitSet.get(0, 5), is(ImmutableBitSet.of(4)));
+    assertThat(bitSet.get(0, 4), is(ImmutableBitSet.of()));
+    assertThat(bitSet.get(4, 4), is(ImmutableBitSet.of()));
+    assertThat(bitSet.get(5, 5), is(ImmutableBitSet.of()));
+    assertThat(bitSet.get(4, 5), is(ImmutableBitSet.of(4)));
+    assertThat(bitSet.get(4, 1000), is(ImmutableBitSet.of(4, 29)));
+    assertThat(bitSet.get(4, 32), is(ImmutableBitSet.of(4, 29)));
+    assertThat(bitSet.get(2000, 10000), is(ImmutableBitSet.of()));
+    assertThat(bitSet.get(1000, 10000), is(ImmutableBitSet.of(1969)));
+    assertThat(bitSet.get(5, 10000), is(ImmutableBitSet.of(29, 1969)));
+    assertThat(bitSet.get(65, 10000), is(ImmutableBitSet.of(1969)));
+
+    final ImmutableBitSet emptyBitSet = ImmutableBitSet.of();
+    assertThat(emptyBitSet.get(0, 4), is(ImmutableBitSet.of()));
+    assertThat(emptyBitSet.get(0, 0), is(ImmutableBitSet.of()));
+    assertThat(emptyBitSet.get(0, 10000), is(ImmutableBitSet.of()));
+    assertThat(emptyBitSet.get(7, 10000), is(ImmutableBitSet.of()));
+    assertThat(emptyBitSet.get(73, 10000), is(ImmutableBitSet.of()));
+  }
 }
 
 // End ImmutableBitSetTest.java


[04/10] incubator-calcite git commit: [CALCITE-865] Unknown table type causes NullPointerException in JdbcSchema

Posted by jh...@apache.org.
[CALCITE-865] Unknown table type causes NullPointerException in JdbcSchema


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

Branch: refs/heads/master
Commit: d69f2c20c5a75977d50c182565d8e7b8e011515e
Parents: f98ed96
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Sep 3 15:09:32 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Sep 3 15:09:32 2015 -0700

----------------------------------------------------------------------
 .../java/org/apache/calcite/avatica/Meta.java   |   4 +
 .../apache/calcite/adapter/jdbc/JdbcSchema.java |   6 +-
 .../apache/calcite/adapter/jdbc/JdbcTable.java  |   3 +-
 .../java/org/apache/calcite/schema/Schema.java  | 105 +++++++++++++++----
 .../main/java/org/apache/calcite/util/Util.java |  22 +++-
 .../apache/calcite/test/JdbcAdapterTest.java    |  35 +++++++
 6 files changed, 153 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d69f2c20/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 d9fab4d..fe61aaf 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
@@ -260,6 +260,10 @@ public interface Meta {
       this.s = s;
     }
 
+    @Override public String toString() {
+      return "Pat[" + s + "]";
+    }
+
     @JsonCreator
     public static Pat of(@JsonProperty("s") String name) {
       return new Pat(name);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d69f2c20/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java
index 6495574..b83c76c 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java
@@ -201,6 +201,7 @@ public class JdbcSchema implements Schema {
         // returned by Phoenix among others, maps to TableType.SYSTEM_TABLE.
         // We know enum constants are upper-case without spaces, so we can't
         // make things worse.
+        //
         // PostgreSQL returns tableTypeName==null for pg_toast* tables
         // This can happen if you start JdbcSchema off a "public" PG schema
         // The tables are not designed to be queried by users, however we do
@@ -210,7 +211,10 @@ public class JdbcSchema implements Schema {
             ? null
             : tableTypeName.toUpperCase().replace(' ', '_');
         final TableType tableType =
-            Util.enumVal(TableType.class, tableTypeName2);
+            Util.enumVal(TableType.OTHER, tableTypeName2);
+        if (tableType == TableType.OTHER  && tableTypeName2 != null) {
+          System.out.println("Unknown table type: " + tableTypeName2);
+        }
         final JdbcTable table =
             new JdbcTable(this, catalogName, schemaName, tableName, tableType);
         builder.put(tableName, table);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d69f2c20/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
index fe6da60..f820c28 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
@@ -47,6 +47,7 @@ import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
 import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 
 import java.sql.SQLException;
@@ -80,7 +81,7 @@ class JdbcTable extends AbstractQueryableTable
     this.jdbcCatalogName = jdbcCatalogName;
     this.jdbcSchemaName = jdbcSchemaName;
     this.jdbcTableName = tableName;
-    this.jdbcTableType = jdbcTableType;
+    this.jdbcTableType = Preconditions.checkNotNull(jdbcTableType);
   }
 
   public String toString() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d69f2c20/core/src/main/java/org/apache/calcite/schema/Schema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/Schema.java b/core/src/main/java/org/apache/calcite/schema/Schema.java
index 065ec5d..6745e21 100644
--- a/core/src/main/java/org/apache/calcite/schema/Schema.java
+++ b/core/src/main/java/org/apache/calcite/schema/Schema.java
@@ -144,31 +144,30 @@ public interface Schema {
 
   /** Table type. */
   enum TableType {
-    /** A regular table. */
+    /** A regular table.
+     *
+     * <p>Used by PostgreSQL, MySQL and others. */
     TABLE,
 
     /** A relation whose contents are calculated by evaluating a SQL
-     * expression. */
+     * expression.
+     *
+     * <p>Used by PostgreSQL and others. */
     VIEW,
 
-    /** A table maintained by the system. Data dictionary tables, such as the
-     * "TABLES" and "COLUMNS" table in the "metamodel" schema, examples of
-     * system tables. */
-    SYSTEM_TABLE,
-
-    /** A table that is only visible to one connection. */
-    LOCAL_TEMPORARY,
+    /** Foreign table.
+     *
+     * <p>Used by PostgreSQL. */
+    FOREIGN_TABLE,
 
-    /** A structure, similar to a view, that is the basis for auto-generated
-     * materializations. It is either a single table or a collection of tables
-     * that are joined via many-to-one relationships from a central hub table.
-     * It is not available for queries, but is just used as an intermediate
-     * structure during query planning. */
-    STAR,
+    /** Materialized view.
+     *
+     * <p>Used by PostgreSQL. */
+    MATERIALIZED_VIEW,
 
     /** Index table.
      *
-     * <p>Used by Apache Phoenix. */
+     * <p>Used by Apache Phoenix, PostgreSQL. */
     INDEX,
 
     /** Join table.
@@ -178,12 +177,82 @@ public interface Schema {
 
     /** Sequence table.
      *
-     * <p>Used by Apache Phoenix, and others. Must have a single BIGINT column
-     * called "$seq". */
+     * <p>Used by Apache Phoenix, PostgreSQL and others.
+     * In Phoenix, must have a single BIGINT column called "$seq". */
     SEQUENCE,
 
+    /** A structure, similar to a view, that is the basis for auto-generated
+     * materializations. It is either a single table or a collection of tables
+     * that are joined via many-to-one relationships from a central hub table.
+     * It is not available for queries, but is just used as an intermediate
+     * structure during query planning. */
+    STAR,
+
     /** Stream. */
     STREAM,
+
+    /** Type.
+     *
+     * <p>Used by PostgreSQL. */
+    TYPE,
+
+    /** A table maintained by the system. Data dictionary tables, such as the
+     * "TABLES" and "COLUMNS" table in the "metamodel" schema, examples of
+     * system tables.
+     *
+     * <p>Used by PostgreSQL, MySQL and others. */
+    SYSTEM_TABLE,
+
+    /** System view.
+     *
+     * <p>Used by PostgreSQL, MySQL. */
+    SYSTEM_VIEW,
+
+    /** System index.
+     *
+     * <p>Used by PostgreSQL. */
+    SYSTEM_INDEX,
+
+    /** System TOAST index.
+     *
+     * <p>Used by PostgreSQL. */
+    SYSTEM_TOAST_INDEX,
+
+    /** System TOAST table.
+     *
+     * <p>Used by PostgreSQL. */
+    SYSTEM_TOAST_TABLE,
+
+    /** Temporary index.
+     *
+     * <p>Used by PostgreSQL. */
+    TEMPORARY_INDEX,
+
+    /** Temporary sequence.
+     *
+     * <p>Used by PostgreSQL. */
+    TEMPORARY_SEQUENCE,
+
+    /** Temporary table.
+     *
+     * <p>Used by PostgreSQL. */
+    TEMPORARY_TABLE,
+
+    /** Temporary view.
+     *
+     * <p>Used by PostgreSQL. */
+    TEMPORARY_VIEW,
+
+    /** A table that is only visible to one connection.
+     *
+     * <p>Used by PostgreSQL, MySQL. */
+    LOCAL_TEMPORARY,
+
+    /** Table type not known to Calcite.
+     *
+     * <p>If you get one of these, please fix the problem by adding an enum
+     * value. */
+    OTHER,
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d69f2c20/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 040775f..dbaf0a8 100644
--- a/core/src/main/java/org/apache/calcite/util/Util.java
+++ b/core/src/main/java/org/apache/calcite/util/Util.java
@@ -1859,11 +1859,29 @@ public class Util {
    * @param <T>   Enum class type
    * @return Enum constant or null
    */
-  @SuppressWarnings({"unchecked" })
   public static synchronized <T extends Enum<T>> T enumVal(
       Class<T> clazz,
       String name) {
-    return (T) ENUM_CONSTANTS.getUnchecked(clazz).get(name);
+    return clazz.cast(ENUM_CONSTANTS.getUnchecked(clazz).get(name));
+  }
+
+  /**
+   * Returns the value of an enumeration with a particular or default value if
+   * not found.
+   *
+   * @param default_ Default value (not null)
+   * @param name     Name of enum constant
+   * @param <T>      Enum class type
+   * @return         Enum constant, never null
+   */
+  public static synchronized <T extends Enum<T>> T enumVal(T default_,
+      String name) {
+    final Class<T> clazz = default_.getDeclaringClass();
+    final T t = clazz.cast(ENUM_CONSTANTS.getUnchecked(clazz).get(name));
+    if (t == null) {
+      return default_;
+    }
+    return t;
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d69f2c20/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 ea69cae..cc7ec8c 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
@@ -16,17 +16,25 @@
  */
 package org.apache.calcite.test;
 
+import org.apache.calcite.jdbc.CalciteConnection;
+
+import com.google.common.base.Function;
+import com.google.common.base.Throwables;
+
 import org.hsqldb.jdbcDriver;
+
 import org.junit.Test;
 
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.ResultSet;
+import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.Properties;
 
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
 
 /**
@@ -350,6 +358,33 @@ public class JdbcAdapterTest {
         .explainContains("SINGLE_VALUE")
         .throws_(expected);
   }
+
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-865">[CALCITE-865]
+   * Unknown table type causes NullPointerException in JdbcSchema</a>. The issue
+   * occurred because of the "SYSTEM_INDEX" table type when run against
+   * PostgreSQL. */
+  @Test public void testMetadataTables() throws Exception {
+    // The troublesome tables occur in PostgreSQL's system schema.
+    final String model =
+        JdbcTest.FOODMART_MODEL.replace("jdbcSchema: 'foodmart'",
+            "jdbcSchema: null");
+    CalciteAssert.model(
+        model)
+        .doWithConnection(
+            new Function<CalciteConnection, Void>() {
+              public Void apply(CalciteConnection connection) {
+                try {
+                  final ResultSet resultSet =
+                      connection.getMetaData().getTables(null, null, "%", null);
+                  assertFalse(CalciteAssert.toString(resultSet).isEmpty());
+                  return null;
+                } catch (SQLException e) {
+                  throw Throwables.propagate(e);
+                }
+              }
+            });
+  }
 }
 
 // End JdbcAdapterTest.java


[10/10] incubator-calcite git commit: [CALCITE-874] ReflectiveRelMetadataProvider is not thread-safe

Posted by jh...@apache.org.
[CALCITE-874] ReflectiveRelMetadataProvider is not thread-safe


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

Branch: refs/heads/master
Commit: ba789deb425402aa3f92672f8ec956a90359ca2e
Parents: 977206c
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Sep 3 21:22:11 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Sep 4 00:34:00 2015 -0700

----------------------------------------------------------------------
 .../metadata/ReflectiveRelMetadataProvider.java | 58 +++++++++++---------
 1 file changed, 31 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/ba789deb/core/src/main/java/org/apache/calcite/rel/metadata/ReflectiveRelMetadataProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/ReflectiveRelMetadataProvider.java b/core/src/main/java/org/apache/calcite/rel/metadata/ReflectiveRelMetadataProvider.java
index 9c420b4..7db2c6a 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/ReflectiveRelMetadataProvider.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/ReflectiveRelMetadataProvider.java
@@ -239,43 +239,47 @@ public class ReflectiveRelMetadataProvider
 
   //~ Methods ----------------------------------------------------------------
 
-  @SuppressWarnings({ "unchecked", "SuspiciousMethodCalls" })
   public Function<RelNode, Metadata> apply(
       Class<? extends RelNode> relClass,
       Class<? extends Metadata> metadataClass) {
     if (metadataClass == metadataClass0) {
-      //noinspection SuspiciousMethodCalls
-      List<Class<? extends RelNode>> newSources = Lists.newArrayList();
-      Function<RelNode, Metadata> function;
-      while (relClass != null) {
-        function = map.get(relClass);
-        if (function != null) {
-          for (@SuppressWarnings("rawtypes") Class clazz : newSources) {
-            map.put(clazz, function);
-          }
-          return function;
-        } else {
-          newSources.add(relClass);
+      return apply(relClass);
+    } else {
+      return null;
+    }
+  }
+
+  @SuppressWarnings({ "unchecked", "SuspiciousMethodCalls" })
+  private synchronized Function<RelNode, Metadata> apply(
+      Class<? extends RelNode> relClass) {
+    List<Class<? extends RelNode>> newSources = Lists.newArrayList();
+    for (;;) {
+      final Function<RelNode, Metadata> function = map.get(relClass);
+      if (function != null) {
+        for (@SuppressWarnings("rawtypes") Class clazz : newSources) {
+          map.put(clazz, function);
         }
-        for (Class<?> interfaceClass : relClass.getInterfaces()) {
-          if (RelNode.class.isAssignableFrom(interfaceClass)) {
-            function = map.get(interfaceClass);
-            if (function != null) {
-              for (@SuppressWarnings("rawtypes") Class clazz : newSources) {
-                map.put(clazz, function);
-              }
-              return function;
+        return function;
+      } else {
+        newSources.add(relClass);
+      }
+      for (Class<?> interfaceClass : relClass.getInterfaces()) {
+        if (RelNode.class.isAssignableFrom(interfaceClass)) {
+          final Function<RelNode, Metadata> function2 = map.get(interfaceClass);
+          if (function2 != null) {
+            for (@SuppressWarnings("rawtypes") Class clazz : newSources) {
+              map.put(clazz, function2);
             }
+            return function2;
           }
         }
-        if (RelNode.class.isAssignableFrom(relClass.getSuperclass())) {
-          relClass = (Class<RelNode>) relClass.getSuperclass();
-        } else {
-          relClass = null;
-        }
+      }
+      if (RelNode.class.isAssignableFrom(relClass.getSuperclass())) {
+        relClass = (Class<RelNode>) relClass.getSuperclass();
+      } else {
+        return null;
       }
     }
-    return null;
   }
 }
 


[07/10] incubator-calcite git commit: Add LogicalWindow.create()

Posted by jh...@apache.org.
Add LogicalWindow.create()


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

Branch: refs/heads/master
Commit: 0a4fa379f189be4b8b7cdcb810694af939d2e5cf
Parents: f73c730
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Sep 3 18:02:47 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Sep 4 00:33:53 2015 -0700

----------------------------------------------------------------------
 .../org/apache/calcite/rel/core/Window.java     | 10 ++--
 .../calcite/rel/logical/LogicalWindow.java      | 55 ++++++++++++--------
 2 files changed, 39 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0a4fa379/core/src/main/java/org/apache/calcite/rel/core/Window.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Window.java b/core/src/main/java/org/apache/calcite/rel/core/Window.java
index 103b24f..8db59cb 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Window.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Window.java
@@ -63,21 +63,21 @@ import java.util.List;
  */
 public abstract class Window extends SingleRel {
   public final ImmutableList<Group> groups;
-  public final List<RexLiteral> constants;
+  public final ImmutableList<RexLiteral> constants;
 
   /**
    * Creates a window relational expression.
    *
    * @param cluster Cluster
-   * @param child   Input relational expression
+   * @param traitSet Trait set
+   * @param input   Input relational expression
    * @param constants List of constants that are additional inputs
    * @param rowType Output row type
    * @param groups Windows
    */
-  public Window(
-      RelOptCluster cluster, RelTraitSet traits, RelNode child,
+  public Window(RelOptCluster cluster, RelTraitSet traitSet, RelNode input,
       List<RexLiteral> constants, RelDataType rowType, List<Group> groups) {
-    super(cluster, traits, child);
+    super(cluster, traitSet, input);
     this.constants = ImmutableList.copyOf(constants);
     assert rowType != null;
     this.rowType = rowType;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0a4fa379/core/src/main/java/org/apache/calcite/rel/logical/LogicalWindow.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalWindow.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalWindow.java
index 2e65115..ea9e3c1 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalWindow.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalWindow.java
@@ -60,16 +60,19 @@ public final class LogicalWindow extends Window {
   /**
    * Creates a LogicalWindow.
    *
+   * <p>Use {@link #create} unless you know what you're doing.
+   *
    * @param cluster Cluster
-   * @param child   Input relational expression
+   * @param traitSet Trait set
+   * @param input   Input relational expression
    * @param constants List of constants that are additional inputs
    * @param rowType Output row type
-   * @param groups Windows
+   * @param groups Window groups
    */
-  public LogicalWindow(
-      RelOptCluster cluster, RelTraitSet traits, RelNode child,
-      List<RexLiteral> constants, RelDataType rowType, List<Group> groups) {
-    super(cluster, traits, child, constants, rowType, groups);
+  public LogicalWindow(RelOptCluster cluster, RelTraitSet traitSet,
+      RelNode input, List<RexLiteral> constants, RelDataType rowType,
+      List<Group> groups) {
+    super(cluster, traitSet, input, constants, rowType, groups);
   }
 
   @Override public LogicalWindow copy(RelTraitSet traitSet,
@@ -80,6 +83,21 @@ public final class LogicalWindow extends Window {
 
   /**
    * Creates a LogicalWindow.
+   *
+   * @param input   Input relational expression
+   * @param traitSet Trait set
+   * @param constants List of constants that are additional inputs
+   * @param rowType Output row type
+   * @param groups Window groups
+   */
+  public static LogicalWindow create(RelTraitSet traitSet, RelNode input,
+      List<RexLiteral> constants, RelDataType rowType, List<Group> groups) {
+    return new LogicalWindow(input.getCluster(), traitSet, input, constants,
+        rowType, groups);
+  }
+
+  /**
+   * Creates a LogicalWindow by parsing a {@link RexProgram}.
    */
   public static RelNode create(
       RelOptCluster cluster,
@@ -94,9 +112,8 @@ public final class LogicalWindow extends Window {
 
     final int inputFieldCount = child.getRowType().getFieldCount();
 
-    final Map<RexLiteral, RexInputRef> constantPool =
-        new HashMap<RexLiteral, RexInputRef>();
-    final List<RexLiteral> constants = new ArrayList<RexLiteral>();
+    final Map<RexLiteral, RexInputRef> constantPool = new HashMap<>();
+    final List<RexLiteral> constants = new ArrayList<>();
 
     // Identify constants in the expression tree and replace them with
     // references to newly generated constant pool.
@@ -127,14 +144,12 @@ public final class LogicalWindow extends Window {
       }
     }
 
-    final Map<RexOver, Window.RexWinAggCall> aggMap =
-        new HashMap<RexOver, Window.RexWinAggCall>();
-    List<Group> groups = new ArrayList<Group>();
+    final Map<RexOver, Window.RexWinAggCall> aggMap = new HashMap<>();
+    List<Group> groups = new ArrayList<>();
     for (Map.Entry<WindowKey, Collection<RexOver>> entry
         : windowMap.asMap().entrySet()) {
       final WindowKey windowKey = entry.getKey();
-      final List<RexWinAggCall> aggCalls =
-          new ArrayList<RexWinAggCall>();
+      final List<RexWinAggCall> aggCalls = new ArrayList<>();
       for (RexOver over : entry.getValue()) {
         final RexWinAggCall aggCall =
             new RexWinAggCall(
@@ -163,15 +178,14 @@ public final class LogicalWindow extends Window {
     // Figure out the type of the inputs to the output program.
     // They are: the inputs to this rel, followed by the outputs of
     // each window.
-    final List<Window.RexWinAggCall> flattenedAggCallList =
-        new ArrayList<Window.RexWinAggCall>();
-    List<Map.Entry<String, RelDataType>> fieldList =
+    final List<Window.RexWinAggCall> flattenedAggCallList = new ArrayList<>();
+    final List<Map.Entry<String, RelDataType>> fieldList =
         new ArrayList<Map.Entry<String, RelDataType>>(
             child.getRowType().getFieldList());
     final int offset = fieldList.size();
 
     // Use better field names for agg calls that are projected.
-    Map<Integer, String> fieldNames = new HashMap<Integer, String>();
+    final Map<Integer, String> fieldNames = new HashMap<>();
     for (Ord<RexLocalRef> ref : Ord.zip(program.getProjectList())) {
       final int index = ref.e.getIndex();
       if (index >= offset) {
@@ -242,9 +256,8 @@ public final class LogicalWindow extends Window {
           }
         };
 
-    LogicalWindow window =
-        new LogicalWindow(
-            cluster, traitSet, child, constants, intermediateRowType,
+    final LogicalWindow window =
+        LogicalWindow.create(traitSet, child, constants, intermediateRowType,
             groups);
 
     // The order that the "over" calls occur in the groups and


[05/10] incubator-calcite git commit: [CALCITE-841] Redundant windows when window function arguments are expressions (Hsuan-Yi Chu)

Posted by jh...@apache.org.
[CALCITE-841] Redundant windows when window function arguments are expressions (Hsuan-Yi Chu)

In ProjectToWindowRule, RexOver will be put in the same cohort if the
following conditions are satisfied:
(1). They have the same RexWindow
(2). They are not dependent on each other

Close apache/incubator-calcite#124


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

Branch: refs/heads/master
Commit: c1fb82996b702397a2506970a31f3a6b4c7a956a
Parents: d69f2c2
Author: Hsuan-Yi Chu <hs...@usc.edu>
Authored: Mon Aug 24 18:24:59 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Sep 3 16:08:46 2015 -0700

----------------------------------------------------------------------
 .../calcite/rel/rules/ProjectToWindowRule.java  | 136 ++++++++++++++++++-
 .../apache/calcite/test/RelOptRulesTest.java    |  19 +++
 .../org/apache/calcite/test/RelOptRulesTest.xml |  23 ++++
 3 files changed, 172 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c1fb8299/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java
index 3719253..92fd282 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.rel.rules;
 
+import org.apache.calcite.linq4j.Ord;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
@@ -37,13 +38,25 @@ 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.RexVisitorImpl;
+import org.apache.calcite.rex.RexWindow;
+import org.apache.calcite.util.ImmutableIntList;
+import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
+import org.apache.calcite.util.graph.DefaultDirectedGraph;
+import org.apache.calcite.util.graph.DefaultEdge;
+import org.apache.calcite.util.graph.DirectedGraph;
+import org.apache.calcite.util.graph.TopologicalOrderIterator;
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 
-import java.util.Collections;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -239,11 +252,122 @@ public abstract class ProjectToWindowRule extends RelOptRule {
     }
 
     @Override protected List<Set<Integer>> getCohorts() {
-      // Here used to be the implementation that treats all the RexOvers
-      // as a single Cohort. This is flawed if the RexOvers
-      // depend on each other (i.e. the second one uses the result
-      // of the first).
-      return Collections.emptyList();
+      // Two RexOver will be put in the same cohort
+      // if the following conditions are satisfied
+      // (1). They have the same RexWindow
+      // (2). They are not dependent on each other
+      final List<RexNode> exprs = this.program.getExprList();
+      final DirectedGraph<Integer, DefaultEdge> graph =
+          createGraphFromExpression(exprs);
+      final List<Integer> rank = getRank(graph);
+
+      final List<Pair<RexWindow, Set<Integer>>> windowToIndices = new ArrayList<>();
+      for (int i = 0; i < exprs.size(); ++i) {
+        final RexNode expr = exprs.get(i);
+        if (expr instanceof RexOver) {
+          final RexOver over = (RexOver) expr;
+
+          // If we can found an existing cohort which satisfies the two conditions,
+          // we will add this RexOver into that cohort
+          boolean isFound = false;
+          for (Pair<RexWindow, Set<Integer>> pair : windowToIndices) {
+            // Check the first condition
+            if (pair.left.equals(over.getWindow())) {
+              // Check the second condition
+              boolean hasDependency = false;
+              for (int ordinal : pair.right) {
+                if (isDependent(graph, rank, ordinal, i)) {
+                  hasDependency = true;
+                  break;
+                }
+              }
+
+              if (!hasDependency) {
+                pair.right.add(i);
+                isFound = true;
+                break;
+              }
+            }
+          }
+
+          // This RexOver cannot be added into any existing cohort
+          if (!isFound) {
+            final Set<Integer> newSet = Sets.newHashSet(i);
+            windowToIndices.add(Pair.of(over.getWindow(), newSet));
+          }
+        }
+      }
+
+      final List<Set<Integer>> cohorts = new ArrayList<>();
+      for (Pair<RexWindow, Set<Integer>> pair : windowToIndices) {
+        cohorts.add(pair.right);
+      }
+      return cohorts;
+    }
+
+    private boolean isDependent(final DirectedGraph<Integer, DefaultEdge> graph,
+        final List<Integer> rank,
+        final int ordinal1,
+        final int ordinal2) {
+      if (rank.get(ordinal2) > rank.get(ordinal1)) {
+        return isDependent(graph, rank, ordinal2, ordinal1);
+      }
+
+      // Check if the expression in ordinal1
+      // could depend on expression in ordinal2 by Depth-First-Search
+      final Deque<Integer> dfs = new ArrayDeque<>();
+      final Set<Integer> visited = new HashSet<>();
+      dfs.push(ordinal2);
+      while (!dfs.isEmpty()) {
+        int source = dfs.pop();
+        if (visited.contains(source)) {
+          continue;
+        }
+
+        if (source == ordinal1) {
+          return true;
+        }
+
+        visited.add(source);
+        for (DefaultEdge e : graph.getOutwardEdges(source)) {
+          int target = (int) e.target;
+          if (rank.get(target) < rank.get(ordinal1)) {
+            dfs.push(target);
+          }
+        }
+      }
+
+      return false;
+    }
+
+    private List<Integer> getRank(DirectedGraph<Integer, DefaultEdge> graph) {
+      final int[] rankArr = new int[graph.vertexSet().size()];
+      int rank = 0;
+      for (int i : TopologicalOrderIterator.of(graph)) {
+        rankArr[i] = rank++;
+      }
+      return ImmutableIntList.of(rankArr);
+    }
+
+    private DirectedGraph<Integer, DefaultEdge> createGraphFromExpression(
+        final List<RexNode> exprs) {
+      final DirectedGraph<Integer, DefaultEdge> graph =
+          DefaultDirectedGraph.create();
+      for (int i = 0; i < exprs.size(); i++) {
+        graph.addVertex(i);
+      }
+
+      for (final Ord<RexNode> expr : Ord.zip(exprs)) {
+        expr.e.accept(
+            new RexVisitorImpl<Void>(true) {
+              public Void visitLocalRef(RexLocalRef localRef) {
+                graph.addEdge(localRef.getIndex(), expr.i);
+                return null;
+              }
+            });
+      }
+      assert graph.vertexSet().size() == exprs.size();
+      return graph;
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c1fb8299/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 fc6d5bb..bdea4af 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -1632,6 +1632,25 @@ public class RelOptRulesTest extends RelOptTestBase {
         + "where r < 2");
   }
 
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-841">[CALCITE-841],
+   * Redundant windows when window function arguments are expressions</a>. */
+  @Test public void testExpressionInWindowFunction() {
+    HepProgram preProgram =  new HepProgramBuilder().build();
+
+    HepProgramBuilder builder = new HepProgramBuilder();
+    builder.addRuleClass(ProjectToWindowRule.class);
+
+    HepPlanner hepPlanner = new HepPlanner(builder.build());
+    hepPlanner.addRule(ProjectToWindowRule.PROJECT);
+
+    final String sql = "select\n"
+        + " sum(deptno) over(partition by deptno order by sal) as sum1,\n"
+        + "sum(deptno + sal) over(partition by deptno order by sal) as sum2\n"
+        + "from emp";
+    checkPlanning(tester, preProgram, hepPlanner, sql);
+  }
+
   @Test public void testPushAggregateThroughJoin1() throws Exception {
     final HepProgram preProgram = new HepProgramBuilder()
         .addRuleInstance(AggregateProjectMergeRule.INSTANCE)

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c1fb8299/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 199fb6b..4ab7a81 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -3424,6 +3424,29 @@ LogicalProject(EXPR$0=[$0], EXPR$1=[$1])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testExpressionInWindowFunction">
+        <Resource name="sql">
+            <![CDATA[
+select sum(deptno) over(partition by deptno order by sal) as sum1,
+sum(deptno + sal) over(partition by deptno order by sal) as sum2
+from emp
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalProject($0=[$3], $1=[$4])
+  LogicalWindow(window#0=[window(partition {1} order by [0] range between UNBOUNDED PRECEDING and CURRENT ROW aggs [SUM($1), SUM($2)])])
+    LogicalProject(SAL=[$5], DEPTNO=[$7], $2=[+($7, $5)])
+      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(SUM1=[SUM($7) OVER (PARTITION BY $7 ORDER BY $5 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)], SUM2=[SUM(+($7, $5)) OVER (PARTITION BY $7 ORDER BY $5 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)])
+  LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testPushAggregateThroughJoin1">
         <Resource name="sql">
             <![CDATA[select e.empno,d.deptno 


[08/10] incubator-calcite git commit: [CALCITE-844] Push Project through Window (Hsuan-Yi Chu)

Posted by jh...@apache.org.
[CALCITE-844] Push Project through Window (Hsuan-Yi Chu)

Close apache/incubator-calcite#123


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

Branch: refs/heads/master
Commit: 5219eb8cd4e8c1f0b1654da3136ce1c04e38a96e
Parents: 0a4fa37
Author: Hsuan-Yi Chu <hs...@usc.edu>
Authored: Fri Aug 21 23:20:15 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Sep 4 00:34:00 2015 -0700

----------------------------------------------------------------------
 .../rel/rules/ProjectWindowTransposeRule.java   | 245 +++++++++++++++++++
 .../apache/calcite/test/RelOptRulesTest.java    |  11 +
 .../org/apache/calcite/test/RelOptRulesTest.xml |  20 ++
 3 files changed, 276 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5219eb8c/core/src/main/java/org/apache/calcite/rel/rules/ProjectWindowTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectWindowTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectWindowTransposeRule.java
new file mode 100644
index 0000000..2705420
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectWindowTransposeRule.java
@@ -0,0 +1,245 @@
+/*
+ * 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.rel.RelCollations;
+import org.apache.calcite.rel.RelFieldCollation;
+import org.apache.calcite.rel.core.Window;
+import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.rel.logical.LogicalWindow;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rel.type.RelRecordType;
+import org.apache.calcite.rex.RexCall;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexShuttle;
+import org.apache.calcite.sql.SqlAggFunction;
+import org.apache.calcite.util.ImmutableBitSet;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+
+/**
+ * Planner rule that pushes
+ * a {@link org.apache.calcite.rel.logical.LogicalProject}
+ * past a {@link org.apache.calcite.rel.logical.LogicalWindow}.
+ */
+public class ProjectWindowTransposeRule extends RelOptRule {
+  /** The default instance of
+   * {@link org.apache.calcite.rel.rules.ProjectWindowTransposeRule}. */
+  public static final ProjectWindowTransposeRule INSTANCE = new ProjectWindowTransposeRule();
+
+  private ProjectWindowTransposeRule() {
+    super(
+        operand(
+            LogicalProject.class,
+                operand(LogicalWindow.class,
+                    any())));
+  }
+
+  @Override
+  public void onMatch(RelOptRuleCall call) {
+    final LogicalProject project = call.rel(0);
+    final LogicalWindow window = call.rel(1);
+    final List<RelDataTypeField> rowTypeWindowInput = window.getInput().getRowType().getFieldList();
+    final int windowInputColumn = rowTypeWindowInput.size();
+
+    // Record the window input columns which are actually referred
+    // either in the LogicalProject above LogicalWindow or LogicalWindow itself
+    final BitSet beReferred = findReference(project, window);
+
+    // If all the the window input columns are referred,
+    // it is impossible to trim anyone of them out
+    if (beReferred.cardinality() == windowInputColumn) {
+      return;
+    }
+
+    // Put a DrillProjectRel below LogicalWindow
+    final List<RexNode> exps = new ArrayList<>();
+    final List<RelDataTypeField> fields = new ArrayList<>();
+
+    // Keep only the fields which are referred
+    for  (int index = beReferred.nextSetBit(0); index >= 0;
+        index = beReferred.nextSetBit(index + 1)) {
+      final RelDataTypeField relDataTypeField = rowTypeWindowInput.get(index);
+      exps.add(new RexInputRef(index, relDataTypeField.getType()));
+      fields.add(relDataTypeField);
+    }
+
+    final LogicalProject projectBelowWindow = new LogicalProject(
+        window.getCluster(),
+        window.getTraitSet(),
+        window.getInput(),
+        exps,
+        new RelRecordType(fields));
+
+    // Create a new LogicalWindow with necessary inputs only
+    final List<RelDataTypeField> inputWinFields = fields;
+    final List<RelDataTypeField> outputWindFields = new ArrayList<>(inputWinFields);
+    final List<Window.Group> groups = new ArrayList<>();
+
+    // As the un-referred columns are trimmed by the LogicalProject,
+    // the indices specified in LogicalWindow would need to be adjusted
+    final RexShuttle indexAdjustment = new RexShuttle() {
+      @Override
+      public RexNode visitInputRef(RexInputRef inputRef) {
+        final int index = inputRef.getIndex();
+        final int newIndex = beReferred.get(0, index).cardinality();
+        return new RexInputRef(newIndex, inputRef.getType());
+      }
+
+      @Override
+      public RexNode visitCall(final RexCall call) {
+        final List<RexNode> clonedOperands = visitList(call.operands, new boolean[]{false});
+        if (call instanceof Window.RexWinAggCall) {
+          return new Window.RexWinAggCall(
+              (SqlAggFunction) call.getOperator(),
+              call.getType(),
+              clonedOperands,
+              ((Window.RexWinAggCall) call).ordinal);
+        } else {
+          return call;
+        }
+      }
+    };
+
+    int aggCallIndex = windowInputColumn;
+    for (Window.Group group : window.groups) {
+      final ImmutableBitSet.Builder keys = ImmutableBitSet.builder();
+      final List<RelFieldCollation> orderKeys = new ArrayList<>();
+      final List<Window.RexWinAggCall> aggCalls = new ArrayList<>();
+
+      // Adjust keys
+      for (int index : group.keys) {
+        keys.set(beReferred.get(0, index).cardinality());
+      }
+
+      // Adjust orderKeys
+      for (RelFieldCollation relFieldCollation : group.orderKeys.getFieldCollations()) {
+        final int index = relFieldCollation.getFieldIndex();
+        orderKeys.add(relFieldCollation.copy(beReferred.get(0, index).cardinality()));
+      }
+
+      // Adjust Window Functions
+      for (Window.RexWinAggCall rexWinAggCall : group.aggCalls) {
+        aggCalls.add((Window.RexWinAggCall) rexWinAggCall.accept(indexAdjustment));
+
+        final RelDataTypeField relDataTypeField =
+            window.getRowType().getFieldList().get(aggCallIndex);
+        outputWindFields.add(relDataTypeField);
+        ++aggCallIndex;
+      }
+
+      groups.add(new Window.Group(
+          keys.build(),
+          group.isRows,
+          group.lowerBound,
+          group.upperBound,
+          RelCollations.of(orderKeys),
+          aggCalls));
+    }
+
+    final LogicalWindow newLogicalWindow = new LogicalWindow(
+        window.getCluster(),
+        window.getTraitSet(),
+        projectBelowWindow,
+        window.constants,
+        new RelRecordType(outputWindFields),
+        groups);
+
+    // Modify the top LogicalProject
+    final List<RexNode> topProjExps = new ArrayList<>();
+    final RexShuttle topProjAdjustment = new RexShuttle() {
+      @Override
+      public RexNode visitInputRef(RexInputRef inputRef) {
+        final int index = inputRef.getIndex();
+        final int newIndex;
+        if (index >= windowInputColumn) {
+          newIndex = beReferred.cardinality() + (index - windowInputColumn);
+        } else {
+          newIndex = beReferred.get(0, index).cardinality();
+        }
+        return new RexInputRef(newIndex, inputRef.getType());
+      }
+    };
+
+    for (RexNode rexNode : project.getChildExps()) {
+      topProjExps.add(rexNode.accept(topProjAdjustment));
+    }
+
+    final LogicalProject newTopProj = project.copy(
+        newLogicalWindow.getTraitSet(),
+        newLogicalWindow,
+        topProjExps,
+        project.getRowType());
+
+    if (ProjectRemoveRule.isTrivial(newTopProj)) {
+      call.transformTo(newLogicalWindow);
+    } else {
+      call.transformTo(newTopProj);
+    }
+  }
+
+  private BitSet findReference(final LogicalProject project, final LogicalWindow window) {
+    final int windowInputColumn = window.getInput().getRowType().getFieldCount();
+    final BitSet beReferred = new BitSet(window.getInput().getRowType().getFieldCount());
+
+    final RexShuttle referenceFinder = new RexShuttle() {
+      @Override
+      public RexNode visitInputRef(RexInputRef inputRef) {
+        final int index = inputRef.getIndex();
+        if (index < windowInputColumn) {
+          beReferred.set(index);
+        }
+        return inputRef;
+      }
+    };
+
+    // Reference in LogicalProject
+    for (RexNode rexNode : project.getChildExps()) {
+      rexNode.accept(referenceFinder);
+    }
+
+    // Reference in LogicalWindow
+    for (Window.Group group : window.groups) {
+      // Reference in Partition-By
+      for (int index : group.keys) {
+        if (index < windowInputColumn) {
+          beReferred.set(index);
+        }
+      }
+
+      // Reference in Order-By
+      for (RelFieldCollation relFieldCollation : group.orderKeys.getFieldCollations()) {
+        if (relFieldCollation.getFieldIndex() < windowInputColumn) {
+          beReferred.set(relFieldCollation.getFieldIndex());
+        }
+      }
+
+      // Reference in Window Functions
+      for (Window.RexWinAggCall rexWinAggCall : group.aggCalls) {
+        rexWinAggCall.accept(referenceFinder);
+      }
+    }
+    return beReferred;
+  }
+}
+
+// End ProjectWindowTransposeRule.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5219eb8c/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 bdea4af..e34b1bb 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -64,6 +64,7 @@ import org.apache.calcite.rel.rules.ProjectRemoveRule;
 import org.apache.calcite.rel.rules.ProjectSetOpTransposeRule;
 import org.apache.calcite.rel.rules.ProjectToCalcRule;
 import org.apache.calcite.rel.rules.ProjectToWindowRule;
+import org.apache.calcite.rel.rules.ProjectWindowTransposeRule;
 import org.apache.calcite.rel.rules.PruneEmptyRules;
 import org.apache.calcite.rel.rules.ReduceExpressionsRule;
 import org.apache.calcite.rel.rules.SemiJoinFilterTransposeRule;
@@ -1609,6 +1610,16 @@ public class RelOptRulesTest extends RelOptTestBase {
         FilterProjectTransposeRule.INSTANCE);
   }
 
+  @Test public void testProjectWindowTransposeRule() {
+    HepProgram program = new HepProgramBuilder()
+      .addRuleInstance(ProjectToWindowRule.PROJECT)
+      .addRuleInstance(ProjectWindowTransposeRule.INSTANCE)
+      .build();
+
+    final String sql = "select count(empno) over(), deptno from emp";
+    checkPlanning(program, sql);
+  }
+
   @Test public void testPushFilterWithRank() throws Exception {
     HepProgram program = new HepProgramBuilder().addRuleInstance(
         FilterProjectTransposeRule.INSTANCE).build();

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5219eb8c/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 4ab7a81..7b40b5d 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -3041,6 +3041,26 @@ LogicalAggregate(group=[{0, 1}])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testProjectWindowTransposeRule">
+        <Resource name="sql">
+            <![CDATA[select count(empno) over(), deptno from emp]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalProject(EXPR$0=[$1], DEPTNO=[$0])
+  LogicalProject(DEPTNO=[$1], $1=[$2])
+    LogicalWindow(window#0=[window(partition {} order by [] range between UNBOUNDED PRECEDING and UNBOUNDED FOLLOWING aggs [COUNT($0)])])
+      LogicalProject(EMPNO=[$0], DEPTNO=[$7])
+        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(EXPR$0=[COUNT($0) OVER (RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)], DEPTNO=[$7])
+  LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testPushFilterWithRank">
         <Resource name="sql">
             <![CDATA[select e1.ename, r


[02/10] incubator-calcite git commit: [CALCITE-847] AVG window function in GROUP BY gives AssertionError (Hsuan-Yi Chu)

Posted by jh...@apache.org.
[CALCITE-847] AVG window function in GROUP BY gives AssertionError (Hsuan-Yi Chu)

Close apache/incubator-calcite#126


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

Branch: refs/heads/master
Commit: d19a9133f4941ef80195b8ef19fb7c21a1258abd
Parents: 2a215df
Author: Hsuan-Yi Chu <hs...@usc.edu>
Authored: Sun Aug 16 17:41:54 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Wed Sep 2 15:09:27 2015 -0700

----------------------------------------------------------------------
 .../apache/calcite/sql2rel/SqlToRelConverter.java   |  5 +++--
 .../apache/calcite/test/SqlToRelConverterTest.java  | 12 ++++++++++++
 .../apache/calcite/test/SqlToRelConverterTest.xml   | 16 ++++++++++++++++
 3 files changed, 31 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d19a9133/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 50f22c1..b3169c5 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -3414,7 +3414,6 @@ public class SqlToRelConverter {
     return ret;
   }
 
-
   private void convertSelectList(
       Blackboard bb,
       SqlSelect select,
@@ -4160,7 +4159,8 @@ public class SqlToRelConverter {
     public RexNode visit(SqlCall call) {
       if (agg != null) {
         final SqlOperator op = call.getOperator();
-        if (op.isAggregator() || op.getKind() == SqlKind.FILTER) {
+        if (window == null
+            && (op.isAggregator() || op.getKind() == SqlKind.FILTER)) {
           return agg.lookupAggregates(call);
         }
       }
@@ -4195,6 +4195,7 @@ public class SqlToRelConverter {
     public List<SqlMonotonicity> getColumnMonotonicities() {
       return columnMonotonicities;
     }
+
   }
 
   /** Deferred lookup. */

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d19a9133/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 28f31f5..dc5b051 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
@@ -1303,6 +1303,18 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
 
   /**
    * Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-847">[CALCITE-847]
+   * AVG window function in GROUP BY gives AssertionError</a>.
+   */
+  @Test public void testWindowAverageWithGroupBy() {
+    final String sql = "select avg(deptno) over ()\n"
+        + "from emp\n"
+        + "group by deptno";
+    sql(sql).convertsTo("${plan}");
+  }
+
+  /**
+   * Test case for
    * <a href="https://issues.apache.org/jira/browse/CALCITE-770">[CALCITE-770]
    * variant involving joins</a>.
    */

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d19a9133/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 0ff7c29..95c5507 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -2330,6 +2330,22 @@ LogicalProject(EXPR$0=[$2], EXPR$1=[RANK() OVER (ORDER BY $1 RANGE BETWEEN UNBOU
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testWindowAverageWithGroupBy">
+        <Resource name="sql">
+            <![CDATA[select avg(deptno) over ()
+from emp
+group by deptno
+]]>
+        </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalProject(EXPR$0=[CAST(/(SUM($0) OVER (RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING), COUNT($0) OVER (RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING))):INTEGER NOT NULL])
+  LogicalAggregate(group=[{0}])
+    LogicalProject(DEPTNO=[$7])
+      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testWindowAggWithGroupByAndJoin">
         <Resource name="sql">
             <![CDATA[select min(d.deptno), rank() over (order by e.empno),


[09/10] incubator-calcite git commit: Fix up [CALCITE-844], and enable ProjectWindowTransposeRule by default

Posted by jh...@apache.org.
Fix up [CALCITE-844], and enable ProjectWindowTransposeRule by default


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

Branch: refs/heads/master
Commit: 977206c5c0521f4e7aa3f18159b19a6467e0744c
Parents: 5219eb8
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Sep 3 18:17:24 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Sep 4 00:34:00 2015 -0700

----------------------------------------------------------------------
 .../calcite/prepare/CalcitePrepareImpl.java     |  2 +
 .../rel/rules/ProjectWindowTransposeRule.java   | 86 +++++++++-----------
 2 files changed, 39 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/977206c5/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 87bd09f..f761e3c 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -86,6 +86,7 @@ import org.apache.calcite.rel.rules.JoinPushThroughJoinRule;
 import org.apache.calcite.rel.rules.ProjectFilterTransposeRule;
 import org.apache.calcite.rel.rules.ProjectMergeRule;
 import org.apache.calcite.rel.rules.ProjectTableScanRule;
+import org.apache.calcite.rel.rules.ProjectWindowTransposeRule;
 import org.apache.calcite.rel.rules.ReduceExpressionsRule;
 import org.apache.calcite.rel.rules.SortProjectTransposeRule;
 import org.apache.calcite.rel.rules.TableScanRule;
@@ -222,6 +223,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
           AggregateExpandDistinctAggregatesRule.INSTANCE,
           AggregateReduceFunctionsRule.INSTANCE,
           FilterAggregateTransposeRule.INSTANCE,
+          ProjectWindowTransposeRule.INSTANCE,
           JoinCommuteRule.INSTANCE,
           JoinPushThroughJoinRule.RIGHT,
           JoinPushThroughJoinRule.LEFT,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/977206c5/core/src/main/java/org/apache/calcite/rel/rules/ProjectWindowTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectWindowTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectWindowTransposeRule.java
index 2705420..c79c10c 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectWindowTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectWindowTransposeRule.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.rel.rules;
 
+import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.rel.RelCollations;
@@ -23,17 +24,17 @@ import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.core.Window;
 import org.apache.calcite.rel.logical.LogicalProject;
 import org.apache.calcite.rel.logical.LogicalWindow;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeField;
-import org.apache.calcite.rel.type.RelRecordType;
 import org.apache.calcite.rex.RexCall;
 import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexShuttle;
 import org.apache.calcite.sql.SqlAggFunction;
+import org.apache.calcite.util.BitSets;
 import org.apache.calcite.util.ImmutableBitSet;
 
 import java.util.ArrayList;
-import java.util.BitSet;
 import java.util.List;
 
 /**
@@ -44,26 +45,26 @@ import java.util.List;
 public class ProjectWindowTransposeRule extends RelOptRule {
   /** The default instance of
    * {@link org.apache.calcite.rel.rules.ProjectWindowTransposeRule}. */
-  public static final ProjectWindowTransposeRule INSTANCE = new ProjectWindowTransposeRule();
+  public static final ProjectWindowTransposeRule INSTANCE =
+      new ProjectWindowTransposeRule();
 
   private ProjectWindowTransposeRule() {
     super(
-        operand(
-            LogicalProject.class,
-                operand(LogicalWindow.class,
-                    any())));
+        operand(LogicalProject.class,
+            operand(LogicalWindow.class, any())));
   }
 
-  @Override
-  public void onMatch(RelOptRuleCall call) {
+  @Override public void onMatch(RelOptRuleCall call) {
     final LogicalProject project = call.rel(0);
     final LogicalWindow window = call.rel(1);
-    final List<RelDataTypeField> rowTypeWindowInput = window.getInput().getRowType().getFieldList();
+    final RelOptCluster cluster = window.getCluster();
+    final List<RelDataTypeField> rowTypeWindowInput =
+        window.getInput().getRowType().getFieldList();
     final int windowInputColumn = rowTypeWindowInput.size();
 
     // Record the window input columns which are actually referred
     // either in the LogicalProject above LogicalWindow or LogicalWindow itself
-    final BitSet beReferred = findReference(project, window);
+    final ImmutableBitSet beReferred = findReference(project, window);
 
     // If all the the window input columns are referred,
     // it is impossible to trim anyone of them out
@@ -73,40 +74,33 @@ public class ProjectWindowTransposeRule extends RelOptRule {
 
     // Put a DrillProjectRel below LogicalWindow
     final List<RexNode> exps = new ArrayList<>();
-    final List<RelDataTypeField> fields = new ArrayList<>();
+    final RelDataTypeFactory.FieldInfoBuilder builder =
+        cluster.getTypeFactory().builder();
 
     // Keep only the fields which are referred
-    for  (int index = beReferred.nextSetBit(0); index >= 0;
-        index = beReferred.nextSetBit(index + 1)) {
+    for (int index : BitSets.toIter(beReferred)) {
       final RelDataTypeField relDataTypeField = rowTypeWindowInput.get(index);
       exps.add(new RexInputRef(index, relDataTypeField.getType()));
-      fields.add(relDataTypeField);
+      builder.add(relDataTypeField);
     }
 
-    final LogicalProject projectBelowWindow = new LogicalProject(
-        window.getCluster(),
-        window.getTraitSet(),
-        window.getInput(),
-        exps,
-        new RelRecordType(fields));
+    final LogicalProject projectBelowWindow =
+        new LogicalProject(cluster, window.getTraitSet(),
+            window.getInput(), exps, builder.build());
 
     // Create a new LogicalWindow with necessary inputs only
-    final List<RelDataTypeField> inputWinFields = fields;
-    final List<RelDataTypeField> outputWindFields = new ArrayList<>(inputWinFields);
     final List<Window.Group> groups = new ArrayList<>();
 
     // As the un-referred columns are trimmed by the LogicalProject,
     // the indices specified in LogicalWindow would need to be adjusted
     final RexShuttle indexAdjustment = new RexShuttle() {
-      @Override
-      public RexNode visitInputRef(RexInputRef inputRef) {
+      @Override public RexNode visitInputRef(RexInputRef inputRef) {
         final int index = inputRef.getIndex();
         final int newIndex = beReferred.get(0, index).cardinality();
         return new RexInputRef(newIndex, inputRef.getType());
       }
 
-      @Override
-      public RexNode visitCall(final RexCall call) {
+      @Override public RexNode visitCall(final RexCall call) {
         final List<RexNode> clonedOperands = visitList(call.operands, new boolean[]{false});
         if (call instanceof Window.RexWinAggCall) {
           return new Window.RexWinAggCall(
@@ -121,6 +115,9 @@ public class ProjectWindowTransposeRule extends RelOptRule {
     };
 
     int aggCallIndex = windowInputColumn;
+    final RelDataTypeFactory.FieldInfoBuilder outputBuilder =
+        cluster.getTypeFactory().builder();
+    outputBuilder.addAll(projectBelowWindow.getRowType().getFieldList());
     for (Window.Group group : window.groups) {
       final ImmutableBitSet.Builder keys = ImmutableBitSet.builder();
       final List<RelFieldCollation> orderKeys = new ArrayList<>();
@@ -143,32 +140,23 @@ public class ProjectWindowTransposeRule extends RelOptRule {
 
         final RelDataTypeField relDataTypeField =
             window.getRowType().getFieldList().get(aggCallIndex);
-        outputWindFields.add(relDataTypeField);
+        outputBuilder.add(relDataTypeField);
         ++aggCallIndex;
       }
 
-      groups.add(new Window.Group(
-          keys.build(),
-          group.isRows,
-          group.lowerBound,
-          group.upperBound,
-          RelCollations.of(orderKeys),
-          aggCalls));
+      groups.add(
+          new Window.Group(keys.build(), group.isRows, group.lowerBound,
+              group.upperBound, RelCollations.of(orderKeys), aggCalls));
     }
 
-    final LogicalWindow newLogicalWindow = new LogicalWindow(
-        window.getCluster(),
-        window.getTraitSet(),
-        projectBelowWindow,
-        window.constants,
-        new RelRecordType(outputWindFields),
-        groups);
+    final LogicalWindow newLogicalWindow =
+        LogicalWindow.create(window.getTraitSet(), projectBelowWindow,
+        window.constants, outputBuilder.build(), groups);
 
     // Modify the top LogicalProject
     final List<RexNode> topProjExps = new ArrayList<>();
     final RexShuttle topProjAdjustment = new RexShuttle() {
-      @Override
-      public RexNode visitInputRef(RexInputRef inputRef) {
+      @Override public RexNode visitInputRef(RexInputRef inputRef) {
         final int index = inputRef.getIndex();
         final int newIndex;
         if (index >= windowInputColumn) {
@@ -197,13 +185,13 @@ public class ProjectWindowTransposeRule extends RelOptRule {
     }
   }
 
-  private BitSet findReference(final LogicalProject project, final LogicalWindow window) {
+  private ImmutableBitSet findReference(final LogicalProject project,
+      final LogicalWindow window) {
     final int windowInputColumn = window.getInput().getRowType().getFieldCount();
-    final BitSet beReferred = new BitSet(window.getInput().getRowType().getFieldCount());
+    final ImmutableBitSet.Builder beReferred = ImmutableBitSet.builder();
 
     final RexShuttle referenceFinder = new RexShuttle() {
-      @Override
-      public RexNode visitInputRef(RexInputRef inputRef) {
+      @Override public RexNode visitInputRef(RexInputRef inputRef) {
         final int index = inputRef.getIndex();
         if (index < windowInputColumn) {
           beReferred.set(index);
@@ -238,7 +226,7 @@ public class ProjectWindowTransposeRule extends RelOptRule {
         rexWinAggCall.accept(referenceFinder);
       }
     }
-    return beReferred;
+    return beReferred.build();
   }
 }
 


[03/10] incubator-calcite git commit: [CALCITE-862] JdbcSchema gives NullPointerException on non-standard column type (Marc Prud'hommeaux)

Posted by jh...@apache.org.
[CALCITE-862] JdbcSchema gives NullPointerException on non-standard column type (Marc Prud'hommeaux)

Solution is for SqlTypeName.getNameForJdbcType to fall back to ANY.

Close apache/incubator-calcite#125


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

Branch: refs/heads/master
Commit: f98ed96f041b615dca1560b7014d112a40e43d6e
Parents: d19a913
Author: Marc Prud'hommeaux <mw...@cornell.edu>
Authored: Mon Aug 31 14:19:31 2015 -0400
Committer: Julian Hyde <jh...@apache.org>
Committed: Wed Sep 2 15:47:39 2015 -0700

----------------------------------------------------------------------
 .../main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java    | 4 +++-
 core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java  | 2 +-
 2 files changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f98ed96f/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java
index 6d5b3cd..6495574 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java
@@ -287,7 +287,9 @@ public class JdbcSchema implements Schema {
 
   private RelDataType sqlType(RelDataTypeFactory typeFactory, int dataType,
       int precision, int scale, String typeString) {
-    SqlTypeName sqlTypeName = SqlTypeName.getNameForJdbcType(dataType);
+    // Fall back to ANY if type is unknown
+    final SqlTypeName sqlTypeName =
+        Util.first(SqlTypeName.getNameForJdbcType(dataType), SqlTypeName.ANY);
     switch (sqlTypeName) {
     case ARRAY:
       RelDataType component = null;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f98ed96f/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java
index 5f5b90c..7d0c590 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java
@@ -326,7 +326,7 @@ public enum SqlTypeName {
    * Gets the SqlTypeName corresponding to a JDBC type.
    *
    * @param jdbcType the JDBC type of interest
-   * @return corresponding SqlTypeName
+   * @return corresponding SqlTypeName, or null if the type is not known
    */
   public static SqlTypeName getNameForJdbcType(int jdbcType) {
     return JDBC_TYPE_TO_NAME.get(jdbcType);