diff --git a/babel/src/test/resources/sql/big-query.iq b/babel/src/test/resources/sql/big-query.iq index 0dce3ba5fdc..834bd65dd8d 100755 --- a/babel/src/test/resources/sql/big-query.iq +++ b/babel/src/test/resources/sql/big-query.iq @@ -2720,6 +2720,18 @@ SELECT TIMESTAMP(DATE "2008-12-25") AS timestamp_date; !ok +# This tests the no-op TIMESTAMP and DATETIME functions. +select TIMESTAMP(TIMESTAMP "2008-01-01 01:03:05") as ts, + DATETIME(DATETIME "2008-01-01 01:03:05") as dt; ++---------------------+---------------------+ +| ts | dt | ++---------------------+---------------------+ +| 2008-01-01 01:03:05 | 2008-01-01 01:03:05 | ++---------------------+---------------------+ +(1 row) + +!ok + # All these timestamps should be equal. # This tests the BQ timestamp literal string formatter # (optional 'T', optional leading zeros, optional offset with conversion). diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java index 4dd9a390fa0..680301cc472 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java @@ -783,7 +783,9 @@ static RelDataType deriveTypeSplit(SqlOperatorBinding operatorBinding, // DATETIME(timestampLtz, timeZone) OperandTypes.sequence( "DATETIME(TIMESTAMP WITH LOCAL TIME ZONE, VARCHAR)", - OperandTypes.TIMESTAMP_LTZ, OperandTypes.CHARACTER)), + OperandTypes.TIMESTAMP_LTZ, OperandTypes.CHARACTER), + // DATETIME(timestamp) -- This is a no-op. + OperandTypes.TIMESTAMP_NTZ), SqlFunctionCategory.TIMEDATE); /** The "TIME" function. It has the following overloads: @@ -838,7 +840,9 @@ static RelDataType deriveTypeSplit(SqlOperatorBinding operatorBinding, OperandTypes.TIMESTAMP_NTZ, // TIMESTAMP(timestamp, timeZone) OperandTypes.sequence("TIMESTAMP(TIMESTAMP, VARCHAR)", - OperandTypes.TIMESTAMP_NTZ, OperandTypes.CHARACTER)), + OperandTypes.TIMESTAMP_NTZ, OperandTypes.CHARACTER), + // TIMESTAMP(timestampLtz) -- This is a no-op. + OperandTypes.TIMESTAMP_LTZ), SqlFunctionCategory.TIMEDATE); /** The "CURRENT_DATETIME([timezone])" function. */ diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java index 6a43a487f70..9eacf4f5ec2 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java @@ -5099,4 +5099,24 @@ void checkUserDefinedOrderByOver(NullCollation nullCollation) { String sql = "SELECT CAST(CAST(? AS INTEGER) AS CHAR)"; sql(sql).ok(); } + + /** + * Test case for + * DATETIME and TIMESTAMP constructor + * functions that take single arguments with the same type as the function's return type. + * + *

The function counts as a no-op in this case. + */ + @Test void testNoOpTimeDateFunctions() { + String sql = "SELECT TIMESTAMP(TIMESTAMP WITH LOCAL TIME ZONE '2023-12-21 12:34:56'), " + + "DATETIME(TIMESTAMP '2023-12-21 12:34:56') " + + "FROM emp"; + + fixture() + .withFactory(c -> + c.withOperatorTable(t -> + SqlValidatorTest.operatorTableFor(SqlLibrary.BIG_QUERY))) + .withSql(sql) + .ok(); + } } diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml index bf246b3a0b2..adad333e559 100644 --- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml @@ -4927,6 +4927,17 @@ LogicalProject(SKILL=[ROW($0)]) LogicalFilter(condition=[=($0, '')]) LogicalProject(TYPE=[$0.TYPE]) LogicalTableScan(table=[[CATALOG, SALES, DEPT_SINGLE]]) +]]> + + + + + + + +