diff --git a/build.gradle.kts b/build.gradle.kts index 73b07e16062a..19adb73e5972 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -108,8 +108,8 @@ releaseArtifacts { releaseParams { tlp.set("Calcite") componentName.set("Apache Calcite") - releaseTag.set("rel/v$buildVersion") - rcTag.set(rc.map { "v$buildVersion-rc$it" }) + releaseTag.set("$buildVersion") + rcTag.set(rc.map { "$buildVersion-rc$it" }) sitePreviewEnabled.set(false) nexus { // https://github.com/marcphilipp/nexus-publish-plugin/issues/35 diff --git a/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java b/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java index 2396c3faac69..9a43ec4de620 100644 --- a/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java +++ b/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java @@ -555,6 +555,8 @@ private boolean requiresAlias(SqlNode node) { case JOIN: case EXPLICIT_TABLE: return false; + case SELECT: + return node instanceof SqlSelect; // TODO workaround asIs hack default: return true; } @@ -1359,6 +1361,7 @@ public Builder builder(RelNode rel, Clause... clauses) { } clauseList.appendAll(clauses); final Context newContext; + Map newAliases = null; final SqlNodeList selectList = select.getSelectList(); if (selectList != null) { newContext = new Context(dialect, selectList.size()) { @@ -1408,15 +1411,20 @@ public SqlNode field(int ordinal) { if (needNew && neededAlias != null && (aliases.size() != 1 || !aliases.containsKey(neededAlias))) { - final Map newAliases = + newAliases = ImmutableMap.of(neededAlias, rel.getInput(0).getRowType()); newContext = aliasContext(newAliases, qualified); } else { newContext = aliasContext(aliases, qualified); } } - return new Builder(rel, clauseList, select, newContext, isAnon(), - needNew ? null : aliases); + final Map nextAliases; + if (needNew) { + nextAliases = aliases.containsKey(neededAlias) ? aliases : newAliases; + } else { + nextAliases = aliases; + } + return new Builder(rel, clauseList, select, newContext, isAnon(), nextAliases); } /** Returns whether a new sub-query is required. */ diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AbstractMaterializedViewRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AbstractMaterializedViewRule.java new file mode 100644 index 000000000000..13b8c9b84547 --- /dev/null +++ b/core/src/main/java/org/apache/calcite/rel/rules/AbstractMaterializedViewRule.java @@ -0,0 +1,27 @@ +/* + * 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.rel.rules.materialize.MaterializedViewRules; + +/** For backwards compatibility. + * + * @deprecated Use {@link MaterializedViewRules}. + */ +@Deprecated +public class AbstractMaterializedViewRule extends MaterializedViewRules { +} diff --git a/core/src/main/java/org/apache/calcite/rel/rules/materialize/MaterializedViewRules.java b/core/src/main/java/org/apache/calcite/rel/rules/materialize/MaterializedViewRules.java new file mode 100644 index 000000000000..8f5575258d33 --- /dev/null +++ b/core/src/main/java/org/apache/calcite/rel/rules/materialize/MaterializedViewRules.java @@ -0,0 +1,42 @@ +/* + * 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.materialize; + +import org.apache.calcite.plan.RelOptRule; + +/** + * Utilities for {@link MaterializedViewRule}. + */ +public abstract class MaterializedViewRules { + public static final RelOptRule INSTANCE_PROJECT_AGGREGATE = + MaterializedViewProjectAggregateRule.INSTANCE; + + public static final RelOptRule INSTANCE_AGGREGATE = + MaterializedViewOnlyAggregateRule.INSTANCE; + + public static final RelOptRule INSTANCE_FILTER = + MaterializedViewOnlyFilterRule.INSTANCE; + + public static final RelOptRule INSTANCE_JOIN = + MaterializedViewOnlyJoinRule.INSTANCE; + + public static final RelOptRule INSTANCE_PROJECT_FILTER = + MaterializedViewProjectFilterRule.INSTANCE; + + public static final RelOptRule INSTANCE_PROJECT_JOIN = + MaterializedViewProjectJoinRule.INSTANCE; +} diff --git a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java index a7568223fb7d..3efce7fd93d8 100644 --- a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java +++ b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java @@ -2443,6 +2443,44 @@ private static String toSql(RelNode root, SqlDialect dialect) { sql(query).withDb2().ok(expected); } + @Test void testDb2DialectSubselect() { + String query = "select count(foo), \"units_per_case\" " + + "from (select \"units_per_case\", \"cases_per_pallet\", \"product_id\", 1 as foo from \"product\") where \"cases_per_pallet\" > 100 " + + "group by \"product_id\", \"units_per_case\" " + + "order by \"units_per_case\" desc"; + final String expected = "SELECT COUNT(*), t.units_per_case\n" + + "FROM (SELECT product.units_per_case, product.cases_per_pallet, product.product_id, 1 AS " + + "FOO\n" + + "FROM foodmart.product AS product) AS t\n" + + "WHERE t.cases_per_pallet > 100\n" + + "GROUP BY t.product_id, t.units_per_case\n" + + "ORDER BY t.units_per_case DESC"; + sql(query).withDb2().ok(expected); + } + + @Test void testDb2DialectSubselectFromUnion() { + String query = "select count(foo), \"units_per_case\" " + + "from (select \"units_per_case\", \"cases_per_pallet\", \"product_id\", 1 as foo from \"product\" where \"cases_per_pallet\" > 100 " + + "union all select \"units_per_case\", \"cases_per_pallet\", \"product_id\", 1 as foo from \"product\" where \"cases_per_pallet\" < 100) " + + "where \"cases_per_pallet\" > 100\n" + + "group by \"product_id\", \"units_per_case\" " + + "order by \"units_per_case\" desc"; + final String expected = "SELECT COUNT(*), t3.units_per_case\n" + + "FROM (SELECT product.units_per_case, product.cases_per_pallet, product.product_id, 1 AS " + + "FOO\n" + + "FROM foodmart.product AS product\n" + + "WHERE product.cases_per_pallet > 100\n" + + "UNION ALL\n" + + "SELECT product0.units_per_case, product0.cases_per_pallet, product0.product_id, 1 AS " + + "FOO\n" + + "FROM foodmart.product AS product0\n" + + "WHERE product0.cases_per_pallet < 100) AS t3\n" + + "WHERE t3.cases_per_pallet > 100\n" + + "GROUP BY t3.product_id, t3.units_per_case\n" + + "ORDER BY t3.units_per_case DESC"; + sql(query).withDb2().ok(expected); + } + @Test void testDb2DialectSelectQueryWithGroup() { String query = "select count(*), sum(\"employee_id\") " + "from \"reserve_employee\" " diff --git a/gradle.properties b/gradle.properties index e460e242810a..d5f4c810acf7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -23,7 +23,7 @@ kotlin.parallel.tasks.in.project=true # This is version for Calcite itself # Note: it should not include "-SNAPSHOT" as it is automatically added by build.gradle.kts # Release version can be generated by using -Prelease or -Prc= arguments -calcite.version=1.23.0 +calcite.version=1.22.1-looker # This is a version to be used from Maven repository. It can be overridden by localAvatica below calcite.avatica.version=1.16.0 diff --git a/looker.md b/looker.md new file mode 100644 index 000000000000..3ff92929982e --- /dev/null +++ b/looker.md @@ -0,0 +1,107 @@ + +# Looker's branch of Calcite + +This document describes how to develop Looker's branch of Calcite. + +Do not merge to Calcite's master branch. + +## Development + +For development, build and deploy to your local Maven repository: + +``` +cd calcite +./gradlew publishToMavenLocal +``` + +On the HT side, edit `looker-libs/build.gradle`: + +``` + compile "org.apache.calcite:calcite-core:1.xx.x-SNAPSHOT" + compile "org.apache.calcite:calcite-babel:1.xx.x-SNAPSHOT" +``` + +## Release + +Release will have a name like `1.21.1-looker` (if the most +recent official Calcite release is `1.21`) and have a git tag +`calcite-1.21.1-looker`. + +You should make it from a branch that differs from Calcite's +`master` branch in only minor ways: +* Cherry-pick commits from the previous `calcite-x.xx.x-looker` + release that set up Looker's repositories (or, if you prefer, + rebase the previous release branch onto the latest master) +* If necessary, include one or two commits for short-term fixes, but + log [JIRA cases](https://issues.apache.org/jira/browse/CALCITE) to + get them into `master`. + +In Calcite's `gradle.properties`, update the value of +`calcite.version` to the release name (something like +`1.22.1-looker`) and commit. + +Define Looker's Nexus repository in your `~/.gradle/init.gradle.kts` +file: + +```kotlin +allprojects { + plugins.withId("maven-publish") { + configure { + repositories { + maven { + name = "lookerNexus" + val baseUrl = "https://nexusrepo.looker.com" + val releasesUrl = "$baseUrl/repository/maven-releases" + val snapshotsUrl = "$baseUrl/repository/maven-snapshots" + val release = !project.version.toString().endsWith("-SNAPSHOT") + // val release = project.hasProperty("release") + url = uri(if (release) releasesUrl else snapshotsUrl) + credentials { + username = "xxx" + password = "xxx" + } + } + } + } + } +} +``` + +In the above fragment, replace the values of the `username` and +`password` properties with the secret credentials. + +*NOTE* This fragment *must* be in a file outside of your git sandbox. +If the file were in the git sandbox, it would be too easy to +accidentally commit the secret credentials and expose them on a +public site. + +Publish: +```sh +./gradlew -Prelease -PskipSign publishAllPublicationsToLookerNexusRepository +``` + +Check the artifacts +[on Nexus](https://nexusproxy.looker.com/#browse/search=keyword%3Dorg.apache.calcite). + +If the release was successful, tag the release and push the tag: +```sh +git tag calcite-1.21.1-looker HEAD +git push julianhyde calcite-1.21.1-looker +```