mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-22 15:04:04 +00:00
Support TRIM syntax (#331)
* Support TRIM syntax - Implement the following cases - TRIM([BOTH | LEADING | TRAILING] <expr> [FROM <expr>]) - TRIM(<expr>) * Resolve 1.54.0 clippy error - Remove needless borrow * Add test cases for TRIM
This commit is contained in:
parent
67e17b27f5
commit
e548d38de8
3 changed files with 64 additions and 0 deletions
|
@ -219,6 +219,14 @@ pub enum Expr {
|
||||||
substring_from: Option<Box<Expr>>,
|
substring_from: Option<Box<Expr>>,
|
||||||
substring_for: Option<Box<Expr>>,
|
substring_for: Option<Box<Expr>>,
|
||||||
},
|
},
|
||||||
|
/// TRIM([BOTH | LEADING | TRAILING] <expr> [FROM <expr>])\
|
||||||
|
/// Or\
|
||||||
|
/// TRIM(<expr>)
|
||||||
|
Trim {
|
||||||
|
expr: Box<Expr>,
|
||||||
|
// ([BOTH | LEADING | TRAILING], <expr>)
|
||||||
|
trim_where: Option<(Box<Ident>, Box<Expr>)>,
|
||||||
|
},
|
||||||
/// `expr COLLATE collation`
|
/// `expr COLLATE collation`
|
||||||
Collate {
|
Collate {
|
||||||
expr: Box<Expr>,
|
expr: Box<Expr>,
|
||||||
|
@ -361,6 +369,16 @@ impl fmt::Display for Expr {
|
||||||
write!(f, " FOR {}", from_part)?;
|
write!(f, " FOR {}", from_part)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
write!(f, ")")
|
||||||
|
}
|
||||||
|
Expr::Trim { expr, trim_where } => {
|
||||||
|
write!(f, "TRIM(")?;
|
||||||
|
if let Some((ident, trim_char)) = trim_where {
|
||||||
|
write!(f, "{} {} FROM {}", ident, trim_char, expr)?;
|
||||||
|
} else {
|
||||||
|
write!(f, "{}", expr)?;
|
||||||
|
}
|
||||||
|
|
||||||
write!(f, ")")
|
write!(f, ")")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -357,6 +357,7 @@ impl<'a> Parser<'a> {
|
||||||
Keyword::EXISTS => self.parse_exists_expr(),
|
Keyword::EXISTS => self.parse_exists_expr(),
|
||||||
Keyword::EXTRACT => self.parse_extract_expr(),
|
Keyword::EXTRACT => self.parse_extract_expr(),
|
||||||
Keyword::SUBSTRING => self.parse_substring_expr(),
|
Keyword::SUBSTRING => self.parse_substring_expr(),
|
||||||
|
Keyword::TRIM => self.parse_trim_expr(),
|
||||||
Keyword::INTERVAL => self.parse_literal_interval(),
|
Keyword::INTERVAL => self.parse_literal_interval(),
|
||||||
Keyword::LISTAGG => self.parse_listagg_expr(),
|
Keyword::LISTAGG => self.parse_listagg_expr(),
|
||||||
Keyword::NOT => Ok(Expr::UnaryOp {
|
Keyword::NOT => Ok(Expr::UnaryOp {
|
||||||
|
@ -647,6 +648,31 @@ impl<'a> Parser<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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;
|
||||||
|
if let Token::Word(word) = self.peek_token() {
|
||||||
|
if [Keyword::BOTH, Keyword::LEADING, Keyword::TRAILING]
|
||||||
|
.iter()
|
||||||
|
.any(|d| word.keyword == *d)
|
||||||
|
{
|
||||||
|
let ident = self.parse_identifier()?;
|
||||||
|
let sub_expr = self.parse_expr()?;
|
||||||
|
self.expect_keyword(Keyword::FROM)?;
|
||||||
|
where_expr = Some((ident, sub_expr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let expr = self.parse_expr()?;
|
||||||
|
self.expect_token(&Token::RParen)?;
|
||||||
|
|
||||||
|
Ok(Expr::Trim {
|
||||||
|
expr: Box::new(expr),
|
||||||
|
trim_where: where_expr.map(|(ident, expr)| (Box::new(ident), Box::new(expr))),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// 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)?;
|
||||||
|
|
|
@ -2747,6 +2747,26 @@ fn parse_substring() {
|
||||||
one_statement_parses_to("SELECT SUBSTRING('1' FOR 3)", "SELECT SUBSTRING('1' FOR 3)");
|
one_statement_parses_to("SELECT SUBSTRING('1' FOR 3)", "SELECT SUBSTRING('1' FOR 3)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_trim() {
|
||||||
|
one_statement_parses_to(
|
||||||
|
"SELECT TRIM(BOTH 'xyz' FROM 'xyzfooxyz')",
|
||||||
|
"SELECT TRIM(BOTH 'xyz' FROM 'xyzfooxyz')",
|
||||||
|
);
|
||||||
|
|
||||||
|
one_statement_parses_to(
|
||||||
|
"SELECT TRIM(LEADING 'xyz' FROM 'xyzfooxyz')",
|
||||||
|
"SELECT TRIM(LEADING 'xyz' FROM 'xyzfooxyz')",
|
||||||
|
);
|
||||||
|
|
||||||
|
one_statement_parses_to(
|
||||||
|
"SELECT TRIM(TRAILING 'xyz' FROM 'xyzfooxyz')",
|
||||||
|
"SELECT TRIM(TRAILING 'xyz' FROM 'xyzfooxyz')",
|
||||||
|
);
|
||||||
|
|
||||||
|
one_statement_parses_to("SELECT TRIM(' foo ')", "SELECT TRIM(' foo ')");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_exists_subquery() {
|
fn parse_exists_subquery() {
|
||||||
let expected_inner = verified_query("SELECT 1");
|
let expected_inner = verified_query("SELECT 1");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue