diff --git a/bom/build.gradle.kts b/bom/build.gradle.kts index 79fb7cc56bb6..a2ccd8d23d5f 100644 --- a/bom/build.gradle.kts +++ b/bom/build.gradle.kts @@ -161,7 +161,10 @@ dependencies { // Eventually we should get rid of slf4j-log4j12 dependency but currently it is not possible // since certain modules (Pig, Piglet) have dependencies using directly Log4j 1.x APIs runtimev("org.slf4j:slf4j-log4j12", "slf4j") - apiv("org.testcontainers:testcontainers") + apiv("org.testcontainers:testcontainers", "testcontainers") + apiv("org.testcontainers:oracle-xe", "testcontainers") + apiv("org.testcontainers:mysql", "testcontainers") + apiv("org.testcontainers:postgresql", "testcontainers") apiv("redis.clients:jedis") apiv("sqlline:sqlline") runtimev("org.openjdk.jmh:jmh-core", "jmh") diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 9674eb8d9213..e0cb58c6d5a8 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -82,10 +82,10 @@ dependencies { testCompileOnly("org.immutables:value-annotations") testCompileOnly("com.google.code.findbugs:jsr305") - testH2("com.h2database:h2") - testMysql("mysql:mysql-connector-java") - testOracle("com.oracle.ojdbc:ojdbc8") - testPostgresql("org.postgresql:postgresql") + testRuntimeOnly("com.h2database:h2") + testRuntimeOnly("mysql:mysql-connector-java") + testRuntimeOnly("com.oracle.ojdbc:ojdbc8") + testRuntimeOnly("org.postgresql:postgresql") testImplementation(project(":testkit")) testImplementation("commons-lang:commons-lang") @@ -94,6 +94,9 @@ dependencies { testImplementation("net.hydromatic:quidem") testImplementation("org.apache.calcite.avatica:avatica-server") testImplementation("org.apache.commons:commons-pool2") + testImplementation("org.testcontainers:oracle-xe") + testImplementation("org.testcontainers:mysql") + testImplementation("org.testcontainers:postgresql") testImplementation("org.hsqldb:hsqldb::jdk8") testImplementation("sqlline:sqlline") testImplementation(kotlin("stdlib-jdk8")) diff --git a/core/src/test/java/org/apache/calcite/test/DBFunctionConsistencyTest.java b/core/src/test/java/org/apache/calcite/test/DBFunctionConsistencyTest.java new file mode 100644 index 000000000000..50559dd3dfc2 --- /dev/null +++ b/core/src/test/java/org/apache/calcite/test/DBFunctionConsistencyTest.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.calcite.test; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.containers.MySQLContainer; +import org.testcontainers.containers.OracleContainer; +import org.testcontainers.containers.PostgreSQLContainer; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +public class DBFunctionConsistencyTest { + + private enum Type { + ORACLE { + @Override String query(final String sqlFunction) { + return "SELECT " + sqlFunction + " FROM DUAL"; + } + }, POSTGRES_9_6, POSTGRES_12_2, MYSQL; + + String query(String sqlFunction) { + return "SELECT " + sqlFunction; + } + } + + private final static Map> DBS = initContainers(); + + private static Map> initContainers() { + Map> dbs = new HashMap<>(); + dbs.put(Type.POSTGRES_9_6, new PostgreSQLContainer<>("postgres:9.6")); + dbs.put(Type.POSTGRES_12_2, new PostgreSQLContainer<>("postgres:12.2")); + dbs.put(Type.MYSQL, new MySQLContainer<>()); + dbs.put(Type.ORACLE, new OracleContainer( + "gvenzl/oracle-xe:21-slim-faststart")); + return dbs; + } + + @BeforeAll + static void setup() throws SQLException { + DBS.values().forEach(GenericContainer::start); + } + + @AfterAll + static void teardown() { + DBS.values().forEach(GenericContainer::stop); + } + + @ParameterizedTest + @CsvSource({ + "SQRT(4),ORACLE", + "SQRT(4),POSTGRES_9_6", + "SQRT(4),POSTGRES_12_2", + "SQRT(4),MYSQL", + "SQRT(-1),ORACLE", + "SQRT(-1),POSTGRES_9_6", + "SQRT(-1),POSTGRES_12_2", + "SQRT(-1),MYSQL" + }) + void testFunction(String function, String db) { + String calciteResult = execute(Type.valueOf(db), true, function); + String rawResult = execute(Type.valueOf(db), false, function); + Assertions.assertEquals(rawResult, calciteResult); + } + + String execute(Type dbType, boolean useCalcite, String exp) { + JdbcDatabaseContainer db = DBS.get(dbType); + final String url; + final String query; + if (useCalcite) { + url = String.format( + "jdbc:calcite:schemaType=JDBC; schema.jdbcUser=%s; schema.jdbcPassword=%s; schema" + + ".jdbcUrl=%s", db.getUsername(), db.getPassword(), db.getJdbcUrl()); + query = "SELECT " + exp; + } else { + url = db.getJdbcUrl(); + query = dbType.query(exp); + } + try (Connection c = DriverManager.getConnection(url, db.getUsername(), db.getPassword())) { + try (PreparedStatement stmt = c.prepareStatement(query)) { + try (ResultSet rs = stmt.executeQuery()) { + if (rs.next()) { + return rs.getString(1); + } else { + return ""; + } + } + } + } catch (Exception e) { + return e.getMessage(); + } + } +} diff --git a/gradle.properties b/gradle.properties index 51e13a26c701..f2e6a0f9edc8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -150,6 +150,7 @@ natty.version=0.13 ojdbc8.version=19.3.0.0 opencsv.version=2.3 oshi-core.version=6.4.9 +oracle-xe.version=1.19.6 pig.version=0.16.0 pigunit.version=0.16.0 postgresql.version=9.3-1102-jdbc41