You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by vl...@apache.org on 2019/11/19 08:15:38 UTC

[calcite] 03/11: [CALCITE-2905] Migrate build scripts to Gradle

This is an automated email from the ASF dual-hosted git repository.

vladimirsitnikov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git

commit 66c9cd5e1c88ebe834e6f0f299cfb1e1dffa4296
Author: Vladimir Sitnikov <si...@gmail.com>
AuthorDate: Mon Nov 11 10:55:40 2019 +0300

    [CALCITE-2905] Migrate build scripts to Gradle
    
    In case you are lost:
    
    ./gradlew tasks # shows the list of possible tasks
    ./gradlew assemble # creates the archives, zips, etc
    
    The results of the tasks is produced to build/* folders
    For instance, core/build/libs/...
    
    ./gradlew test # executes tests
    ./gradlew build # builds and executes the tests
    
    ./gradlew dependencies # shows "classpath"
---
 .editorconfig                                      |  46 ++
 .github/workflows/main.yml                         |  64 ++
 .gitignore                                         |  18 +-
 .ratignore                                         |  47 ++
 .travis.yml                                        |  40 +-
 README.md                                          |   1 +
 babel/build.gradle.kts                             |  62 ++
 bom/build.gradle.kts                               | 147 +++++
 build.gradle.kts                                   | 649 +++++++++++++++++++++
 buildSrc/build.gradle.kts                          |  75 +++
 buildSrc/gradle.properties                         |  21 +
 buildSrc/settings.gradle.kts                       |  43 ++
 buildSrc/subprojects/fmpp/fmpp.gradle.kts          |  29 +
 .../apache/calcite/buildtools/fmpp/FmppPlugin.kt   |  42 ++
 .../org/apache/calcite/buildtools/fmpp/FmppTask.kt |  64 ++
 buildSrc/subprojects/javacc/javacc.gradle.kts      |  29 +
 .../calcite/buildtools/javacc/JavaCCPlugin.kt      |  48 ++
 .../apache/calcite/buildtools/javacc/JavaCCTask.kt |  69 +++
 cassandra/build.gradle.kts                         |  35 ++
 .gitignore => cassandra/gradle.properties          |  31 +-
 .../license.header.java                            |  28 -
 core/build.gradle.kts                              | 152 +++++
 .gitignore => core/gradle.properties               |  31 +-
 core/pom.xml                                       |  14 -
 .../calcite/rel/hint/ExplicitHintMatcher.java      |   1 -
 .../calcite/rel/hint/ExplicitHintStrategy.java     |   1 -
 .../apache/calcite/rel/hint/HintStrategies.java    |   1 -
 .../calcite/rel/hint/HintStrategyCascade.java      |   1 -
 .../calcite/rel/hint/NodeTypeHintStrategy.java     |   1 -
 .../java/org/apache/calcite/rel/hint/RelHint.java  |   1 -
 .../org/apache/calcite/schema/SchemaFactory.java   |   2 +-
 .../apache/calcite/sql/SqlFunctionCategory.java    |   6 +-
 .../org/apache/calcite/runtime/AutomatonTest.java  |   2 -
 .../apache/calcite/sql/test/DocumentationTest.java |   2 +-
 .../apache/calcite/sql/type/SqlTypeUtilTest.java   |   4 +-
 .../java/org/apache/calcite/test/Matchers.java     |   6 -
 .../apache/calcite/test/SqlHintsConverterTest.java |  11 +-
 druid/build.gradle.kts                             |  35 ++
 .gitignore => druid/gradle.properties              |  31 +-
 .../calcite/adapter/druid/DruidConnectionImpl.java |   4 +-
 elasticsearch/build.gradle.kts                     |  63 ++
 .gitignore => elasticsearch/gradle.properties      |  31 +-
 .../adapter/elasticsearch/PredicateAnalyzer.java   |   1 -
 .../calcite/adapter/elasticsearch/MatchTest.java   |  12 +-
 example/csv/build.gradle.kts                       |  53 ++
 .gitignore => example/csv/gradle.properties        |  31 +-
 example/csv/sqlline                                |  15 +-
 example/csv/sqlline.bat                            |   9 +-
 example/function/build.gradle.kts                  |  29 +
 .gitignore => example/function/gradle.properties   |  31 +-
 file/build.gradle.kts                              |  30 +
 .gitignore => file/gradle.properties               |  31 +-
 geode/README.md                                    |   1 -
 geode/build.gradle.kts                             |  32 +
 .gitignore => geode/gradle.properties              |  31 +-
 gradle.properties                                  | 130 +++++
 gradle/wrapper/gradle-wrapper.jar                  | Bin 0 -> 55616 bytes
 gradle/wrapper/gradle-wrapper.properties           |  21 +
 gradlew                                            | 188 ++++++
 gradlew.bat                                        | 100 ++++
 kafka/build.gradle.kts                             |  27 +
 .gitignore => kafka/gradle.properties              |  31 +-
 linq4j/build.gradle.kts                            |  22 +
 .gitignore => linq4j/gradle.properties             |  31 +-
 .../calcite/linq4j/test/JoinPreserveOrderTest.java |   4 +-
 mongodb/build.gradle.kts                           |  32 +
 .gitignore => mongodb/gradle.properties            |  31 +-
 pig/build.gradle.kts                               |  39 ++
 .gitignore => pig/gradle.properties                |  31 +-
 piglet/build.gradle.kts                            |  52 ++
 .gitignore => piglet/gradle.properties             |  31 +-
 plus/build.gradle.kts                              |  36 ++
 .gitignore => plus/gradle.properties               |  31 +-
 pom.xml                                            |   1 -
 release/build.gradle.kts                           | 195 +++++++
 server/build.gradle.kts                            |  61 ++
 settings.gradle.kts                                |  91 +++
 site/README.md                                     |   6 +-
 site/_docs/adapter.md                              |   1 -
 site/_docs/algebra.md                              |   1 -
 site/_docs/elasticsearch_adapter.md                |   1 -
 site/_docs/howto.md                                | 290 ++++-----
 site/_docs/index.md                                |   2 -
 site/_docs/lattice.md                              |   1 -
 site/_docs/tutorial.md                             |  26 +-
 site/_posts/2019-03-26-release-1.19.0.md           |   1 -
 site/develop/index.md                              |  13 +-
 site/docker-compose.yml                            |   2 +-
 spark/build.gradle.kts                             |  33 ++
 splunk/build.gradle.kts                            |  30 +
 .gitignore => splunk/gradle.properties             |  31 +-
 sqlline                                            |  29 +-
 sqlline.bat                                        |  12 +-
 sqlsh                                              |  23 +-
 example/csv/sqlline.bat => sqlsh.bat               |   9 +-
 src/main/config/checkstyle/checker.xml             |   4 +
 src/main/config/checkstyle/suppressions.xml        |  10 +-
 ubenchmark/build.gradle.kts                        |  26 +
 .gitignore => ubenchmark/gradle.properties         |  31 +-
 99 files changed, 3284 insertions(+), 777 deletions(-)

diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..d2284ae
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,46 @@
+root = true
+
+[*]
+trim_trailing_whitespace = true
+insert_final_newline = true
+charset = utf-8
+indent_style = space
+
+[{*.sh,gradlew}]
+end_of_line = lf
+
+[{*.bat,*.cmd}]
+end_of_line = crlf
+
+[{*.kts,*.kt}]
+ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL
+ij_kotlin_name_count_to_use_star_import = 99
+ij_kotlin_name_count_to_use_star_import_for_members = 99
+ij_java_use_single_class_imports = true
+max_line_length = 100
+ij_any_wrap_long_lines = true
+
+[*.java]
+# Doc: https://youtrack.jetbrains.com/issue/IDEA-170643#focus=streamItem-27-3708697.0-0
+# $ means "static"
+ij_java_imports_layout = org.apache.calcite.**,|,org.apache.**,|,au.com.**,|,com.**,|,io.**,|,mondrian.**,|,net.**,|,org.**,|,scala.**,|,java.**,javax.**,|,*,|,$com.**,|,$org.apache.calcite.**,|,$org.apache.**,|,$org.**,|,$java,|,$*
+indent_size = 2
+tab_width = 2
+max_line_length = 100
+ij_any_spaces_around_additive_operators = true
+ij_any_spaces_around_assignment_operators = true
+ij_any_spaces_around_bitwise_operators = true
+ij_any_spaces_around_equality_operators = true
+ij_any_spaces_around_lambda_arrow = true
+ij_any_spaces_around_logical_operators = true
+ij_any_spaces_around_multiplicative_operators = true
+ij_any_spaces_around_relational_operators = true
+ij_any_spaces_around_shift_operators = true
+ij_continuation_indent_size = 4
+ij_java_if_brace_force = always
+ij_java_indent_case_from_switch = false
+ij_java_space_after_colon = true
+ij_java_space_before_colon = true
+ij_java_ternary_operation_signs_on_next_line = true
+ij_java_use_single_class_imports = true
+ij_java_wrap_long_lines = true
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000..9a74b1b
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,64 @@
+name: CI
+
+on:
+  push:
+    branches:
+      - '*'
+  pull_request:
+    branches:
+      - '*'
+
+# https://help.github.com/en/actions/automating-your-workflow-with-github-actions/software-installed-on-github-hosted-runners
+
+jobs:
+  windows:
+    name: 'Windows (JDK 11)'
+    runs-on: windows-latest
+    steps:
+    - uses: actions/checkout@master
+      with:
+        fetch-depth: 50
+    - name: 'Set up JDK 11'
+      uses: actions/setup-java@v1
+      with:
+        java-version: 11
+    - name: 'Test'
+      shell: cmd
+      run: |
+        ./gradlew --no-parallel --no-daemon build javadoc
+
+  linux-avatica:
+    name: 'Linux (JDK 13), Avatica master'
+    runs-on: ubuntu-latest
+    steps:
+    - name: 'Set up JDK 13'
+      uses: actions/setup-java@v1
+      with:
+        java-version: 13
+    - name: 'Install Avatica to Maven Local repository'
+      run: |
+        git clone --branch master --depth 100 https://github.com/apache/calcite-avatica.git ../calcite-avatica
+        cd ../calcite-avatica
+        ./gradlew publishToMavenLocal -Pcalcite.avatica.version=1.0.0-dev-master -PskipJavadoc
+    - uses: actions/checkout@master
+      with:
+        fetch-depth: 50
+    - name: 'Test'
+      run: |
+        ./gradlew --no-parallel --no-daemon build javadoc -Pcalcite.avatica.version=1.0.0-dev-master-SNAPSHOT -PenableMavenLocal
+
+  mac:
+    name: 'macOS (JDK 13)'
+    runs-on: macos-latest
+    steps:
+      - uses: actions/checkout@master
+        with:
+          fetch-depth: 50
+      - name: 'Set up JDK 13'
+        uses: actions/setup-java@v1
+        with:
+          java-version: 13
+      - name: 'Test'
+        run: |
+          ./gradlew --no-parallel --no-daemon build javadoc
+
diff --git a/.gitignore b/.gitignore
index 75badb2..d18d766 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,9 +14,23 @@
 # limitations under the License.
 #
 *~
-target
-.idea
+.gradle
+/target
+/*/target
+/example/*/target
+/build
+/*/build
+/example/*/build
+/buildSrc/build
+/buildSrc/subprojects/*/build
+
+# IDEA
+/out
+/*/out/
+/example/*/out
+/.idea
 *.iml
+
 settings.xml
 .classpath.txt
 .fullclasspath.txt
diff --git a/.ratignore b/.ratignore
new file mode 100644
index 0000000..cb03673
--- /dev/null
+++ b/.ratignore
@@ -0,0 +1,47 @@
+**/.editorconfig
+**/.gitignore
+**/.gitattributes
+.github/workflows
+.ratignore
+**/META-INF/services/java.sql.Driver
+**/src/test/resources/**/*.csv
+**/src/test/resources/**/*.txt
+**/src/test/resources/bug/archers.json
+**/src/test/resources/foodmart-schema.spec
+**/src/test/resources/*.json
+**/data.txt
+**/data2.txt
+#bu ildSrc/build
+#b uildSrc/subprojects/*/build
+
+# TODO: remove when pom.xml files are removed
+src/main/config/licenses
+
+# Files generated by Jekyll
+site/_includes/anchor_links.html
+site/_includes/docs_contents.html
+site/_includes/docs_contents_mobile.html
+site/_includes/docs_option.html
+site/_includes/docs_ul.html
+site/_includes/footer.html
+site/_includes/header.html
+site/_includes/news_contents.html
+site/_includes/news_contents_mobile.html
+site/_includes/news_item.html
+site/_includes/primary-nav-items.html
+site/_includes/section_nav.html
+site/_includes/top.html
+site/_layouts/default.html
+site/_layouts/docs.html
+site/_layouts/external.html
+site/_layouts/news.html
+site/_layouts/news_item.html
+site/_layouts/page.html
+site/_sass/**
+site/css/screen.scss
+site/fonts/**
+site/js/**
+
+# Images
+site/img/*.png
+site/favicon.ico
diff --git a/.travis.yml b/.travis.yml
index ceec9dc..ec94f6f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -20,12 +20,11 @@ language: java
 matrix:
   fast_finish: true
   include:
-    - env: IMAGE=maven:3-jdk-13
-    - env: IMAGE=maven:3-jdk-12
-    - env: IMAGE=maven:3-jdk-11 JDOC=Y RAT=Y
-    - env: IMAGE=maven:3-jdk-10 SLOW_TESTS=Y
-    - env: IMAGE=maven:3-jdk-9
-    - env: IMAGE=maven:3-jdk-8 JDOC=Y
+    - jdk: openjdk8
+    - jdk: openjdk11
+    - jdk: openjdk11
+      env:
+        - SLOW_TESTS=Y
 branches:
   only:
     - master
@@ -33,27 +32,20 @@ branches:
     - javadoc
     - /^branch-.*$/
     - /^[0-9]+-.*$/
-env:
-  global:
-  - DOCKERRUN="docker run -it --rm -v $PWD:/src -v $HOME/.m2:/root/.m2 -w /src"
-services:
-  - docker
-before_install:
-  - docker pull $IMAGE
-install:
-  # Print the Maven version, skip tests and javadoc
-  - $DOCKERRUN $IMAGE mvn install -DskipTests=true -Dmaven.javadoc.skip=true -Djavax.net.ssl.trustStorePassword=changeit -B -V
+install: true
 script:
   # Print surefire output to the console instead of files
-  - unset _JAVA_OPTIONS
-  - if [ $JDOC = "Y" ]; then export JDOC=javadoc:javadoc; fi
-  - if [ $RAT = "Y" ]; then export RAT="apache-rat:check -Drat.consoleOutput"; fi
-  - if [ $SLOW_TESTS = "Y" ]; then export TESTS="-Dgroups=org.apache.calcite.test.SlowTests --projects :calcite-core"; else export TESTS=-DskipSlowTests; fi
-  - $DOCKERRUN $IMAGE mvn -Dcheckstyle.skip -Dsurefire.useFile=false -Dsurefire.threadCount=1 -Dsurefire.perCoreThreadCount=false -Djavax.net.ssl.trustStorePassword=changeit test $TESTS $JDOC $RAT
+  - if [ $SLOW_TESTS = "Y" ]; then export TEST_TAGS=-PincludeTestTags=org.apache.calcite.test.SlowTests; fi
+  - ./gradlew --no-daemon build $TEST_TAGS
 git:
-  depth: 10000
-sudo: required
+  depth: 100
 cache:
   directories:
-    - $HOME/.m2
+    - $HOME/.gradle/caches/
+    - $HOME/.gradle/wrapper/
+
+before_cache:
+  - rm -f  $HOME/.gradle/caches/modules-2/modules-2.lock
+  - rm -fr $HOME/.gradle/caches/*/plugin-resolution/
+
 # End .travis.yml
diff --git a/README.md b/README.md
index a9cfee9..2ba2fc5 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,7 @@ limitations under the License.
 {% endcomment %}
 -->
 [![Travis Build Status](https://travis-ci.org/apache/calcite.svg?branch=master)](https://travis-ci.org/apache/calcite)
+[![CI Status](https://github.com/apache/calcite/workflows/CI/badge.svg)](https://github.com/apache/calcite/actions)
 [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/apache/calcite?svg=true&branch=master)](https://ci.appveyor.com/project/ApacheSoftwareFoundation/calcite)
 
 # Apache Calcite
diff --git a/babel/build.gradle.kts b/babel/build.gradle.kts
new file mode 100644
index 0000000..a4ed693
--- /dev/null
+++ b/babel/build.gradle.kts
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ *
+ */
+
+plugins {
+    kotlin("jvm")
+    id("com.github.vlsi.ide")
+    calcite.fmpp
+    calcite.javacc
+}
+
+dependencies {
+    api(project(":core"))
+
+    implementation("com.google.guava:guava")
+    implementation("org.apache.calcite.avatica:avatica-core")
+    implementation("org.slf4j:slf4j-api")
+
+    testImplementation("net.hydromatic:quidem")
+    testImplementation("net.hydromatic:scott-data-hsqldb")
+    testImplementation("org.hsqldb:hsqldb")
+    testImplementation("org.incava:java-diff")
+    testImplementation("org.slf4j:slf4j-log4j12")
+    testImplementation(project(":core", "testClasses"))
+}
+
+val fmppMain by tasks.registering(org.apache.calcite.buildtools.fmpp.FmppTask::class) {
+    inputs.dir("src/main/codegen")
+    config.set(file("src/main/codegen/config.fmpp"))
+    templates.set(file("$rootDir/core/src/main/codegen/templates"))
+}
+
+val javaCCMain by tasks.registering(org.apache.calcite.buildtools.javacc.JavaCCTask::class) {
+    dependsOn(fmppMain)
+    lookAhead.set(2)
+    val parserFile = fmppMain.map {
+        it.output.asFileTree.matching { include("**/Parser.jj") }.singleFile
+    }
+    inputFile.set(parserFile)
+    packageName.set("org.apache.calcite.sql.parser.babel")
+}
+
+ide {
+    fun generatedSource(javacc: TaskProvider<org.apache.calcite.buildtools.javacc.JavaCCTask>, sourceSet: String) =
+        generatedJavaSources(javacc.get(), javacc.get().output.get().asFile, sourceSets.named(sourceSet))
+
+    generatedSource(javaCCMain, "main")
+}
diff --git a/bom/build.gradle.kts b/bom/build.gradle.kts
new file mode 100644
index 0000000..c75f8a0
--- /dev/null
+++ b/bom/build.gradle.kts
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ *
+ */
+
+plugins {
+    `java-platform`
+}
+
+val String.v: String get() = rootProject.extra["$this.version"] as String
+
+// Note: Gradle allows to declare dependency on "bom" as "api",
+// and it makes the contraints to be transitively visible
+// However Maven can't express that, so the approach is to use Gradle resolution
+// and generate pom files with resolved versions
+// See https://github.com/gradle/gradle/issues/9866
+
+fun DependencyConstraintHandlerScope.apiv(
+    notation: String,
+    versionProp: String = notation.substringAfterLast(':')
+) =
+    "api"(notation + ":" + versionProp.v)
+
+fun DependencyConstraintHandlerScope.runtimev(
+    notation: String,
+    versionProp: String = notation.substringAfterLast(':')
+) =
+    "runtime"(notation + ":" + versionProp.v)
+
+dependencies {
+    // Parenthesis are needed here: https://github.com/gradle/gradle/issues/9248
+    (constraints) {
+        // api means "the dependency is for both compilation and runtime"
+        // runtime means "the dependency is only for runtime, not for compilation"
+        // In other words, marking dependency as "runtime" would avoid accidental
+        // dependency on it during compilation
+        apiv("com.beust:jcommander")
+        apiv("com.datastax.cassandra:cassandra-driver-core")
+        apiv("com.esri.geometry:esri-geometry-api")
+        apiv("com.fasterxml.jackson.core:jackson-annotations", "jackson")
+        apiv("com.fasterxml.jackson.core:jackson-core", "jackson")
+        apiv("com.fasterxml.jackson.core:jackson-databind")
+        apiv("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml", "jackson")
+        apiv("com.github.stephenc.jcip:jcip-annotations")
+        apiv("com.google.code.findbugs:jsr305", "findbugs.jsr305")
+        apiv("com.google.guava:guava")
+        apiv("com.google.protobuf:protobuf-java", "protobuf")
+        apiv("com.h2database:h2")
+        apiv("com.jayway.jsonpath:json-path")
+        apiv("com.joestelmach:natty")
+        apiv("com.oracle.ojdbc:ojdbc8")
+        apiv("com.teradata.tpcds:tpcds", "teradata.tpcds")
+        apiv("com.yahoo.datasketches:sketches-core")
+        apiv("commons-codec:commons-codec")
+        apiv("commons-io:commons-io")
+        apiv("de.bwaldvogel:mongo-java-server", "mongo-java-server")
+        apiv("de.bwaldvogel:mongo-java-server-core", "mongo-java-server")
+        apiv("de.bwaldvogel:mongo-java-server-memory-backend", "mongo-java-server")
+        apiv("io.airlift.tpch:tpch")
+        apiv("javax.servlet:javax.servlet-api", "servlet")
+        apiv("joda-time:joda-time")
+        apiv("junit:junit", "junit4")
+        apiv("mysql:mysql-connector-java")
+        apiv("net.hydromatic:aggdesigner-algorithm")
+        apiv("net.hydromatic:chinook-data-hsqldb")
+        apiv("net.hydromatic:foodmart-data-hsqldb")
+        apiv("net.hydromatic:foodmart-data-json")
+        apiv("net.hydromatic:foodmart-queries")
+        apiv("net.hydromatic:quidem")
+        apiv("net.hydromatic:scott-data-hsqldb")
+        apiv("net.hydromatic:tpcds", "hydromatic.tpcds")
+        apiv("net.sf.opencsv:opencsv")
+        apiv("org.apache.calcite.avatica:avatica-core", "calcite.avatica")
+        apiv("org.apache.calcite.avatica:avatica-server", "calcite.avatica")
+        apiv("org.apache.cassandra:cassandra-all")
+        apiv("org.apache.commons:commons-dbcp2")
+        apiv("org.apache.commons:commons-lang3")
+        apiv("org.apache.geode:geode-core")
+        apiv("org.apache.hadoop:hadoop-client", "hadoop")
+        apiv("org.apache.hadoop:hadoop-common", "hadoop")
+        apiv("org.apache.httpcomponents:httpclient")
+        apiv("org.apache.httpcomponents:httpcore")
+        apiv("org.apache.kafka:kafka-clients")
+        apiv("org.apache.kerby:kerb-client", "kerby")
+        apiv("org.apache.kerby:kerb-core", "kerby")
+        apiv("org.apache.kerby:kerb-simplekdc", "kerby")
+        apiv("org.apache.logging.log4j:log4j-api", "log4j")
+        apiv("org.apache.logging.log4j:log4j-core", "log4j")
+        apiv("org.apache.pig:pig")
+        apiv("org.apache.pig:pigunit", "pig")
+        apiv("org.apache.spark:spark-core_2.10", "spark")
+        apiv("org.bouncycastle:bcpkix-jdk15on", "bouncycastle")
+        apiv("org.bouncycastle:bcprov-jdk15on", "bouncycastle")
+        apiv("org.cassandraunit:cassandra-unit")
+        apiv("org.codehaus.janino:commons-compiler", "janino")
+        apiv("org.codehaus.janino:janino")
+        apiv("org.codelibs.elasticsearch.module:lang-painless", "elasticsearch")
+        apiv("org.eclipse.jetty:jetty-http", "jetty")
+        apiv("org.eclipse.jetty:jetty-security", "jetty")
+        apiv("org.eclipse.jetty:jetty-server", "jetty")
+        apiv("org.eclipse.jetty:jetty-util", "jetty")
+        apiv("org.elasticsearch.client:elasticsearch-rest-client", "elasticsearch")
+        apiv("org.elasticsearch.plugin:transport-netty4-client", "elasticsearch")
+        apiv("org.elasticsearch:elasticsearch")
+        apiv("org.exparity:hamcrest-date")
+        apiv("org.hamcrest:hamcrest")
+        apiv("org.hamcrest:hamcrest-core", "hamcrest")
+        apiv("org.hamcrest:hamcrest-library", "hamcrest")
+        apiv("org.hsqldb:hsqldb")
+        apiv("org.incava:java-diff")
+        apiv("org.jsoup:jsoup")
+        apiv("org.junit.jupiter:junit-jupiter-api", "junit5")
+        apiv("org.junit.jupiter:junit-jupiter-params", "junit5")
+        apiv("org.mockito:mockito-core", "mockito")
+        apiv("org.mongodb:mongo-java-driver")
+        apiv("org.ow2.asm:asm")
+        apiv("org.ow2.asm:asm-all", "asm")
+        apiv("org.ow2.asm:asm-analysis", "asm")
+        apiv("org.ow2.asm:asm-commons", "asm")
+        apiv("org.ow2.asm:asm-tree", "asm")
+        apiv("org.ow2.asm:asm-util", "asm")
+        apiv("org.postgresql:postgresql")
+        apiv("org.scala-lang:scala-library")
+        apiv("org.slf4j:slf4j-api", "slf4j")
+        apiv("org.slf4j:slf4j-log4j12", "slf4j")
+        apiv("sqlline:sqlline")
+        runtimev("org.junit.jupiter:junit-jupiter-engine", "junit5")
+        runtimev("org.junit.vintage:junit-vintage-engine", "junit5")
+        runtimev("org.openjdk.jmh:jmh-core", "jmh")
+        runtimev("org.openjdk.jmh:jmh-generator-annprocess", "jmh")
+        runtimev("xalan:xalan")
+        runtimev("xerces:xercesImpl")
+    }
+}
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 0000000..6c25408
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,649 @@
+/*
+ * 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.
+ *
+ */
+
+import com.github.spotbugs.SpotBugsTask
+import com.github.vlsi.gradle.crlf.CrLfSpec
+import com.github.vlsi.gradle.crlf.LineEndings
+import com.github.vlsi.gradle.git.FindGitAttributes
+import com.github.vlsi.gradle.git.dsl.gitignore
+import com.github.vlsi.gradle.properties.dsl.lastEditYear
+import com.github.vlsi.gradle.properties.dsl.props
+import com.github.vlsi.gradle.release.RepositoryType
+import de.thetaphi.forbiddenapis.gradle.CheckForbiddenApis
+import de.thetaphi.forbiddenapis.gradle.CheckForbiddenApisExtension
+import org.gradle.api.tasks.testing.logging.TestExceptionFormat
+
+plugins {
+    publishing
+    // Verification
+    checkstyle
+    id("com.diffplug.gradle.spotless")
+    id("org.nosphere.apache.rat")
+    id("com.github.spotbugs")
+    id("de.thetaphi.forbiddenapis") apply false
+    id("org.owasp.dependencycheck")
+    id("com.github.johnrengelman.shadow") apply false
+    // IDE configuration
+    id("org.jetbrains.gradle.plugin.idea-ext")
+    id("com.github.vlsi.ide")
+    // Release
+    id("com.github.vlsi.crlf")
+    id("com.github.vlsi.gradle-extensions")
+    id("com.github.vlsi.license-gather") apply false
+    id("com.github.vlsi.stage-vote-release")
+}
+
+repositories {
+    // At least for RAT
+    mavenCentral()
+}
+
+fun reportsForHumans() = !(System.getenv()["CI"]?.toBoolean() ?: false)
+
+val lastEditYear by extra(lastEditYear())
+
+// Do not enable spotbugs by default. Execute it only when -Pspotbugs is present
+val enableSpotBugs = props.bool("spotbugs", default = false)
+val skipCheckstyle by props()
+val skipSpotless by props()
+val skipJavadoc by props()
+val enableMavenLocal by props()
+val enableGradleMetadata by props()
+val includeTestTags by props("!org.apache.calcite.test.SlowTests")
+// By default use Java implementation to sign artifacts
+// When useGpgCmd=true, then gpg command line tool is used for signing
+val useGpgCmd by props()
+
+ide {
+    copyrightToAsf()
+    ideaInstructionsUri =
+        uri("https://calcite.apache.org/docs/howto.html#setting-up-intellij-idea")
+    doNotDetectFrameworks("android", "jruby")
+}
+
+// This task scans the project for gitignore / gitattributes, and that is reused for building
+// source/binary artifacts with the appropriate eol/executable file flags
+// It enables to automatically exclude patterns from .gitignore
+val gitProps by tasks.registering(FindGitAttributes::class) {
+    // Scanning for .gitignore and .gitattributes files in a task avoids doing that
+    // when distribution build is not required (e.g. code is just compiled)
+    root.set(rootDir)
+}
+
+val rat by tasks.getting(org.nosphere.apache.rat.RatTask::class) {
+    gitignore(gitProps)
+    // Note: patterns are in non-standard syntax for RAT, so we use exclude(..) instead of excludeFile
+    exclude(rootDir.resolve(".ratignore").readLines())
+}
+
+tasks.validateBeforeBuildingReleaseArtifacts {
+    dependsOn(rat)
+}
+
+val String.v: String get() = rootProject.extra["$this.version"] as String
+
+val buildVersion = "calcite".v + releaseParams.snapshotSuffix
+
+println("Building Apache Calcite $buildVersion")
+
+val isReleaseVersion = rootProject.releaseParams.release.get()
+
+releaseArtifacts {
+    fromProject(":release")
+}
+
+// Configures URLs to SVN and Nexus
+releaseParams {
+    tlp.set("Calcite")
+    componentName.set("Apache Calcite")
+    releaseTag.set("rel/v$buildVersion")
+    rcTag.set(rc.map { "v$buildVersion-rc$it" })
+    sitePreviewEnabled.set(false)
+    nexus {
+        // https://github.com/marcphilipp/nexus-publish-plugin/issues/35
+        packageGroup.set("org.apache.calcite")
+        if (repositoryType.get() == RepositoryType.PROD) {
+            // org.apache.calcite at repository.apache.org
+            stagingProfileId.set("778fd0d4358bb")
+        }
+    }
+    svnDist {
+        staleRemovalFilters {
+            includes.add(Regex(".*apache-calcite-\\d.*"))
+            validates.empty()
+            validates.add(provider {
+                Regex("release/calcite/apache-calcite-${version.toString().removeSuffix("-SNAPSHOT")}")
+            })
+        }
+    }
+    validateBeforeBuildingReleaseArtifacts += Runnable {
+        if (useGpgCmd && findProperty("signing.gnupg.keyName") == null) {
+            throw GradleException("Please specify signing key id via signing.gnupg.keyName " +
+                    "(see https://github.com/gradle/gradle/issues/8657)")
+        }
+    }
+}
+
+val javadocAggregate by tasks.registering(Javadoc::class) {
+    group = JavaBasePlugin.DOCUMENTATION_GROUP
+    description = "Generates aggregate javadoc for all the artifacts"
+
+    val sourceSets = allprojects
+        .mapNotNull { it.extensions.findByType<SourceSetContainer>() }
+        .map { it.named("main") }
+
+    classpath = files(sourceSets.map { set -> set.map { it.output + it.compileClasspath } })
+    setSource(sourceSets.map { set -> set.map { it.allJava } })
+    setDestinationDir(file("$buildDir/docs/javadocAggregate"))
+}
+
+val adaptersForSqlline = listOf(
+    ":babel", ":cassandra", ":druid", ":elasticsearch", ":file", ":geode", ":kafka", ":mongodb",
+    ":pig", ":piglet", ":plus", ":spark", ":splunk"
+)
+
+val sqllineClasspath by configurations.creating {
+    isCanBeConsumed = false
+}
+
+dependencies {
+    sqllineClasspath(platform(project(":bom")))
+    sqllineClasspath("sqlline:sqlline")
+    for (p in adaptersForSqlline) {
+        sqllineClasspath(project(p))
+    }
+}
+
+val buildSqllineClasspath by tasks.registering(Jar::class) {
+    description = "Creates classpath-only jar for running SqlLine"
+    // One can debug classpath with ./gradlew dependencies --configuration sqllineClasspath
+    inputs.files(sqllineClasspath).withNormalizer(ClasspathNormalizer::class.java)
+    archiveFileName.set("sqllineClasspath.jar")
+    manifest {
+        manifest {
+            attributes(
+                "Main-Class" to "sqlline.SqlLine",
+                "Class-Path" to sqllineClasspath.map { it.absolutePath }.joinToString(" ")
+            )
+        }
+    }
+}
+
+val semaphore = `java.util.concurrent`.Semaphore(1)
+val licenseHeaderFile = file("config/license.header.java")
+
+val javaccGeneratedPatterns = arrayOf(
+    "**/parser/**/*ParserImpl*.*",
+    "**/parser/**/PigletParser.*",
+    "**/parser/**/PigletParserConstants.*",
+    "**/parser/**/ParseException.*",
+    "**/parser/**/SimpleCharStream.*",
+    "**/parser/**/Token.*",
+    "**/parser/**/TokenMgrError.*",
+    "**/org/apache/calcite/runtime/Resources.java",
+    "**/parser/**/*ParserTokenManager.*"
+)
+
+fun PatternFilterable.excludeJavaCcGenerated() {
+    exclude(*javaccGeneratedPatterns)
+}
+
+allprojects {
+    group = "org.apache.calcite"
+    version = buildVersion
+
+    val javaUsed = file("src/main/java").isDirectory
+    if (javaUsed) {
+        apply(plugin = "java-library")
+    }
+
+    plugins.withId("java-library") {
+        dependencies {
+            "implementation"(platform(project(":bom")))
+        }
+    }
+
+    val hasTests = file("src/test/java").isDirectory || file("src/test/kotlin").isDirectory
+    if (hasTests) {
+        // Add default tests dependencies
+        dependencies {
+            val testImplementation by configurations
+            val testRuntimeOnly by configurations
+            testImplementation("org.junit.jupiter:junit-jupiter-api")
+            testImplementation("org.junit.jupiter:junit-jupiter-params")
+            testImplementation("org.hamcrest:hamcrest")
+            testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
+            testRuntimeOnly("org.junit.vintage:junit-vintage-engine")
+            testImplementation("junit:junit")
+        }
+    }
+
+    if (!skipSpotless) {
+        apply(plugin = "com.diffplug.gradle.spotless")
+        spotless {
+            kotlinGradle {
+                ktlint()
+                trimTrailingWhitespace()
+                endWithNewline()
+            }
+            if (project == rootProject) {
+                // Spotless does not exclude subprojects when using target(...)
+                // So **/*.md is enough to scan all the md files in the codebase
+                // See https://github.com/diffplug/spotless/issues/468
+                format("markdown") {
+                    target("**/*.md")
+                    // Flot is known to have trailing whitespace, so the files
+                    // are kept in their original format (e.g. to simplify diff on library upgrade)
+                    trimTrailingWhitespace()
+                    endWithNewline()
+                }
+            }
+        }
+    }
+    if (!skipCheckstyle) {
+        apply<CheckstylePlugin>()
+        dependencies {
+            checkstyle("com.puppycrawl.tools:checkstyle:${"checkstyle".v}")
+            checkstyle("net.hydromatic:toolbox:${"hydromatic-toolbox".v}")
+        }
+        checkstyle {
+            // Current one is ~8.8
+            // https://github.com/julianhyde/toolbox/issues/3
+            isShowViolations = true
+            configDirectory.set(File(rootDir, "src/main/config/checkstyle"))
+            configFile = configDirectory.get().file("checker.xml").asFile
+            configProperties = mapOf(
+                "base_dir" to rootDir.toString()
+            )
+        }
+        tasks.withType<Checkstyle>().configureEach {
+            // Excludes here are faster than in suppressions.xml
+            // Since here we can completely remove file from the analysis.
+            // On the other hand, supporessions.xml still analyzes the file, and
+            // then it recognizes it should suppress all the output.
+            excludeJavaCcGenerated()
+            // There are concurrency issues with Checkstyle 7.8.2
+            // It could be in Checkstyle, in CheckstyleAnt task or in Gradle's Checkstyle plugin
+            // The bug looks like as if suppression was not working
+            doFirst {
+                semaphore.acquire()
+            }
+            doLast {
+                semaphore.release()
+            }
+        }
+    }
+
+    tasks.withType<AbstractArchiveTask>().configureEach {
+        // Ensure builds are reproducible
+        isPreserveFileTimestamps = false
+        isReproducibleFileOrder = true
+        dirMode = "775".toInt(8)
+        fileMode = "664".toInt(8)
+    }
+
+    plugins.withType<SigningPlugin> {
+        afterEvaluate {
+            configure<SigningExtension> {
+                val release = rootProject.releaseParams.release.get()
+                // Note it would still try to sign the artifacts,
+                // however it would fail only when signing a RELEASE version fails
+                isRequired = release
+                if (useGpgCmd) {
+                    useGpgCmd()
+                }
+            }
+        }
+    }
+
+    tasks {
+        withType<Javadoc>().configureEach {
+            excludeJavaCcGenerated()
+            (options as StandardJavadocDocletOptions).apply {
+                // Please refrain from using non-ASCII chars below since the options are passed as
+                // javadoc.options file which is parsed with "default encoding"
+                noTimestamp.value = true
+                showFromProtected()
+                // javadoc: error - The code being documented uses modules but the packages
+                // defined in https://docs.oracle.com/javase/9/docs/api/ are in the unnamed module
+                source = "1.8"
+                docEncoding = "UTF-8"
+                charSet = "UTF-8"
+                encoding = "UTF-8"
+                docTitle = "Apache Calcite ${project.name} API"
+                windowTitle = "Apache Calcite ${project.name} API"
+                header = "<b>Apache Calcite</b>"
+                bottom =
+                    "Copyright &copy; 2012-$lastEditYear Apache Software Foundation. All Rights Reserved."
+                if (JavaVersion.current() >= JavaVersion.VERSION_1_9) {
+                    addBooleanOption("html5", true)
+                    links("https://docs.oracle.com/javase/9/docs/api/")
+                } else {
+                    links("https://docs.oracle.com/javase/8/docs/api/")
+                }
+            }
+        }
+    }
+
+    plugins.withType<JavaPlugin> {
+        configure<JavaPluginConvention> {
+            sourceCompatibility = JavaVersion.VERSION_1_8
+            targetCompatibility = JavaVersion.VERSION_1_8
+        }
+
+        repositories {
+            if (enableMavenLocal) {
+                mavenLocal()
+            }
+            mavenCentral()
+        }
+        val sourceSets: SourceSetContainer by project
+
+        apply(plugin = "signing")
+        apply(plugin = "de.thetaphi.forbiddenapis")
+        apply(plugin = "maven-publish")
+
+        if (!enableGradleMetadata) {
+            tasks.withType<GenerateModuleMetadata> {
+                enabled = false
+            }
+        }
+
+        if (isReleaseVersion) {
+            configure<SigningExtension> {
+                // Sign all the publications
+                sign(publishing.publications)
+            }
+        }
+
+        if (!skipSpotless) {
+            spotless {
+                java {
+                    targetExclude(*javaccGeneratedPatterns + "**/test/java/*.java")
+                    licenseHeaderFile(licenseHeaderFile)
+                    importOrder(
+                        "org.apache.calcite.",
+                        "org.apache.",
+                        "au.com.",
+                        "com.",
+                        "io.",
+                        "mondrian.",
+                        "net.",
+                        "org.",
+                        "scala.",
+                        "java",
+                        "",
+                        "static com.",
+                        "static org.apache.calcite.",
+                        "static org.apache.",
+                        "static org.",
+                        "static java",
+                        "static "
+                    )
+                    removeUnusedImports()
+                    trimTrailingWhitespace()
+                    indentWithSpaces(4)
+                    endWithNewline()
+                }
+            }
+        }
+        if (enableSpotBugs) {
+            apply(plugin = "com.github.spotbugs")
+            spotbugs {
+                toolVersion = "spotbugs".v
+                reportLevel = "high"
+                //  excludeFilter = file("$rootDir/src/main/config/spotbugs/spotbugs-filter.xml")
+                // By default spotbugs verifies TEST classes as well, and we do not want that
+                this.sourceSets = listOf(sourceSets["main"])
+            }
+            dependencies {
+                // Parenthesis are needed here: https://github.com/gradle/gradle/issues/9248
+                (constraints) {
+                    "spotbugs"("org.ow2.asm:asm:${"asm".v}")
+                    "spotbugs"("org.ow2.asm:asm-all:${"asm".v}")
+                    "spotbugs"("org.ow2.asm:asm-analysis:${"asm".v}")
+                    "spotbugs"("org.ow2.asm:asm-commons:${"asm".v}")
+                    "spotbugs"("org.ow2.asm:asm-tree:${"asm".v}")
+                    "spotbugs"("org.ow2.asm:asm-util:${"asm".v}")
+                }
+            }
+        }
+
+        configure<CheckForbiddenApisExtension> {
+            failOnUnsupportedJava = false
+            bundledSignatures.addAll(
+                listOf(
+                    "jdk-unsafe",
+                    "jdk-deprecated",
+                    "jdk-non-portable"
+                )
+            )
+            signaturesFiles = files("$rootDir/src/main/config/forbidden-apis/signatures.txt")
+        }
+
+        (sourceSets) {
+            "main" {
+                resources {
+                    // TODO: remove when LICENSE is removed (it is used by Maven build for now)
+                    exclude("src/main/resources/META-INF/LICENSE")
+                }
+            }
+        }
+
+        tasks {
+            withType<Jar>().configureEach {
+                manifest {
+                    attributes["Bundle-License"] = "Apache-2.0"
+                    attributes["Implementation-Title"] = "Apache Calcite"
+                    attributes["Implementation-Version"] = project.version
+                    attributes["Specification-Vendor"] = "The Apache Software Foundation"
+                    attributes["Specification-Version"] = project.version
+                    attributes["Specification-Title"] = "Apache Calcite"
+                    attributes["Implementation-Vendor"] = "Apache Software Foundation"
+                    attributes["Implementation-Vendor-Id"] = "org.apache.calcite"
+                }
+            }
+
+            withType<CheckForbiddenApis>().configureEach {
+                excludeJavaCcGenerated()
+                exclude(
+                    "**/org/apache/calcite/adapter/os/Processes${'$'}ProcessFactory.class",
+                    "**/org/apache/calcite/adapter/os/OsAdapterTest.class",
+                    "**/org/apache/calcite/runtime/Resources${'$'}Inst.class",
+                    "**/org/apache/calcite/test/concurrent/ConcurrentTestCommandScript.class",
+                    "**/org/apache/calcite/test/concurrent/ConcurrentTestCommandScript${'$'}ShellCommand.class",
+                    "**/org/apache/calcite/util/Unsafe.class"
+                )
+            }
+
+            withType<JavaCompile>().configureEach {
+                options.encoding = "UTF-8"
+            }
+            withType<Test>().configureEach {
+                useJUnitPlatform {
+                    if (includeTestTags.isNotBlank()) {
+                        includeTags.add(includeTestTags)
+                    }
+                }
+                exclude("**/*Suite*")
+                jvmArgs("-Xmx1536m")
+                jvmArgs("-Djdk.net.URLClassPath.disableClassPathURLCheck=true")
+                testLogging {
+                    exceptionFormat = TestExceptionFormat.FULL
+                    showStandardStreams = true
+                }
+            }
+            withType<SpotBugsTask>().configureEach {
+                group = LifecycleBasePlugin.VERIFICATION_GROUP
+                if (enableSpotBugs) {
+                    description = "$description (skipped by default, to enable it add -Dspotbugs)"
+                }
+                reports {
+                    html.isEnabled = reportsForHumans()
+                    xml.isEnabled = !reportsForHumans()
+                }
+                enabled = enableSpotBugs
+            }
+
+            afterEvaluate {
+                // Add default license/notice when missing
+                withType<Jar>().configureEach {
+                    CrLfSpec(LineEndings.LF).run {
+                        into("META-INF") {
+                            filteringCharset = "UTF-8"
+                            duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+                            // Note: we need "generic Apache-2.0" text without third-party items
+                            // So we use the text from $rootDir/config/ since source distribution
+                            // contains altered text at $rootDir/LICENSE
+                            textFrom("$rootDir/src/main/config/licenses/LICENSE")
+                            textFrom("$rootDir/NOTICE")
+                        }
+                    }
+                }
+            }
+        }
+
+        // Note: jars below do not normalize line endings.
+        // Those jars, however are not included to source/binary distributions
+        // so the normailzation is not that important
+
+        val testJar by tasks.registering(Jar::class) {
+            from(sourceSets["test"].output)
+            archiveClassifier.set("tests")
+        }
+
+        val testSourcesJar by tasks.registering(Jar::class) {
+            from(sourceSets["test"].allJava)
+            archiveClassifier.set("test-sources")
+        }
+
+        val sourcesJar by tasks.registering(Jar::class) {
+            from(sourceSets["main"].allJava)
+            archiveClassifier.set("sources")
+        }
+
+        val javadocJar by tasks.registering(Jar::class) {
+            from(tasks.named(JavaPlugin.JAVADOC_TASK_NAME))
+            archiveClassifier.set("javadoc")
+        }
+
+        val testClasses by configurations.creating {
+            extendsFrom(configurations["testRuntime"])
+        }
+
+        val archives by configurations.getting
+
+        // Parenthesis needed to use Project#getArtifacts
+        (artifacts) {
+            testClasses(testJar)
+            archives(sourcesJar)
+            archives(testJar)
+            archives(testSourcesJar)
+        }
+
+        val archivesBaseName = "calcite-$name"
+        setProperty("archivesBaseName", archivesBaseName)
+
+        configure<PublishingExtension> {
+            if (project.path == ":") {
+                // Do not publish "root" project. Java plugin is applied here for DSL purposes only
+                return@configure
+            }
+            publications {
+                create<MavenPublication>(project.name) {
+                    artifactId = archivesBaseName
+                    version = rootProject.version.toString()
+                    description = project.description
+                    from(components["java"])
+
+                    if (!skipJavadoc) {
+                        // Eager task creation is required due to
+                        // https://github.com/gradle/gradle/issues/6246
+                        artifact(sourcesJar.get())
+                        artifact(javadocJar.get())
+                    }
+
+                    // Use the resolved versions in pom.xml
+                    // Gradle might have different resolution rules, so we set the versions
+                    // that were used in Gradle build/test.
+                    versionMapping {
+                        usage(Usage.JAVA_RUNTIME) {
+                            fromResolutionResult()
+                        }
+                        usage(Usage.JAVA_API) {
+                            fromResolutionOf("runtimeClasspath")
+                        }
+                    }
+                    pom {
+                        withXml {
+                            val sb = asString()
+                            var s = sb.toString()
+                            // <scope>compile</scope> is Maven default, so delete it
+                            s = s.replace("<scope>compile</scope>", "")
+                            // Cut <dependencyManagement> because all dependencies have the resolved versions
+                            s = s.replace(
+                                Regex(
+                                    "<dependencyManagement>.*?</dependencyManagement>",
+                                    RegexOption.DOT_MATCHES_ALL
+                                ),
+                                ""
+                            )
+                            sb.setLength(0)
+                            sb.append(s)
+                            // Re-format the XML
+                            asNode()
+                        }
+                        name.set(
+                            (project.findProperty("artifact.name") as? String) ?: "Calcite ${project.name.capitalize()}"
+                        )
+                        description.set(project.description ?: "Calcite ${project.name.capitalize()}")
+                        inceptionYear.set("2012")
+                        url.set("https://calcite.apache.org")
+                        licenses {
+                            license {
+                                name.set("The Apache License, Version 2.0")
+                                url.set("https://www.apache.org/licenses/LICENSE-2.0.txt")
+                                comments.set("A business-friendly OSS license")
+                                distribution.set("repo")
+                            }
+                        }
+                        issueManagement {
+                            system.set("Jira")
+                            url.set("https://issues.apache.org/jira/browse/CALCITE")
+                        }
+                        mailingLists {
+                            mailingList {
+                                name.set("Apache Calcite developers list")
+                                subscribe.set("dev-subscribe@calcite.apache.org")
+                                unsubscribe.set("dev-unsubscribe@calcite.apache.org")
+                                post.set("dev@calcite.apache.org")
+                                archive.set("https://lists.apache.org/list.html?dev@calcite.apache.org")
+                            }
+                        }
+                        scm {
+                            connection.set("scm:git:https://gitbox.apache.org/repos/asf/calcite.git")
+                            developerConnection.set("scm:git:https://gitbox.apache.org/repos/asf/calcite.git")
+                            url.set("https://github.com/apache/calcite")
+                            tag.set("HEAD")
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
new file mode 100644
index 0000000..0d50afb
--- /dev/null
+++ b/buildSrc/build.gradle.kts
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ *
+ */
+
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+plugins {
+    java
+    `kotlin-dsl` apply false
+    id("com.diffplug.gradle.spotless")
+}
+
+repositories {
+    jcenter()
+    gradlePluginPortal()
+}
+
+subprojects {
+    repositories {
+        jcenter()
+        gradlePluginPortal()
+    }
+    applyKotlinProjectConventions()
+}
+
+fun Project.applyKotlinProjectConventions() {
+    apply(plugin = "org.gradle.kotlin.kotlin-dsl")
+
+    plugins.withType<KotlinDslPlugin> {
+        configure<KotlinDslPluginOptions> {
+            experimentalWarning.set(false)
+        }
+    }
+
+    tasks.withType<KotlinCompile> {
+        sourceCompatibility = "unused"
+        targetCompatibility = "unused"
+        kotlinOptions {
+            jvmTarget = "1.8"
+        }
+    }
+    apply(plugin = "com.diffplug.gradle.spotless")
+    spotless {
+        kotlin {
+            ktlint()
+            trimTrailingWhitespace()
+            endWithNewline()
+        }
+        kotlinGradle {
+            ktlint()
+            trimTrailingWhitespace()
+            endWithNewline()
+        }
+    }
+}
+
+dependencies {
+    subprojects.forEach {
+        runtimeOnly(project(it.path))
+    }
+}
diff --git a/buildSrc/gradle.properties b/buildSrc/gradle.properties
new file mode 100644
index 0000000..962990e
--- /dev/null
+++ b/buildSrc/gradle.properties
@@ -0,0 +1,21 @@
+#   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.
+org.gradle.parallel=true
+kotlin.code.style=official
+kotlin.parallel.tasks.in.project=true
+
+# Plugins
+com.diffplug.gradle.spotless.version=3.25.0
+
diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts
new file mode 100644
index 0000000..2ba2662
--- /dev/null
+++ b/buildSrc/settings.gradle.kts
@@ -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.
+ *
+ */
+
+pluginManagement {
+    plugins {
+        fun PluginDependenciesSpec.idv(id: String) = id(id) version extra["$id.version"].toString()
+        idv("com.diffplug.gradle.spotless")
+    }
+}
+
+include("javacc")
+include("fmpp")
+
+val upperCaseLetters = "\\p{Upper}".toRegex()
+
+fun String.toKebabCase() =
+    replace(upperCaseLetters) { "-${it.value.toLowerCase()}" }
+
+fun buildFileNameFor(projectDirName: String) =
+    "$projectDirName.gradle.kts"
+
+for (project in rootProject.children) {
+    val projectDirName = project.name.toKebabCase()
+    project.projectDir = file("subprojects/$projectDirName")
+    project.buildFileName = buildFileNameFor(projectDirName)
+    assert(project.projectDir.isDirectory)
+    assert(project.buildFile.isFile)
+}
diff --git a/buildSrc/subprojects/fmpp/fmpp.gradle.kts b/buildSrc/subprojects/fmpp/fmpp.gradle.kts
new file mode 100644
index 0000000..a80b1d3
--- /dev/null
+++ b/buildSrc/subprojects/fmpp/fmpp.gradle.kts
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ *
+ */
+
+dependencies {
+}
+
+gradlePlugin {
+    plugins {
+        register("fmpp") {
+            id = "calcite.fmpp"
+            implementationClass = "org.apache.calcite.buildtools.fmpp.FmppPlugin"
+        }
+    }
+}
diff --git a/buildSrc/subprojects/fmpp/src/main/kotlin/org/apache/calcite/buildtools/fmpp/FmppPlugin.kt b/buildSrc/subprojects/fmpp/src/main/kotlin/org/apache/calcite/buildtools/fmpp/FmppPlugin.kt
new file mode 100644
index 0000000..19bcfdf
--- /dev/null
+++ b/buildSrc/subprojects/fmpp/src/main/kotlin/org/apache/calcite/buildtools/fmpp/FmppPlugin.kt
@@ -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.buildtools.fmpp
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+
+open class FmppPlugin : Plugin<Project> {
+    companion object {
+        const val FMPP_CLASSPATH_CONFIGURATION_NAME = "fmppClaspath"
+    }
+
+    override fun apply(target: Project) {
+        target.configureFmpp()
+    }
+
+    fun Project.configureFmpp() {
+        configurations.create(FMPP_CLASSPATH_CONFIGURATION_NAME) {
+            isCanBeConsumed = false
+        }.defaultDependencies {
+            // TODO: use properties for versions
+            add(dependencies.create("org.freemarker:freemarker:2.3.29"))
+            add(dependencies.create("net.sourceforge.fmpp:fmpp:0.9.16"))
+        }
+    }
+}
diff --git a/buildSrc/subprojects/fmpp/src/main/kotlin/org/apache/calcite/buildtools/fmpp/FmppTask.kt b/buildSrc/subprojects/fmpp/src/main/kotlin/org/apache/calcite/buildtools/fmpp/FmppTask.kt
new file mode 100644
index 0000000..1a4bfcc
--- /dev/null
+++ b/buildSrc/subprojects/fmpp/src/main/kotlin/org/apache/calcite/buildtools/fmpp/FmppTask.kt
@@ -0,0 +1,64 @@
+/*
+ * 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.buildtools.fmpp
+
+import javax.inject.Inject
+import org.gradle.api.DefaultTask
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.model.ObjectFactory
+import org.gradle.api.tasks.Classpath
+import org.gradle.api.tasks.InputDirectory
+import org.gradle.api.tasks.InputFile
+import org.gradle.api.tasks.OutputDirectory
+import org.gradle.api.tasks.TaskAction
+import org.gradle.kotlin.dsl.property
+import org.gradle.kotlin.dsl.withGroovyBuilder
+
+open class FmppTask @Inject constructor(
+    objectFactory: ObjectFactory
+) : DefaultTask() {
+    @Classpath
+    val fmppClasspath = objectFactory.property<Configuration>()
+        .convention(project.configurations.named(FmppPlugin.FMPP_CLASSPATH_CONFIGURATION_NAME))
+
+    @InputFile
+    val config = objectFactory.fileProperty()
+
+    @InputDirectory
+    val templates = objectFactory.directoryProperty()
+
+    @OutputDirectory
+    val output = objectFactory.directoryProperty()
+        .convention(project.layout.buildDirectory.dir("fmpp/$name"))
+
+    @TaskAction
+    fun run() {
+        project.delete(output.asFileTree)
+        ant.withGroovyBuilder {
+            "taskdef"("name" to "fmpp",
+                "classname" to "fmpp.tools.AntTask",
+                "classpath" to fmppClasspath.get().asPath)
+            "fmpp"(
+                "configuration" to config.get(),
+                "sourceRoot" to templates.get().asFile,
+                "outputRoot" to output.get().asFile
+            )
+        }
+    }
+}
diff --git a/buildSrc/subprojects/javacc/javacc.gradle.kts b/buildSrc/subprojects/javacc/javacc.gradle.kts
new file mode 100644
index 0000000..a2a9271
--- /dev/null
+++ b/buildSrc/subprojects/javacc/javacc.gradle.kts
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ *
+ */
+
+dependencies {
+}
+
+gradlePlugin {
+    plugins {
+        register("javacc") {
+            id = "calcite.javacc"
+            implementationClass = "org.apache.calcite.buildtools.javacc.JavaCCPlugin"
+        }
+    }
+}
diff --git a/buildSrc/subprojects/javacc/src/main/kotlin/org/apache/calcite/buildtools/javacc/JavaCCPlugin.kt b/buildSrc/subprojects/javacc/src/main/kotlin/org/apache/calcite/buildtools/javacc/JavaCCPlugin.kt
new file mode 100644
index 0000000..a134f8f
--- /dev/null
+++ b/buildSrc/subprojects/javacc/src/main/kotlin/org/apache/calcite/buildtools/javacc/JavaCCPlugin.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.buildtools.javacc
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.withType
+
+open class JavaCCPlugin : Plugin<Project> {
+    companion object {
+        const val JAVACC_CLASSPATH_CONFIGURATION_NAME = "javaccClaspath"
+        const val GENERATE_SOURCES_TASK_NAME = "generateSources"
+    }
+
+    override fun apply(target: Project) {
+        target.configureJavaCC()
+    }
+
+    fun Project.configureJavaCC() {
+        configurations.create(JAVACC_CLASSPATH_CONFIGURATION_NAME) {
+            isCanBeConsumed = false
+        }.defaultDependencies {
+            // TODO: use properties for versions
+            add(dependencies.create("net.java.dev.javacc:javacc:4.0")) // 7.0.5"))
+        }
+
+        tasks.register(GENERATE_SOURCES_TASK_NAME) {
+            description = "Generates sources (e.g. JavaCC)"
+            dependsOn(tasks.withType<JavaCCTask>())
+        }
+    }
+}
diff --git a/buildSrc/subprojects/javacc/src/main/kotlin/org/apache/calcite/buildtools/javacc/JavaCCTask.kt b/buildSrc/subprojects/javacc/src/main/kotlin/org/apache/calcite/buildtools/javacc/JavaCCTask.kt
new file mode 100644
index 0000000..510b492
--- /dev/null
+++ b/buildSrc/subprojects/javacc/src/main/kotlin/org/apache/calcite/buildtools/javacc/JavaCCTask.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.buildtools.javacc
+
+import java.io.File
+import javax.inject.Inject
+import org.gradle.api.DefaultTask
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.model.ObjectFactory
+import org.gradle.api.tasks.Classpath
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.InputFile
+import org.gradle.api.tasks.OutputDirectory
+import org.gradle.api.tasks.TaskAction
+import org.gradle.kotlin.dsl.property
+
+open class JavaCCTask @Inject constructor(
+    objectFactory: ObjectFactory
+) : DefaultTask() {
+    @Classpath
+    val javaCCClasspath = objectFactory.property<Configuration>()
+        .convention(project.configurations.named(JavaCCPlugin.JAVACC_CLASSPATH_CONFIGURATION_NAME))
+
+    @InputFile
+    val inputFile = objectFactory.property<File>()
+
+    @Input
+    val lookAhead = objectFactory.property<Int>().convention(1)
+
+    @Input
+    val static = objectFactory.property<Boolean>().convention(false)
+
+    @OutputDirectory
+    val output = objectFactory.directoryProperty()
+        .convention(project.layout.buildDirectory.dir("javacc/$name"))
+
+    @Input
+    val packageName = objectFactory.property<String>()
+
+    @TaskAction
+    fun run() {
+        project.delete(output.asFileTree)
+        project.javaexec {
+            classpath = javaCCClasspath.get()
+            // The class is in the top-level package
+            main = "javacc"
+            args("-STATIC=${static.get()}")
+            args("-LOOKAHEAD:${lookAhead.get()}")
+            args("-OUTPUT_DIRECTORY:${output.get()}/${packageName.get().replace('.', '/')}")
+            args(inputFile.get())
+        }
+    }
+}
diff --git a/cassandra/build.gradle.kts b/cassandra/build.gradle.kts
new file mode 100644
index 0000000..5b6b73e
--- /dev/null
+++ b/cassandra/build.gradle.kts
@@ -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.
+ *
+ */
+
+dependencies {
+    api(project(":core"))
+    api(project(":linq4j"))
+
+    implementation("com.datastax.cassandra:cassandra-driver-core")
+    implementation("com.google.guava:guava")
+    implementation("org.apache.calcite.avatica:avatica-core")
+    implementation("org.slf4j:slf4j-api")
+
+    testImplementation(project(":core", "testClasses"))
+    testImplementation("org.apache.cassandra:cassandra-all") {
+        exclude("org.slf4j", "log4j-over-slf4j")
+            .because("log4j is already present in the classpath")
+    }
+    testImplementation("org.cassandraunit:cassandra-unit")
+    testImplementation("com.github.stephenc.jcip:jcip-annotations")
+}
diff --git a/.gitignore b/cassandra/gradle.properties
similarity index 64%
copy from .gitignore
copy to cassandra/gradle.properties
index 75badb2..82b0ca1 100644
--- a/.gitignore
+++ b/cassandra/gradle.properties
@@ -1,11 +1,12 @@
+#
 # 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 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
+#   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,
@@ -13,26 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-*~
-target
-.idea
-*.iml
-settings.xml
-.classpath.txt
-.fullclasspath.txt
-
-# eclipse
-.project
-.buildpath
-.classpath
-.factorypath
-.settings
-.checkstyle
-
-# netbeans
-nb-configuration.xml
-*/nb-configuration.xml
-
-.mvn/wrapper/maven-wrapper.jar
-
-# End .gitignore
+#
+description=A library designed to abstract away any required dependency on a metrics library
+artifact.name=Apache Calcite Avatica Metrics
diff --git a/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java b/config/license.header.java
similarity index 54%
rename from mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java
rename to config/license.header.java
index 218dba3..2a42971 100644
--- a/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java
+++ b/config/license.header.java
@@ -14,31 +14,3 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.calcite.test;
-
-import org.apache.calcite.adapter.mongodb.MongoAdapterTest;
-
-import org.junit.BeforeClass;
-
-import static org.junit.Assume.assumeTrue;
-
-/**
- * Used to trigger integration tests from maven (thus class name is suffixed with {@code IT}).
- *
- * <p>If you want to run integration tests from the, IDE manually set the
- * {@code -Dcalcite.integrationTest=true} system property.
- *
- * <p>For command line use:
- * <pre>
- *     $ mvn install -Pit
- * </pre>
- */
-public class MongoAdapterIT extends MongoAdapterTest {
-
-  @BeforeClass
-  public static void enforceMongo() {
-    assumeTrue(MongoAssertions.useMongo());
-  }
-}
-
-// End MongoAdapterIT.java
diff --git a/core/build.gradle.kts b/core/build.gradle.kts
new file mode 100644
index 0000000..4648132
--- /dev/null
+++ b/core/build.gradle.kts
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ *
+ */
+
+import com.github.vlsi.gradle.crlf.CrLfSpec
+import com.github.vlsi.gradle.crlf.LineEndings
+
+plugins {
+    kotlin("jvm")
+    id("com.github.vlsi.crlf")
+    id("com.github.vlsi.ide")
+    calcite.fmpp
+    calcite.javacc
+}
+
+val integrationTestConfig: (Configuration.() -> Unit) = {
+    isCanBeConsumed = false
+    isTransitive = true
+    extendsFrom(configurations.testRuntimeClasspath.get())
+}
+
+val testH2 by configurations.creating(integrationTestConfig)
+val testOracle by configurations.creating(integrationTestConfig)
+val testPostgresql by configurations.creating(integrationTestConfig)
+val testMysql by configurations.creating(integrationTestConfig)
+
+dependencies {
+    api(project(":linq4j"))
+
+    api("com.fasterxml.jackson.core:jackson-annotations")
+    api("org.apache.calcite.avatica:avatica-core")
+
+    implementation("com.esri.geometry:esri-geometry-api")
+    implementation("com.fasterxml.jackson.core:jackson-core")
+    implementation("com.fasterxml.jackson.core:jackson-databind")
+    implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml")
+    implementation("com.google.code.findbugs:jsr305"/* optional*/)
+    implementation("com.google.guava:guava")
+    implementation("com.jayway.jsonpath:json-path")
+    implementation("com.yahoo.datasketches:sketches-core")
+    implementation("commons-codec:commons-codec")
+    implementation("net.hydromatic:aggdesigner-algorithm")
+    implementation("org.apache.calcite.avatica:avatica-server")
+    implementation("org.apache.commons:commons-dbcp2")
+    implementation("org.apache.commons:commons-lang3")
+    implementation("org.codehaus.janino:commons-compiler")
+    implementation("org.codehaus.janino:janino")
+    implementation("org.slf4j:slf4j-api")
+
+    testH2("com.h2database:h2")
+    testMysql("mysql:mysql-connector-java")
+    testOracle("com.oracle.ojdbc:ojdbc8")
+    testPostgresql("org.postgresql:postgresql")
+
+    testImplementation("com.github.stephenc.jcip:jcip-annotations")
+    testImplementation("net.hydromatic:foodmart-data-hsqldb")
+    testImplementation("net.hydromatic:foodmart-queries")
+    testImplementation("net.hydromatic:quidem")
+    testImplementation("net.hydromatic:scott-data-hsqldb")
+    testImplementation("org.apache.commons:commons-pool2")
+    testImplementation("org.hsqldb:hsqldb")
+    testImplementation("org.incava:java-diff")
+    testImplementation("sqlline:sqlline")
+    testImplementation(kotlin("stdlib-jdk8"))
+    testImplementation(kotlin("test"))
+    testImplementation(kotlin("test-junit"))
+    testRuntimeOnly("org.slf4j:slf4j-log4j12")
+}
+
+tasks.jar {
+    CrLfSpec(LineEndings.LF).run {
+        into("codegen") {
+            textFrom("$projectDir/src/main/codegen")
+        }
+    }
+}
+
+tasks.withType<Checkstyle>().configureEach {
+    exclude("org/apache/calcite/runtime/Resources.java")
+}
+
+val fmppMain by tasks.registering(org.apache.calcite.buildtools.fmpp.FmppTask::class) {
+    config.set(file("src/main/codegen/config.fmpp"))
+    templates.set(file("src/main/codegen/templates"))
+}
+
+val javaCCMain by tasks.registering(org.apache.calcite.buildtools.javacc.JavaCCTask::class) {
+    dependsOn(fmppMain)
+    val parserFile = fmppMain.map {
+        it.output.asFileTree.matching { include("**/Parser.jj") }.singleFile
+    }
+    inputFile.set(parserFile)
+    packageName.set("org.apache.calcite.sql.parser.impl")
+}
+
+val fmppTest by tasks.registering(org.apache.calcite.buildtools.fmpp.FmppTask::class) {
+    config.set(file("src/test/codegen/config.fmpp"))
+    templates.set(file("src/main/codegen/templates"))
+}
+
+val javaCCTest by tasks.registering(org.apache.calcite.buildtools.javacc.JavaCCTask::class) {
+    dependsOn(fmppTest)
+    val parserFile = fmppTest.map {
+        it.output.asFileTree.matching { include("**/Parser.jj") }.singleFile
+    }
+    inputFile.set(parserFile)
+    packageName.set("org.apache.calcite.sql.parser.parserextensiontesting")
+}
+
+ide {
+    fun generatedSource(javacc: TaskProvider<org.apache.calcite.buildtools.javacc.JavaCCTask>, sourceSet: String) =
+        generatedJavaSources(javacc.get(), javacc.get().output.get().asFile, sourceSets.named(sourceSet))
+
+    generatedSource(javaCCMain, "main")
+    generatedSource(javaCCTest, "test")
+}
+
+val integTestAll by tasks.registering() {
+    group = LifecycleBasePlugin.VERIFICATION_GROUP
+    description = "Executes integration JDBC tests for all DBs"
+}
+
+val coreTestClasses = sourceSets.main.get().output
+val coreClasses = sourceSets.main.get().output + coreTestClasses
+for (db in listOf("h2", "mysql", "oracle", "postgresql")) {
+    val task = tasks.register("integTest" + db.capitalize(), Test::class) {
+        group = LifecycleBasePlugin.VERIFICATION_GROUP
+        description = "Executes integration JDBC tests with $db database"
+        include("org/apache/calcite/test/JdbcAdapterTest.class")
+        include("org/apache/calcite/test/JdbcTest.class")
+        systemProperty("calcite.test.db", db)
+        testClassesDirs = coreTestClasses.classesDirs
+        classpath = coreClasses + configurations.getAt("test" + db.capitalize())
+    }
+    integTestAll {
+        dependsOn(task)
+    }
+}
diff --git a/.gitignore b/core/gradle.properties
similarity index 64%
copy from .gitignore
copy to core/gradle.properties
index 75badb2..a7df9ea 100644
--- a/.gitignore
+++ b/core/gradle.properties
@@ -1,11 +1,12 @@
+#
 # 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 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
+#   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,
@@ -13,26 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-*~
-target
-.idea
-*.iml
-settings.xml
-.classpath.txt
-.fullclasspath.txt
-
-# eclipse
-.project
-.buildpath
-.classpath
-.factorypath
-.settings
-.checkstyle
-
-# netbeans
-nb-configuration.xml
-*/nb-configuration.xml
-
-.mvn/wrapper/maven-wrapper.jar
-
-# End .gitignore
+#
+description=Core Calcite APIs and engine
+artifact.name=Calcite Core
diff --git a/core/pom.xml b/core/pom.xml
index da6597e..0797642 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -333,20 +333,6 @@ limitations under the License.
         </executions>
       </plugin>
       <plugin>
-        <groupId>net.hydromatic</groupId>
-        <artifactId>hydromatic-resource-maven-plugin</artifactId>
-        <executions>
-          <execution>
-            <goals>
-              <goal>generate-sources</goal>
-            </goals>
-            <configuration>
-              <packageName>org.apache.calcite.runtime</packageName>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jar-plugin</artifactId>
         <executions>
diff --git a/core/src/main/java/org/apache/calcite/rel/hint/ExplicitHintMatcher.java b/core/src/main/java/org/apache/calcite/rel/hint/ExplicitHintMatcher.java
index b366545..c839a95 100644
--- a/core/src/main/java/org/apache/calcite/rel/hint/ExplicitHintMatcher.java
+++ b/core/src/main/java/org/apache/calcite/rel/hint/ExplicitHintMatcher.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.calcite.rel.hint;
 
 import org.apache.calcite.rel.RelNode;
diff --git a/core/src/main/java/org/apache/calcite/rel/hint/ExplicitHintStrategy.java b/core/src/main/java/org/apache/calcite/rel/hint/ExplicitHintStrategy.java
index a70187d..b96fdf9 100644
--- a/core/src/main/java/org/apache/calcite/rel/hint/ExplicitHintStrategy.java
+++ b/core/src/main/java/org/apache/calcite/rel/hint/ExplicitHintStrategy.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.calcite.rel.hint;
 
 import org.apache.calcite.rel.RelNode;
diff --git a/core/src/main/java/org/apache/calcite/rel/hint/HintStrategies.java b/core/src/main/java/org/apache/calcite/rel/hint/HintStrategies.java
index 4d97786..ba7b44d 100644
--- a/core/src/main/java/org/apache/calcite/rel/hint/HintStrategies.java
+++ b/core/src/main/java/org/apache/calcite/rel/hint/HintStrategies.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.calcite.rel.hint;
 
 /**
diff --git a/core/src/main/java/org/apache/calcite/rel/hint/HintStrategyCascade.java b/core/src/main/java/org/apache/calcite/rel/hint/HintStrategyCascade.java
index 7494f7b..de7e4a6 100644
--- a/core/src/main/java/org/apache/calcite/rel/hint/HintStrategyCascade.java
+++ b/core/src/main/java/org/apache/calcite/rel/hint/HintStrategyCascade.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.calcite.rel.hint;
 
 import org.apache.calcite.rel.RelNode;
diff --git a/core/src/main/java/org/apache/calcite/rel/hint/NodeTypeHintStrategy.java b/core/src/main/java/org/apache/calcite/rel/hint/NodeTypeHintStrategy.java
index 3b95492..a32d394 100644
--- a/core/src/main/java/org/apache/calcite/rel/hint/NodeTypeHintStrategy.java
+++ b/core/src/main/java/org/apache/calcite/rel/hint/NodeTypeHintStrategy.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.calcite.rel.hint;
 
 import org.apache.calcite.rel.RelNode;
diff --git a/core/src/main/java/org/apache/calcite/rel/hint/RelHint.java b/core/src/main/java/org/apache/calcite/rel/hint/RelHint.java
index 62ea6a2..cbec243 100644
--- a/core/src/main/java/org/apache/calcite/rel/hint/RelHint.java
+++ b/core/src/main/java/org/apache/calcite/rel/hint/RelHint.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.calcite.rel.hint;
 
 import org.apache.calcite.util.ImmutableBitSet;
diff --git a/core/src/main/java/org/apache/calcite/schema/SchemaFactory.java b/core/src/main/java/org/apache/calcite/schema/SchemaFactory.java
index e9f1b10..8fcd6ec 100644
--- a/core/src/main/java/org/apache/calcite/schema/SchemaFactory.java
+++ b/core/src/main/java/org/apache/calcite/schema/SchemaFactory.java
@@ -37,7 +37,7 @@ import java.util.Map;
  *       "factory": "org.apache.calcite.adapter.csv.CsvSchemaFactory",
  *       "mutable": true,
  *       "operand": {
- *         directory: "target/test-classes/sales"
+ *         directory: "sales"
  *       },
  *       "tables": [
  *         {
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlFunctionCategory.java b/core/src/main/java/org/apache/calcite/sql/SqlFunctionCategory.java
index 288adfc..2e8e6b4 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlFunctionCategory.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlFunctionCategory.java
@@ -18,14 +18,14 @@ package org.apache.calcite.sql;
 
 import org.apache.calcite.util.Util;
 
+import java.util.Arrays;
+import java.util.EnumSet;
+
 import static org.apache.calcite.sql.SqlFunctionCategory.Property.FUNCTION;
 import static org.apache.calcite.sql.SqlFunctionCategory.Property.SPECIFIC;
 import static org.apache.calcite.sql.SqlFunctionCategory.Property.TABLE_FUNCTION;
 import static org.apache.calcite.sql.SqlFunctionCategory.Property.USER_DEFINED;
 
-import java.util.Arrays;
-import java.util.EnumSet;
-
 /**
  * Enumeration of the categories of
  * SQL-invoked routines.
diff --git a/core/src/test/java/org/apache/calcite/runtime/AutomatonTest.java b/core/src/test/java/org/apache/calcite/runtime/AutomatonTest.java
index 38be52f..63a7ca5 100644
--- a/core/src/test/java/org/apache/calcite/runtime/AutomatonTest.java
+++ b/core/src/test/java/org/apache/calcite/runtime/AutomatonTest.java
@@ -21,7 +21,6 @@ import org.apache.calcite.test.Matchers;
 
 import com.google.common.collect.ImmutableList;
 
-import org.hamcrest.Factory;
 import org.hamcrest.core.Is;
 import org.junit.Test;
 
@@ -38,7 +37,6 @@ public class AutomatonTest {
   /** Creates a Matcher that matches a list of
    * {@link org.apache.calcite.runtime.Matcher.PartialMatch} if they
    * a formatted to a given string. */
-  @Factory
   private static <E> org.hamcrest.Matcher<List<Matcher.PartialMatch<E>>>
       isMatchList(final String value) {
     return Matchers.compose(Is.is(value),
diff --git a/core/src/test/java/org/apache/calcite/sql/test/DocumentationTest.java b/core/src/test/java/org/apache/calcite/sql/test/DocumentationTest.java
index 75ea1ea..14fb1e2 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/DocumentationTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/DocumentationTest.java
@@ -211,7 +211,7 @@ public class DocumentationTest {
       inFile = new File(base, "site/_docs/reference.md");
       // TODO: replace with core/build/ when Maven is migrated to Gradle
       // It does work in Gradle, however, we don't want to create "target" folder in Gradle
-      outFile = new File(base, "core/target/surefire/reference.md");
+      outFile = new File(base, "core/build/reports/documentationTest/reference.md");
     }
   }
 }
diff --git a/core/src/test/java/org/apache/calcite/sql/type/SqlTypeUtilTest.java b/core/src/test/java/org/apache/calcite/sql/type/SqlTypeUtilTest.java
index 6707a2b..0c44ba7 100644
--- a/core/src/test/java/org/apache/calcite/sql/type/SqlTypeUtilTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/type/SqlTypeUtilTest.java
@@ -19,12 +19,12 @@ package org.apache.calcite.sql.type;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 
-import static org.apache.calcite.sql.type.SqlTypeUtil.areSameFamily;
-
 import com.google.common.collect.ImmutableList;
 
 import org.junit.Test;
 
+import static org.apache.calcite.sql.type.SqlTypeUtil.areSameFamily;
+
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
 
diff --git a/core/src/test/java/org/apache/calcite/test/Matchers.java b/core/src/test/java/org/apache/calcite/test/Matchers.java
index 1d85be6..d0ad99c 100644
--- a/core/src/test/java/org/apache/calcite/test/Matchers.java
+++ b/core/src/test/java/org/apache/calcite/test/Matchers.java
@@ -28,7 +28,6 @@ import org.hamcrest.BaseMatcher;
 import org.hamcrest.CoreMatchers;
 import org.hamcrest.CustomTypeSafeMatcher;
 import org.hamcrest.Description;
-import org.hamcrest.Factory;
 import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
 import org.hamcrest.core.Is;
@@ -130,7 +129,6 @@ public class Matchers {
    * Creates a matcher that matches when the examined object is within
    * {@code epsilon} of the specified <code>operand</code>.
    */
-  @Factory
   public static <T extends Number> Matcher<T> within(T value, double epsilon) {
     return new IsWithin<T>(value, epsilon);
   }
@@ -175,7 +173,6 @@ public class Matchers {
    *
    * @see Util#toLinux(String)
    */
-  @Factory
   public static Matcher<String> isLinux(final String value) {
     return compose(Is.is(value), input -> input == null ? null : Util.toLinux(input));
   }
@@ -185,7 +182,6 @@ public class Matchers {
    * representation, after converting Windows-style line endings ("\r\n")
    * to Unix-style line endings ("\n"), is equal to the given {@code value}.
    */
-  @Factory
   public static Matcher<RelNode> hasTree(final String value) {
     return compose(Is.is(value), input -> {
       // Convert RelNode to a string with Linux line-endings
@@ -199,7 +195,6 @@ public class Matchers {
    * to Unix-style line endings ("\n"), contains the given {@code value}
    * as a substring.
    */
-  @Factory
   public static Matcher<RelNode> inTree(final String value) {
     return compose(StringContains.containsString(value), input -> {
       // Convert RelNode to a string with Linux line-endings
@@ -223,7 +218,6 @@ public class Matchers {
    *
    * @see Util#toLinux(String)
    */
-  @Factory
   public static Matcher<String> containsStringLinux(String value) {
     return compose(CoreMatchers.containsString(value), Util::toLinux);
   }
diff --git a/core/src/test/java/org/apache/calcite/test/SqlHintsConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlHintsConverterTest.java
index 9659fbc..6d7c562 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlHintsConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlHintsConverterTest.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.calcite.test;
 
 import org.apache.calcite.adapter.enumerable.EnumerableConvention;
@@ -66,11 +65,6 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -78,6 +72,11 @@ import java.util.List;
 import java.util.Locale;
 import java.util.stream.Collectors;
 
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
 /**
  * Unit test for {@link org.apache.calcite.rel.hint.RelHint}.
  */
diff --git a/druid/build.gradle.kts b/druid/build.gradle.kts
new file mode 100644
index 0000000..66141b4
--- /dev/null
+++ b/druid/build.gradle.kts
@@ -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.
+ *
+ */
+
+dependencies {
+    api(platform(project(":bom")))
+
+    api("org.apache.calcite.avatica:avatica-core")
+    api(project(":core"))
+    testImplementation(project(":core", "testClasses"))
+    api(project(":linq4j"))
+    api("org.apache.commons:commons-lang3")
+    api("com.fasterxml.jackson.core:jackson-core")
+    api("com.fasterxml.jackson.core:jackson-databind")
+    api("com.google.code.findbugs:jsr305")
+    api("com.google.guava:guava")
+    api("joda-time:joda-time")
+    api("org.slf4j:slf4j-api")
+    testImplementation("org.slf4j:slf4j-log4j12")
+    testImplementation("org.mockito:mockito-core")
+}
diff --git a/.gitignore b/druid/gradle.properties
similarity index 64%
copy from .gitignore
copy to druid/gradle.properties
index 75badb2..0c3a310 100644
--- a/.gitignore
+++ b/druid/gradle.properties
@@ -1,11 +1,12 @@
+#
 # 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 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
+#   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,
@@ -13,26 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-*~
-target
-.idea
-*.iml
-settings.xml
-.classpath.txt
-.fullclasspath.txt
-
-# eclipse
-.project
-.buildpath
-.classpath
-.factorypath
-.settings
-.checkstyle
-
-# netbeans
-nb-configuration.xml
-*/nb-configuration.xml
-
-.mvn/wrapper/maven-wrapper.jar
-
-# End .gitignore
+#
+description=Druid adapter for Calcite
+artifact.name=Calcite Druid
diff --git a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidConnectionImpl.java b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidConnectionImpl.java
index 09d90f9..de64369 100644
--- a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidConnectionImpl.java
+++ b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidConnectionImpl.java
@@ -29,8 +29,6 @@ import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.util.Holder;
 import org.apache.calcite.util.Util;
 
-import static org.apache.calcite.runtime.HttpUtils.post;
-
 import com.fasterxml.jackson.core.JsonFactory;
 import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.core.JsonToken;
@@ -63,6 +61,8 @@ import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import static org.apache.calcite.runtime.HttpUtils.post;
+
 /**
  * Implementation of {@link DruidConnection}.
  */
diff --git a/elasticsearch/build.gradle.kts b/elasticsearch/build.gradle.kts
new file mode 100644
index 0000000..9a0d91d
--- /dev/null
+++ b/elasticsearch/build.gradle.kts
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ *
+ */
+
+import com.github.vlsi.gradle.properties.dsl.props
+
+plugins {
+    id("com.github.vlsi.gradle-extensions")
+}
+
+dependencies {
+    api(project(":core"))
+    api(project(":linq4j"))
+
+    api("com.fasterxml.jackson.core:jackson-annotations")
+
+    implementation("com.fasterxml.jackson.core:jackson-core")
+    implementation("com.fasterxml.jackson.core:jackson-databind")
+    implementation("com.google.code.findbugs:jsr305")
+    implementation("com.google.guava:guava")
+    implementation("org.apache.calcite.avatica:avatica-core")
+    implementation("org.apache.httpcomponents:httpclient")
+    implementation("org.apache.httpcomponents:httpcore")
+    implementation("org.elasticsearch.client:elasticsearch-rest-client")
+    implementation("org.slf4j:slf4j-api")
+
+    // https://github.com/elastic/elasticsearch/issues/49218
+    if (project.props.bool("elasticStrictAsm", default = true)) {
+        val asm = Action<DependencyConstraint> {
+            version { strictly("5.1") }
+        }
+        constraints {
+            testRuntimeOnly("org.ow2.asm:asm", asm)
+            testRuntimeOnly("org.ow2.asm:asm-all", asm)
+            testRuntimeOnly("org.ow2.asm:asm-debug-all", asm)
+            testRuntimeOnly("org.ow2.asm:asm-analysis", asm)
+            testRuntimeOnly("org.ow2.asm:asm-commons", asm)
+            testRuntimeOnly("org.ow2.asm:asm-tree", asm)
+            testRuntimeOnly("org.ow2.asm:asm-util", asm)
+        }
+    }
+
+    testImplementation("org.apache.logging.log4j:log4j-api")
+    testImplementation("org.apache.logging.log4j:log4j-core")
+    testImplementation("org.codelibs.elasticsearch.module:lang-painless")
+    testImplementation("org.elasticsearch.plugin:transport-netty4-client")
+    testImplementation("org.elasticsearch:elasticsearch")
+    testImplementation(project(":core", "testClasses"))
+}
diff --git a/.gitignore b/elasticsearch/gradle.properties
similarity index 64%
copy from .gitignore
copy to elasticsearch/gradle.properties
index 75badb2..674d067 100644
--- a/.gitignore
+++ b/elasticsearch/gradle.properties
@@ -1,11 +1,12 @@
+#
 # 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 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
+#   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,
@@ -13,26 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-*~
-target
-.idea
-*.iml
-settings.xml
-.classpath.txt
-.fullclasspath.txt
-
-# eclipse
-.project
-.buildpath
-.classpath
-.factorypath
-.settings
-.checkstyle
-
-# netbeans
-nb-configuration.xml
-*/nb-configuration.xml
-
-.mvn/wrapper/maven-wrapper.jar
-
-# End .gitignore
+#
+description=Elasticsearch adapter for Calcite
+artifact.name=Calcite Elasticsearch
diff --git a/elasticsearch/src/main/java/org/apache/calcite/adapter/elasticsearch/PredicateAnalyzer.java b/elasticsearch/src/main/java/org/apache/calcite/adapter/elasticsearch/PredicateAnalyzer.java
index fe61b52..3acf2b6 100644
--- a/elasticsearch/src/main/java/org/apache/calcite/adapter/elasticsearch/PredicateAnalyzer.java
+++ b/elasticsearch/src/main/java/org/apache/calcite/adapter/elasticsearch/PredicateAnalyzer.java
@@ -51,7 +51,6 @@ import static org.apache.calcite.adapter.elasticsearch.QueryBuilders.rangeQuery;
 import static org.apache.calcite.adapter.elasticsearch.QueryBuilders.regexpQuery;
 import static org.apache.calcite.adapter.elasticsearch.QueryBuilders.termQuery;
 
-
 import static java.lang.String.format;
 /**
  * Query predicate analyzer. Uses visitor pattern to traverse existing expression
diff --git a/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/MatchTest.java b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/MatchTest.java
index 2f4bfa0..6bbfb3a 100644
--- a/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/MatchTest.java
+++ b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/MatchTest.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.calcite.adapter.elasticsearch;
 
 
@@ -45,16 +44,10 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.io.LineProcessor;
 import com.google.common.io.Resources;
 
-
 import org.junit.BeforeClass;
 import org.junit.ClassRule;
 import org.junit.Test;
 
-import static org.apache.calcite.test.Matchers.hasTree;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.sql.Connection;
@@ -66,6 +59,11 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+
+import static org.apache.calcite.test.Matchers.hasTree;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
 /**
  * Testing Elasticsearch match query.
  */
diff --git a/example/csv/build.gradle.kts b/example/csv/build.gradle.kts
new file mode 100644
index 0000000..642ec96
--- /dev/null
+++ b/example/csv/build.gradle.kts
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ *
+ */
+
+val sqllineClasspath by configurations.creating {
+    isCanBeConsumed = false
+    extendsFrom(configurations.testRuntimeClasspath.get())
+}
+
+dependencies {
+    api(project(":core"))
+    api(project(":linq4j"))
+
+    implementation("com.fasterxml.jackson.core:jackson-core")
+    implementation("com.fasterxml.jackson.core:jackson-databind")
+    implementation("com.google.guava:guava")
+    implementation("commons-io:commons-io")
+    implementation("net.sf.opencsv:opencsv")
+    implementation("org.apache.calcite.avatica:avatica-core")
+    implementation("org.apache.commons:commons-lang3")
+
+    testImplementation("sqlline:sqlline")
+    testImplementation(project(":core", "testClasses"))
+
+    sqllineClasspath(project(":example:csv", "testClasses"))
+}
+
+val buildSqllineClasspath by tasks.registering(Jar::class) {
+    inputs.files(sqllineClasspath).withNormalizer(ClasspathNormalizer::class.java)
+    archiveFileName.set("sqllineClasspath.jar")
+    manifest {
+        manifest {
+            attributes(
+                "Main-Class" to "sqlline.SqlLine",
+                "Class-Path" to sqllineClasspath.map { it.absolutePath }.joinToString(" ")
+            )
+        }
+    }
+}
diff --git a/.gitignore b/example/csv/gradle.properties
similarity index 64%
copy from .gitignore
copy to example/csv/gradle.properties
index 75badb2..38f18bc 100644
--- a/.gitignore
+++ b/example/csv/gradle.properties
@@ -1,11 +1,12 @@
+#
 # 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 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
+#   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,
@@ -13,26 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-*~
-target
-.idea
-*.iml
-settings.xml
-.classpath.txt
-.fullclasspath.txt
-
-# eclipse
-.project
-.buildpath
-.classpath
-.factorypath
-.settings
-.checkstyle
-
-# netbeans
-nb-configuration.xml
-*/nb-configuration.xml
-
-.mvn/wrapper/maven-wrapper.jar
-
-# End .gitignore
+#
+description=An example Calcite provider that reads CSV files
+artifact.name=Calcite Example CSV
diff --git a/example/csv/sqlline b/example/csv/sqlline
index e8441fd..e2f73b0 100755
--- a/example/csv/sqlline
+++ b/example/csv/sqlline
@@ -18,7 +18,8 @@
 #
 # Example:
 # $ ./sqlline
-# sqlline> !connect jdbc:calcite:model=target/test-classes/model.json admin admin
+# sqlline> !connect jdbc:calcite:model=src/test/resources/model.json admin admin
+# sqlline> !tables
 
 # Deduce whether we are running cygwin
 case $(uname -s) in
@@ -26,21 +27,19 @@ case $(uname -s) in
 (*) cygwin=;;
 esac
 
-# Build classpath on first call. (To force rebuild, remove .classpath.txt.)
+# Build classpath on first call. (To update it run ../gradlew buildSqllineClasspath)
 cd $(dirname $0)
-if [ ! -f target/classpath.txt ]; then
-    mvn dependency:build-classpath -Dmdep.outputFile=target/classpath.txt
+
+if [ ! -f build/libs/sqllineClasspath.jar ]; then
+    ../../gradlew buildSqllineClasspath
 fi
 
-CP="target/classes:target/test-classes:$(cat target/classpath.txt)"
 VM_OPTS=
 if [ "$cygwin" ]; then
-  CP=$(cygpath -wp "$CP")
-
   # Work around https://github.com/jline/jline2/issues/62
   VM_OPTS=-Djline.terminal=jline.UnixTerminal
 fi
 
-exec java $VM_OPTS -cp "${CP}" sqlline.SqlLine "$@"
+exec java -Xmx1g $VM_OPTS -jar build/libs/sqllineClasspath.jar "$@"
 
 # End sqlline
diff --git a/example/csv/sqlline.bat b/example/csv/sqlline.bat
index ac7bfc3..b7092f2 100644
--- a/example/csv/sqlline.bat
+++ b/example/csv/sqlline.bat
@@ -18,11 +18,12 @@
 ::
 :: Example:
 :: > sqlline.bat
-:: sqlline> !connect jdbc:calcite:model=target/test-classes/model.json admin admin 
+:: sqlline> !connect jdbc:calcite:model=target/test-classes/model.json admin admin
+:: sqlline> !tables
 
-:: Copy dependency jars on first call. (To force jar refresh, remove target\dependencies)
-if not exist target\dependencies (call mvn -B dependency:copy-dependencies -DoverWriteReleases=false -DoverWriteSnapshots=false -DoverWriteIfNewer=true -DoutputDirectory=target\dependencies)
+:: Copy dependency jars on first call. To update it run ./gradlew buildSqllineClasspath
+if not exist build\libs\sqllineClasspath.jar (call ../../gradlew buildSqllineClasspath)
 
-java -Xmx1G -cp ".\target\test-classes;.\target\classes;.\target\dependencies\*" sqlline.SqlLine --verbose=true %*
+java -Xmx1g -jar build\libs\sqllineClasspath.jar sqlline.SqlLine %*
 
 :: End sqlline.bat
diff --git a/example/function/build.gradle.kts b/example/function/build.gradle.kts
new file mode 100644
index 0000000..e4965e0
--- /dev/null
+++ b/example/function/build.gradle.kts
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ *
+ */
+
+dependencies {
+    api(project(":core"))
+    api(project(":linq4j"))
+
+    implementation("com.google.guava:guava") {
+        because("""ForbiddenApis' signatures.txt contains com.google.common.base.Precondition
+          and it needs the file on a classpath to parse the configuration"""
+        )
+    }
+    testImplementation("sqlline:sqlline")
+}
diff --git a/.gitignore b/example/function/gradle.properties
similarity index 64%
copy from .gitignore
copy to example/function/gradle.properties
index 75badb2..fb02edd 100644
--- a/.gitignore
+++ b/example/function/gradle.properties
@@ -1,11 +1,12 @@
+#
 # 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 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
+#   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,
@@ -13,26 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-*~
-target
-.idea
-*.iml
-settings.xml
-.classpath.txt
-.fullclasspath.txt
-
-# eclipse
-.project
-.buildpath
-.classpath
-.factorypath
-.settings
-.checkstyle
-
-# netbeans
-nb-configuration.xml
-*/nb-configuration.xml
-
-.mvn/wrapper/maven-wrapper.jar
-
-# End .gitignore
+#
+description=Examples of user-defined Calcite functions
+artifact.name=Calcite Example Function
diff --git a/file/build.gradle.kts b/file/build.gradle.kts
new file mode 100644
index 0000000..77c945e
--- /dev/null
+++ b/file/build.gradle.kts
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ *
+ */
+
+dependencies {
+    api(project(":core"))
+    api(project(":example:csv"))
+    api(project(":linq4j"))
+
+    implementation("com.google.guava:guava")
+    implementation("com.joestelmach:natty")
+    implementation("org.apache.calcite.avatica:avatica-core")
+    implementation("org.jsoup:jsoup")
+
+    testImplementation(project(":core", "testClasses"))
+}
diff --git a/.gitignore b/file/gradle.properties
similarity index 64%
copy from .gitignore
copy to file/gradle.properties
index 75badb2..5fa6315 100644
--- a/.gitignore
+++ b/file/gradle.properties
@@ -1,11 +1,12 @@
+#
 # 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 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
+#   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,
@@ -13,26 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-*~
-target
-.idea
-*.iml
-settings.xml
-.classpath.txt
-.fullclasspath.txt
-
-# eclipse
-.project
-.buildpath
-.classpath
-.factorypath
-.settings
-.checkstyle
-
-# netbeans
-nb-configuration.xml
-*/nb-configuration.xml
-
-.mvn/wrapper/maven-wrapper.jar
-
-# End .gitignore
+#
+description=Calcite provider that reads files and URIs
+artifact.name=Calcite File
diff --git a/geode/README.md b/geode/README.md
index 7099e23..5c6a69d 100644
--- a/geode/README.md
+++ b/geode/README.md
@@ -18,4 +18,3 @@ limitations under the License.
 -->
 
 ##Apache Geode SQL/JBC Adapter
-
diff --git a/geode/build.gradle.kts b/geode/build.gradle.kts
new file mode 100644
index 0000000..f1b9e7c
--- /dev/null
+++ b/geode/build.gradle.kts
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ *
+ */
+
+dependencies {
+    api(project(":core"))
+    api(project(":linq4j"))
+
+    implementation("com.google.guava:guava")
+    implementation("org.apache.calcite.avatica:avatica-core")
+    implementation("org.apache.commons:commons-lang3")
+    implementation("org.apache.geode:geode-core")
+    implementation("org.slf4j:slf4j-api")
+
+    testImplementation(project(":core", "testClasses"))
+    testImplementation("com.fasterxml.jackson.core:jackson-databind")
+    testRuntimeOnly("org.slf4j:slf4j-log4j12")
+}
diff --git a/.gitignore b/geode/gradle.properties
similarity index 64%
copy from .gitignore
copy to geode/gradle.properties
index 75badb2..dfc048a 100644
--- a/.gitignore
+++ b/geode/gradle.properties
@@ -1,11 +1,12 @@
+#
 # 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 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
+#   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,
@@ -13,26 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-*~
-target
-.idea
-*.iml
-settings.xml
-.classpath.txt
-.fullclasspath.txt
-
-# eclipse
-.project
-.buildpath
-.classpath
-.factorypath
-.settings
-.checkstyle
-
-# netbeans
-nb-configuration.xml
-*/nb-configuration.xml
-
-.mvn/wrapper/maven-wrapper.jar
-
-# End .gitignore
+#
+description=Geode adapter for Calcite
+artifact.name=Calcite Geode
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..a696f66
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,130 @@
+#   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.
+
+org.gradle.parallel=true
+# See https://github.com/gradle/gradle/pull/11358 , https://issues.apache.org/jira/browse/INFRA-14923
+# repository.apache.org does not yet support .sha256 and .sha512 checksums
+systemProp.org.gradle.internal.publish.checksums.insecure=true
+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=<int> arguments
+calcite.version=1.22.0
+# This is a version to be used from Maven repository. It can be overridden by localAvatica below
+calcite.avatica.version=1.15.0
+
+# The options below configures the use of local clone (e.g. testing development versions)
+# You can pass un-comment it, or pass option -PlocalReleasePlugins, or -PlocalReleasePlugins=<path>
+# localReleasePlugins=../vlsi-release-plugins
+# localAvatica=../calcite-avatica
+
+# By default, Maven Local repository is not used
+# enableMavenLocal=true
+# Gradle metadata is not well supported in the build script, so it is disabled for now
+# publishGradleMetadata=true
+
+# Plugins
+com.diffplug.gradle.spotless.version=3.25.0
+com.github.johnrengelman.shadow.version=5.1.0
+com.github.spotbugs.version=2.0.0
+com.github.vlsi.vlsi-release-plugins.version=1.48.0
+com.google.protobuf.version=0.8.10
+de.thetaphi.forbiddenapis.version=2.7
+kotlin.version=1.3.50
+org.jetbrains.gradle.plugin.idea-ext.version=0.5
+org.nosphere.apache.rat.version=0.5.2
+org.owasp.dependencycheck.version=5.2.2
+
+# TODO
+# error_prone_core.version=2.3.3
+# docker-maven-plugin.version=1.2.0
+
+# Tools
+checkstyle.version=7.8.2
+spotbugs.version=3.1.11
+# For Checkstyle
+hydromatic-toolbox.version=0.3
+
+# We support Guava versions as old as 14.0.1 (the version used by Hive)
+# but prefer more recent versions.
+# elasticsearch does not like asm:6.2.1+
+aggdesigner-algorithm.version=6.0
+asm.version=7.2
+bouncycastle.version=1.60
+cassandra-all.version=3.11.2
+cassandra-driver-core.version=3.6.0
+cassandra-unit.version=3.5.0.1
+chinook-data-hsqldb.version=0.1
+commons-codec.version=1.12
+commons-dbcp2.version=2.6.0
+commons-io.version=2.4
+commons-lang3.version=3.8
+dropwizard-metrics.version=4.0.5
+elasticsearch.version=7.0.1
+esri-geometry-api.version=2.2.0
+findbugs.jsr305.version=3.0.1
+foodmart-data-hsqldb.version=0.3
+foodmart-data-json.version=0.4
+foodmart-queries.version=0.4.1
+geode-core.version=1.10.0
+guava.version=19.0
+h2.version=1.4.197
+hadoop.version=2.7.5
+hamcrest-date.version=2.0.4
+hamcrest.version=2.1
+hsqldb.version=2.4.1
+httpclient.version=4.5.9
+httpcore.version=4.4.11
+hydromatic.tpcds.version=0.4
+jackson-databind.version=2.9.10.1
+jackson.version=2.10.0
+janino.version=3.0.11
+java-diff.version=1.1.2
+jcip-annotations.version=1.0-1
+jcommander.version=1.72
+jetty.version=9.4.15.v20190215
+jmh.version=1.12
+joda-time.version=2.8.1
+json-path.version=2.4.0
+jsoup.version=1.11.3
+junit4.version=4.12
+junit5.version=5.5.1
+kafka-clients.version=2.1.1
+kerby.version=1.1.1
+log4j.version=2.11.0
+mockito.version=2.23.4
+mongo-java-driver.version=3.10.2
+mongo-java-server.version=1.16.0
+mysql-connector-java.version=5.1.20
+natty.version=0.13
+ojdbc8.version=19.3.0.0
+opencsv.version=2.3
+pig.version=0.16.0
+pigunit.version=
+postgresql.version=9.3-1102-jdbc41
+protobuf.version=3.6.1
+quidem.version=0.9
+scala-library.version=2.10.3
+scott-data-hsqldb.version=0.1
+servlet.version=4.0.1
+sketches-core.version=0.9.0
+slf4j.version=1.7.25
+spark.version=2.2.0
+sqlline.version=1.9.0
+teradata.tpcds.version=1.2
+tpch.version=0.1
+xalan.version=2.7.1
+xercesImpl.version=2.9.1
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..5c2d1cf
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..c571965
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,21 @@
+#   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.
+
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionSha256Sum=6f6cfdbb12a577c3845522a1c7fbfe1295ea05d87edabedd4e23fd2bf02b88b1
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-all.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..83f2acf
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,188 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed 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
+#
+#      https://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.
+#
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..9618d8d
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,100 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/kafka/build.gradle.kts b/kafka/build.gradle.kts
new file mode 100644
index 0000000..6987d4d
--- /dev/null
+++ b/kafka/build.gradle.kts
@@ -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.
+ *
+ */
+
+dependencies {
+    api(project(":core"))
+    api(project(":linq4j"))
+
+    implementation("com.google.guava:guava")
+    implementation("org.apache.kafka:kafka-clients")
+
+    testImplementation(project(":core", "testClasses"))
+}
diff --git a/.gitignore b/kafka/gradle.properties
similarity index 64%
copy from .gitignore
copy to kafka/gradle.properties
index 75badb2..b753dbb 100644
--- a/.gitignore
+++ b/kafka/gradle.properties
@@ -1,11 +1,12 @@
+#
 # 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 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
+#   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,
@@ -13,26 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-*~
-target
-.idea
-*.iml
-settings.xml
-.classpath.txt
-.fullclasspath.txt
-
-# eclipse
-.project
-.buildpath
-.classpath
-.factorypath
-.settings
-.checkstyle
-
-# netbeans
-nb-configuration.xml
-*/nb-configuration.xml
-
-.mvn/wrapper/maven-wrapper.jar
-
-# End .gitignore
+#
+description=Kafka adapter for Calcite; exposes Kafka topics as stream tables
+artifact.name=Calcite Kafka
diff --git a/linq4j/build.gradle.kts b/linq4j/build.gradle.kts
new file mode 100644
index 0000000..4c7bb81
--- /dev/null
+++ b/linq4j/build.gradle.kts
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ *
+ */
+
+dependencies {
+    implementation("com.google.guava:guava")
+    implementation("org.apache.calcite.avatica:avatica-core")
+}
diff --git a/.gitignore b/linq4j/gradle.properties
similarity index 64%
copy from .gitignore
copy to linq4j/gradle.properties
index 75badb2..3ed3fb7 100644
--- a/.gitignore
+++ b/linq4j/gradle.properties
@@ -1,11 +1,12 @@
+#
 # 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 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
+#   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,
@@ -13,26 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-*~
-target
-.idea
-*.iml
-settings.xml
-.classpath.txt
-.fullclasspath.txt
-
-# eclipse
-.project
-.buildpath
-.classpath
-.factorypath
-.settings
-.checkstyle
-
-# netbeans
-nb-configuration.xml
-*/nb-configuration.xml
-
-.mvn/wrapper/maven-wrapper.jar
-
-# End .gitignore
+#
+description=Calcite APIs for LINQ (Language-Integrated Query) in Java
+artifact.name=Calcite Linq4j
diff --git a/linq4j/src/test/java/org/apache/calcite/linq4j/test/JoinPreserveOrderTest.java b/linq4j/src/test/java/org/apache/calcite/linq4j/test/JoinPreserveOrderTest.java
index 2e540be..c1f9e01 100644
--- a/linq4j/src/test/java/org/apache/calcite/linq4j/test/JoinPreserveOrderTest.java
+++ b/linq4j/src/test/java/org/apache/calcite/linq4j/test/JoinPreserveOrderTest.java
@@ -23,8 +23,6 @@ import org.apache.calcite.linq4j.Linq4j;
 import org.apache.calcite.linq4j.function.Function1;
 import org.apache.calcite.linq4j.function.Function2;
 
-import static org.apache.calcite.linq4j.function.Functions.nullsComparator;
-
 import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -35,6 +33,8 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 
+import static org.apache.calcite.linq4j.function.Functions.nullsComparator;
+
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
diff --git a/mongodb/build.gradle.kts b/mongodb/build.gradle.kts
new file mode 100644
index 0000000..7fde092
--- /dev/null
+++ b/mongodb/build.gradle.kts
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ *
+ */
+
+dependencies {
+    api(project(":core"))
+    api(project(":linq4j"))
+
+    implementation("com.google.guava:guava")
+    implementation("org.apache.calcite.avatica:avatica-core")
+    implementation("org.mongodb:mongo-java-driver")
+    implementation("org.slf4j:slf4j-api")
+
+    testImplementation(project(":core", "testClasses"))
+    testImplementation("de.bwaldvogel:mongo-java-server-core")
+    testImplementation("de.bwaldvogel:mongo-java-server-memory-backend")
+    testImplementation("net.hydromatic:foodmart-data-json")
+}
diff --git a/.gitignore b/mongodb/gradle.properties
similarity index 64%
copy from .gitignore
copy to mongodb/gradle.properties
index 75badb2..03d1f53 100644
--- a/.gitignore
+++ b/mongodb/gradle.properties
@@ -1,11 +1,12 @@
+#
 # 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 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
+#   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,
@@ -13,26 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-*~
-target
-.idea
-*.iml
-settings.xml
-.classpath.txt
-.fullclasspath.txt
-
-# eclipse
-.project
-.buildpath
-.classpath
-.factorypath
-.settings
-.checkstyle
-
-# netbeans
-nb-configuration.xml
-*/nb-configuration.xml
-
-.mvn/wrapper/maven-wrapper.jar
-
-# End .gitignore
+#
+description=MongoDB adapter for Calcite
+artifact.name=Calcite MongoDB
diff --git a/pig/build.gradle.kts b/pig/build.gradle.kts
new file mode 100644
index 0000000..6020e17
--- /dev/null
+++ b/pig/build.gradle.kts
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ *
+ */
+
+dependencies {
+    api(project(":core"))
+    api(project(":linq4j"))
+
+    implementation("com.google.guava:guava")
+    implementation("org.apache.calcite.avatica:avatica-core")
+    implementation("org.apache.pig:pig::h2")
+    implementation("org.slf4j:slf4j-api")
+
+    testImplementation(project(":core", "testClasses"))
+    testImplementation("org.apache.hadoop:hadoop-client")
+    testImplementation("org.apache.hadoop:hadoop-common")
+    testImplementation("org.apache.pig:pigunit") {
+        // Note: pigunit is located after pig-h2 in the classpath,
+        // so extra pig.jar (non-h2) should not harm.
+        // But we exclude it just in case.
+        exclude("org.apache.pig", "pig")
+            .because("We need -h2 classifier of the dependency")
+    }
+    testRuntimeOnly("org.slf4j:slf4j-log4j12")
+}
diff --git a/.gitignore b/pig/gradle.properties
similarity index 64%
copy from .gitignore
copy to pig/gradle.properties
index 75badb2..032be53 100644
--- a/.gitignore
+++ b/pig/gradle.properties
@@ -1,11 +1,12 @@
+#
 # 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 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
+#   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,
@@ -13,26 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-*~
-target
-.idea
-*.iml
-settings.xml
-.classpath.txt
-.fullclasspath.txt
-
-# eclipse
-.project
-.buildpath
-.classpath
-.factorypath
-.settings
-.checkstyle
-
-# netbeans
-nb-configuration.xml
-*/nb-configuration.xml
-
-.mvn/wrapper/maven-wrapper.jar
-
-# End .gitignore
+#
+description=Pig adapter for Calcite
+artifact.name=Calcite Pig
diff --git a/piglet/build.gradle.kts b/piglet/build.gradle.kts
new file mode 100644
index 0000000..82a2f43
--- /dev/null
+++ b/piglet/build.gradle.kts
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ *
+ */
+
+plugins {
+    calcite.javacc
+    id("com.github.vlsi.ide")
+}
+
+dependencies {
+    api(project(":core"))
+    api(project(":linq4j"))
+
+    implementation("com.google.code.findbugs:jsr305")
+    implementation("com.google.guava:guava")
+    implementation("org.apache.calcite.avatica:avatica-core")
+    implementation("org.apache.hadoop:hadoop-common")
+    implementation("org.apache.pig:pig::h2")
+    implementation("org.slf4j:slf4j-api")
+
+    testImplementation(project(":core", "testClasses"))
+    testImplementation("net.hydromatic:scott-data-hsqldb")
+    testImplementation("org.apache.hadoop:hadoop-client")
+    testImplementation("org.hsqldb:hsqldb")
+    testRuntimeOnly("org.slf4j:slf4j-log4j12")
+}
+
+val javaCCMain by tasks.registering(org.apache.calcite.buildtools.javacc.JavaCCTask::class) {
+    inputFile.set(file("src/main/javacc/PigletParser.jj"))
+    packageName.set("org.apache.calcite.piglet.parser")
+}
+
+ide {
+    fun generatedSource(javacc: TaskProvider<org.apache.calcite.buildtools.javacc.JavaCCTask>, sourceSet: String) =
+        generatedJavaSources(javacc.get(), javacc.get().output.get().asFile, sourceSets.named(sourceSet))
+
+    generatedSource(javaCCMain, "main")
+}
diff --git a/.gitignore b/piglet/gradle.properties
similarity index 64%
copy from .gitignore
copy to piglet/gradle.properties
index 75badb2..63ba4d2 100644
--- a/.gitignore
+++ b/piglet/gradle.properties
@@ -1,11 +1,12 @@
+#
 # 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 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
+#   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,
@@ -13,26 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-*~
-target
-.idea
-*.iml
-settings.xml
-.classpath.txt
-.fullclasspath.txt
-
-# eclipse
-.project
-.buildpath
-.classpath
-.factorypath
-.settings
-.checkstyle
-
-# netbeans
-nb-configuration.xml
-*/nb-configuration.xml
-
-.mvn/wrapper/maven-wrapper.jar
-
-# End .gitignore
+#
+description=Pig-like language built on top of Calcite algebra
+artifact.name=Apache Calcite Avatica Metrics
diff --git a/plus/build.gradle.kts b/plus/build.gradle.kts
new file mode 100644
index 0000000..9877820
--- /dev/null
+++ b/plus/build.gradle.kts
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ *
+ */
+
+dependencies {
+    api(project(":core"))
+    api(project(":linq4j"))
+
+    implementation("com.google.guava:guava")
+    implementation("com.teradata.tpcds:tpcds")
+    implementation("io.airlift.tpch:tpch")
+    implementation("net.hydromatic:chinook-data-hsqldb")
+    implementation("net.hydromatic:quidem")
+    implementation("net.hydromatic:tpcds")
+    implementation("org.apache.calcite.avatica:avatica-core")
+    implementation("org.apache.calcite.avatica:avatica-server")
+    implementation("org.eclipse.jetty:jetty-server")
+    implementation("org.hsqldb:hsqldb")
+
+    testImplementation(project(":core", "testClasses"))
+    testImplementation("org.incava:java-diff")
+}
diff --git a/.gitignore b/plus/gradle.properties
similarity index 64%
copy from .gitignore
copy to plus/gradle.properties
index 75badb2..a1a38ac 100644
--- a/.gitignore
+++ b/plus/gradle.properties
@@ -1,11 +1,12 @@
+#
 # 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 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
+#   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,
@@ -13,26 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-*~
-target
-.idea
-*.iml
-settings.xml
-.classpath.txt
-.fullclasspath.txt
-
-# eclipse
-.project
-.buildpath
-.classpath
-.factorypath
-.settings
-.checkstyle
-
-# netbeans
-nb-configuration.xml
-*/nb-configuration.xml
-
-.mvn/wrapper/maven-wrapper.jar
-
-# End .gitignore
+#
+description=Miscellaneous extras for Calcite
+artifact.name=Calcite Plus
diff --git a/pom.xml b/pom.xml
index 0036eb9..c4bd0da 100644
--- a/pom.xml
+++ b/pom.xml
@@ -761,7 +761,6 @@ limitations under the License.
             <phase>validate</phase>
             <configuration>
               <configLocation>${top.dir}/src/main/config/checkstyle/checker.xml</configLocation>
-              <suppressionsLocation>${top.dir}/src/main/config/checkstyle/suppressions.xml</suppressionsLocation>
               <propertyExpansion>base_dir=${top.dir}</propertyExpansion>
               <consoleOutput>true</consoleOutput>
               <failOnViolation>true</failOnViolation>
diff --git a/release/build.gradle.kts b/release/build.gradle.kts
new file mode 100644
index 0000000..8f17c2a
--- /dev/null
+++ b/release/build.gradle.kts
@@ -0,0 +1,195 @@
+/*
+ * 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.
+ *
+ */
+
+import com.github.vlsi.gradle.crlf.CrLfSpec
+import com.github.vlsi.gradle.crlf.LineEndings
+import com.github.vlsi.gradle.git.FindGitAttributes
+import com.github.vlsi.gradle.git.dsl.gitignore
+import com.github.vlsi.gradle.license.GatherLicenseTask
+import com.github.vlsi.gradle.license.api.SpdxLicense
+import com.github.vlsi.gradle.release.Apache2LicenseRenderer
+import com.github.vlsi.gradle.release.ArtifactType
+import com.github.vlsi.gradle.release.ReleaseExtension
+import com.github.vlsi.gradle.release.ReleaseParams
+import com.github.vlsi.gradle.release.dsl.dependencyLicenses
+import com.github.vlsi.gradle.release.dsl.licensesCopySpec
+
+plugins {
+    signing
+    id("com.github.vlsi.stage-vote-release")
+}
+
+rootProject.configure<ReleaseExtension> {
+    voteText.set { it.voteTextGen() }
+}
+
+fun ReleaseParams.voteTextGen(): String = """
+Hi all,
+
+I have created a build for $componentName $version, release
+candidate $rc.
+
+Thanks to everyone who has contributed to this release.
+
+You can read the release notes here:
+$previewSiteUri/docs/history.html
+
+The commit to be voted upon:
+https://gitbox.apache.org/repos/asf?p=calcite.git;a=commit;h=$gitSha
+
+Its hash is $gitSha
+
+Tag:
+$sourceCodeTagUrl
+
+The artifacts to be voted on are located here:
+$svnStagingUri
+(revision $svnStagingRevision)
+
+RAT report:
+$previewSiteUri/rat/rat-report.txt
+
+Site preview is here:
+$previewSiteUri/
+
+JavaDoc API preview is here:
+$previewSiteUri/api
+
+The hashes of the artifacts are as follows:
+${artifacts.joinToString(System.lineSeparator()) { it.sha512 + System.lineSeparator() + "*" + it.name }}
+
+A staged Maven repository is available for review at:
+$nexusRepositoryUri/org/apache/$tlpUrl/
+
+Release artifacts are signed with the following key:
+https://people.apache.org/keys/committer/$committerId.asc
+https://www.apache.org/dist/$tlpUrl/KEYS
+
+N.B.
+To create the jars and test $componentName: "./gradlew build".
+
+If you do not have a Java environment available, you can run the tests
+using docker. To do so, install docker and docker-compose, then run
+"docker-compose run test" from the root of the directory.
+
+Please vote on releasing this package as $componentName $version.
+
+The vote is open for the next 72 hours and passes if a majority of at
+least three +1 PMC votes are cast.
+
+[ ] +1 Release this package as Apache Calcite $version
+[ ]  0 I don't feel strongly about it, but I'm okay with the release
+[ ] -1 Do not release this package because...
+
+
+Here is my vote:
+
++1 (binding)
+""".trimIndent()
+
+val distributionGroup = "distribution"
+val baseFolder = "apache-calcite-${rootProject.version}"
+
+// This task scans the project for gitignore / gitattributes, and that is reused for building
+// source/binary artifacts with the appropriate eol/executable file flags
+val gitProps by tasks.registering(FindGitAttributes::class) {
+    // Scanning for .gitignore and .gitattributes files in a task avoids doing that
+    // when distribution build is not required (e.g. code is just compiled)
+    root.set(rootDir)
+}
+
+val getLicenses by tasks.registering(GatherLicenseTask::class) {
+    extraLicenseDir.set(file("$rootDir/src/main/config/licenses"))
+    // Parts of the web site generated by Jekyll (http://jekyllrb.com/)
+    addDependency(":jekyll:", SpdxLicense.MIT)
+    addDependency("font-awesome:font-awesome-code:4.2.0", SpdxLicense.MIT)
+    addDependency("font-awesome:font-awesome-font:4.2.0", SpdxLicense.OFL_1_1)
+    // git.io/normalize
+    addDependency(":normalize:3.0.2", SpdxLicense.MIT)
+    // Gridism: A simple, responsive, and handy CSS grid by @cobyism
+    // https://github.com/cobyism/gridism
+    addDependency(":gridsim:", SpdxLicense.MIT)
+    addDependency("cobyism:html5shiv:3.7.2", SpdxLicense.MIT)
+    addDependency(":respond:1.4.2", SpdxLicense.MIT)
+}
+
+val license by tasks.registering(Apache2LicenseRenderer::class) {
+    group = LifecycleBasePlugin.BUILD_GROUP
+    description = "Generates LICENSE file for the source distribution"
+    artifactType.set(ArtifactType.SOURCE)
+    metadata.from(getLicenses)
+    failOnIncompatibleLicense.set(false)
+}
+
+val licenseFiles = licensesCopySpec(license)
+
+fun CopySpec.excludeLicenseFromSourceRelease() {
+    // Source release has "/licenses" folder with licenses for third-party dependencies
+    // It is populated by "dependencyLicenses" above,
+    // so we ignore the folder when building source releases
+    exclude("licenses/**")
+    exclude("LICENSE")
+}
+
+fun CrLfSpec.sourceLayout() = copySpec {
+    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+    gitattributes(gitProps)
+    into("$baseFolder-src") {
+        // Note: license content is taken from "/build/..", so gitignore should not be used
+        // Note: this is a "license + third-party licenses", not just Apache-2.0
+        dependencyLicenses(licenseFiles)
+        // Include all the source files
+        from(rootDir) {
+            gitignore(gitProps)
+            excludeLicenseFromSourceRelease()
+        }
+    }
+}
+
+for (archive in listOf(Zip::class, Tar::class)) {
+    val taskName = "dist${archive.simpleName}"
+    val archiveTask = tasks.register(taskName, archive) {
+        val eol = if (archive == Tar::class) LineEndings.LF else LineEndings.CRLF
+        group = distributionGroup
+        description = "Creates source distribution with $eol line endings for text files"
+        if (this is Tar) {
+            compression = Compression.GZIP
+            archiveExtension.set("tar.gz")
+        }
+        // Gradle does not track "filters" as archive/copy task dependencies,
+        // So a mere change of a file attribute won't trigger re-execution of a task
+        // So we add a custom property to re-execute the task in case attributes change
+        inputs.property("gitproperties", gitProps.map { it.props.attrs.toString() })
+
+        // Gradle defaults to the following pattern:
+        // [baseName]-[appendix]-[version]-[classifier].[extension]
+        archiveBaseName.set("apache-calcite")
+        archiveClassifier.set("src")
+
+        CrLfSpec(eol).run {
+            wa1191SetInputs(gitProps)
+            with(sourceLayout())
+        }
+        doLast {
+            logger.lifecycle("Source distribution is created: ${archiveFile.get().asFile}")
+        }
+    }
+    releaseArtifacts {
+        artifact(archiveTask)
+    }
+}
diff --git a/server/build.gradle.kts b/server/build.gradle.kts
new file mode 100644
index 0000000..291d976
--- /dev/null
+++ b/server/build.gradle.kts
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ *
+ */
+
+plugins {
+    calcite.fmpp
+    calcite.javacc
+    id("com.github.vlsi.ide")
+}
+
+dependencies {
+    api(project(":core"))
+    api(project(":linq4j"))
+
+    implementation("com.google.guava:guava")
+    implementation("org.apache.calcite.avatica:avatica-core")
+    implementation("org.slf4j:slf4j-api")
+
+    testImplementation(project(":core", "testClasses"))
+    testImplementation("net.hydromatic:quidem")
+    testImplementation("net.hydromatic:scott-data-hsqldb")
+    testImplementation("org.hsqldb:hsqldb")
+    testImplementation("org.incava:java-diff")
+    testRuntimeOnly("org.slf4j:slf4j-log4j12")
+}
+
+val fmppMain by tasks.registering(org.apache.calcite.buildtools.fmpp.FmppTask::class) {
+    inputs.dir("src/main/codegen")
+    config.set(file("src/main/codegen/config.fmpp"))
+    templates.set(file("$rootDir/core/src/main/codegen/templates"))
+}
+
+val javaCCMain by tasks.registering(org.apache.calcite.buildtools.javacc.JavaCCTask::class) {
+    dependsOn(fmppMain)
+    val parserFile = fmppMain.map {
+        it.output.asFileTree.matching { include("**/Parser.jj") }.singleFile
+    }
+    inputFile.set(parserFile)
+    packageName.set("org.apache.calcite.sql.parser.ddl")
+}
+
+ide {
+    fun generatedSource(javacc: TaskProvider<org.apache.calcite.buildtools.javacc.JavaCCTask>, sourceSet: String) =
+        generatedJavaSources(javacc.get(), javacc.get().output.get().asFile, sourceSets.named(sourceSet))
+
+    generatedSource(javaCCMain, "main")
+}
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 0000000..c4c9769
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ *
+ */
+
+pluginManagement {
+    plugins {
+        fun String.v() = extra["$this.version"].toString()
+        fun PluginDependenciesSpec.idv(id: String, key: String = id) = id(id) version key.v()
+
+        idv("com.diffplug.gradle.spotless")
+        idv("com.github.johnrengelman.shadow")
+        idv("com.github.spotbugs")
+        idv("com.github.vlsi.crlf", "com.github.vlsi.vlsi-release-plugins")
+        idv("com.github.vlsi.gradle-extensions", "com.github.vlsi.vlsi-release-plugins")
+        idv("com.github.vlsi.ide", "com.github.vlsi.vlsi-release-plugins")
+        idv("com.github.vlsi.license-gather", "com.github.vlsi.vlsi-release-plugins")
+        idv("com.github.vlsi.stage-vote-release", "com.github.vlsi.vlsi-release-plugins")
+        idv("com.google.protobuf")
+        idv("de.thetaphi.forbiddenapis")
+        idv("org.jetbrains.gradle.plugin.idea-ext")
+        idv("org.nosphere.apache.rat")
+        idv("org.owasp.dependencycheck")
+        kotlin("jvm") version "kotlin".v()
+    }
+}
+
+// This is the name of a current project
+// Note: it cannot be inferred from the directory name as developer might clone Calcite to calcite_tmp folder
+rootProject.name = "calcite"
+
+include(
+    "bom",
+    "release",
+    "babel",
+    "cassandra",
+    "core",
+    "druid",
+    "elasticsearch",
+    "example:csv",
+    "example:function",
+    "file",
+    "geode",
+    "kafka",
+    "linq4j",
+    "mongodb",
+    "pig",
+    "piglet",
+    "plus",
+    "server",
+    "spark",
+    "splunk",
+    "ubenchmark"
+)
+
+// See https://github.com/gradle/gradle/issues/1348#issuecomment-284758705 and
+// https://github.com/gradle/gradle/issues/5321#issuecomment-387561204
+// Gradle inherits Ant "default excludes", however we do want to archive those files
+org.apache.tools.ant.DirectoryScanner.removeDefaultExclude("**/.gitattributes")
+org.apache.tools.ant.DirectoryScanner.removeDefaultExclude("**/.gitignore")
+
+fun property(name: String) =
+    when (extra.has(name)) {
+        true -> extra.get(name) as? String
+        else -> null
+    }
+
+// This enables to use local clone of vlsi-release-plugins for debugging purposes
+property("localReleasePlugins")?.ifBlank { "../vlsi-release-plugins" }?.let {
+    println("Importing project '$it'")
+    includeBuild(it)
+}
+
+// This enables to open both Calcite and Calcite Avatica as a single project
+property("localAvatica")?.ifBlank { "../calcite-avatica" }?.let {
+    println("Importing project '$it'")
+    includeBuild(it)
+}
diff --git a/site/README.md b/site/README.md
index c528f9a..13c1ed5 100644
--- a/site/README.md
+++ b/site/README.md
@@ -41,10 +41,12 @@ Site generation currently works best with ruby-2.5.1.
 ### Add javadoc
 
 1. `cd ..`
-2. `mvn -DskipTests site`
+2. `./gradlew javadocAggregate`
 3. `rm -rf site/target/apidocs site/target/testapidocs`
    `rmdir site\target\apidocs site\target\testapidocs /S /Q` (Windows)
-4. `mv target/site/apidocs target/site/testapidocs site/target`
+4. `mkdir site/target`
+   `mkdir site\target` (Windows)
+4. `mv build/docs/javadocAggregate site/target/apidocs`
    `for /d %a in (target\site\apidocs* target\site\testapidocs*) do move %a site\target` (Windows)
 
 ### Running locally
diff --git a/site/_docs/adapter.md b/site/_docs/adapter.md
index feb357b..3e75b38 100644
--- a/site/_docs/adapter.md
+++ b/site/_docs/adapter.md
@@ -614,4 +614,3 @@ While preparing a query Calcite combines all of the applicable metadata
 providers and maintains a cache so that a given piece of metadata (for example
 the selectivity of the condition `x > 10` in a particular `Filter` operator)
 is computed only once.
-
diff --git a/site/_docs/algebra.md b/site/_docs/algebra.md
index 70301a1..d589fb0 100644
--- a/site/_docs/algebra.md
+++ b/site/_docs/algebra.md
@@ -472,4 +472,3 @@ To further modify the `AggCall`, call its methods:
 | `distinct(distinct)` | Eliminates duplicate values before aggregating if `distinct`
 | `filter(expr)`       | Filters rows before aggregating (see SQL `FILTER (WHERE ...)`)
 | `sort(expr...)`<br/>`sort(exprList)` | Sorts rows before aggregating (see SQL `WITHIN GROUP`)
-
diff --git a/site/_docs/elasticsearch_adapter.md b/site/_docs/elasticsearch_adapter.md
index ab68c25..bdf82c8 100644
--- a/site/_docs/elasticsearch_adapter.md
+++ b/site/_docs/elasticsearch_adapter.md
@@ -157,4 +157,3 @@ scroll is automatically cleared (removed) when all query resuts are consumed.
 Currently this adapter supports ElasticSearch versions 6.x (or newer). Generally
 we try to follow official [support schedule](https://www.elastic.co/support/eol).
 Also, types are not supported (this adapter only supports indices).
-
diff --git a/site/_docs/howto.md b/site/_docs/howto.md
index 6b7a550..23274dc 100644
--- a/site/_docs/howto.md
+++ b/site/_docs/howto.md
@@ -31,7 +31,7 @@ adapters.
 
 ## Building from a source distribution
 
-Prerequisite is Java (JDK 8, 9, 10, 11, or 12) on your path.
+Prerequisite is Java (JDK 8, 9, 10, 11, 12, or 13) on your path.
 
 Unpack the source distribution `.tar.gz` file,
 `cd` to the root directory of the unpacked source,
@@ -40,16 +40,16 @@ then build using the included maven wrapper:
 {% highlight bash %}
 $ tar xvfz calcite-1.21.0-source.tar.gz
 $ cd calcite-1.21.0
-$ ./mvnw install
+$ ./gradlew build
 {% endhighlight %}
 
 [Running tests](#running-tests) describes how to run more or fewer
 tests.
 
-## Building from git
+## Building from Git
 
 Prerequisites are git
-and Java (JDK 8, 9, 10, 11, or 12) on your path.
+and Java (JDK 8, 9, 10, 11, 12, or 13) on your path.
 
 Create a local copy of the github repository,
 `cd` to its root directory,
@@ -58,44 +58,46 @@ then build using the included maven wrapper:
 {% highlight bash %}
 $ git clone git://github.com/apache/calcite.git
 $ cd calcite
-$ ./mvnw install
+$ ./gradlew build
 {% endhighlight %}
 
 Calcite includes a number of machine-generated codes. By default, these are
 regenerated on every build, but this has the negative side-effect of causing
 a re-compilation of the entire project when the non-machine-generated code
-has not changed. To make sure incremental compilation still works as intended,
-provide the `skipGenerate` command line option with your maven command.
-If you invoke the `clean` lifecycle phase, you must not specify the
-`skipGenerate` option as it will not recompile the necessary code for the build
-to succeed.
+has not changed.
 
-{% highlight bash %}
-$ mvn clean
-$ mvn package
-... hacks ...
-$ mvn package -DskipGenerate
-{% endhighlight %}
+Typically re-generation is called automatically when the relevant templates
+are changed, and it should work transparently.
+However if your IDE does not generate sources (e.g. `core/build/javacc/javaCCMain/org/apache/calcite/sql/parser/impl/SqlParserImpl.java`),
+then you can call `./gradlew generateSources` tasks manually.
 
 [Running tests](#running-tests) describes how to run more or fewer
 tests.
 
-## If you already have Apache Maven
+## Gradle vs Gradle wrapper
 
-If you have already installed Maven and it is on your path, then you
-can use `mvn` rather than `./mvnw` in commands. You need Maven version
-3.5.2 or later.
+Calcite uses Gradle wrapper to make a consistent build environment.
+In the typical case you don't need to install Gradle manually, and
+`./gradlew` would download the proper version for you and verify the expected checksum.
+
+You can install Gradle manually, however please note that there might
+be impedance mismatch between different versions.
 
 ## Running tests
 
 The test suite will run by default when you build, unless you specify
-`-DskipTests`:
+`-x test`
 
 {% highlight bash %}
-$ ./mvnw -DskipTests clean install
-$ ./mvnw test
+$ ./gradlew assemble # build the artifacts
+$ ./gradlew build -x test # build the artifacts, verify code style, skip tests
+$ ./gradlew check # verify code style, execute tests
+$ ./gradlew test # execute tests
+$ ./gradlew checkstyleMain checkstyleTest # verify code style
 {% endhighlight %}
 
+You can use `./gradlew assemble` to build the artifacts and skip all tests and verifications.
+
 There are other options that control which tests are run, and in what
 environment, as follows.
 
@@ -115,6 +117,18 @@ environment, as follows.
 * `-Dcalcite.test.splunk` enables tests that run against Splunk.
   Splunk must be installed and running.
 
+Note: tests are executed in a forked JVM, so system properties are not passed automatically
+when running tests with Gradle.
+By default, the build script passes the following `-D...` properties
+(see `passProperty` in `build.gradle.kts`):
+
+* `java.awt.headless`
+* `junit.jupiter.execution.parallel.enabled`, default: `true`
+* `junit.jupiter.execution.timeout.default`, default: `5 m`
+* `user.language`, default: `TR`
+* `user.country`, default: `tr`
+* `calcite.**` (to enable `calcite.test.db` and others above)
+
 ## Running integration tests
 
 For testing Calcite's external adapters, a test virtual machine should be used.
@@ -158,15 +172,16 @@ Note: test VM should be started before you launch integration tests. Calcite its
 
 Command line:
 
-* Executing regular unit tests (does not require external data): no change. `mvn test` or `mvn install`.
-* Executing all tests, for all the DBs: `mvn verify -Pit`. `it` stands for "integration-test". `mvn install -Pit` works as well.
-* Executing just tests for external DBs, excluding unit tests: `mvn -Dtest=foo -DfailIfNoTests=false -Pit verify`
-* Executing just MongoDB tests: `cd mongo; mvn verify -Pit`
+* Executing regular unit tests (does not require external data): no change. `./gradlew test` or `./gradlew build`.
+* Executing all tests, for all the DBs: `./gradlew test integTestAll`.
+* Executing just tests for external DBs, excluding unit tests: `./gradlew integTestAll`
+* Executing PostgreSQL JDBC tests: `./gradlew integTestPostgresql`
+* Executing just MongoDB tests: `./gradlew :mongo:build`
 
 From within IDE:
 
 * Executing regular unit tests: no change.
-* Executing MongoDB tests: run `MongoAdapterIT.java` as usual (no additional properties are required)
+* Executing MongoDB tests: run `MongoAdapterTest.java` with `calcite.integrationTest=true` system property
 * Executing MySQL tests: run `JdbcTest` and `JdbcAdapterTest` with setting `-Dcalcite.test.db=mysql`
 * Executing PostgreSQL tests: run `JdbcTest` and `JdbcAdapterTest` with setting `-Dcalcite.test.db=postgresql`
 
@@ -193,10 +208,10 @@ To setup [IntelliJ IDEA](https://www.jetbrains.com/idea/), follow the standard s
 
 Start with [building Calcite from the command line](#building-from-a-source-distribution).
 
-Go to *File > Open...* and open up Calcite's `pom.xml` file.
+Go to *File > Open...* and open up Calcite's root `build.gradle.kts` file.
 When IntelliJ asks if you want to open it as a project or a file, select project.
 Also, say yes when it asks if you want a new window.
-IntelliJ's Maven project importer should handle the rest.
+IntelliJ's Gradle project importer should handle the rest.
 
 There is a partially implemented IntelliJ code style configuration that you can import located [on GitHub](https://gist.github.com/gianm/27a4e3cad99d7b9b6513b6885d3cfcc9).
 It does not do everything needed to make Calcite's style checker happy, but
@@ -208,18 +223,9 @@ Once the importer is finished, test the project setup.
 For example, navigate to the method `JdbcTest.testWinAgg` with
 *Navigate > Symbol* and enter `testWinAgg`. Run `testWinAgg` by right-clicking and selecting *Run* (or the equivalent keyboard shortcut).
 
-If you encounter an error while running the `JdbcTest.testWinAgg` , run the following Maven command from the command line:
-
-`$ ./mvnw -DskipTests clean install`
-
-You should see `"BUILD SUCCESS"`.
-
-Once that is complete, proceed with running `JdbcTest.testWinAgg`.
-
 ### Setting up NetBeans
 
-From the main menu, select *File > Open Project* and navigate to a name of the project (Calcite) with a small Maven icon, and choose to open.
-(See [this tutorial](https://www.packtpub.com/mapt/book/application_development/9781785286124/2/ch02lvl1sec23/importing-an-existing-maven-project-in-netbeans) for an example of how to open a Maven project)
+From the main menu, select *File > Open Project* and navigate to a name of the project (Calcite) with a small Gradle icon, and choose to open.
 Wait for NetBeans to finish importing all dependencies.
 
 To ensure that the project is configured successfully, navigate to the method `testWinAgg` in `org.apache.calcite.test.JdbcTest`.
@@ -227,6 +233,10 @@ Right-click on the method and select to *Run Focused Test Method*.
 NetBeans will run a Maven process, and you should see in the command output window a line with
  `Running org.apache.calcite.test.JdbcTest` followed by `"BUILD SUCCESS"`.
 
+Note: it is not clear if NetBeans automatically generates relevant sources on project import,
+so you might need to run `./gradlew generateSources` before importing the project (and when you
+update template parser sources, and project version)
+
 ## Tracing
 
 To enable tracing, add the following flags to the java command line:
@@ -312,8 +322,8 @@ Calcite model:
 
 {% highlight bash %}
 $ ./sqlline
-sqlline> !connect jdbc:calcite:model=mongodb/target/test-classes/mongo-model.json admin admin
-Connecting to jdbc:calcite:model=mongodb/target/test-classes/mongo-model.json
+sqlline> !connect jdbc:calcite:model=mongodb/src/test/resources/mongo-model.json admin admin
+Connecting to jdbc:calcite:model=mongodb/src/test/resources/mongo-model.json
 Connected to: Calcite (version 1.x.x)
 Driver: Calcite JDBC Driver (version 1.x.x)
 Autocommit status: true
@@ -499,32 +509,47 @@ file by following instructions in the `KEYS` file.
 ball because that would be
 [redundant](https://issues.apache.org/jira/browse/CALCITE-1746).)
 
-## Set up Maven repository credentials (for Calcite committers)
+## Set up Nexus repository credentials (for Calcite committers)
+
+Gradle provides multiple ways to [configure project properties](https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties).
+For instance, you could update `$HOME/.gradle/gradle.properties`.
+
+Note: the build script would print the missing properties, so you can try running it and let it complain on the missing ones.
 
-Follow the instructions [here](https://www.apache.org/dev/publishing-maven-artifacts.html#dev-env) to add your credentials to your maven configuration.
+The following options are used:
+
+{% highlight properties %}
+asfCommitterId=
+asfNexusUsername=
+asfNexusPassword=
+asfSvnUsername=
+asfSvnPassword=
+{% endhighlight %}
+
+Note: when https://github.com/vlsi/asflike-release-environment is used, the credentials are takend from
+`asfTest...` (e.g. `asfTestNexusUsername=test`)
+
+Note: if you want to uses `gpg-agent`, you need to pass `useGpgCmd` property, and specify the key id
+via `signing.gnupg.keyName`.
 
 ## Making a snapshot (for Calcite committers)
 
 Before you start:
 
-* Set up signing keys as described above.
 * Make sure you are using JDK 8.
 * Make sure build and tests succeed with `-Dcalcite.test.db=hsqldb` (the default)
 
 {% highlight bash %}
-# Tell GPG how to read a password from your terminal
-export GPG_TTY=$(tty)
-
 # Make sure that there are no junk files in the sandbox
 git clean -xn
-./mvnw clean
-
-./mvnw -Papache-release install
+# Publish snapshot artifacts
+./gradlew clean publish -Pasf
 {% endhighlight %}
 
-When the dry-run has succeeded, change `install` to `deploy`.
+## Making a release candidate (for Calcite committers)
 
-## Making a release (for Calcite committers)
+Note: release artifacts (dist.apache.org and repository.apache.org) are managed with
+[stage-vote-release-plugin](https://github.com/vlsi/vlsi-release-plugins/tree/master/plugins/stage-vote-release-plugin)
 
 Before you start:
 
@@ -532,20 +557,18 @@ Before you start:
 * Make sure you are using JDK 8 (not 9 or 10).
 * Check that `README` and `site/_docs/howto.md` have the correct version number.
 * Check that `NOTICE` has the current copyright year.
-* Set `version.major` and `version.minor` in `pom.xml`.
-* Make sure build and tests succeed, including with `-P it,it-oracle`.
-* Make sure that `./mvnw javadoc:javadoc javadoc:test-javadoc` succeeds
+* Check that `calcite.version` has the proper value in `/gradle.properties`.
+* Make sure build and tests succeed
+* Make sure that `./gradlew javadoc` succeeds
   (i.e. gives no errors; warnings are OK)
 * Generate a report of vulnerabilities that occur among dependencies,
-  using `-Ppedantic`; if you like, run again with `-DfailBuildOnCVSS=8` to see
-  whether serious vulnerabilities exist. Report to [private@calcite.apache.org](mailto:private@calcite.apache.org)
+  using `./gradlew dependencyCheckUpdate dependencyCheckAggregate`.
+  Report to [private@calcite.apache.org](mailto:private@calcite.apache.org)
   if new critical vulnerabilities are found among dependencies.
-* Make sure that `./mvnw apache-rat:check` succeeds. (It will be run as part of
-  the release, but it's better to trouble-shoot early.)
 * Decide the supported configurations of JDK, operating system and
   Guava.  These will probably be the same as those described in the
   release notes of the previous release.  Document them in the release
-  notes.  To test Guava version _x.y_, specify `-Dguava.version=x.y`
+  notes.  To test Guava version _x.y_, specify `-Pguava.version=x.y`
 * Optional extra tests:
   * `-Dcalcite.test.db=mysql`
   * `-Dcalcite.test.db=hsqldb`
@@ -580,27 +603,19 @@ SELECT NVL(ST_Is3D(ST_PointFromText('POINT(-71.064544 42.28787)')), TRUE);
 > !quit
 {% endhighlight %}
 
-Create a release branch named after the release, e.g. `branch-1.1`, and push it to Apache.
+The release candidate process does not add commits,
+so there's no harm if it fails. It might leave `-rc` tag behind
+which can be removed if required.
 
-{% highlight bash %}
-$ git checkout -b branch-X.Y
-$ git push -u origin branch-X.Y
-{% endhighlight %}
+You can perform a dry-run release with a help of https://github.com/vlsi/asflike-release-environment
+That would perform the same steps, however it would push changes to the mock Nexus, Git, and SVN servers.
 
-We will use the branch for the entire the release process. Meanwhile,
-we do not allow commits to the master branch. After the release is
-final, we can use `git merge --ff-only` to append the changes on the
-release branch onto the master branch. (Apache does not allow reverts
-to the master branch, which makes it difficult to clean up the kind of
-messy commits that inevitably happen while you are trying to finalize
-a release.)
+If any of the steps fail, fix the problem, and
+start again from the top.
 
-Now, set up your environment and do a dry run. The dry run will not
-commit any changes back to git and gives you the opportunity to verify
-that the release process will complete as expected.
+### To prepare a release candidate directly in your environment:
 
-If any of the steps fail, clean up (see below), fix the problem, and
-start again from the top.
+Pick a release candidate index and ensure it does not interfere with previous candidates for the version.
 
 {% highlight bash %}
 # Tell GPG how to read a password from your terminal
@@ -608,23 +623,17 @@ export GPG_TTY=$(tty)
 
 # Make sure that there are no junk files in the sandbox
 git clean -xn
-./mvnw clean
 
-# Do a dry run of the release:prepare step, which sets version numbers
-# (accept the default tag name of calcite-X.Y.Z).
-# Note X.Y.Z is the current version we're trying to release (e.g. 1.8.0),
-# and X.(Y+1).Z is the next development version (e.g. 1.9.0).
-./mvnw -DdryRun=true -DskipTests -DreleaseVersion=X.Y.Z -DdevelopmentVersion=X.(Y+1).Z-SNAPSHOT -Papache-release -Darguments=-DskipTests release:prepare 2>&1 | tee /tmp/prepare-dry.log
+# Dry run the release candidate (push to asf-like-environment)
+./gradlew prepareVote -Prc=1
 
-# If you have multiple GPG keys, you can select the key used to sign the release by adding `-Dgpg.keyname=${GPG_KEY_ID}` to `-Darguments`:
-./mvnw -DdryRun=true -DskipTests -DreleaseVersion=X.Y.Z -DdevelopmentVersion=X.(Y+1).Z-SNAPSHOT -Papache-release -Darguments="-DskipTests -Dgpg.keyname=${GPG_KEY_ID}" release:prepare 2>&1 | tee /tmp/prepare-dry.log
+# Push release candidate to ASF servers
+./gradlew prepareVote -Prc=1 -Pasf
 {% endhighlight %}
 
-Check the artifacts.
-Note that when performing the dry run `SNAPSHOT` will appear in any file or directory names given below.
-The version will be automatically changed when performing the release for real.
+#### Checking the artifacts
 
-* In the `target` directory should be these 3 files, among others:
+* In the `release/build/distributions` directory should be these 3 files, among others:
   * `apache-calcite-X.Y.Z-src.tar.gz`
   * `apache-calcite-X.Y.Z-src.tar.gz.asc`
   * `apache-calcite-X.Y.Z-src.tar.gz.sha256`
@@ -638,36 +647,12 @@ The version will be automatically changed when performing the release for real.
   * Check that the copyright year in `NOTICE` is correct
 * Make sure that there is no `KEYS` file in the source distros
 * In each .jar (for example
-  `core/target/calcite-core-X.Y.Z.jar` and
-  `mongodb/target/calcite-mongodb-X.Y.Z-sources.jar`), check
-  that the `META-INF` directory contains `DEPENDENCIES`, `LICENSE`,
-  `NOTICE` and `git.properties`
-* In `core/target/calcite-core-X.Y.Z.jar`,
-  check that `org-apache-calcite-jdbc.properties` is
-  present and does not contain un-substituted `${...}` variables
+  `core/build/libs/calcite-core-X.Y.Z.jar` and
+  `mongodb/build/libs/calcite-mongodb-X.Y.Z-sources.jar`), check
+  that the `META-INF` directory contains `LICENSE`,
+  `NOTICE`
 * Check PGP, per [this](https://httpd.apache.org/dev/verification.html)
 
-Now, remove the `-DdryRun` flag and run the release for real.
-For this step you'll have to add the [Apache servers](https://maven.apache.org/developers/committer-settings.html) to `~/.m2/settings.xml`.
-
-{% highlight bash %}
-# Make sure that there are no junk files in the sandbox; performing a dry run may have generated
-# redundant files that do not need to be present in the release artifacts.
-git clean -xn
-./mvnw clean
-
-# Prepare sets the version numbers, creates a tag, and pushes it to git
-# Note X.Y.Z is the current version we're trying to release, and X.Y+1.Z is the next development version.
-# For example, if I am currently building a release for 1.16.0, X.Y.Z would be 1.16.0 and X.Y+1.Z would be 1.17.0.
-./mvnw -DdryRun=false -DskipTests -DreleaseVersion=X.Y.Z -DdevelopmentVersion=X.Y+1.Z-SNAPSHOT -Papache-release -Darguments=-DskipTests release:prepare 2>&1 | tee /tmp/prepare.log
-
-# If you have multiple GPG keys, you can select the key used to sign the release by adding `-Dgpg.keyname=${GPG_KEY_ID}` to `-Darguments`:
-./mvnw -DdryRun=false -DskipTests -DreleaseVersion=X.Y.Z -DdevelopmentVersion=X.Y+1.Z-SNAPSHOT -Papache-release -Darguments="-DskipTests -Dgpg.keyname=${GPG_KEY_ID}" release:prepare 2>&1 | tee /tmp/prepare.log
-
-# Perform checks out the tagged version, builds, and deploys to the staging repository
-./mvnw -DskipTests -Papache-release release:perform 2>&1 | tee /tmp/perform.log
-{% endhighlight %}
-
 Verify the staged artifacts in the Nexus repository:
 
 * Go to [https://repository.apache.org/](https://repository.apache.org/) and login
@@ -679,45 +664,10 @@ Verify the staged artifacts in the Nexus repository:
   https://repository.apache.org/content/repositories/orgapachecalcite-1000
   (or a similar URL)
 
-Upload the artifacts via subversion to a staging area,
-https://dist.apache.org/repos/dist/dev/calcite/apache-calcite-X.Y.Z-rcN:
-
-{% highlight bash %}
-# Create a subversion workspace, if you haven't already
-mkdir -p ~/dist/dev
-pushd ~/dist/dev
-svn co https://dist.apache.org/repos/dist/dev/calcite
-popd
-
-# Move the files into a directory
-mkdir ~/dist/dev/calcite/apache-calcite-X.Y.Z-rcN
-mv apache-calcite-* ~/dist/dev/calcite/apache-calcite-X.Y.Z-rcN
-
-# Check in
-cd ~/dist/dev/calcite
-svn add apache-calcite-X.Y.Z-rcN
-svn ci
-{% endhighlight %}
-
 ## Cleaning up after a failed release attempt (for Calcite committers)
 
-{% highlight bash %}
-# Make sure that the tag you are about to generate does not already
-# exist (due to a failed release attempt)
-git tag
-
-# If the tag exists, delete it locally and remotely
-git tag -d calcite-X.Y.Z
-git push origin :refs/tags/calcite-X.Y.Z
-
-# Remove modified files
-./mvnw release:clean
-
-# Check whether there are modified files and if so, go back to the
-# original git commit
-git status
-git reset --hard HEAD
-{% endhighlight %}
+If something is not correct, you can fix it, commit it, and prepare the next candidate.
+The release candidate tags might be kept for a while.
 
 ## Validate a release
 
@@ -754,6 +704,8 @@ checkHash apache-calcite-X.Y.Z-rcN
 ## Get approval for a release via Apache voting process (for Calcite committers)
 
 Release vote on dev list
+Note: the draft mail is printed as the final step of `prepareVote` task,
+and you can find the draft in `/build/prepareVote/mail.txt`
 
 {% highlight text %}
 To: dev@calcite.apache.org
@@ -848,31 +800,15 @@ This is based on the time when you expect to announce the release.
 This is usually a day after the vote closes.
 Remember that UTC date changes at 4pm Pacific time.
 
-Promote the staged nexus artifacts.
-
-* Go to [https://repository.apache.org/](https://repository.apache.org/) and login
-* Under "Build Promotion" click "Staging Repositories"
-* In the line with "orgapachecalcite-xxxx", check the box
-* Press "Release" button
 
-Check the artifacts into svn.
+### Publishing directly in your environment:
 
 {% highlight bash %}
-# Get the release candidate.
-mkdir -p ~/dist/dev
-cd ~/dist/dev
-svn co https://dist.apache.org/repos/dist/dev/calcite
-
-# Copy the artifacts. Note that the copy does not have '-rcN' suffix.
-mkdir -p ~/dist/release
-cd ~/dist/release
-svn co https://dist.apache.org/repos/dist/release/calcite
-cd calcite
-cp -rp ../../dev/calcite/apache-calcite-X.Y.Z-rcN apache-calcite-X.Y.Z
-svn add apache-calcite-X.Y.Z
-
-# Check in.
-svn ci
+# Dry run publishing the release (push to asf-like-environment)
+./gradlew publishDist -Prc=1
+
+# Publish the release to ASF servers
+./gradlew publishDist -Prc=1 -Pasf
 {% endhighlight %}
 
 Svnpubsub will publish to the
diff --git a/site/_docs/index.md b/site/_docs/index.md
index cf4560c..fda9999 100644
--- a/site/_docs/index.md
+++ b/site/_docs/index.md
@@ -142,5 +142,3 @@ The following features are complete.
   more details in the [SQL reference](reference.html)
 * Local and remote JDBC drivers; see [Avatica](avatica_overview.html)
 * Several [adapters](adapter.html)
-
-
diff --git a/site/_docs/lattice.md b/site/_docs/lattice.md
index 790d137..9c0b635 100644
--- a/site/_docs/lattice.md
+++ b/site/_docs/lattice.md
@@ -351,4 +351,3 @@ Here are some ideas that have not yet been implemented:
     data cubes efficiently</a>.
     In <i>Proc. ACM SIGMOD Conf.</i>, Montreal, 1996.</li>
 </ul>
-
diff --git a/site/_docs/tutorial.md b/site/_docs/tutorial.md
index 182bbc5..f12bfea 100644
--- a/site/_docs/tutorial.md
+++ b/site/_docs/tutorial.md
@@ -53,13 +53,12 @@ several important concepts:
 
 ## Download and build
 
-You need Java (version 8, 9 or 10) and git.
+You need Java (version 8, 9 or 10) and Git.
 
 {% highlight bash %}
 $ git clone https://github.com/apache/calcite.git
-$ cd calcite
-$ ./mvnw install -DskipTests -Dcheckstyle.skip=true
-$ cd example/csv
+$ cd calcite/example/csv
+$ ./sqlline
 {% endhighlight %}
 
 ## First queries
@@ -70,7 +69,7 @@ that is included in this project.
 
 {% highlight bash %}
 $ ./sqlline
-sqlline> !connect jdbc:calcite:model=target/test-classes/model.json admin admin
+sqlline> !connect jdbc:calcite:model=src/test/resources/model.json admin admin
 {% endhighlight %}
 
 (If you are running Windows, the command is `sqlline.bat`.)
@@ -103,7 +102,7 @@ system tables are always present in Calcite, but the other tables are
 provided by the specific implementation of the schema; in this case,
 the <code>EMPS</code> and <code>DEPTS</code> tables are based on the
 <code>EMPS.csv</code> and <code>DEPTS.csv</code> files in the
-<code>target/test-classes</code> directory.
+<code>resources/sales</code> directory.
 
 Let's execute some queries on those tables, to show that Calcite is providing
 a full implementation of SQL. First, a table scan:
@@ -179,7 +178,7 @@ format. Here is the model:
       type: 'custom',
       factory: 'org.apache.calcite.adapter.csv.CsvSchemaFactory',
       operand: {
-        directory: 'target/test-classes/sales'
+        directory: 'sales'
       }
     }
   ]
@@ -280,7 +279,7 @@ private Table createTable(File file) {
 
 The schema scans the directory and finds all files whose name ends
 with ".csv" and creates tables for them. In this case, the directory
-is <code>target/test-classes/sales</code> and contains files
+is <code>sales</code> and contains files
 <code>EMPS.csv</code> and <code>DEPTS.csv</code>, which these become
 the tables <code>EMPS</code> and <code>DEPTS</code>.
 
@@ -314,7 +313,7 @@ Here is a schema that defines a view:
       type: 'custom',
       factory: 'org.apache.calcite.adapter.csv.CsvSchemaFactory',
       operand: {
-        directory: 'target/test-classes/sales'
+        directory: 'sales'
       },
       tables: [
         {
@@ -379,7 +378,7 @@ There is an example in <code>model-with-custom-table.json</code>:
           type: 'custom',
           factory: 'org.apache.calcite.adapter.csv.CsvTableFactory',
           operand: {
-            file: 'target/test-classes/sales/EMPS.csv.gz',
+            file: 'sales/EMPS.csv.gz',
             flavor: "scannable"
           }
         }
@@ -392,7 +391,7 @@ There is an example in <code>model-with-custom-table.json</code>:
 We can query the table in the usual way:
 
 {% highlight sql %}
-sqlline> !connect jdbc:calcite:model=target/test-classes/model-with-custom-table.json admin admin
+sqlline> !connect jdbc:calcite:model=src/test/resources/model-with-custom-table.json admin admin
 sqlline> SELECT empno, name FROM custom_table.emps;
 +--------+--------+
 | EMPNO  |  NAME  |
@@ -476,7 +475,7 @@ a subset of columns from a CSV file. Let's run the same query against two very
 similar schemas:
 
 {% highlight sql %}
-sqlline> !connect jdbc:calcite:model=target/test-classes/model.json admin admin
+sqlline> !connect jdbc:calcite:model=src/test/resources/model.json admin admin
 sqlline> explain plan for select name from emps;
 +-----------------------------------------------------+
 | PLAN                                                |
@@ -484,7 +483,7 @@ sqlline> explain plan for select name from emps;
 | EnumerableCalcRel(expr#0..9=[{inputs}], NAME=[$t1]) |
 |   EnumerableTableScan(table=[[SALES, EMPS]])        |
 +-----------------------------------------------------+
-sqlline> !connect jdbc:calcite:model=target/test-classes/smart.json admin admin
+sqlline> !connect jdbc:calcite:model=src/test/resources/smart.json admin admin
 sqlline> explain plan for select name from emps;
 +-----------------------------------------------------+
 | PLAN                                                |
@@ -721,4 +720,3 @@ initial implementations.
 
 There are many other ways to extend Calcite not yet described in this tutorial.
 The [adapter specification](adapter.html) describes the APIs involved.
-
diff --git a/site/_posts/2019-03-26-release-1.19.0.md b/site/_posts/2019-03-26-release-1.19.0.md
index c85a62f..b8f3802 100644
--- a/site/_posts/2019-03-26-release-1.19.0.md
+++ b/site/_posts/2019-03-26-release-1.19.0.md
@@ -31,4 +31,3 @@ is pleased to announce
 [Apache Calcite release 1.19.0]({{ site.baseurl }}/docs/history.html#v1-19-0).
 
 This release comes three months after 1.18.0. It includes more than 80 resolved issues, comprising of a few new features as well as general improvements and bug-fixes. Among others, there have been significant improvements in JSON query support.
-
diff --git a/site/develop/index.md b/site/develop/index.md
index ded23ea..e39e66d 100644
--- a/site/develop/index.md
+++ b/site/develop/index.md
@@ -40,16 +40,16 @@ user-friendly.
 
 ## Download source, build, and run tests
 
-Prerequisites are git, maven (3.5.2 or later)
-and Java (JDK 8 or later, 9 preferred) on your path.
+Prerequisites are Git,
+and Java (JDK 8 or later, 13 preferred) on your path.
 
-Create a local copy of the git repository, `cd` to its root directory,
-then build using maven:
+Create a local copy of the Git repository, `cd` to its root directory,
+then build using Gradle:
 
 {% highlight bash %}
 $ git clone git://github.com/apache/calcite.git
 $ cd calcite
-$ mvn install
+$ ./gradlew build
 {% endhighlight %}
 
 The HOWTO describes how to
@@ -130,7 +130,7 @@ the contributor(s) involved in the discussion should:
 Fork the GitHub repository, and create a branch for your feature.
 
 Develop your feature and test cases, and make sure that
-`mvn install` succeeds. (Run extra tests if your change warrants it.)
+`./gradlew build` succeeds. (Run extra tests if your change warrants it.)
 
 Commit your change to your branch, and use a comment that starts with
 the JIRA case number, like this:
@@ -218,4 +218,3 @@ We value all contributions that help to build a vibrant community, not just code
 You can contribute by testing the code, helping verify a release,
 writing documentation or the web site,
 or just by answering questions on the list.
-
diff --git a/site/docker-compose.yml b/site/docker-compose.yml
index 13b808c..6134d9d 100644
--- a/site/docker-compose.yml
+++ b/site/docker-compose.yml
@@ -30,7 +30,7 @@ services:
   generate-javadoc:
     image: maven
     working_dir: /usr/src/calcite
-    command: sh -c "mvn -DskipTests site; rm -rf site/target/apidocs site/target/testapidocs; mkdir -p site/target; mv target/site/apidocs target/site/testapidocs site/target"
+    command: sh -c "./gradlew javadocAggregate; rm -rf site/target/apidocs site/target/testapidocs; mkdir -p site/target; mv build/docs/javadocAggregate site/target/apidocs"
     volumes:
       - ../:/usr/src/calcite
       - maven-repo:/root/.m2
diff --git a/spark/build.gradle.kts b/spark/build.gradle.kts
new file mode 100644
index 0000000..bd4a836
--- /dev/null
+++ b/spark/build.gradle.kts
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ *
+ */
+
+dependencies {
+    api(project(":core"))
+    api(project(":linq4j"))
+
+    implementation("com.google.guava:guava")
+    implementation("org.apache.spark:spark-core_2.10")
+    implementation("org.eclipse.jetty:jetty-server")
+    implementation("org.eclipse.jetty:jetty-util")
+    implementation("org.scala-lang:scala-library")
+
+    runtimeOnly("xalan:xalan")
+    runtimeOnly("xerces:xercesImpl")
+
+    testImplementation(project(":core", "testClasses"))
+}
diff --git a/splunk/build.gradle.kts b/splunk/build.gradle.kts
new file mode 100644
index 0000000..4c88616
--- /dev/null
+++ b/splunk/build.gradle.kts
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ *
+ */
+
+dependencies {
+    api(project(":core"))
+    api(project(":linq4j"))
+
+    implementation("com.google.guava:guava")
+    implementation("net.sf.opencsv:opencsv")
+    implementation("org.apache.calcite.avatica:avatica-core")
+    implementation("org.slf4j:slf4j-api")
+
+    testImplementation(project(":core", "testClasses"))
+    testRuntimeOnly("org.slf4j:slf4j-log4j12")
+}
diff --git a/.gitignore b/splunk/gradle.properties
similarity index 64%
copy from .gitignore
copy to splunk/gradle.properties
index 75badb2..795e1e9 100644
--- a/.gitignore
+++ b/splunk/gradle.properties
@@ -1,11 +1,12 @@
+#
 # 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 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
+#   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,
@@ -13,26 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-*~
-target
-.idea
-*.iml
-settings.xml
-.classpath.txt
-.fullclasspath.txt
-
-# eclipse
-.project
-.buildpath
-.classpath
-.factorypath
-.settings
-.checkstyle
-
-# netbeans
-nb-configuration.xml
-*/nb-configuration.xml
-
-.mvn/wrapper/maven-wrapper.jar
-
-# End .gitignore
+#
+description=Splunk adapter for Calcite; also a JDBC driver for Splunk
+artifact.name=Calcite Splunk
diff --git a/sqlline b/sqlline
index 980e95a..3f99480 100755
--- a/sqlline
+++ b/sqlline
@@ -26,34 +26,25 @@ case $(uname -s) in
 (*) cygwin=;;
 esac
 
-# Build classpath on first call.
-# (To force rebuild, remove target/fullclasspath.txt.)
-# Remove slf4j-log4j, otherwise slf4j complains about multiple bindings.
-cd $(dirname $0)
-if [ ! -f target/fullclasspath.txt ]; then
-    ./mvnw dependency:build-classpath -Dmdep.outputFile=target/classpath.txt
-    awk -v RS=: -v ORS=: '{if (!m[$0] && $0 !~ /slf4j-log4j12/) {m[$0]=1; print}}' \
-        target/classpath.txt \
-        */target/classpath.txt > target/fullclasspath.txt
+# Build classpath on first call. To update it run ./gradlew buildSqllineClasspath
+root=$(cd "$(dirname "$(readlink $0)")"; pwd)
+
+CP=$root/build/libs/sqllineClasspath.jar
+if [ ! -f $CP ]; then
+  (
+    cd $root
+    ./gradlew :buildSqllineClasspath
+  )
 fi
 
-CP=
-for module in core cassandra druid elasticsearch file kafka mongodb server spark splunk geode example/csv example/function; do
-  CP=${CP}${module}/target/classes:
-  CP=${CP}${module}/target/test-classes:
-done
-CP="${CP}$(cat target/fullclasspath.txt)"
-
 VM_OPTS=
 if [ "$cygwin" ]; then
-  CP=$(cygpath -wp "$CP")
-
   # Work around https://github.com/jline/jline2/issues/62
   VM_OPTS=-Djline.terminal=jline.UnixTerminal
 fi
 
 export JAVA_OPTS=-Djavax.xml.parsers.DocumentBuilderFactory=com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
 
-exec java $VM_OPTS -cp "${CP}" $JAVA_OPTS sqlline.SqlLine "$@"
+exec java -Xmx1g $VM_OPTS $JAVA_OPTS -jar build/libs/sqllineClasspath.jar "$@"
 
 # End sqlline
diff --git a/sqlline.bat b/sqlline.bat
index 5aa2935..498b99f 100644
--- a/sqlline.bat
+++ b/sqlline.bat
@@ -18,16 +18,12 @@
 ::
 :: Example:
 :: > sqlline.bat
-:: sqlline> !connect jdbc:calcite: admin admin 
+:: sqlline> !connect jdbc:calcite: admin admin
 
 :: Copy dependency jars on first call.
-:: (To force jar refresh, remove core\target\dependencies)
-:: We remove slf4j-log4j, otherwise slf4j complains about multiple bindings.
-if not exist core\target\dependencies (
-  call .\mvnw -B dependency:copy-dependencies -DoverWriteReleases=false -DoverWriteSnapshots=false -DoverWriteIfNewer=true -DoutputDirectory=target\dependencies
-  del /q /s slf4j-log4j12-*.jar
-)
+:: To force jar refresh, remove core\target\dependencies)
+if not exist build\libs\sqllineClasspath.jar (call gradlew buildSqllineClasspath)
 
-java -Xmx1G -cp ".\target\dependencies\*;core\target\dependencies\*;cassandra\target\dependencies\*;druid\target\dependencies\*;elasticsearch\target\dependencies\*;geode\target\dependencies\*;file\target\dependencies\*;mongodb\target\dependencies\*;server\target\dependencies\*;spark\target\dependencies\*;splunk\target\dependencies\*" sqlline.SqlLine --verbose=true %*
+java -Xmx1G -jar build\libs\sqllineClasspath.jar %*
 
 :: End sqlline.bat
diff --git a/sqlsh b/sqlsh
index 983e05c..9149536 100755
--- a/sqlsh
+++ b/sqlsh
@@ -22,25 +22,22 @@
 # Build classpath on first call.
 # (To force rebuild, remove target/fullclasspath.txt.)
 
+# Deduce whether we are running cygwin
+case $(uname -s) in
+(CYGWIN*) cygwin=true;;
+(*) cygwin=;;
+esac
+
 root=$(cd "$(dirname "$(readlink $0)")"; pwd)
 
-if [ ! -f ${root}/target/fullclasspath.txt ]; then
+CP=$root/build/libs/sqllineClasspath.jar
+if [ ! -f $CP ]; then
   (
-    cd ${root}
-    mvn dependency:build-classpath -Dmdep.outputFile=target/classpath.txt
-    awk -v RS=: -v ORS=: '{if (!m[$0]) {m[$0]=1; print}}' \
-        target/classpath.txt \
-        */target/classpath.txt > target/fullclasspath.txt
+    cd $root
+    ./gradlew :buildSqllineClasspath
   )
 fi
 
-CP=
-for module in core file plus; do
-  CP=${CP}${root}/${module}/target/classes:
-  CP=${CP}${root}/${module}/target/test-classes:
-done
-CP="${CP}$(cat ${root}/target/fullclasspath.txt)"
-
 VM_OPTS=
 export JAVA_OPTS=-Djavax.xml.parsers.DocumentBuilderFactory=com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
 
diff --git a/example/csv/sqlline.bat b/sqlsh.bat
similarity index 65%
copy from example/csv/sqlline.bat
copy to sqlsh.bat
index ac7bfc3..0df9a40 100644
--- a/example/csv/sqlline.bat
+++ b/sqlsh.bat
@@ -18,11 +18,12 @@
 ::
 :: Example:
 :: > sqlline.bat
-:: sqlline> !connect jdbc:calcite:model=target/test-classes/model.json admin admin 
+:: sqlline> !connect jdbc:calcite: admin admin
 
-:: Copy dependency jars on first call. (To force jar refresh, remove target\dependencies)
-if not exist target\dependencies (call mvn -B dependency:copy-dependencies -DoverWriteReleases=false -DoverWriteSnapshots=false -DoverWriteIfNewer=true -DoutputDirectory=target\dependencies)
+:: Copy dependency jars on first call.
+:: To force jar refresh, remove core\target\dependencies)
+if not exist build\libs\sqllineClasspath.jar (call gradlew buildSqllineClasspath)
 
-java -Xmx1G -cp ".\target\test-classes;.\target\classes;.\target\dependencies\*" sqlline.SqlLine --verbose=true %*
+java -Xmx1G -cp build\libs\sqllineClasspath.jar org.apache.calcite.adapter.os.SqlShell %*
 
 :: End sqlline.bat
diff --git a/src/main/config/checkstyle/checker.xml b/src/main/config/checkstyle/checker.xml
index f07529e..d32fc54 100644
--- a/src/main/config/checkstyle/checker.xml
+++ b/src/main/config/checkstyle/checker.xml
@@ -285,4 +285,8 @@ limitations under the License.
   </module>
 
   <module name="net.hydromatic.toolbox.checkstyle.HydromaticFileSetCheck"/>
+
+  <module name="SuppressionFilter">
+    <property name="file" value="${base_dir}/src/main/config/checkstyle/suppressions.xml"/>
+  </module>
 </module>
diff --git a/src/main/config/checkstyle/suppressions.xml b/src/main/config/checkstyle/suppressions.xml
index 3cff4a9..d6f7818 100644
--- a/src/main/config/checkstyle/suppressions.xml
+++ b/src/main/config/checkstyle/suppressions.xml
@@ -23,10 +23,12 @@ limitations under the License.
   <suppress checks="Header" files="LICENSE"/>
   <suppress checks="Header" files="NOTICE"/>
   <suppress checks=".*" files="Foo.java"/>
-  <suppress checks=".*" files=".*[/\\]target[/\\]maven-archiver[/\\]pom.properties"/>
-  <suppress checks=".*" files=".*[/\\]target[/\\]generated-sources[/\\].*"/>
-  <suppress checks=".*" files=".*[/\\]target[/\\]generated-test-sources[/\\].*"/>
-  <suppress checks=".*" files=".*[/\\]target[/\\]embeddedCassandra[/\\]log4j-embedded-cassandra.properties"/>
+  <suppress checks=".*" files="[/\\]target[/\\]maven-archiver[/\\]pom.properties"/>
+  <suppress checks=".*" files="[/\\]target[/\\]generated-sources[/\\]"/>
+  <suppress checks=".*" files="[/\\]target[/\\]generated-test-sources[/\\]"/>
+  <suppress checks=".*" files="[/\\]target[/\\]embeddedCassandra[/\\]log4j-embedded-cassandra.properties"/>
+  <suppress checks=".*" files="org[/\\]apache[/\\]calcite[/\\]runtime[/\\]Resources.java"/>
+
   <suppress checks=".*" files="git.properties"/>
   <suppress checks=".*" files="release.properties"/>
   <suppress checks=".*" files="auth-users.properties"/>
diff --git a/ubenchmark/build.gradle.kts b/ubenchmark/build.gradle.kts
new file mode 100644
index 0000000..740e664
--- /dev/null
+++ b/ubenchmark/build.gradle.kts
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ *
+ */
+
+dependencies {
+    api(project(":core"))
+    api(project(":linq4j"))
+    api("com.google.guava:guava")
+    api("org.codehaus.janino:commons-compiler")
+    api("org.openjdk.jmh:jmh-core")
+    api("org.openjdk.jmh:jmh-generator-annprocess")
+}
diff --git a/.gitignore b/ubenchmark/gradle.properties
similarity index 64%
copy from .gitignore
copy to ubenchmark/gradle.properties
index 75badb2..b3fd951 100644
--- a/.gitignore
+++ b/ubenchmark/gradle.properties
@@ -1,11 +1,12 @@
+#
 # 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 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
+#   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,
@@ -13,26 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-*~
-target
-.idea
-*.iml
-settings.xml
-.classpath.txt
-.fullclasspath.txt
-
-# eclipse
-.project
-.buildpath
-.classpath
-.factorypath
-.settings
-.checkstyle
-
-# netbeans
-nb-configuration.xml
-*/nb-configuration.xml
-
-.mvn/wrapper/maven-wrapper.jar
-
-# End .gitignore
+#
+description=Microbenchmarks for Calcite
+artifact.name=Calcite Ubenchmark