Skip to content

Commit 49d1784

Browse files
authored
Fix DoubleColon cast skipping AT TIME ZONE apache#1266 (apache#1267)
1 parent 036a412 commit 49d1784

File tree

2 files changed

+58
-10
lines changed

2 files changed

+58
-10
lines changed

src/parser/mod.rs

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1535,19 +1535,23 @@ impl<'a> Parser<'a> {
15351535
pub fn parse_optional_cast_format(&mut self) -> Result<Option<CastFormat>, ParserError> {
15361536
if self.parse_keyword(Keyword::FORMAT) {
15371537
let value = self.parse_value()?;
1538-
if self.parse_keywords(&[Keyword::AT, Keyword::TIME, Keyword::ZONE]) {
1539-
Ok(Some(CastFormat::ValueAtTimeZone(
1540-
value,
1541-
self.parse_value()?,
1542-
)))
1543-
} else {
1544-
Ok(Some(CastFormat::Value(value)))
1538+
match self.parse_optional_time_zone()? {
1539+
Some(tz) => Ok(Some(CastFormat::ValueAtTimeZone(value, tz))),
1540+
None => Ok(Some(CastFormat::Value(value))),
15451541
}
15461542
} else {
15471543
Ok(None)
15481544
}
15491545
}
15501546

1547+
pub fn parse_optional_time_zone(&mut self) -> Result<Option<Value>, ParserError> {
1548+
if self.parse_keywords(&[Keyword::AT, Keyword::TIME, Keyword::ZONE]) {
1549+
self.parse_value().map(Some)
1550+
} else {
1551+
Ok(None)
1552+
}
1553+
}
1554+
15511555
/// mssql-like convert function
15521556
fn parse_mssql_convert(&mut self) -> Result<Expr, ParserError> {
15531557
self.expect_token(&Token::LParen)?;
@@ -2541,12 +2545,35 @@ impl<'a> Parser<'a> {
25412545
),
25422546
}
25432547
} else if Token::DoubleColon == tok {
2544-
Ok(Expr::Cast {
2548+
let data_type = self.parse_data_type()?;
2549+
2550+
let cast_expr = Expr::Cast {
25452551
kind: CastKind::DoubleColon,
25462552
expr: Box::new(expr),
2547-
data_type: self.parse_data_type()?,
2553+
data_type: data_type.clone(),
25482554
format: None,
2549-
})
2555+
};
2556+
2557+
match data_type {
2558+
DataType::Date
2559+
| DataType::Datetime(_)
2560+
| DataType::Timestamp(_, _)
2561+
| DataType::Time(_, _) => {
2562+
let value = self.parse_optional_time_zone()?;
2563+
match value {
2564+
Some(Value::SingleQuotedString(tz)) => Ok(Expr::AtTimeZone {
2565+
timestamp: Box::new(cast_expr),
2566+
time_zone: tz,
2567+
}),
2568+
None => Ok(cast_expr),
2569+
_ => Err(ParserError::ParserError(format!(
2570+
"Expected Token::SingleQuotedString after AT TIME ZONE, but found: {}",
2571+
value.unwrap()
2572+
))),
2573+
}
2574+
}
2575+
_ => Ok(cast_expr),
2576+
}
25502577
} else if Token::ExclamationMark == tok {
25512578
// PostgreSQL factorial operation
25522579
Ok(Expr::UnaryOp {

tests/sqlparser_common.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7022,6 +7022,27 @@ fn parse_set_variable() {
70227022
one_statement_parses_to("SET SOMETHING TO '1'", "SET SOMETHING = '1'");
70237023
}
70247024

7025+
#[test]
7026+
fn parse_double_colon_cast_at_timezone() {
7027+
let sql = "SELECT '2001-01-01T00:00:00.000Z'::TIMESTAMP AT TIME ZONE 'Europe/Brussels' FROM t";
7028+
let select = verified_only_select(sql);
7029+
7030+
assert_eq!(
7031+
&Expr::AtTimeZone {
7032+
timestamp: Box::new(Expr::Cast {
7033+
kind: CastKind::DoubleColon,
7034+
expr: Box::new(Expr::Value(Value::SingleQuotedString(
7035+
"2001-01-01T00:00:00.000Z".to_string()
7036+
),)),
7037+
data_type: DataType::Timestamp(None, TimezoneInfo::None),
7038+
format: None
7039+
}),
7040+
time_zone: "Europe/Brussels".to_string()
7041+
},
7042+
expr_from_projection(only(&select.projection)),
7043+
);
7044+
}
7045+
70257046
#[test]
70267047
fn parse_set_time_zone() {
70277048
match verified_stmt("SET TIMEZONE = 'UTC'") {

0 commit comments

Comments
 (0)