@@ -533,10 +533,11 @@ impl<'a> Parser<'a> {
533
533
Keyword::EXECUTE | Keyword::EXEC => self.parse_execute(),
534
534
Keyword::PREPARE => self.parse_prepare(),
535
535
Keyword::MERGE => self.parse_merge(),
536
- // `LISTEN` and `NOTIFY` are Postgres-specific
536
+ // `LISTEN`, `UNLISTEN` and `NOTIFY` are Postgres-specific
537
537
// syntaxes. They are used for Postgres statement.
538
- Keyword::LISTEN if self.dialect.supports_listen() => self.parse_listen(),
539
- Keyword::NOTIFY if self.dialect.supports_notify() => self.parse_notify(),
538
+ Keyword::LISTEN if self.dialect.supports_listen_notify() => self.parse_listen(),
539
+ Keyword::UNLISTEN if self.dialect.supports_listen_notify() => self.parse_unlisten(),
540
+ Keyword::NOTIFY if self.dialect.supports_listen_notify() => self.parse_notify(),
540
541
// `PRAGMA` is sqlite specific https://www.sqlite.org/pragma.html
541
542
Keyword::PRAGMA => self.parse_pragma(),
542
543
Keyword::UNLOAD => self.parse_unload(),
@@ -1003,6 +1004,21 @@ impl<'a> Parser<'a> {
1003
1004
Ok(Statement::LISTEN { channel })
1004
1005
}
1005
1006
1007
+ pub fn parse_unlisten(&mut self) -> Result<Statement, ParserError> {
1008
+ let channel = if self.consume_token(&Token::Mul) {
1009
+ Ident::new(Expr::Wildcard(AttachedToken::empty()).to_string())
1010
+ } else {
1011
+ match self.parse_identifier(false) {
1012
+ Ok(expr) => expr,
1013
+ _ => {
1014
+ self.prev_token();
1015
+ return self.expected("wildcard or identifier", self.peek_token());
1016
+ }
1017
+ }
1018
+ };
1019
+ Ok(Statement::UNLISTEN { channel })
1020
+ }
1021
+
1006
1022
pub fn parse_notify(&mut self) -> Result<Statement, ParserError> {
1007
1023
let channel = self.parse_identifier(false)?;
1008
1024
let payload = if self.consume_token(&Token::Comma) {
@@ -2927,7 +2943,7 @@ impl<'a> Parser<'a> {
2927
2943
} else if Token::LBracket == tok {
2928
2944
if dialect_of!(self is PostgreSqlDialect | DuckDbDialect | GenericDialect) {
2929
2945
self.parse_subscript(expr)
2930
- } else if dialect_of!(self is SnowflakeDialect) {
2946
+ } else if dialect_of!(self is SnowflakeDialect) || self.dialect.supports_partiql() {
2931
2947
self.prev_token();
2932
2948
self.parse_json_access(expr)
2933
2949
} else {
@@ -3063,6 +3079,14 @@ impl<'a> Parser<'a> {
3063
3079
}
3064
3080
3065
3081
fn parse_json_access(&mut self, expr: Expr) -> Result<Expr, ParserError> {
3082
+ let path = self.parse_json_path()?;
3083
+ Ok(Expr::JsonAccess {
3084
+ value: Box::new(expr),
3085
+ path,
3086
+ })
3087
+ }
3088
+
3089
+ fn parse_json_path(&mut self) -> Result<JsonPath, ParserError> {
3066
3090
let mut path = Vec::new();
3067
3091
loop {
3068
3092
match self.next_token().token {
@@ -3086,10 +3110,7 @@ impl<'a> Parser<'a> {
3086
3110
}
3087
3111
3088
3112
debug_assert!(!path.is_empty());
3089
- Ok(Expr::JsonAccess {
3090
- value: Box::new(expr),
3091
- path: JsonPath { path },
3092
- })
3113
+ Ok(JsonPath { path })
3093
3114
}
3094
3115
3095
3116
pub fn parse_map_access(&mut self, expr: Expr) -> Result<Expr, ParserError> {
@@ -3522,16 +3543,11 @@ impl<'a> Parser<'a> {
3522
3543
// e.g. `SELECT 1, 2, FROM t`
3523
3544
// https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#trailing_commas
3524
3545
// https://docs.snowflake.com/en/release-notes/2024/8_11#select-supports-trailing-commas
3525
- //
3526
- // This pattern could be captured better with RAII type semantics, but it's quite a bit of
3527
- // code to add for just one case, so we'll just do it manually here.
3528
- let old_value = self.options.trailing_commas;
3529
- self.options.trailing_commas |= self.dialect.supports_projection_trailing_commas();
3530
3546
3531
- let ret = self.parse_comma_separated(|p| p.parse_select_item());
3532
- self.options.trailing_commas = old_value ;
3547
+ let trailing_commas =
3548
+ self.options.trailing_commas | self.dialect.supports_projection_trailing_commas() ;
3533
3549
3534
- ret
3550
+ self.parse_comma_separated_with_trailing_commas(|p| p.parse_select_item(), trailing_commas)
3535
3551
}
3536
3552
3537
3553
pub fn parse_actions_list(&mut self) -> Result<Vec<ParsedAction>, ParserError> {
@@ -3558,11 +3574,12 @@ impl<'a> Parser<'a> {
3558
3574
}
3559
3575
3560
3576
/// Parse the comma of a comma-separated syntax element.
3577
+ /// Allows for control over trailing commas
3561
3578
/// Returns true if there is a next element
3562
- fn is_parse_comma_separated_end (&mut self) -> bool {
3579
+ fn is_parse_comma_separated_end_with_trailing_commas (&mut self, trailing_commas: bool ) -> bool {
3563
3580
if !self.consume_token(&Token::Comma) {
3564
3581
true
3565
- } else if self.options. trailing_commas {
3582
+ } else if trailing_commas {
3566
3583
let token = self.peek_token().token;
3567
3584
match token {
3568
3585
Token::Word(ref kw)
@@ -3580,15 +3597,34 @@ impl<'a> Parser<'a> {
3580
3597
}
3581
3598
}
3582
3599
3600
+ /// Parse the comma of a comma-separated syntax element.
3601
+ /// Returns true if there is a next element
3602
+ fn is_parse_comma_separated_end(&mut self) -> bool {
3603
+ self.is_parse_comma_separated_end_with_trailing_commas(self.options.trailing_commas)
3604
+ }
3605
+
3583
3606
/// Parse a comma-separated list of 1+ items accepted by `F`
3584
- pub fn parse_comma_separated<T, F>(&mut self, mut f: F) -> Result<Vec<T>, ParserError>
3607
+ pub fn parse_comma_separated<T, F>(&mut self, f: F) -> Result<Vec<T>, ParserError>
3608
+ where
3609
+ F: FnMut(&mut Parser<'a>) -> Result<T, ParserError>,
3610
+ {
3611
+ self.parse_comma_separated_with_trailing_commas(f, self.options.trailing_commas)
3612
+ }
3613
+
3614
+ /// Parse a comma-separated list of 1+ items accepted by `F`
3615
+ /// Allows for control over trailing commas
3616
+ fn parse_comma_separated_with_trailing_commas<T, F>(
3617
+ &mut self,
3618
+ mut f: F,
3619
+ trailing_commas: bool,
3620
+ ) -> Result<Vec<T>, ParserError>
3585
3621
where
3586
3622
F: FnMut(&mut Parser<'a>) -> Result<T, ParserError>,
3587
3623
{
3588
3624
let mut values = vec![];
3589
3625
loop {
3590
3626
values.push(f(self)?);
3591
- if self.is_parse_comma_separated_end( ) {
3627
+ if self.is_parse_comma_separated_end_with_trailing_commas(trailing_commas ) {
3592
3628
break;
3593
3629
}
3594
3630
}
@@ -10326,6 +10362,11 @@ impl<'a> Parser<'a> {
10326
10362
} else {
10327
10363
let name = self.parse_object_name(true)?;
10328
10364
10365
+ let json_path = match self.peek_token().token {
10366
+ Token::LBracket if self.dialect.supports_partiql() => Some(self.parse_json_path()?),
10367
+ _ => None,
10368
+ };
10369
+
10329
10370
let partitions: Vec<Ident> = if dialect_of!(self is MySqlDialect | GenericDialect)
10330
10371
&& self.parse_keyword(Keyword::PARTITION)
10331
10372
{
@@ -10368,6 +10409,7 @@ impl<'a> Parser<'a> {
10368
10409
version,
10369
10410
partitions,
10370
10411
with_ordinality,
10412
+ json_path,
10371
10413
};
10372
10414
10373
10415
while let Some(kw) = self.parse_one_of_keywords(&[Keyword::PIVOT, Keyword::UNPIVOT]) {
0 commit comments