Skip to content

Commit 42c5d43

Browse files
authored
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
1 parent 31ba001 commit 42c5d43

File tree

3 files changed

+42
-18
lines changed

3 files changed

+42
-18
lines changed

src/ast/mod.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -331,13 +331,14 @@ pub enum Expr {
331331
substring_from: Option<Box<Expr>>,
332332
substring_for: Option<Box<Expr>>,
333333
},
334-
/// TRIM([BOTH | LEADING | TRAILING] <expr> [FROM <expr>])\
334+
/// TRIM([BOTH | LEADING | TRAILING] [<expr> FROM] <expr>)\
335335
/// Or\
336336
/// TRIM(<expr>)
337337
Trim {
338338
expr: Box<Expr>,
339-
// ([BOTH | LEADING | TRAILING], <expr>)
340-
trim_where: Option<(TrimWhereField, Box<Expr>)>,
339+
// ([BOTH | LEADING | TRAILING]
340+
trim_where: Option<TrimWhereField>,
341+
trim_what: Option<Box<Expr>>,
341342
},
342343
/// `expr COLLATE collation`
343344
Collate {
@@ -632,10 +633,17 @@ impl fmt::Display for Expr {
632633
}
633634
Expr::IsDistinctFrom(a, b) => write!(f, "{} IS DISTINCT FROM {}", a, b),
634635
Expr::IsNotDistinctFrom(a, b) => write!(f, "{} IS NOT DISTINCT FROM {}", a, b),
635-
Expr::Trim { expr, trim_where } => {
636+
Expr::Trim {
637+
expr,
638+
trim_where,
639+
trim_what,
640+
} => {
636641
write!(f, "TRIM(")?;
637-
if let Some((ident, trim_char)) = trim_where {
638-
write!(f, "{} {} FROM {}", ident, trim_char, expr)?;
642+
if let Some(ident) = trim_where {
643+
write!(f, "{} ", ident)?;
644+
}
645+
if let Some(trim_char) = trim_what {
646+
write!(f, "{} FROM {}", trim_char, expr)?;
639647
} else {
640648
write!(f, "{}", expr)?;
641649
}

src/parser.rs

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -881,29 +881,37 @@ impl<'a> Parser<'a> {
881881
})
882882
}
883883

884-
/// TRIM (WHERE 'text' FROM 'text')\
884+
/// TRIM ([WHERE] ['text' FROM] 'text')\
885885
/// TRIM ('text')
886886
pub fn parse_trim_expr(&mut self) -> Result<Expr, ParserError> {
887887
self.expect_token(&Token::LParen)?;
888-
let mut where_expr = None;
888+
let mut trim_where = None;
889889
if let Token::Word(word) = self.peek_token() {
890890
if [Keyword::BOTH, Keyword::LEADING, Keyword::TRAILING]
891891
.iter()
892892
.any(|d| word.keyword == *d)
893893
{
894-
let trim_where = self.parse_trim_where()?;
895-
let sub_expr = self.parse_expr()?;
896-
self.expect_keyword(Keyword::FROM)?;
897-
where_expr = Some((trim_where, Box::new(sub_expr)));
894+
trim_where = Some(self.parse_trim_where()?);
898895
}
899896
}
900897
let expr = self.parse_expr()?;
901-
self.expect_token(&Token::RParen)?;
902-
903-
Ok(Expr::Trim {
904-
expr: Box::new(expr),
905-
trim_where: where_expr,
906-
})
898+
if self.parse_keyword(Keyword::FROM) {
899+
let trim_what = Box::new(expr);
900+
let expr = self.parse_expr()?;
901+
self.expect_token(&Token::RParen)?;
902+
Ok(Expr::Trim {
903+
expr: Box::new(expr),
904+
trim_where,
905+
trim_what: Some(trim_what),
906+
})
907+
} else {
908+
self.expect_token(&Token::RParen)?;
909+
Ok(Expr::Trim {
910+
expr: Box::new(expr),
911+
trim_where,
912+
trim_what: None,
913+
})
914+
}
907915
}
908916

909917
pub fn parse_trim_where(&mut self) -> Result<TrimWhereField, ParserError> {

tests/sqlparser_common.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3928,7 +3928,15 @@ fn parse_trim() {
39283928
"SELECT TRIM(TRAILING 'xyz' FROM 'xyzfooxyz')",
39293929
);
39303930

3931+
one_statement_parses_to(
3932+
"SELECT TRIM('xyz' FROM 'xyzfooxyz')",
3933+
"SELECT TRIM('xyz' FROM 'xyzfooxyz')",
3934+
);
39313935
one_statement_parses_to("SELECT TRIM(' foo ')", "SELECT TRIM(' foo ')");
3936+
one_statement_parses_to(
3937+
"SELECT TRIM(LEADING ' foo ')",
3938+
"SELECT TRIM(LEADING ' foo ')",
3939+
);
39323940

39333941
assert_eq!(
39343942
ParserError::ParserError("Expected ), found: 'xyz'".to_owned()),

0 commit comments

Comments
 (0)