Add TrimWhereField for parse_trim_expr (#334)

* Remove Box from `trim_where`

* Add TrimWhereField for `parse_trim_expr`

* Add negative test case
This commit is contained in:
Jiseok CHOI 2021-08-23 23:51:36 +09:00 committed by GitHub
parent 5ce67177b3
commit af1ac865b1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 41 additions and 5 deletions

View file

@ -40,7 +40,7 @@ pub use self::query::{
Query, Select, SelectItem, SetExpr, SetOperator, TableAlias, TableFactor, TableWithJoins, Top, Query, Select, SelectItem, SetExpr, SetOperator, TableAlias, TableFactor, TableWithJoins, Top,
Values, With, Values, With,
}; };
pub use self::value::{DateTimeField, Value}; pub use self::value::{DateTimeField, TrimWhereField, Value};
struct DisplaySeparated<'a, T> struct DisplaySeparated<'a, T>
where where
@ -231,7 +231,7 @@ pub enum Expr {
Trim { Trim {
expr: Box<Expr>, expr: Box<Expr>,
// ([BOTH | LEADING | TRAILING], <expr>) // ([BOTH | LEADING | TRAILING], <expr>)
trim_where: Option<(Box<Ident>, Box<Expr>)>, trim_where: Option<(TrimWhereField, Box<Expr>)>,
}, },
/// `expr COLLATE collation` /// `expr COLLATE collation`
Collate { Collate {

View file

@ -157,3 +157,22 @@ impl<'a> fmt::Display for EscapeSingleQuoteString<'a> {
pub fn escape_single_quote_string(s: &str) -> EscapeSingleQuoteString<'_> { pub fn escape_single_quote_string(s: &str) -> EscapeSingleQuoteString<'_> {
EscapeSingleQuoteString(s) EscapeSingleQuoteString(s)
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TrimWhereField {
Both,
Leading,
Trailing,
}
impl fmt::Display for TrimWhereField {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use TrimWhereField::*;
f.write_str(match self {
Both => "BOTH",
Leading => "LEADING",
Trailing => "TRAILING",
})
}
}

View file

@ -666,10 +666,10 @@ impl<'a> Parser<'a> {
.iter() .iter()
.any(|d| word.keyword == *d) .any(|d| word.keyword == *d)
{ {
let ident = self.parse_identifier()?; let trim_where = self.parse_trim_where()?;
let sub_expr = self.parse_expr()?; let sub_expr = self.parse_expr()?;
self.expect_keyword(Keyword::FROM)?; self.expect_keyword(Keyword::FROM)?;
where_expr = Some((ident, sub_expr)) where_expr = Some((trim_where, Box::new(sub_expr)));
} }
} }
let expr = self.parse_expr()?; let expr = self.parse_expr()?;
@ -677,10 +677,22 @@ impl<'a> Parser<'a> {
Ok(Expr::Trim { Ok(Expr::Trim {
expr: Box::new(expr), expr: Box::new(expr),
trim_where: where_expr.map(|(ident, expr)| (Box::new(ident), Box::new(expr))), trim_where: where_expr,
}) })
} }
pub fn parse_trim_where(&mut self) -> Result<TrimWhereField, ParserError> {
match self.next_token() {
Token::Word(w) => match w.keyword {
Keyword::BOTH => Ok(TrimWhereField::Both),
Keyword::LEADING => Ok(TrimWhereField::Leading),
Keyword::TRAILING => Ok(TrimWhereField::Trailing),
_ => self.expected("trim_where field", Token::Word(w))?,
},
unexpected => self.expected("trim_where field", unexpected),
}
}
/// Parse a SQL LISTAGG expression, e.g. `LISTAGG(...) WITHIN GROUP (ORDER BY ...)`. /// Parse a SQL LISTAGG expression, e.g. `LISTAGG(...) WITHIN GROUP (ORDER BY ...)`.
pub fn parse_listagg_expr(&mut self) -> Result<Expr, ParserError> { pub fn parse_listagg_expr(&mut self) -> Result<Expr, ParserError> {
self.expect_token(&Token::LParen)?; self.expect_token(&Token::LParen)?;

View file

@ -2765,6 +2765,11 @@ fn parse_trim() {
); );
one_statement_parses_to("SELECT TRIM(' foo ')", "SELECT TRIM(' foo ')"); one_statement_parses_to("SELECT TRIM(' foo ')", "SELECT TRIM(' foo ')");
assert_eq!(
ParserError::ParserError("Expected ), found: 'xyz'".to_owned()),
parse_sql_statements("SELECT TRIM(FOO 'xyz' FROM 'xyzfooxyz')").unwrap_err()
);
} }
#[test] #[test]