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);