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 594048556010..71157191e8ee 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlDialect.java @@ -760,6 +760,13 @@ public boolean supportsApproxCountDistinct() { return false; } + /** + * Returns whether this dialect supports TIMESTAMP with precision. + */ + public boolean supportsTimestampPrecision() { + return true; + } + /** Returns whether this dialect supports the use of FILTER clauses for * aggregate functions. e.g. {@code COUNT(*) FILTER (WHERE a = 2)}. */ public boolean supportsAggregateFunctionFilter() { @@ -839,6 +846,13 @@ public boolean supportsDataType(RelDataType type) { // if needed, adjust varchar length to max length supported by the system maxPrecision = getTypeSystem().getMaxPrecision(type.getSqlTypeName()); break; + case TIMESTAMP: + if (!supportsTimestampPrecision()) { + return new SqlDataTypeSpec( + new SqlBasicTypeNameSpec(type.getSqlTypeName(), SqlParserPos.ZERO), + SqlParserPos.ZERO); + } + break; default: break; } 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 index 6e127cfc3dca..e3122b41a165 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/ExasolSqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/ExasolSqlDialect.java @@ -16,15 +16,11 @@ */ 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; @@ -134,6 +130,10 @@ public ExasolSqlDialect(Context context) { return false; } + @Override public boolean supportsTimestampPrecision() { + return false; + } + @Override public boolean supportsAggregateFunction(SqlKind kind) { switch (kind) { case AVG: @@ -158,18 +158,6 @@ public ExasolSqlDialect(Context context) { || 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); diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/PrestoSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/PrestoSqlDialect.java index 75b232e34930..4209fe77bf91 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/PrestoSqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/PrestoSqlDialect.java @@ -64,6 +64,10 @@ public PrestoSqlDialect(Context context) { return true; } + @Override public boolean supportsTimestampPrecision() { + return false; + } + @Override public void unparseOffsetFetch(SqlWriter writer, @Nullable SqlNode offset, @Nullable SqlNode fetch) { unparseUsingLimit(writer, offset, fetch); diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/SparkSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/SparkSqlDialect.java index e97cfcac01ba..f1f67fa35b6a 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/SparkSqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/SparkSqlDialect.java @@ -104,6 +104,10 @@ public SparkSqlDialect(SqlDialect.Context context) { return true; } + @Override public boolean supportsTimestampPrecision() { + return false; + } + @Override public void unparseOffsetFetch(SqlWriter writer, @Nullable SqlNode offset, @Nullable SqlNode fetch) { unparseFetchUsingLimit(writer, offset, fetch); 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 b73cc8016cfd..1578d0112e18 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 @@ -2415,6 +2415,23 @@ private SqlDialect nonOrdinalDialect() { .withRedshift().ok(expectedRedshift); } + /** Test case for + * [CALCITE-6121] + * Invalid unparse for TIMESTAMP with SparkSqlDialect. */ + @Test void testCastToTimestampWithoutPrecision() { + final String query = "select * from \"employee\" where \"hire_date\" - " + + "INTERVAL '19800' SECOND(5) > cast(\"hire_date\" as TIMESTAMP(0))"; + final String expectedSpark = "SELECT *\n" + + "FROM foodmart.employee\n" + + "WHERE (hire_date - INTERVAL '19800' SECOND(5)) > CAST(hire_date AS TIMESTAMP)"; + final String expectedPresto = "SELECT *\n" + + "FROM \"foodmart\".\"employee\"\n" + + "WHERE (\"hire_date\" - INTERVAL '19800' SECOND) > CAST(\"hire_date\" AS TIMESTAMP)"; + sql(query) + .withSpark().ok(expectedSpark) + .withPresto().ok(expectedPresto); + } + @Test void testExasolCastToTimestamp() { final String query = "select * from \"employee\" where \"hire_date\" - " + "INTERVAL '19800' SECOND(5) > cast(\"hire_date\" as TIMESTAMP(0))";