Skip to content

Commit

Permalink
Implement BigQuery date/time constructors
Browse files Browse the repository at this point in the history
  • Loading branch information
wnob committed Jan 10, 2023
1 parent e863784 commit eb281b1
Show file tree
Hide file tree
Showing 11 changed files with 654 additions and 22 deletions.
2 changes: 2 additions & 0 deletions babel/src/main/codegen/config.fmpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,8 @@ data: {
# Example: "DateFunctionCall()".
builtinFunctionCallMethods: [
"DateFunctionCall()"
"TimestampFunctionCall()"
"TimeFunctionCall()"
"DateaddFunctionCall()"
]

Expand Down
42 changes: 41 additions & 1 deletion babel/src/main/codegen/includes/parserImpls.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ JoinType LeftSemiJoin() :

SqlNode DateFunctionCall() :
{
final SqlFunctionCategory funcType = SqlFunctionCategory.USER_DEFINED_FUNCTION;
final SqlFunctionCategory funcType = SqlFunctionCategory.TIMEDATE;
final SqlIdentifier qualifiedName;
final Span s;
final SqlLiteral quantifier;
Expand All @@ -42,6 +42,46 @@ SqlNode DateFunctionCall() :
}
}

SqlNode TimestampFunctionCall() :
{
final SqlFunctionCategory funcType = SqlFunctionCategory.TIMEDATE;
final SqlIdentifier qualifiedName;
final Span s;
final SqlLiteral quantifier;
final List<? extends SqlNode> args;
}
{
<TIMESTAMP> {
s = span();
qualifiedName = new SqlIdentifier(unquotedIdentifier(), getPos());
}
args = FunctionParameterList(ExprContext.ACCEPT_SUB_QUERY) {
quantifier = (SqlLiteral) args.get(0);
args.remove(0);
return createCall(qualifiedName, s.end(this), funcType, quantifier, args);
}
}

SqlNode TimeFunctionCall() :
{
final SqlFunctionCategory funcType = SqlFunctionCategory.TIMEDATE;
final SqlIdentifier qualifiedName;
final Span s;
final SqlLiteral quantifier;
final List<? extends SqlNode> args;
}
{
<TIME> {
s = span();
qualifiedName = new SqlIdentifier(unquotedIdentifier(), getPos());
}
args = FunctionParameterList(ExprContext.ACCEPT_SUB_QUERY) {
quantifier = (SqlLiteral) args.get(0);
args.remove(0);
return createCall(qualifiedName, s.end(this), funcType, quantifier, args);
}
}

SqlNode DateaddFunctionCall() :
{
final Span s;
Expand Down
140 changes: 129 additions & 11 deletions babel/src/test/resources/sql/big-query.iq
Original file line number Diff line number Diff line change
Expand Up @@ -1082,29 +1082,147 @@ select unix_date(datetime '2008-12-25') as d;

!ok

#####################################################################
# DATE
# 'date(x) is shorthand for 'cast(x as date)'
select date('1970-01-01') as d;
#
# 1. DATE(year, month, day)
# 2. DATE(timestamp_expression[, time_zone])
# 3. DATE(datetime_expression)
#
# 1. Constructs a DATE from INT64 values representing the year, month, and day.
# 1. Extracts the DATE from a TIMESTAMP expression. It supports an optional
# parameter to specify a time zone. If no time zone is specified, the default
# time zone, UTC, is used.
# 1. Extracts the DATE from a DATETIME expression.
#
# Return Data Type: DATE

select date(2022, 11, 15) as d;
+------------+
| d |
+------------+
| 1970-01-01 |
| 2022-11-15 |
+------------+
(1 row)

!ok

!if (false) {
select date(cast(null as varchar(10))) as d;
+---+
| D |
+---+
| |
+---+
#####################################################################
# TIMESTAMP
#
# TIMESTAMP(string_expression[, time_zone])
# TIMESTAMP(date_expression[, time_zone])
# TIMESTAMP(datetime_expression[, time_zone])
#
# - string_expression[, time_zone]:
# Converts a STRING expression to a TIMESTAMP data type. string_expression
# must include a timestamp literal. If string_expression includes a time_zone
# in the timestamp literal, do not include an explicit time_zone argument.
# - date_expression[, time_zone]: Converts a DATE object to a TIMESTAMP data
# type.
# - datetime_expression[, time_zone]: Converts a DATETIME object to a TIMESTAMP
# data type.
#
# This function supports an optional parameter to specify a time zone. If no
# time zone is specified, the default time zone, UTC, is used.
#
# Return Data Type: TIMESTAMP

# All these timestamps should be equal.
# This tests the BQ timestamp literal string formatter
# (optional 'T', optional leading zeros, optional offset with conversion).
select timestamp("2008-01-01 01:03:05+00") as t_space,
timestamp("2008-01-01T01:03:05+00") as t_iso,
timestamp("2008-01-01 01:03:05") as t_no_offset,
timestamp("2008-1-1 3:5:7+02:02:02") as t_offset;
+---------------------+---------------------+---------------------+---------------------+
| t_space | t_iso | t_no_offset | t_offset |
+---------------------+---------------------+---------------------+---------------------+
| 2008-01-01 01:03:05 | 2008-01-01 01:03:05 | 2008-01-01 01:03:05 | 2008-01-01 01:03:05 |
+---------------------+---------------------+---------------------+---------------------+
(1 row)

!ok

#####################################################################
# TIME
#
# 1. TIME(hour, minute, second)
# 2. TIME(timestamp[, time_zone])
# 3. TIME(datetime)
#
# 1. Constructs a TIME object using INT64 values representing the hour, minute,
# and second.
# 2. Constructs a TIME object using a TIMESTAMP object. It supports an optional
# parameter to specify a time zone. If no time zone is specified, the default
# time zone, UTC, is used.
# 3. Constructs a TIME object using a DATETIME object.
#
# Return Data Type: TIMESTAMP

select time(12, 30, 59) as t;
+----------+
| t |
+----------+
| 12:30:59 |
+----------+
(1 row)

!ok

# Test timezone conversion when converting TIMESTAMP to DATE.
# Denver observes DST whereas Phoenix does not.
# Both cities have a -07:00 offset in winter, but Denver has -06:00 in summer.
select date(timestamp("2008-06-21 06:30:00")) as sum_utc,
date(timestamp("2008-06-21 06:30:00"), "America/Denver") as sum_dst,
date(timestamp("2008-06-21 06:30:00"), "America/Phoenix") as sum_std,
date(timestamp("2008-12-21 06:30:00")) as win_utc,
date(timestamp("2008-12-21 06:30:00"), "America/Denver") as win_dst,
date(timestamp("2008-12-21 06:30:00"), "America/Phoenix") as win_std;
+------------+------------+------------+------------+------------+------------+
| sum_utc | sum_dst | sum_std | win_utc | win_dst | win_std |
+------------+------------+------------+------------+------------+------------+
| 2008-06-21 | 2008-06-21 | 2008-06-20 | 2008-12-21 | 2008-12-20 | 2008-12-20 |
+------------+------------+------------+------------+------------+------------+
(1 row)

!ok

# Test timezone conversion when converting TIMESTAMP to TIME.
# Denver observes DST whereas Phoenix does not.
# Both cities have a -07:00 offset in winter, but Denver has -06:00 in summer.
select time(timestamp("2008-06-21 06:30:00")) as sum_utc,
time(timestamp("2008-06-21 06:30:00"), "America/Denver") as sum_dst,
time(timestamp("2008-06-21 06:30:00"), "America/Phoenix") as sum_std,
time(timestamp("2008-12-21 06:30:00")) as win_utc,
time(timestamp("2008-12-21 06:30:00"), "America/Denver") as win_dst,
time(timestamp("2008-12-21 06:30:00"), "America/Phoenix") as win_std;
+----------+----------+----------+----------+----------+----------+
| sum_utc | sum_dst | sum_std | win_utc | win_dst | win_std |
+----------+----------+----------+----------+----------+----------+
| 06:30:00 | 00:30:00 | 23:30:00 | 06:30:00 | 23:30:00 | 23:30:00 |
+----------+----------+----------+----------+----------+----------+
(1 row)

!ok

# Test timezone conversion when converting DATE to TIMESTAMP.
# Denver observes DST whereas Phoenix does not.
# Both cities have a -07:00 offset in winter, but Denver has -06:00 in summer.
select timestamp(date(2008, 6, 21)) as sum_utc,
timestamp(date(2008, 6, 21), "America/Denver") as sum_dst,
timestamp(date(2008, 6, 21), "America/Phoenix") as sum_std,
timestamp(date(2008, 12, 21)) as win_utc,
timestamp(date(2008, 12, 21), "America/Denver") as win_dst,
timestamp(date(2008, 12, 21), "America/Phoenix") as win_std;
+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
| sum_utc | sum_dst | sum_std | win_utc | win_dst | win_std |
+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
| 2008-06-21 00:00:00 | 2008-06-21 06:00:00 | 2008-06-21 07:00:00 | 2008-12-21 00:00:00 | 2008-12-21 07:00:00 | 2008-12-21 07:00:00 |
+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
(1 row)

!ok
!}

#####################################################################
# DATE_ADD
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@
import static org.apache.calcite.sql.fun.SqlLibraryOperators.STARTS_WITH;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.STRCMP;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.TANH;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.TIME;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.TIMESTAMP;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.TIMESTAMP_MICROS;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.TIMESTAMP_MILLIS;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.TIMESTAMP_SECONDS;
Expand Down Expand Up @@ -533,6 +535,10 @@ Builder populate2() {
defineMethod(DATE_FROM_UNIX_DATE, "dateFromUnixDate", NullPolicy.STRICT);
defineMethod(UNIX_DATE, "unixDate", NullPolicy.STRICT);

defineMethod(DATE, "date", NullPolicy.STRICT);
defineMethod(TIMESTAMP, "timestamp", NullPolicy.STRICT);
defineMethod(TIME, "time", NullPolicy.STRICT);

map.put(IS_NULL, new IsNullImplementor());
map.put(IS_NOT_NULL, new IsNotNullImplementor());
map.put(IS_TRUE, new IsTrueImplementor());
Expand Down Expand Up @@ -607,7 +613,6 @@ Builder populate2() {

map.put(COALESCE, new CoalesceImplementor());
map.put(CAST, new CastImplementor());
map.put(DATE, new CastImplementor());

map.put(REINTERPRET, new ReinterpretImplementor());

Expand Down

0 comments on commit eb281b1

Please sign in to comment.