Skip to content

Commit ebff9ba

Browse files
committed
supporting snowflake extract syntax
1 parent 1e209d8 commit ebff9ba

File tree

5 files changed

+47
-3
lines changed

5 files changed

+47
-3
lines changed

src/ast/mod.rs

+20-2
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,17 @@ pub enum CastKind {
477477
DoubleColon,
478478
}
479479

480+
/// `EXTRACT` syntax types.
481+
///
482+
483+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
484+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
485+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
486+
pub enum ExtractSyntax {
487+
From,
488+
Comma
489+
}
490+
480491
/// An SQL expression of any type.
481492
///
482493
/// The parser does not distinguish between expressions of different types
@@ -637,13 +648,15 @@ pub enum Expr {
637648
time_zone: Box<Expr>,
638649
},
639650
/// Extract a field from a timestamp e.g. `EXTRACT(MONTH FROM foo)`
651+
/// Or `EXTRACT(MONTH, foo)`
640652
///
641653
/// Syntax:
642654
/// ```sql
643-
/// EXTRACT(DateTimeField FROM <expr>)
655+
/// EXTRACT(DateTimeField FROM <expr>) | EXTRACT(DateTimeField, <expr>)
644656
/// ```
645657
Extract {
646658
field: DateTimeField,
659+
syntax: ExtractSyntax,
647660
expr: Box<Expr>,
648661
},
649662
/// ```sql
@@ -1197,7 +1210,12 @@ impl fmt::Display for Expr {
11971210
write!(f, "{expr}::{data_type}")
11981211
}
11991212
},
1200-
Expr::Extract { field, expr } => write!(f, "EXTRACT({field} FROM {expr})"),
1213+
Expr::Extract { field, syntax, expr } => {
1214+
match syntax {
1215+
ExtractSyntax::From => write!(f, "EXTRACT({field} FROM {expr})"),
1216+
ExtractSyntax::Comma => write!(f, "EXTRACT({field}, {expr})")
1217+
}
1218+
}
12011219
Expr::Ceil { expr, field } => {
12021220
if field == &DateTimeField::NoDateTime {
12031221
write!(f, "CEIL({expr})")

src/parser/mod.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -1682,12 +1682,21 @@ impl<'a> Parser<'a> {
16821682
pub fn parse_extract_expr(&mut self) -> Result<Expr, ParserError> {
16831683
self.expect_token(&Token::LParen)?;
16841684
let field = self.parse_date_time_field()?;
1685-
self.expect_keyword(Keyword::FROM)?;
1685+
1686+
let syntax = if self.parse_keyword(Keyword::FROM) {
1687+
ExtractSyntax::From
1688+
} else if self.consume_token(&Token::Comma) {
1689+
ExtractSyntax::Comma
1690+
} else {
1691+
return Err(ParserError::ParserError("Expected 'FROM' or ','".to_string()));
1692+
};
1693+
16861694
let expr = self.parse_expr()?;
16871695
self.expect_token(&Token::RParen)?;
16881696
Ok(Expr::Extract {
16891697
field,
16901698
expr: Box::new(expr),
1699+
syntax,
16911700
})
16921701
}
16931702

tests/sqlparser_bigquery.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2136,6 +2136,7 @@ fn parse_extract_weekday() {
21362136
assert_eq!(
21372137
&Expr::Extract {
21382138
field: DateTimeField::Week(Some(Ident::new("MONDAY"))),
2139+
syntax: ExtractSyntax::From,
21392140
expr: Box::new(Expr::Identifier(Ident::new("d"))),
21402141
},
21412142
expr_from_projection(only(&select.projection)),

tests/sqlparser_common.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2430,6 +2430,7 @@ fn parse_extract() {
24302430
assert_eq!(
24312431
&Expr::Extract {
24322432
field: DateTimeField::Year,
2433+
syntax: ExtractSyntax::From,
24332434
expr: Box::new(Expr::Identifier(Ident::new("d"))),
24342435
},
24352436
expr_from_projection(only(&select.projection)),

tests/sqlparser_snowflake.rs

+15
Original file line numberDiff line numberDiff line change
@@ -2019,6 +2019,21 @@ fn parse_extract_custom_part() {
20192019
assert_eq!(
20202020
&Expr::Extract {
20212021
field: DateTimeField::Custom(Ident::new("eod")),
2022+
syntax: ExtractSyntax::From,
2023+
expr: Box::new(Expr::Identifier(Ident::new("d"))),
2024+
},
2025+
expr_from_projection(only(&select.projection)),
2026+
);
2027+
}
2028+
2029+
#[test]
2030+
fn parse_extract_comma() {
2031+
let sql = "SELECT EXTRACT(HOUR, d)";
2032+
let select = snowflake_and_generic().verified_only_select(sql);
2033+
assert_eq!(
2034+
&Expr::Extract {
2035+
field: DateTimeField::Hour,
2036+
syntax: ExtractSyntax::Comma,
20222037
expr: Box::new(Expr::Identifier(Ident::new("d"))),
20232038
},
20242039
expr_from_projection(only(&select.projection)),

0 commit comments

Comments
 (0)