Skip to content

Commit d526a64

Browse files
committed
Add support for PostgreSQL LISTEN/NOTIFY
1 parent 38f1e57 commit d526a64

File tree

4 files changed

+80
-0
lines changed

4 files changed

+80
-0
lines changed

src/ast/mod.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3278,6 +3278,23 @@ pub enum Statement {
32783278
include_final: bool,
32793279
deduplicate: Option<Deduplicate>,
32803280
},
3281+
/// ```sql
3282+
/// LISTEN
3283+
/// ```
3284+
/// listen for a notification channel
3285+
///
3286+
/// See Postgres <https://www.postgresql.org/docs/current/sql-notify.html>
3287+
LISTEN { channel: Ident },
3288+
/// ```sql
3289+
/// NOTIFY channel [ , payload ]
3290+
/// ```
3291+
/// send a notification event together with an optional “payload” string to channel
3292+
///
3293+
/// See Postgres <https://www.postgresql.org/docs/current/sql-listen.html>
3294+
NOTIFY {
3295+
channel: Ident,
3296+
payload: Option<String>,
3297+
},
32813298
}
32823299

32833300
impl fmt::Display for Statement {
@@ -4782,6 +4799,17 @@ impl fmt::Display for Statement {
47824799
}
47834800
Ok(())
47844801
}
4802+
Statement::LISTEN { channel } => {
4803+
write!(f, "LISTEN {channel}")?;
4804+
Ok(())
4805+
}
4806+
Statement::NOTIFY { channel, payload } => {
4807+
write!(f, "NOTIFY {channel}")?;
4808+
if let Some(payload) = payload {
4809+
write!(f, ", '{payload}'")?;
4810+
}
4811+
Ok(())
4812+
}
47854813
}
47864814
}
47874815
}

src/keywords.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@ define_keywords!(
437437
LIKE_REGEX,
438438
LIMIT,
439439
LINES,
440+
LISTEN,
440441
LN,
441442
LOAD,
442443
LOCAL,
@@ -512,6 +513,7 @@ define_keywords!(
512513
NOSUPERUSER,
513514
NOT,
514515
NOTHING,
516+
NOTIFY,
515517
NOWAIT,
516518
NO_WRITE_TO_BINLOG,
517519
NTH_VALUE,

src/parser/mod.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,10 @@ impl<'a> Parser<'a> {
532532
Keyword::EXECUTE => self.parse_execute(),
533533
Keyword::PREPARE => self.parse_prepare(),
534534
Keyword::MERGE => self.parse_merge(),
535+
// `LISTEN` and `NOTIFY` are Postgres-specific
536+
// syntaxes. They are used for Postgres statement.
537+
Keyword::LISTEN => self.parse_listen(),
538+
Keyword::NOTIFY => self.parse_notify(),
535539
// `PRAGMA` is sqlite specific https://www.sqlite.org/pragma.html
536540
Keyword::PRAGMA => self.parse_pragma(),
537541
Keyword::UNLOAD => self.parse_unload(),
@@ -946,6 +950,21 @@ impl<'a> Parser<'a> {
946950
Ok(Statement::ReleaseSavepoint { name })
947951
}
948952

953+
pub fn parse_listen(&mut self) -> Result<Statement, ParserError> {
954+
let channel = self.parse_identifier(false)?;
955+
Ok(Statement::LISTEN { channel })
956+
}
957+
958+
pub fn parse_notify(&mut self) -> Result<Statement, ParserError> {
959+
let channel = self.parse_identifier(false)?;
960+
let payload = if self.consume_token(&Token::Comma) {
961+
Some(self.parse_literal_string()?)
962+
} else {
963+
None
964+
};
965+
Ok(Statement::NOTIFY { channel, payload })
966+
}
967+
949968
/// Parse an expression prefix.
950969
pub fn parse_prefix(&mut self) -> Result<Expr, ParserError> {
951970
// allow the dialect to override prefix parsing

tests/sqlparser_common.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11460,3 +11460,34 @@ fn test_try_convert() {
1146011460
all_dialects_where(|d| d.supports_try_convert() && !d.convert_type_before_value());
1146111461
dialects.verified_expr("TRY_CONVERT('foo', VARCHAR(MAX))");
1146211462
}
11463+
11464+
#[test]
11465+
fn test_listen() {
11466+
match verified_stmt("LISTEN test1") {
11467+
Statement::LISTEN { channel } => {
11468+
assert_eq!(Ident::new("test1"), channel);
11469+
}
11470+
_ => unreachable!(),
11471+
}
11472+
}
11473+
11474+
#[test]
11475+
fn test_notify() {
11476+
match verified_stmt("NOTIFY test1") {
11477+
Statement::NOTIFY { channel, payload } => {
11478+
assert_eq!(Ident::new("test1"), channel);
11479+
assert_eq!(payload, None);
11480+
}
11481+
_ => unreachable!(),
11482+
}
11483+
match verified_stmt("NOTIFY test1, 'this is a test notification'") {
11484+
Statement::NOTIFY {
11485+
channel,
11486+
payload: Some(payload),
11487+
} => {
11488+
assert_eq!(Ident::new("test1"), channel);
11489+
assert_eq!("this is a test notification", payload);
11490+
}
11491+
_ => unreachable!(),
11492+
}
11493+
}

0 commit comments

Comments
 (0)