Add Support in the "Position" Function (#463)

* Add support in the position function

* Add Test

* Add lint fixes

* Remove if

* Change from to in

* Remove special method for position

* Fix lint

* PR Review
This commit is contained in:
yuval-illumex 2022-04-25 13:32:16 +03:00 committed by GitHub
parent d2487445b7
commit 8f4f01e517
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 0 deletions

View file

@ -291,6 +291,11 @@ pub enum Expr {
field: DateTimeField, field: DateTimeField,
expr: Box<Expr>, expr: Box<Expr>,
}, },
/// POSITION(<expr> in <expr>)
Position {
expr: Box<Expr>,
r#in: Box<Expr>,
},
/// SUBSTRING(<expr> [FROM <expr>] [FOR <expr>]) /// SUBSTRING(<expr> [FROM <expr>] [FOR <expr>])
Substring { Substring {
expr: Box<Expr>, expr: Box<Expr>,
@ -438,6 +443,7 @@ impl fmt::Display for Expr {
Expr::Cast { expr, data_type } => write!(f, "CAST({} AS {})", expr, data_type), Expr::Cast { expr, data_type } => write!(f, "CAST({} AS {})", expr, data_type),
Expr::TryCast { expr, data_type } => write!(f, "TRY_CAST({} AS {})", expr, data_type), Expr::TryCast { expr, data_type } => write!(f, "TRY_CAST({} AS {})", expr, data_type),
Expr::Extract { field, expr } => write!(f, "EXTRACT({} FROM {})", field, expr), Expr::Extract { field, expr } => write!(f, "EXTRACT({} FROM {})", field, expr),
Expr::Position { expr, r#in } => write!(f, "POSITION({} IN {})", expr, r#in),
Expr::Collate { expr, collation } => write!(f, "{} COLLATE {}", expr, collation), Expr::Collate { expr, collation } => write!(f, "{} COLLATE {}", expr, collation),
Expr::Nested(ast) => write!(f, "({})", ast), Expr::Nested(ast) => write!(f, "({})", ast),
Expr::Value(v) => write!(f, "{}", v), Expr::Value(v) => write!(f, "{}", v),

View file

@ -423,6 +423,7 @@ impl<'a> Parser<'a> {
Keyword::TRY_CAST => self.parse_try_cast_expr(), Keyword::TRY_CAST => self.parse_try_cast_expr(),
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::POSITION => self.parse_position_expr(),
Keyword::SUBSTRING => self.parse_substring_expr(), Keyword::SUBSTRING => self.parse_substring_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(),
@ -779,6 +780,24 @@ impl<'a> Parser<'a> {
}) })
} }
pub fn parse_position_expr(&mut self) -> Result<Expr, ParserError> {
// PARSE SELECT POSITION('@' in field)
self.expect_token(&Token::LParen)?;
// Parse the subexpr till the IN keyword
let expr = self.parse_subexpr(Self::BETWEEN_PREC)?;
if self.parse_keyword(Keyword::IN) {
let from = self.parse_expr()?;
self.expect_token(&Token::RParen)?;
Ok(Expr::Position {
expr: Box::new(expr),
r#in: Box::new(from),
})
} else {
return parser_err!("Position function must include IN keyword".to_string());
}
}
pub fn parse_substring_expr(&mut self) -> Result<Expr, ParserError> { pub fn parse_substring_expr(&mut self) -> Result<Expr, ParserError> {
// PARSE SUBSTRING (EXPR [FROM 1] [FOR 3]) // PARSE SUBSTRING (EXPR [FROM 1] [FOR 3])
self.expect_token(&Token::LParen)?; self.expect_token(&Token::LParen)?;

View file

@ -4588,3 +4588,16 @@ fn parse_time_functions() {
// Validating Parenthesis // Validating Parenthesis
one_statement_parses_to("SELECT CURRENT_DATE", sql); one_statement_parses_to("SELECT CURRENT_DATE", sql);
} }
#[test]
fn parse_position() {
let sql = "SELECT POSITION('@' IN field)";
let select = verified_only_select(sql);
assert_eq!(
&Expr::Position {
expr: Box::new(Expr::Value(Value::SingleQuotedString("@".to_string()))),
r#in: Box::new(Expr::Identifier(Ident::new("field"))),
},
expr_from_projection(only(&select.projection))
);
}