From 021fd12a3645b7d8ee45fd022f9ea4866d58bcbb Mon Sep 17 00:00:00 2001 From: Dandandan Date: Wed, 15 Jul 2020 20:35:11 +0200 Subject: [PATCH 1/5] Implement ASSERT statement --- src/ast/mod.rs | 14 ++++++++++++++ src/dialect/keywords.rs | 1 + src/parser.rs | 13 +++++++++++++ tests/sqlparser_common.rs | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 9486f16c6..507889c97 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -551,6 +551,12 @@ pub enum Statement { Rollback { chain: bool }, /// CREATE SCHEMA CreateSchema { schema_name: ObjectName }, + + // ASSERT [, ] + Assert { + condition: Box, + message: Option>, + }, } impl fmt::Display for Statement { @@ -810,6 +816,14 @@ impl fmt::Display for Statement { write!(f, "ROLLBACK{}", if *chain { " AND CHAIN" } else { "" },) } Statement::CreateSchema { schema_name } => write!(f, "CREATE SCHEMA {}", schema_name), + Statement::Assert { condition, message } => { + write!(f, "ASSERT {}", condition)?; + + if let Some(m) = message { + write!(f, ", {}", m)?; + } + Ok(()) + } } } } diff --git a/src/dialect/keywords.rs b/src/dialect/keywords.rs index b6cfe35e9..dd663e9b6 100644 --- a/src/dialect/keywords.rs +++ b/src/dialect/keywords.rs @@ -79,6 +79,7 @@ define_keywords!( AS, ASC, ASENSITIVE, + ASSERT, ASYMMETRIC, AT, ATOMIC, diff --git a/src/parser.rs b/src/parser.rs index a1e542484..6dd98dbdc 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -148,6 +148,7 @@ impl Parser { Keyword::BEGIN => Ok(self.parse_begin()?), Keyword::COMMIT => Ok(self.parse_commit()?), Keyword::ROLLBACK => Ok(self.parse_rollback()?), + Keyword::ASSERT => Ok(self.parse_assert()?), _ => self.expected("an SQL statement", Token::Word(w)), }, Token::LParen => { @@ -179,6 +180,18 @@ impl Parser { } Ok(expr) } + pub fn parse_assert(&mut self) -> Result { + let condition = self.parse_expr()?; + let mut message = None; + if self.consume_token(&Token::Comma) { + message = Some(Box::new(self.parse_expr()?)); + } + + Ok(Statement::Assert { + condition: Box::new(condition), + message, + }) + } /// Parse an expression prefix pub fn parse_prefix(&mut self) -> Result { diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 79e922c87..eed7c84b7 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -1156,6 +1156,42 @@ fn parse_create_table_with_multiple_on_delete_fails() { .expect_err("should have failed"); } +#[test] +fn parse_assert() { + let sql = "ASSERT (SELECT COUNT(*) FROM table) > 0"; + let ast = one_statement_parses_to(sql, "ASSERT (SELECT COUNT(*) FROM table) > 0"); + match ast { + Statement::Assert { + condition: _condition, + message, + } => { + assert!(message.is_none()); + } + _ => unreachable!(), + } +} + +#[test] +fn parse_assert_message() { + let sql = "ASSERT (SELECT COUNT(*) FROM table) > 0, 'No rows in table'"; + let ast = one_statement_parses_to( + sql, + "ASSERT (SELECT COUNT(*) FROM table) > 0, 'No rows in table'", + ); + match ast { + Statement::Assert { + condition: _condition, + message: Some(message), + } => { + match *message { + Expr::Value(Value::SingleQuotedString(s)) => assert_eq!(s, "No rows in table"), + _ => unreachable!(), + }; + } + _ => unreachable!(), + } +} + #[test] fn parse_create_schema() { let sql = "CREATE SCHEMA X"; From 7c1898d668952d9c51e6328fa7c542f82a9fed48 Mon Sep 17 00:00:00 2001 From: Dandandan Date: Wed, 15 Jul 2020 20:49:15 +0200 Subject: [PATCH 2/5] Parse either comma or AS --- src/parser.rs | 9 +++++---- tests/sqlparser_common.rs | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 6dd98dbdc..248e0a528 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -182,10 +182,11 @@ impl Parser { } pub fn parse_assert(&mut self) -> Result { let condition = self.parse_expr()?; - let mut message = None; - if self.consume_token(&Token::Comma) { - message = Some(Box::new(self.parse_expr()?)); - } + let message = if self.consume_token(&Token::Comma) || self.parse_keyword(Keyword::AS) { + Some(Box::new(self.parse_expr()?)) + } else { + None + }; Ok(Statement::Assert { condition: Box::new(condition), diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index eed7c84b7..5ae225521 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -1173,10 +1173,10 @@ fn parse_assert() { #[test] fn parse_assert_message() { - let sql = "ASSERT (SELECT COUNT(*) FROM table) > 0, 'No rows in table'"; + let sql = "ASSERT (SELECT COUNT(*) FROM table) > 0 AS 'No rows in table'"; let ast = one_statement_parses_to( sql, - "ASSERT (SELECT COUNT(*) FROM table) > 0, 'No rows in table'", + "ASSERT (SELECT COUNT(*) FROM table) > 0 AS 'No rows in table'", ); match ast { Statement::Assert { From 79165fc0885f38ae37742d193809362bcb242b53 Mon Sep 17 00:00:00 2001 From: Dandandan Date: Wed, 15 Jul 2020 20:59:42 +0200 Subject: [PATCH 3/5] Support both comma and AS --- src/ast/mod.rs | 12 +++++++++--- src/parser.rs | 9 ++++++--- tests/sqlparser_common.rs | 6 +++++- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 507889c97..2a9567041 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -552,9 +552,11 @@ pub enum Statement { /// CREATE SCHEMA CreateSchema { schema_name: ObjectName }, - // ASSERT [, ] + /// ASSERT [AS ] Assert { condition: Box, + // AS or , + separator: String, message: Option>, }, } @@ -816,11 +818,15 @@ impl fmt::Display for Statement { write!(f, "ROLLBACK{}", if *chain { " AND CHAIN" } else { "" },) } Statement::CreateSchema { schema_name } => write!(f, "CREATE SCHEMA {}", schema_name), - Statement::Assert { condition, message } => { + Statement::Assert { + condition, + separator, + message, + } => { write!(f, "ASSERT {}", condition)?; if let Some(m) = message { - write!(f, ", {}", m)?; + write!(f, " {} {}", separator, m)?; } Ok(()) } diff --git a/src/parser.rs b/src/parser.rs index 248e0a528..ca387eaef 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -182,14 +182,17 @@ impl Parser { } pub fn parse_assert(&mut self) -> Result { let condition = self.parse_expr()?; - let message = if self.consume_token(&Token::Comma) || self.parse_keyword(Keyword::AS) { - Some(Box::new(self.parse_expr()?)) + let (separator, message) = if self.consume_token(&Token::Comma) { + (",".to_string(), Some(Box::new(self.parse_expr()?))) + } else if self.parse_keyword(Keyword::AS) { + ("AS".to_string(), Some(Box::new(self.parse_expr()?))) } else { - None + ("".to_string(), None) }; Ok(Statement::Assert { condition: Box::new(condition), + separator, message, }) } diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 5ae225521..0c0255668 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -1163,9 +1163,11 @@ fn parse_assert() { match ast { Statement::Assert { condition: _condition, + separator, message, } => { - assert!(message.is_none()); + assert_eq!(message, None); + assert_eq!(separator, ""); } _ => unreachable!(), } @@ -1182,7 +1184,9 @@ fn parse_assert_message() { Statement::Assert { condition: _condition, message: Some(message), + separator } => { + assert_eq!(separator, "AS"); match *message { Expr::Value(Value::SingleQuotedString(s)) => assert_eq!(s, "No rows in table"), _ => unreachable!(), From e8f910a82c670327a61a3fba48aa4c3db1856afa Mon Sep 17 00:00:00 2001 From: Dandandan Date: Wed, 15 Jul 2020 21:02:33 +0200 Subject: [PATCH 4/5] Formatting --- tests/sqlparser_common.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 0c0255668..a3e09b70a 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -1184,7 +1184,7 @@ fn parse_assert_message() { Statement::Assert { condition: _condition, message: Some(message), - separator + separator, } => { assert_eq!(separator, "AS"); match *message { From 5a98e61a6cbb8a3ab58c81b491119b3796ea498a Mon Sep 17 00:00:00 2001 From: Dandandan Date: Thu, 16 Jul 2020 17:23:46 +0200 Subject: [PATCH 5/5] Remove box --- src/ast/mod.rs | 4 ++-- src/parser.rs | 6 +++--- tests/sqlparser_common.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 2a9567041..9e0992bce 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -554,10 +554,10 @@ pub enum Statement { /// ASSERT [AS ] Assert { - condition: Box, + condition: Expr, // AS or , separator: String, - message: Option>, + message: Option, }, } diff --git a/src/parser.rs b/src/parser.rs index ca387eaef..f5389ccd8 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -183,15 +183,15 @@ impl Parser { pub fn parse_assert(&mut self) -> Result { let condition = self.parse_expr()?; let (separator, message) = if self.consume_token(&Token::Comma) { - (",".to_string(), Some(Box::new(self.parse_expr()?))) + (",".to_string(), Some(self.parse_expr()?)) } else if self.parse_keyword(Keyword::AS) { - ("AS".to_string(), Some(Box::new(self.parse_expr()?))) + ("AS".to_string(), Some(self.parse_expr()?)) } else { ("".to_string(), None) }; Ok(Statement::Assert { - condition: Box::new(condition), + condition, separator, message, }) diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index a3e09b70a..547b8c11f 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -1187,7 +1187,7 @@ fn parse_assert_message() { separator, } => { assert_eq!(separator, "AS"); - match *message { + match message { Expr::Value(Value::SingleQuotedString(s)) => assert_eq!(s, "No rows in table"), _ => unreachable!(), };