Skip to content

Commit

Permalink
[CALCITE-5543] WIP: Implement BigQuery functions for parsing DATE, TI…
Browse files Browse the repository at this point in the history
…ME, TIMESTAMP, DATETIME (#27)
  • Loading branch information
tjbanghart committed Mar 24, 2023
1 parent 88f664a commit 49cac0f
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,49 @@ static RelDataType deriveTypeSplit(SqlOperatorBinding operatorBinding,
OperandTypes.STRING_STRING,
SqlFunctionCategory.TIMEDATE);

/**
* The "PARSE_TIME(string, string)" function (BigQuery); Converts a string representation of time
* to a TIME object.
*/
@LibraryOperator(libraries = {BIG_QUERY})
public static final SqlFunction PARSE_TIME =
SqlBasicFunction.create("PARSE_TIME", ReturnTypes.TIME_NULLABLE,
OperandTypes.STRING_STRING, SqlFunctionCategory.TIMEDATE);

/**
* The "PARSE_DATE(string, string)" function (BigQuery); Converts a string representation of date
* to a DATE object.
*/
@LibraryOperator(libraries = {BIG_QUERY})
public static final SqlFunction PARSE_DATE =
SqlBasicFunction.create("PARSE_DATE",
ReturnTypes.DATE_NULLABLE, OperandTypes.STRING_STRING, SqlFunctionCategory.TIMEDATE);

/**
* The "PARSE_TIMESTAMP(string, string [, timezone])" function (BigQuery); Formats a timestamp
* object according to the specified string.
*
* <p>In BigQuery, the "TIMESTAMP" datatype maps to Calcite's
* TIMESTAMP_WITH_LOCAL_TIME_ZONE
*/
@LibraryOperator(libraries = {BIG_QUERY})
public static final SqlFunction PARSE_TIMESTAMP =
SqlBasicFunction.create("PARSE_TIMESTAMP",
ReturnTypes.TIMESTAMP_LTZ_NULLABLE, OperandTypes.STRING_STRING_OPTIONAL_STRING,
SqlFunctionCategory.TIMEDATE);

/**
* The "PARSE_DATETIME(string, string [, timezone])" function (BigQuery); Formats a timestamp
* object according to the specified string.
*
* <p>Note that the {@code TIMESTAMP} type of Calcite and Standard SQL
* is called {@code DATETIME} in BigQuery.
*/
@LibraryOperator(libraries = {BIG_QUERY})
public static final SqlFunction PARSE_DATETIME =
SqlBasicFunction.create("PARSE_DATETIME", ReturnTypes.TIMESTAMP_NULLABLE,
OperandTypes.STRING_STRING, SqlFunctionCategory.TIMEDATE);

/** The "FORMAT_TIME(string, time)" function (BigQuery);
* Formats a time object according to the specified string. */
@LibraryOperator(libraries = {BIG_QUERY})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,13 @@ public static SqlCall stripSeparator(SqlCall call) {
public static final SqlReturnTypeInference TIMESTAMP_LTZ =
explicit(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE);

/**
* Type-inference strategy whereby the result type of a call is nullable
* TIMESTAMP WITH LOCAL TIME ZONE.
*/
public static final SqlReturnTypeInference TIMESTAMP_LTZ_NULLABLE =
TIMESTAMP_LTZ.andThen(SqlTypeTransforms.TO_NULLABLE);

/**
* Type-inference strategy whereby the result type of a call is Double.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1828,6 +1828,38 @@ private SqlDialect nonOrdinalDialect() {
sql(query).withBigQuery().ok(expected);
}

@Test void testBigQueryParseDatetimeFunctions() {
String parseTime = "select parse_time('%I:%M:%S', '07:30:00')\n"
+ "from \"foodmart\".\"product\"\n";
final String expectedTimestampTrunc =
"SELECT PARSE_TIME('%I:%M:%S', '07:30:00')\n"
+ "FROM \"foodmart\".\"product\"";
sql(parseTime).withLibrary(SqlLibrary.BIG_QUERY).ok(expectedTimestampTrunc);

String parseDate = "select parse_date('%A %b %e %Y', 'Thursday Dec 25 2008')\n"
+ "from \"foodmart\".\"product\"\n";
final String expectedParseDate =
"SELECT PARSE_DATE('%A %b %e %Y', 'Thursday Dec 25 2008')\n"
+ "FROM \"foodmart\".\"product\"";
sql(parseDate).withLibrary(SqlLibrary.BIG_QUERY).ok(expectedParseDate);

String parseTimestamp =
"select parse_timestamp('%a %b %e %I:%M:%S %Y', 'Thu Dec 25 07:30:00 2008')\n"
+ "from \"foodmart\".\"product\"\n";
final String expectedParseTimestamp =
"SELECT PARSE_TIMESTAMP('%a %b %e %I:%M:%S %Y', 'Thu Dec 25 07:30:00 2008')\n"
+ "FROM \"foodmart\".\"product\"";
sql(parseTimestamp).withLibrary(SqlLibrary.BIG_QUERY).ok(expectedParseTimestamp);

String parseDatetime =
"select parse_datetime('%a %b %e %I:%M:%S %Y', 'Thu Dec 25 07:30:00 2008')\n"
+ "from \"foodmart\".\"product\"\n";
final String expectedParseDatetime =
"SELECT PARSE_DATETIME('%a %b %e %I:%M:%S %Y', 'Thu Dec 25 07:30:00 2008')\n"
+ "FROM \"foodmart\".\"product\"";
sql(parseDatetime).withLibrary(SqlLibrary.BIG_QUERY).ok(expectedParseDatetime);
}

@Test void testBigQueryTimeTruncFunctions() {
String timestampTrunc = "select timestamp_trunc(timestamp '2012-02-03 15:30:00', month)\n"
+ "from \"foodmart\".\"product\"\n";
Expand Down
4 changes: 4 additions & 0 deletions site/_docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2713,6 +2713,10 @@ BigQuery's type system uses confusingly different names for types and functions:
| b m p | MD5(string) | Calculates an MD5 128-bit checksum of *string* and returns it as a hex string
| m | MONTHNAME(date) | Returns the name, in the connection's locale, of the month in *datetime*; for example, it returns '二月' for both DATE '2020-02-10' and TIMESTAMP '2020-02-10 10:10:10'
| o | NVL(value1, value2) | Returns *value1* if *value1* is not null, otherwise *value2*
| b | PARSE_DATE(string1, string2) | Uses format specified by *string1* to convert *string2* representation of date to a DATE object
| b | PARSE_DATETIME(string1, string2) | Uses format specified by *string1* to convert *string2* representation of datetime to a TIMESTAMP object
| b | PARSE_TIME(string1, string2) | Uses format specified by *string1* to convert *string2* representation of time to a TIME object
| b | PARSE_TIMESTAMP(string1, string2[, timeZone]) | Uses format specified by *string1* to convert *string2* representation of timestamp to a TIMESTAMP WITH LOCAL TIME ZONE object in *timeZone*
| b | POW(numeric1, numeric2) | Returns *numeric1* raised to the power *numeric2*
| m o | REGEXP_REPLACE(string, regexp, rep, [, pos [, occurrence [, matchType]]]) | Replaces all substrings of *string* that match *regexp* with *rep* at the starting *pos* in expr (if omitted, the default is 1), *occurrence* means which occurrence of a match to search for (if omitted, the default is 1), *matchType* specifies how to perform matching
| b m p | REPEAT(string, integer) | Returns a string consisting of *string* repeated of *integer* times; returns an empty string if *integer* is less than 1
Expand Down

1 comment on commit 49cac0f

@tjbanghart
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calcite PR: apache#3132

Please sign in to comment.