Skip to content

Commit 1051900

Browse files
authored
recursive select calls are parsed with bad trailing_commas parameter (#1521)
1 parent a115022 commit 1051900

File tree

2 files changed

+44
-12
lines changed

2 files changed

+44
-12
lines changed

src/parser/mod.rs

+27-12
Original file line numberDiff line numberDiff line change
@@ -3532,16 +3532,11 @@ impl<'a> Parser<'a> {
35323532
// e.g. `SELECT 1, 2, FROM t`
35333533
// https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#trailing_commas
35343534
// https://docs.snowflake.com/en/release-notes/2024/8_11#select-supports-trailing-commas
3535-
//
3536-
// This pattern could be captured better with RAII type semantics, but it's quite a bit of
3537-
// code to add for just one case, so we'll just do it manually here.
3538-
let old_value = self.options.trailing_commas;
3539-
self.options.trailing_commas |= self.dialect.supports_projection_trailing_commas();
35403535

3541-
let ret = self.parse_comma_separated(|p| p.parse_select_item());
3542-
self.options.trailing_commas = old_value;
3536+
let trailing_commas =
3537+
self.options.trailing_commas | self.dialect.supports_projection_trailing_commas();
35433538

3544-
ret
3539+
self.parse_comma_separated_with_trailing_commas(|p| p.parse_select_item(), trailing_commas)
35453540
}
35463541

35473542
pub fn parse_actions_list(&mut self) -> Result<Vec<ParsedAction>, ParserError> {
@@ -3568,11 +3563,12 @@ impl<'a> Parser<'a> {
35683563
}
35693564

35703565
/// Parse the comma of a comma-separated syntax element.
3566+
/// Allows for control over trailing commas
35713567
/// Returns true if there is a next element
3572-
fn is_parse_comma_separated_end(&mut self) -> bool {
3568+
fn is_parse_comma_separated_end_with_trailing_commas(&mut self, trailing_commas: bool) -> bool {
35733569
if !self.consume_token(&Token::Comma) {
35743570
true
3575-
} else if self.options.trailing_commas {
3571+
} else if trailing_commas {
35763572
let token = self.peek_token().token;
35773573
match token {
35783574
Token::Word(ref kw)
@@ -3590,15 +3586,34 @@ impl<'a> Parser<'a> {
35903586
}
35913587
}
35923588

3589+
/// Parse the comma of a comma-separated syntax element.
3590+
/// Returns true if there is a next element
3591+
fn is_parse_comma_separated_end(&mut self) -> bool {
3592+
self.is_parse_comma_separated_end_with_trailing_commas(self.options.trailing_commas)
3593+
}
3594+
35933595
/// Parse a comma-separated list of 1+ items accepted by `F`
3594-
pub fn parse_comma_separated<T, F>(&mut self, mut f: F) -> Result<Vec<T>, ParserError>
3596+
pub fn parse_comma_separated<T, F>(&mut self, f: F) -> Result<Vec<T>, ParserError>
3597+
where
3598+
F: FnMut(&mut Parser<'a>) -> Result<T, ParserError>,
3599+
{
3600+
self.parse_comma_separated_with_trailing_commas(f, self.options.trailing_commas)
3601+
}
3602+
3603+
/// Parse a comma-separated list of 1+ items accepted by `F`
3604+
/// Allows for control over trailing commas
3605+
fn parse_comma_separated_with_trailing_commas<T, F>(
3606+
&mut self,
3607+
mut f: F,
3608+
trailing_commas: bool,
3609+
) -> Result<Vec<T>, ParserError>
35953610
where
35963611
F: FnMut(&mut Parser<'a>) -> Result<T, ParserError>,
35973612
{
35983613
let mut values = vec![];
35993614
loop {
36003615
values.push(f(self)?);
3601-
if self.is_parse_comma_separated_end() {
3616+
if self.is_parse_comma_separated_end_with_trailing_commas(trailing_commas) {
36023617
break;
36033618
}
36043619
}

tests/sqlparser_snowflake.rs

+17
Original file line numberDiff line numberDiff line change
@@ -2846,3 +2846,20 @@ 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 = "SELECT (SELECT a, FROM b, LATERAL FLATTEN(input => events))";
2857+
let _ = snowflake().parse_sql_statements(sql).unwrap();
2858+
2859+
//Double nesting
2860+
let sql = "SELECT (SELECT (SELECT a, FROM b, LATERAL FLATTEN(input => events)))";
2861+
let _ = snowflake().parse_sql_statements(sql).unwrap();
2862+
2863+
let sql = "SELECT a, b, FROM c, (SELECT d, e, FROM f, LATERAL FLATTEN(input => events))";
2864+
let _ = snowflake().parse_sql_statements(sql).unwrap();
2865+
}

0 commit comments

Comments
 (0)