This is an automated email from the ASF dual-hosted git repository. jhyde pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/master by this push: new f928e07 [CALCITE-4614] Exasol dialect implementation (TJ Banghart) f928e07 is described below commit f928e073c384010c294370b63ffb748c15caab8a Author: TJ Banghart <tjbangh...@google.com> AuthorDate: Wed Jun 9 12:34:45 2021 -0700 [CALCITE-4614] Exasol dialect implementation (TJ Banghart) Formatting; import SqlDialect.DatabaseProduct to make code more concise. Close apache/calcite#2431 --- .../java/org/apache/calcite/sql/SqlDialect.java | 3 + .../apache/calcite/sql/SqlDialectFactoryImpl.java | 5 + .../calcite/sql/dialect/ExasolSqlDialect.java | 183 +++++++++++++++++++++ .../calcite/rel/rel2sql/RelToSqlConverterTest.java | 102 +++++++----- 4 files changed, 252 insertions(+), 41 deletions(-) diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDialect.java b/core/src/main/java/org/apache/calcite/sql/SqlDialect.java index fdb69fd..0f6f3fe 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlDialect.java @@ -270,6 +270,8 @@ public class SqlDialect { return DatabaseProduct.CLICKHOUSE; case "DBMS:CLOUDSCAPE": return DatabaseProduct.DERBY; + case "EXASOL": + return DatabaseProduct.EXASOL; case "HIVE": return DatabaseProduct.HIVE; case "INGRES": @@ -1263,6 +1265,7 @@ public class SqlDialect { ORACLE("Oracle", "\"", NullCollation.HIGH), DERBY("Apache Derby", null, NullCollation.HIGH), DB2("IBM DB2", null, NullCollation.HIGH), + EXASOL("Exasol", "\"", NullCollation.LOW), FIREBIRD("Firebird", null, NullCollation.HIGH), H2("H2", "\"", NullCollation.HIGH), HIVE("Apache Hive", null, NullCollation.LOW), diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDialectFactoryImpl.java b/core/src/main/java/org/apache/calcite/sql/SqlDialectFactoryImpl.java index 3a5aaeb..91f0f31 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlDialectFactoryImpl.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlDialectFactoryImpl.java @@ -25,6 +25,7 @@ import org.apache.calcite.sql.dialect.CalciteSqlDialect; import org.apache.calcite.sql.dialect.ClickHouseSqlDialect; import org.apache.calcite.sql.dialect.Db2SqlDialect; import org.apache.calcite.sql.dialect.DerbySqlDialect; +import org.apache.calcite.sql.dialect.ExasolSqlDialect; import org.apache.calcite.sql.dialect.FirebirdSqlDialect; import org.apache.calcite.sql.dialect.H2SqlDialect; import org.apache.calcite.sql.dialect.HiveSqlDialect; @@ -105,6 +106,8 @@ public class SqlDialectFactoryImpl implements SqlDialectFactory { return new ClickHouseSqlDialect(c); case "DBMS:CLOUDSCAPE": return new DerbySqlDialect(c); + case "EXASOL": + return new ExasolSqlDialect(c); case "HIVE": return new HiveSqlDialect(c); case "INGRES": @@ -253,6 +256,8 @@ public class SqlDialectFactoryImpl implements SqlDialectFactory { return Db2SqlDialect.DEFAULT; case DERBY: return DerbySqlDialect.DEFAULT; + case EXASOL: + return ExasolSqlDialect.DEFAULT; case FIREBIRD: return FirebirdSqlDialect.DEFAULT; case H2: diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/ExasolSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/ExasolSqlDialect.java new file mode 100644 index 0000000..6e127cf --- /dev/null +++ b/core/src/main/java/org/apache/calcite/sql/dialect/ExasolSqlDialect.java @@ -0,0 +1,183 @@ +/* + * 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.sql.dialect; + +import org.apache.calcite.rel.type.RelDataType; +import org.apache.calcite.sql.SqlBasicTypeNameSpec; +import org.apache.calcite.sql.SqlCall; +import org.apache.calcite.sql.SqlDataTypeSpec; +import org.apache.calcite.sql.SqlDialect; +import org.apache.calcite.sql.SqlKind; +import org.apache.calcite.sql.SqlNode; +import org.apache.calcite.sql.SqlWriter; +import org.apache.calcite.sql.parser.SqlParserPos; + +import com.google.common.collect.ImmutableList; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.List; +import java.util.Locale; +import java.util.regex.Pattern; + +/** + * A <code>SqlDialect</code> implementation for the Exasol database. + */ +public class ExasolSqlDialect extends SqlDialect { + public static final SqlDialect.Context DEFAULT_CONTEXT = + SqlDialect.EMPTY_CONTEXT + .withDatabaseProduct(DatabaseProduct.EXASOL) + .withIdentifierQuoteString("\""); + + public static final SqlDialect DEFAULT = new ExasolSqlDialect(DEFAULT_CONTEXT); + + /** An unquoted Exasol identifier must start with a letter and be followed + * by zero or more letters, digits or _. */ + private static final Pattern IDENTIFIER_REGEX = + Pattern.compile("[A-Za-z][A-Za-z0-9_]*"); + + private static final List<String> RESERVED_KEYWORDS = + ImmutableList.of("ABS", "ACCESS", "ACOS", "ADAPTER", "ADD_DAYS", + "ADD_HOURS", "ADD_MINUTES", "ADD_MONTHS", "ADD_SECONDS", "ADD_WEEKS", + "ADD_YEARS", "ADMIN", "ALIGN", "ALWAYS", "ANALYZE", "ANSI", + "APPROXIMATE_COUNT_DISTINCT", "ASCII", "ASIN", "ASSIGNMENT", + "ASYMMETRIC", "ATAN", "ATAN2", "ATOMIC", "ATTEMPTS", "AUDIT", + "AUTHENTICATED", "AUTO", "AVG", "BACKUP", "BERNOULLI", "BIT_AND", + "BIT_CHECK", "BIT_LENGTH", "BIT_LROTATE", "BIT_LSHIFT", "BIT_NOT", + "BIT_OR", "BIT_RROTATE", "BIT_RSHIFT", "BIT_SET", "BIT_TO_NUM", + "BIT_XOR", "BREADTH", "CEIL", "CEILING", "CHANGE", "CHARACTERS", + "CHARACTER_LENGTH", "CHR", "CLEAR", "COBOL", "COLOGNE_PHONETIC", + "COMMENT", "COMMENTS", "COMMITTED", "CONCAT", "CONNECT", "CONVERT_TZ", + "CORR", "COS", "COSH", "COT", "COUNT", "COVAR_POP", "COVAR_SAMP", + "CREATED", "CROSS", "CURDATE", "DATABASE", "DATE_TRUNC", + "DAYS_BETWEEN", "DECODE", "DEFAULTS", "DEFAULT_PRIORITY_GROUP", + "DEGREES", "DELIMIT", "DELIMITER", "DENSE_RANK", "DEPTH", + "DIAGNOSTICS", "DICTIONARY", "DISTRIBUTE", "DISTRIBUTION", "DIV", + "DOWN", "DUMP", "EDIT_DISTANCE", "ENCODING", "ESTIMATE", "EVALUATE", + "EVERY", "EXA", "EXCLUDE", "EXCLUDING", "EXP", "EXPIRE", "EXPLAIN", + "EXPRESSION", "FAILED", "FIRST_VALUE", "FLOOR", "FLUSH", "FOREIGN", + "FORTRAN", "FROM_POSIX_TIME", "GREATEST", "GROUPING_ID", "HANDLER", + "HAS", "HASH", "HASH_MD5", "HASH_SHA", "HASH_SHA1", "HASH_SHA256", + "HASH_SHA512", "HASH_TIGER", "HIERARCHY", "HOURS_BETWEEN", + "IDENTIFIED", "IGNORE", "IMPERSONATION", "INCLUDING", "INITCAP", + "INITIALLY", "INSTR", "INVALID", "IPROC", "ISOLATION", "IS_BOOLEAN", + "IS_DATE", "IS_DSINTERVAL", "IS_NUMBER", "IS_TIMESTAMP", + "IS_YMINTERVAL", "JAVA", "JAVASCRIPT", "KEEP", "KEY", "KEYS", "KILL", + "LAG", "LANGUAGE", "LAST_VALUE", "LCASE", "LEAD", "LEAST", "LENGTH", + "LINK", "LN", "LOCATE", "LOCK", "LOG10", "LOG2", "LOGIN", "LOGS", + "LONG", "LOWER", "LPAD", "LTRIM", "LUA", "MANAGE", "MAX", "MAXIMAL", + "MEDIAN", "MID", "MIN", "MINUTES_BETWEEN", "MONTHS_BETWEEN", "MUMPS", + "NEVER", "NICE", "NORMALIZED", "NOW", "NPROC", "NULLIFZERO", "NULLS", + "NUMTODSINTERVAL", "NUMTOYMINTERVAL", "NVL", "NVL2", "OCTETS", + "OCTET_LENGTH", "OFFSET", "OPTIMIZE", "ORA", "OWNER", "PADDING", + "PARTITION", "PASCAL", "PASSWORD", "PASSWORD_EXPIRY_POLICY", + "PASSWORD_SECURITY_POLICY", "PERCENTILE_CONT", "PERCENTILE_DISC", + "PI", "PLI", "POSIX_TIME", "POWER", "PRECISION", "PRELOAD", "PRIMARY", + "PRIORITY", "PRIVILEGE", "PYTHON", "QUERY_CACHE", "QUERY_TIMEOUT", + "R", "RADIANS", "RAND", "RANK", "RATIO_TO_REPORT", "RAW_SIZE_LIMIT", + "RECOMPRESS", "RECORD", "REGEXP_INSTR", "REGEXP_REPLACE", + "REGEXP_SUBSTR", "REGR_AVGX", "REGR_AVGY", "REGR_COUNT", + "REGR_INTERCEPT", "REGR_R2", "REGR_SLOPE", "REGR_SXX", "REGR_SXY", + "REGR_SYY", "REJECT", "REORGANIZE", "REPEATABLE", "RESET", "REVERSE", + "ROLE", "ROUND", "ROWID", "ROW_NUMBER", "RPAD", "RTRIM", "SCALAR", + "SCHEMAS", "SCHEME", "SCRIPT_LANGUAGES", "SCRIPT_OUTPUT_ADDRESS", + "SECONDS_BETWEEN", "SECURE", "SERIALIZABLE", "SHUT", "SIGN", "SIMPLE", + "SIN", "SINH", "SIZE", "SKIP", "SOUNDEX", "SQRT", "STATISTICS", + "STDDEV", "STDDEV_POP", "STDDEV_SAMP", "ST_AREA", "ST_BOUNDARY", + "ST_BUFFER", "ST_CENTROID", "ST_CONTAINS", "ST_CONVEXHULL", + "ST_CROSSES", "ST_DIFFERENCE", "ST_DIMENSION", "ST_DISJOINT", + "ST_DISTANCE", "ST_ENDPOINT", "ST_ENVELOPE", "ST_EQUALS", + "ST_EXTERIORRING", "ST_FORCE2D", "ST_GEOMETRYN", "ST_GEOMETRYTYPE", + "ST_INTERIORRINGN", "ST_INTERSECTION", "ST_INTERSECTS", "ST_ISCLOSED", + "ST_ISEMPTY", "ST_ISRING", "ST_ISSIMPLE", "ST_LENGTH", + "ST_NUMGEOMETRIES", "ST_NUMINTERIORRINGS", "ST_NUMPOINTS", + "ST_OVERLAPS", "ST_POINTN", "ST_SETSRID", "ST_STARTPOINT", + "ST_SYMDIFFERENCE", "ST_TOUCHES", "ST_TRANSFORM", "ST_UNION", + "ST_WITHIN", "ST_X", "ST_Y", "SUBSTR", "SUM", "SYMMETRIC", + "SYS_CONNECT_BY_PATH", "SYS_GUID", "TABLES", "TABLESAMPLE", "TAN", + "TANH", "TASKS", "TIES", "TIMESTAMP_ARITHMETIC_BEHAVIOR", "TIME_ZONE", + "TIME_ZONE_BEHAVIOR", "TO_CHAR", "TO_DATE", "TO_DSINTERVAL", + "TO_NUMBER", "TO_TIMESTAMP", "TO_YMINTERVAL", "TRANSLATE", "TRUNC", + "TYPE", "UCASE", "UNBOUNDED", "UNCOMMITTED", "UNDO", "UNICODE", + "UNICODECHR", "UNLIMITED", "UPPER", "UTF8", "VALUE2PROC", "VARIANCE", + "VARYING", "VAR_POP", "VAR_SAMP", "VIRTUAL", "WEEK", "WEIGHT", + "WRITE", "YEARS_BETWEEN", "ZEROIFNULL"); + + /** Creates a ExasolSqlDialect. */ + public ExasolSqlDialect(Context context) { + super(context); + } + + @Override public boolean supportsCharSet() { + return false; + } + + @Override public boolean supportsNestedAggregations() { + return false; + } + + @Override public boolean supportsAggregateFunctionFilter() { + return false; + } + + @Override public boolean supportsAggregateFunction(SqlKind kind) { + switch (kind) { + case AVG: + case COUNT: + case COVAR_POP: + case COVAR_SAMP: + case MAX: + case MIN: + case STDDEV_POP: + case STDDEV_SAMP: + case SUM: + case VAR_POP: + case VAR_SAMP: + return true; + default: + return false; + } + } + + @Override protected boolean identifierNeedsQuote(String val) { + return !IDENTIFIER_REGEX.matcher(val).matches() + || RESERVED_KEYWORDS.contains(val.toUpperCase(Locale.ROOT)); + } + + @Override public @Nullable SqlNode getCastSpec(RelDataType type) { + switch (type.getSqlTypeName()) { + case TIMESTAMP: + // Exasol does not support TIMESTAMP with precision. + return new SqlDataTypeSpec( + new SqlBasicTypeNameSpec(type.getSqlTypeName(), SqlParserPos.ZERO), + SqlParserPos.ZERO); + default: + return super.getCastSpec(type); + } + } + + @Override public void unparseOffsetFetch(SqlWriter writer, @Nullable SqlNode offset, + @Nullable SqlNode fetch) { + unparseFetchUsingLimit(writer, offset, fetch); + } + + @Override public void unparseCall(SqlWriter writer, SqlCall call, + int leftPrec, int rightPrec) { + // Same as PostgreSQL implementation + PostgresqlSqlDialect.DEFAULT.unparseCall(writer, call, leftPrec, rightPrec); + } +} diff --git a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java index b276a15..6851e82 100644 --- a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java +++ b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java @@ -41,7 +41,6 @@ import org.apache.calcite.runtime.Hook; import org.apache.calcite.schema.SchemaPlus; import org.apache.calcite.sql.SqlCall; import org.apache.calcite.sql.SqlDialect; -import org.apache.calcite.sql.SqlDialect.Context; import org.apache.calcite.sql.SqlDialect.DatabaseProduct; import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.SqlSelect; @@ -141,8 +140,8 @@ class RelToSqlConverterTest { } private static JethroDataSqlDialect jethroDataSqlDialect() { - Context dummyContext = SqlDialect.EMPTY_CONTEXT - .withDatabaseProduct(SqlDialect.DatabaseProduct.JETHRO) + SqlDialect.Context dummyContext = SqlDialect.EMPTY_CONTEXT + .withDatabaseProduct(DatabaseProduct.JETHRO) .withDatabaseMajorVersion(1) .withDatabaseMinorVersion(0) .withDatabaseVersion("1.0") @@ -161,28 +160,18 @@ class RelToSqlConverterTest { * represent. */ private static Map<SqlDialect, DatabaseProduct> dialects() { return ImmutableMap.<SqlDialect, DatabaseProduct>builder() - .put(SqlDialect.DatabaseProduct.BIG_QUERY.getDialect(), - SqlDialect.DatabaseProduct.BIG_QUERY) - .put(SqlDialect.DatabaseProduct.CALCITE.getDialect(), - SqlDialect.DatabaseProduct.CALCITE) - .put(SqlDialect.DatabaseProduct.DB2.getDialect(), - SqlDialect.DatabaseProduct.DB2) - .put(SqlDialect.DatabaseProduct.HIVE.getDialect(), - SqlDialect.DatabaseProduct.HIVE) - .put(jethroDataSqlDialect(), - SqlDialect.DatabaseProduct.JETHRO) - .put(SqlDialect.DatabaseProduct.MSSQL.getDialect(), - SqlDialect.DatabaseProduct.MSSQL) - .put(SqlDialect.DatabaseProduct.MYSQL.getDialect(), - SqlDialect.DatabaseProduct.MYSQL) - .put(mySqlDialect(NullCollation.HIGH), - SqlDialect.DatabaseProduct.MYSQL) - .put(SqlDialect.DatabaseProduct.ORACLE.getDialect(), - SqlDialect.DatabaseProduct.ORACLE) - .put(SqlDialect.DatabaseProduct.POSTGRESQL.getDialect(), - SqlDialect.DatabaseProduct.POSTGRESQL) - .put(DatabaseProduct.PRESTO.getDialect(), - DatabaseProduct.PRESTO) + .put(DatabaseProduct.BIG_QUERY.getDialect(), DatabaseProduct.BIG_QUERY) + .put(DatabaseProduct.CALCITE.getDialect(), DatabaseProduct.CALCITE) + .put(DatabaseProduct.DB2.getDialect(), DatabaseProduct.DB2) + .put(DatabaseProduct.EXASOL.getDialect(), DatabaseProduct.EXASOL) + .put(DatabaseProduct.HIVE.getDialect(), DatabaseProduct.HIVE) + .put(jethroDataSqlDialect(), DatabaseProduct.JETHRO) + .put(DatabaseProduct.MSSQL.getDialect(), DatabaseProduct.MSSQL) + .put(DatabaseProduct.MYSQL.getDialect(), DatabaseProduct.MYSQL) + .put(mySqlDialect(NullCollation.HIGH), DatabaseProduct.MYSQL) + .put(DatabaseProduct.ORACLE.getDialect(), DatabaseProduct.ORACLE) + .put(DatabaseProduct.POSTGRESQL.getDialect(), DatabaseProduct.POSTGRESQL) + .put(DatabaseProduct.PRESTO.getDialect(), DatabaseProduct.PRESTO) .build(); } @@ -193,7 +182,7 @@ class RelToSqlConverterTest { /** Converts a relational expression to SQL. */ private String toSql(RelNode root) { - return toSql(root, SqlDialect.DatabaseProduct.CALCITE.getDialect()); + return toSql(root, DatabaseProduct.CALCITE.getDialect()); } /** Converts a relational expression to SQL in a given dialect. */ @@ -805,7 +794,7 @@ class RelToSqlConverterTest { .mapToObj(i -> b.equals(b.field("EMPNO"), b.literal(i))) .collect(Collectors.toList()))) .build(); - final SqlDialect dialect = SqlDialect.DatabaseProduct.CALCITE.getDialect(); + final SqlDialect dialect = DatabaseProduct.CALCITE.getDialect(); final RelNode root = relFn.apply(relBuilder()); final RelToSqlConverter converter = new RelToSqlConverter(dialect); final SqlNode sqlNode = converter.visitRoot(root).asStatement(); @@ -1025,6 +1014,7 @@ class RelToSqlConverterTest { + "FROM foodmart.product\n" + "GROUP BY product_id) t1"; final String expectedSpark = expectedHive; + final String expectedExasol = expectedBigQuery; sql(query) .withOracle() .ok(expectedOracle) @@ -1039,7 +1029,9 @@ class RelToSqlConverterTest { .withHive() .ok(expectedHive) .withSpark() - .ok(expectedSpark); + .ok(expectedSpark) + .withExasol() + .ok(expectedExasol); } /** Test case for @@ -1603,6 +1595,24 @@ class RelToSqlConverterTest { sql(query).withMssql().ok(expected); } + @Test void testExasolCharacterSet() { + String query = "select \"hire_date\", cast(\"hire_date\" as varchar(10))\n" + + "from \"foodmart\".\"reserve_employee\""; + final String expected = "SELECT hire_date, CAST(hire_date AS VARCHAR(10))\n" + + "FROM foodmart.reserve_employee"; + sql(query).withExasol().ok(expected); + } + + @Test void testExasolCastToTimestamp() { + final String query = "select * from \"employee\" where \"hire_date\" - " + + "INTERVAL '19800' SECOND(5) > cast(\"hire_date\" as TIMESTAMP(0))"; + final String expected = "SELECT *\n" + + "FROM foodmart.employee\n" + + "WHERE (hire_date - INTERVAL '19800' SECOND(5))" + + " > CAST(hire_date AS TIMESTAMP)"; + sql(query).withExasol().ok(expected); + } + /** * Tests that IN can be un-parsed. * @@ -1724,11 +1734,17 @@ class RelToSqlConverterTest { + "FROM \"foodmart\".\"days\") AS \"t\"\n" + "WHERE \"one\" < \"tWo\" AND \"THREE\" < \"fo$ur\""; final String expectedOracle = expectedPostgresql.replace(" AS ", " "); + final String expectedExasol = "SELECT *\n" + + "FROM (SELECT 1 AS one, 2 AS tWo, 3 AS THREE," + + " 4 AS \"fo$ur\", 5 AS \"ignore\"\n" + + "FROM foodmart.days) AS t\n" + + "WHERE one < tWo AND THREE < \"fo$ur\""; sql(query) .withBigQuery().ok(expectedBigQuery) .withMysql().ok(expectedMysql) .withOracle().ok(expectedOracle) - .withPostgresql().ok(expectedPostgresql); + .withPostgresql().ok(expectedPostgresql) + .withExasol().ok(expectedExasol); } @Test void testModFunctionForHive() { @@ -5390,10 +5406,10 @@ class RelToSqlConverterTest { new SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT); final RelDataType booleanDataType = typeFactory.createSqlType(SqlTypeName.BOOLEAN); final RelDataType integerDataType = typeFactory.createSqlType(SqlTypeName.INTEGER); - final SqlDialect oracleDialect = SqlDialect.DatabaseProduct.ORACLE.getDialect(); + final SqlDialect oracleDialect = DatabaseProduct.ORACLE.getDialect(); assertFalse(oracleDialect.supportsDataType(booleanDataType)); assertTrue(oracleDialect.supportsDataType(integerDataType)); - final SqlDialect postgresqlDialect = SqlDialect.DatabaseProduct.POSTGRESQL.getDialect(); + final SqlDialect postgresqlDialect = DatabaseProduct.POSTGRESQL.getDialect(); assertTrue(postgresqlDialect.supportsDataType(booleanDataType)); assertTrue(postgresqlDialect.supportsDataType(integerDataType)); } @@ -5803,23 +5819,27 @@ class RelToSqlConverterTest { } Sql withCalcite() { - return dialect(SqlDialect.DatabaseProduct.CALCITE.getDialect()); + return dialect(DatabaseProduct.CALCITE.getDialect()); } Sql withClickHouse() { - return dialect(SqlDialect.DatabaseProduct.CLICKHOUSE.getDialect()); + return dialect(DatabaseProduct.CLICKHOUSE.getDialect()); } Sql withDb2() { - return dialect(SqlDialect.DatabaseProduct.DB2.getDialect()); + return dialect(DatabaseProduct.DB2.getDialect()); + } + + Sql withExasol() { + return dialect(DatabaseProduct.EXASOL.getDialect()); } Sql withHive() { - return dialect(SqlDialect.DatabaseProduct.HIVE.getDialect()); + return dialect(DatabaseProduct.HIVE.getDialect()); } Sql withHsqldb() { - return dialect(SqlDialect.DatabaseProduct.HSQLDB.getDialect()); + return dialect(DatabaseProduct.HSQLDB.getDialect()); } Sql withMssql() { @@ -5837,7 +5857,7 @@ class RelToSqlConverterTest { } Sql withMysql() { - return dialect(SqlDialect.DatabaseProduct.MYSQL.getDialect()); + return dialect(DatabaseProduct.MYSQL.getDialect()); } Sql withMysql8() { @@ -5851,11 +5871,11 @@ class RelToSqlConverterTest { } Sql withOracle() { - return dialect(SqlDialect.DatabaseProduct.ORACLE.getDialect()); + return dialect(DatabaseProduct.ORACLE.getDialect()); } Sql withPostgresql() { - return dialect(SqlDialect.DatabaseProduct.POSTGRESQL.getDialect()); + return dialect(DatabaseProduct.POSTGRESQL.getDialect()); } Sql withPresto() { @@ -5875,11 +5895,11 @@ class RelToSqlConverterTest { } Sql withVertica() { - return dialect(SqlDialect.DatabaseProduct.VERTICA.getDialect()); + return dialect(DatabaseProduct.VERTICA.getDialect()); } Sql withBigQuery() { - return dialect(SqlDialect.DatabaseProduct.BIG_QUERY.getDialect()); + return dialect(DatabaseProduct.BIG_QUERY.getDialect()); } Sql withSpark() {