Skip to content

Commit 1d1547e

Browse files
committed
recursive select calls are parsed with bad trailing_commas parameter
1 parent 724a1d1 commit 1d1547e

File tree

2 files changed

+43
-11
lines changed

2 files changed

+43
-11
lines changed

src/parser/mod.rs

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3516,14 +3516,12 @@ impl<'a> Parser<'a> {
35163516
// e.g. `SELECT 1, 2, FROM t`
35173517
// https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#trailing_commas
35183518
// https://docs.snowflake.com/en/release-notes/2024/8_11#select-supports-trailing-commas
3519-
//
3520-
// This pattern could be captured better with RAII type semantics, but it's quite a bit of
3521-
// code to add for just one case, so we'll just do it manually here.
3522-
let old_value = self.options.trailing_commas;
3523-
self.options.trailing_commas |= self.dialect.supports_projection_trailing_commas();
35243519

3525-
let ret = self.parse_comma_separated(|p| p.parse_select_item());
3526-
self.options.trailing_commas = old_value;
3520+
let trailing_commas =
3521+
self.options.trailing_commas | self.dialect.supports_projection_trailing_commas();
3522+
3523+
let ret = self
3524+
.parse_comma_separated_with_trailing_commas(|p| p.parse_select_item(), trailing_commas);
35273525

35283526
ret
35293527
}
@@ -3552,11 +3550,12 @@ impl<'a> Parser<'a> {
35523550
}
35533551

35543552
/// Parse the comma of a comma-separated syntax element.
3553+
/// Allows for control over trailing commas
35553554
/// Returns true if there is a next element
3556-
fn is_parse_comma_separated_end(&mut self) -> bool {
3555+
fn is_parse_comma_separated_end_with_trailing_commas(&mut self, trailing_commas: bool) -> bool {
35573556
if !self.consume_token(&Token::Comma) {
35583557
true
3559-
} else if self.options.trailing_commas {
3558+
} else if trailing_commas {
35603559
let token = self.peek_token().token;
35613560
match token {
35623561
Token::Word(ref kw)
@@ -3574,15 +3573,34 @@ impl<'a> Parser<'a> {
35743573
}
35753574
}
35763575

3576+
/// Parse the comma of a comma-separated syntax element.
3577+
/// Returns true if there is a next element
3578+
fn is_parse_comma_separated_end(&mut self) -> bool {
3579+
self.is_parse_comma_separated_end_with_trailing_commas(self.options.trailing_commas)
3580+
}
3581+
3582+
/// Parse a comma-separated list of 1+ items accepted by `F`
3583+
pub fn parse_comma_separated<T, F>(&mut self, f: F) -> Result<Vec<T>, ParserError>
3584+
where
3585+
F: FnMut(&mut Parser<'a>) -> Result<T, ParserError>,
3586+
{
3587+
self.parse_comma_separated_with_trailing_commas(f, self.options.trailing_commas)
3588+
}
3589+
35773590
/// Parse a comma-separated list of 1+ items accepted by `F`
3578-
pub fn parse_comma_separated<T, F>(&mut self, mut f: F) -> Result<Vec<T>, ParserError>
3591+
/// Allows for control over trailing commas
3592+
fn parse_comma_separated_with_trailing_commas<T, F>(
3593+
&mut self,
3594+
mut f: F,
3595+
trailing_commas: bool,
3596+
) -> Result<Vec<T>, ParserError>
35793597
where
35803598
F: FnMut(&mut Parser<'a>) -> Result<T, ParserError>,
35813599
{
35823600
let mut values = vec![];
35833601
loop {
35843602
values.push(f(self)?);
3585-
if self.is_parse_comma_separated_end() {
3603+
if self.is_parse_comma_separated_end_with_trailing_commas(trailing_commas) {
35863604
break;
35873605
}
35883606
}

tests/sqlparser_snowflake.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2846,3 +2846,17 @@ fn test_parse_show_columns_sql() {
28462846
snowflake().verified_stmt("SHOW COLUMNS IN TABLE abc");
28472847
snowflake().verified_stmt("SHOW COLUMNS LIKE '%xyz%' IN TABLE abc");
28482848
}
2849+
2850+
#[test]
2851+
fn test_projection_with_nested_trailing_commas() {
2852+
let sql = "SELECT a FROM b, LATERAL FLATTEN(input => events)";
2853+
let _ = snowflake().parse_sql_statements(&sql).unwrap();
2854+
2855+
//Single nesting
2856+
let sql = format!("SELECT ({sql})");
2857+
let _ = snowflake().parse_sql_statements(&sql).unwrap();
2858+
2859+
//Double nesting
2860+
let sql = format!("SELECT ({sql})");
2861+
let _ = snowflake().parse_sql_statements(&sql).unwrap();
2862+
}

0 commit comments

Comments
 (0)