Skip to content

Commit 5c5f66f

Browse files
committed
Fix DoubleColonCast skipping AT TIME ZONE apache#1266
1 parent eb36bd7 commit 5c5f66f

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
@@ -1528,19 +1528,23 @@ impl<'a> Parser<'a> {
15281528
pub fn parse_optional_cast_format(&mut self) -> Result<Option<CastFormat>, ParserError> {
15291529
if self.parse_keyword(Keyword::FORMAT) {
15301530
let value = self.parse_value()?;
1531-
if self.parse_keywords(&[Keyword::AT, Keyword::TIME, Keyword::ZONE]) {
1532-
Ok(Some(CastFormat::ValueAtTimeZone(
1533-
value,
1534-
self.parse_value()?,
1535-
)))
1536-
} else {
1537-
Ok(Some(CastFormat::Value(value)))
1531+
match self.parse_optional_time_zone()? {
1532+
Some(tz) => Ok(Some(CastFormat::ValueAtTimeZone(value, tz))),
1533+
None => Ok(Some(CastFormat::Value(value))),
15381534
}
15391535
} else {
15401536
Ok(None)
15411537
}
15421538
}
15431539

1540+
pub fn parse_optional_time_zone(&mut self) -> Result<Option<Value>, ParserError> {
1541+
if self.parse_keywords(&[Keyword::AT, Keyword::TIME, Keyword::ZONE]) {
1542+
self.parse_value().map(Some)
1543+
} else {
1544+
Ok(None)
1545+
}
1546+
}
1547+
15441548
/// mssql-like convert function
15451549
fn parse_mssql_convert(&mut self) -> Result<Expr, ParserError> {
15461550
self.expect_token(&Token::LParen)?;
@@ -2534,12 +2538,35 @@ impl<'a> Parser<'a> {
25342538
),
25352539
}
25362540
} else if Token::DoubleColon == tok {
2537-
Ok(Expr::Cast {
2541+
let data_type = self.parse_data_type()?;
2542+
2543+
let cast_expr = Expr::Cast {
25382544
kind: CastKind::DoubleColon,
25392545
expr: Box::new(expr),
2540-
data_type: self.parse_data_type()?,
2546+
data_type: data_type.clone(),
25412547
format: None,
2542-
})
2548+
};
2549+
2550+
match data_type {
2551+
DataType::Date
2552+
| DataType::Datetime(_)
2553+
| DataType::Timestamp(_, _)
2554+
| DataType::Time(_, _) => {
2555+
let value = self.parse_optional_time_zone()?;
2556+
match value {
2557+
Some(Value::SingleQuotedString(tz)) => Ok(Expr::AtTimeZone {
2558+
timestamp: Box::new(cast_expr),
2559+
time_zone: tz,
2560+
}),
2561+
None => Ok(cast_expr),
2562+
_ => Err(ParserError::ParserError(format!(
2563+
"Expected Token::SingleQuotedString after AT TIME ZONE, but found: {}",
2564+
value.unwrap()
2565+
))),
2566+
}
2567+
}
2568+
_ => Ok(cast_expr),
2569+
}
25432570
} else if Token::ExclamationMark == tok {
25442571
// PostgreSQL factorial operation
25452572
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)