mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-27 16:09:09 +00:00
Add overlay expr (#594)
* Add PLACING keyword to keywords list * Add high level overlay expr to Expr enum * Add parsing logic for overlay op * add ovleray and is not true/false/unknown tests
This commit is contained in:
parent
95fbb55f2c
commit
6f55dead53
4 changed files with 117 additions and 8 deletions
|
@ -348,6 +348,13 @@ pub enum Expr {
|
||||||
trim_where: Option<TrimWhereField>,
|
trim_where: Option<TrimWhereField>,
|
||||||
trim_what: Option<Box<Expr>>,
|
trim_what: Option<Box<Expr>>,
|
||||||
},
|
},
|
||||||
|
/// OVERLAY(<expr> PLACING <expr> FROM <expr>[ FOR <expr> ]
|
||||||
|
Overlay {
|
||||||
|
expr: Box<Expr>,
|
||||||
|
overlay_what: Box<Expr>,
|
||||||
|
overlay_from: Box<Expr>,
|
||||||
|
overlay_for: Option<Box<Expr>>,
|
||||||
|
},
|
||||||
/// `expr COLLATE collation`
|
/// `expr COLLATE collation`
|
||||||
Collate {
|
Collate {
|
||||||
expr: Box<Expr>,
|
expr: Box<Expr>,
|
||||||
|
@ -639,8 +646,25 @@ impl fmt::Display for Expr {
|
||||||
if let Some(from_part) = substring_from {
|
if let Some(from_part) = substring_from {
|
||||||
write!(f, " FROM {}", from_part)?;
|
write!(f, " FROM {}", from_part)?;
|
||||||
}
|
}
|
||||||
if let Some(from_part) = substring_for {
|
if let Some(for_part) = substring_for {
|
||||||
write!(f, " FOR {}", from_part)?;
|
write!(f, " FOR {}", for_part)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, ")")
|
||||||
|
}
|
||||||
|
Expr::Overlay {
|
||||||
|
expr,
|
||||||
|
overlay_what,
|
||||||
|
overlay_from,
|
||||||
|
overlay_for,
|
||||||
|
} => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"OVERLAY({} PLACING {} FROM {}",
|
||||||
|
expr, overlay_what, overlay_from
|
||||||
|
)?;
|
||||||
|
if let Some(for_part) = overlay_for {
|
||||||
|
write!(f, " FOR {}", for_part)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, ")")
|
write!(f, ")")
|
||||||
|
|
|
@ -382,6 +382,7 @@ define_keywords!(
|
||||||
PERCENTILE_DISC,
|
PERCENTILE_DISC,
|
||||||
PERCENT_RANK,
|
PERCENT_RANK,
|
||||||
PERIOD,
|
PERIOD,
|
||||||
|
PLACING,
|
||||||
PLANS,
|
PLANS,
|
||||||
PORTION,
|
PORTION,
|
||||||
POSITION,
|
POSITION,
|
||||||
|
|
|
@ -449,6 +449,7 @@ impl<'a> Parser<'a> {
|
||||||
Keyword::EXTRACT => self.parse_extract_expr(),
|
Keyword::EXTRACT => self.parse_extract_expr(),
|
||||||
Keyword::POSITION => self.parse_position_expr(),
|
Keyword::POSITION => self.parse_position_expr(),
|
||||||
Keyword::SUBSTRING => self.parse_substring_expr(),
|
Keyword::SUBSTRING => self.parse_substring_expr(),
|
||||||
|
Keyword::OVERLAY => self.parse_overlay_expr(),
|
||||||
Keyword::TRIM => self.parse_trim_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(),
|
||||||
|
@ -884,6 +885,28 @@ impl<'a> Parser<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_overlay_expr(&mut self) -> Result<Expr, ParserError> {
|
||||||
|
// PARSE OVERLAY (EXPR PLACING EXPR FROM 1 [FOR 3])
|
||||||
|
self.expect_token(&Token::LParen)?;
|
||||||
|
let expr = self.parse_expr()?;
|
||||||
|
self.expect_keyword(Keyword::PLACING)?;
|
||||||
|
let what_expr = self.parse_expr()?;
|
||||||
|
self.expect_keyword(Keyword::FROM)?;
|
||||||
|
let from_expr = self.parse_expr()?;
|
||||||
|
let mut for_expr = None;
|
||||||
|
if self.parse_keyword(Keyword::FOR) {
|
||||||
|
for_expr = Some(self.parse_expr()?);
|
||||||
|
}
|
||||||
|
self.expect_token(&Token::RParen)?;
|
||||||
|
|
||||||
|
Ok(Expr::Overlay {
|
||||||
|
expr: Box::new(expr),
|
||||||
|
overlay_what: Box::new(what_expr),
|
||||||
|
overlay_from: Box::new(from_expr),
|
||||||
|
overlay_for: for_expr.map(Box::new),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// TRIM ([WHERE] ['text' FROM] 'text')\
|
/// TRIM ([WHERE] ['text' FROM] 'text')\
|
||||||
/// TRIM ('text')
|
/// TRIM ('text')
|
||||||
pub fn parse_trim_expr(&mut self) -> Result<Expr, ParserError> {
|
pub fn parse_trim_expr(&mut self) -> Result<Expr, ParserError> {
|
||||||
|
|
|
@ -3973,6 +3973,38 @@ 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_overlay() {
|
||||||
|
one_statement_parses_to(
|
||||||
|
"SELECT OVERLAY('abccccde' PLACING 'abc' FROM 3)",
|
||||||
|
"SELECT OVERLAY('abccccde' PLACING 'abc' FROM 3)",
|
||||||
|
);
|
||||||
|
one_statement_parses_to(
|
||||||
|
"SELECT OVERLAY('abccccde' PLACING 'abc' FROM 3 FOR 12)",
|
||||||
|
"SELECT OVERLAY('abccccde' PLACING 'abc' FROM 3 FOR 12)",
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ParserError::ParserError("Expected PLACING, found: FROM".to_owned()),
|
||||||
|
parse_sql_statements("SELECT OVERLAY('abccccde' FROM 3)").unwrap_err(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let sql = "SELECT OVERLAY('abcdef' PLACING name FROM 3 FOR id + 1) FROM CUSTOMERS";
|
||||||
|
let select = verified_only_select(sql);
|
||||||
|
assert_eq!(
|
||||||
|
&Expr::Overlay {
|
||||||
|
expr: Box::new(Expr::Value(Value::SingleQuotedString("abcdef".to_string()))),
|
||||||
|
overlay_what: Box::new(Expr::Identifier(Ident::new("name"))),
|
||||||
|
overlay_from: Box::new(Expr::Value(number("3"))),
|
||||||
|
overlay_for: Some(Box::new(Expr::BinaryOp {
|
||||||
|
left: Box::new(Expr::Identifier(Ident::new("id"))),
|
||||||
|
op: BinaryOperator::Plus,
|
||||||
|
right: Box::new(Expr::Value(number("1"))),
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
expr_from_projection(only(&select.projection))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_trim() {
|
fn parse_trim() {
|
||||||
one_statement_parses_to(
|
one_statement_parses_to(
|
||||||
|
@ -5357,21 +5389,50 @@ fn parse_position_negative() {
|
||||||
fn parse_is_boolean() {
|
fn parse_is_boolean() {
|
||||||
use self::Expr::*;
|
use self::Expr::*;
|
||||||
|
|
||||||
let sql = "a IS FALSE";
|
|
||||||
assert_eq!(
|
|
||||||
IsFalse(Box::new(Identifier(Ident::new("a")))),
|
|
||||||
verified_expr(sql)
|
|
||||||
);
|
|
||||||
|
|
||||||
let sql = "a IS TRUE";
|
let sql = "a IS TRUE";
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
IsTrue(Box::new(Identifier(Ident::new("a")))),
|
IsTrue(Box::new(Identifier(Ident::new("a")))),
|
||||||
verified_expr(sql)
|
verified_expr(sql)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let sql = "a IS NOT TRUE";
|
||||||
|
assert_eq!(
|
||||||
|
IsNotTrue(Box::new(Identifier(Ident::new("a")))),
|
||||||
|
verified_expr(sql)
|
||||||
|
);
|
||||||
|
|
||||||
|
let sql = "a IS FALSE";
|
||||||
|
assert_eq!(
|
||||||
|
IsFalse(Box::new(Identifier(Ident::new("a")))),
|
||||||
|
verified_expr(sql)
|
||||||
|
);
|
||||||
|
|
||||||
|
let sql = "a IS NOT FALSE";
|
||||||
|
assert_eq!(
|
||||||
|
IsNotFalse(Box::new(Identifier(Ident::new("a")))),
|
||||||
|
verified_expr(sql)
|
||||||
|
);
|
||||||
|
|
||||||
|
let sql = "a IS UNKNOWN";
|
||||||
|
assert_eq!(
|
||||||
|
IsUnknown(Box::new(Identifier(Ident::new("a")))),
|
||||||
|
verified_expr(sql)
|
||||||
|
);
|
||||||
|
|
||||||
|
let sql = "a IS NOT UNKNOWN";
|
||||||
|
assert_eq!(
|
||||||
|
IsNotUnknown(Box::new(Identifier(Ident::new("a")))),
|
||||||
|
verified_expr(sql)
|
||||||
|
);
|
||||||
|
|
||||||
verified_stmt("SELECT f FROM foo WHERE field IS TRUE");
|
verified_stmt("SELECT f FROM foo WHERE field IS TRUE");
|
||||||
|
verified_stmt("SELECT f FROM foo WHERE field IS NOT TRUE");
|
||||||
|
|
||||||
verified_stmt("SELECT f FROM foo WHERE field IS FALSE");
|
verified_stmt("SELECT f FROM foo WHERE field IS FALSE");
|
||||||
|
verified_stmt("SELECT f FROM foo WHERE field IS NOT FALSE");
|
||||||
|
|
||||||
|
verified_stmt("SELECT f FROM foo WHERE field IS UNKNOWN");
|
||||||
|
verified_stmt("SELECT f FROM foo WHERE field IS NOT UNKNOWN");
|
||||||
|
|
||||||
let sql = "SELECT f from foo where field is 0";
|
let sql = "SELECT f from foo where field is 0";
|
||||||
let res = parse_sql_statements(sql);
|
let res = parse_sql_statements(sql);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue