mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-07-08 01:15:00 +00:00
Support TRIM
from with optional FROM
clause (#573)
* Split trimwhereFlag and trim_char expr to seperate members of Expr::Trim * update trim parsing logic to handle no flag + char from expr combo * add tests * Allow trim flag without trim_what expr * Add trim flag without trim_what test
This commit is contained in:
parent
31ba0012f7
commit
42c5d43b45
3 changed files with 42 additions and 18 deletions
|
@ -331,13 +331,14 @@ pub enum Expr {
|
|||
substring_from: Option<Box<Expr>>,
|
||||
substring_for: Option<Box<Expr>>,
|
||||
},
|
||||
/// TRIM([BOTH | LEADING | TRAILING] <expr> [FROM <expr>])\
|
||||
/// TRIM([BOTH | LEADING | TRAILING] [<expr> FROM] <expr>)\
|
||||
/// Or\
|
||||
/// TRIM(<expr>)
|
||||
Trim {
|
||||
expr: Box<Expr>,
|
||||
// ([BOTH | LEADING | TRAILING], <expr>)
|
||||
trim_where: Option<(TrimWhereField, Box<Expr>)>,
|
||||
// ([BOTH | LEADING | TRAILING]
|
||||
trim_where: Option<TrimWhereField>,
|
||||
trim_what: Option<Box<Expr>>,
|
||||
},
|
||||
/// `expr COLLATE collation`
|
||||
Collate {
|
||||
|
@ -632,10 +633,17 @@ impl fmt::Display for Expr {
|
|||
}
|
||||
Expr::IsDistinctFrom(a, b) => write!(f, "{} IS DISTINCT FROM {}", a, b),
|
||||
Expr::IsNotDistinctFrom(a, b) => write!(f, "{} IS NOT DISTINCT FROM {}", a, b),
|
||||
Expr::Trim { expr, trim_where } => {
|
||||
Expr::Trim {
|
||||
expr,
|
||||
trim_where,
|
||||
trim_what,
|
||||
} => {
|
||||
write!(f, "TRIM(")?;
|
||||
if let Some((ident, trim_char)) = trim_where {
|
||||
write!(f, "{} {} FROM {}", ident, trim_char, expr)?;
|
||||
if let Some(ident) = trim_where {
|
||||
write!(f, "{} ", ident)?;
|
||||
}
|
||||
if let Some(trim_char) = trim_what {
|
||||
write!(f, "{} FROM {}", trim_char, expr)?;
|
||||
} else {
|
||||
write!(f, "{}", expr)?;
|
||||
}
|
||||
|
|
|
@ -881,29 +881,37 @@ impl<'a> Parser<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
/// TRIM (WHERE 'text' FROM 'text')\
|
||||
/// TRIM ([WHERE] ['text' FROM] 'text')\
|
||||
/// TRIM ('text')
|
||||
pub fn parse_trim_expr(&mut self) -> Result<Expr, ParserError> {
|
||||
self.expect_token(&Token::LParen)?;
|
||||
let mut where_expr = None;
|
||||
let mut trim_where = None;
|
||||
if let Token::Word(word) = self.peek_token() {
|
||||
if [Keyword::BOTH, Keyword::LEADING, Keyword::TRAILING]
|
||||
.iter()
|
||||
.any(|d| word.keyword == *d)
|
||||
{
|
||||
let trim_where = self.parse_trim_where()?;
|
||||
let sub_expr = self.parse_expr()?;
|
||||
self.expect_keyword(Keyword::FROM)?;
|
||||
where_expr = Some((trim_where, Box::new(sub_expr)));
|
||||
trim_where = Some(self.parse_trim_where()?);
|
||||
}
|
||||
}
|
||||
let expr = self.parse_expr()?;
|
||||
self.expect_token(&Token::RParen)?;
|
||||
|
||||
Ok(Expr::Trim {
|
||||
expr: Box::new(expr),
|
||||
trim_where: where_expr,
|
||||
})
|
||||
if self.parse_keyword(Keyword::FROM) {
|
||||
let trim_what = Box::new(expr);
|
||||
let expr = self.parse_expr()?;
|
||||
self.expect_token(&Token::RParen)?;
|
||||
Ok(Expr::Trim {
|
||||
expr: Box::new(expr),
|
||||
trim_where,
|
||||
trim_what: Some(trim_what),
|
||||
})
|
||||
} else {
|
||||
self.expect_token(&Token::RParen)?;
|
||||
Ok(Expr::Trim {
|
||||
expr: Box::new(expr),
|
||||
trim_where,
|
||||
trim_what: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_trim_where(&mut self) -> Result<TrimWhereField, ParserError> {
|
||||
|
|
|
@ -3928,7 +3928,15 @@ fn parse_trim() {
|
|||
"SELECT TRIM(TRAILING 'xyz' FROM 'xyzfooxyz')",
|
||||
);
|
||||
|
||||
one_statement_parses_to(
|
||||
"SELECT TRIM('xyz' FROM 'xyzfooxyz')",
|
||||
"SELECT TRIM('xyz' FROM 'xyzfooxyz')",
|
||||
);
|
||||
one_statement_parses_to("SELECT TRIM(' foo ')", "SELECT TRIM(' foo ')");
|
||||
one_statement_parses_to(
|
||||
"SELECT TRIM(LEADING ' foo ')",
|
||||
"SELECT TRIM(LEADING ' foo ')",
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
ParserError::ParserError("Expected ), found: 'xyz'".to_owned()),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue