From 8f4f01e5172d4fcf83cde6d55abd67744570d9e2 Mon Sep 17 00:00:00 2001 From: yuval-illumex <85674443+yuval-illumex@users.noreply.github.com> Date: Mon, 25 Apr 2022 13:32:16 +0300 Subject: [PATCH] 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 --- src/ast/mod.rs | 6 ++++++ src/parser.rs | 19 +++++++++++++++++++ tests/sqlparser_common.rs | 13 +++++++++++++ 3 files changed, 38 insertions(+) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 3fe1945b..89e13575 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -291,6 +291,11 @@ pub enum Expr { field: DateTimeField, expr: Box, }, + /// POSITION( in ) + Position { + expr: Box, + r#in: Box, + }, /// SUBSTRING( [FROM ] [FOR ]) Substring { expr: Box, @@ -438,6 +443,7 @@ impl fmt::Display for Expr { 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::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::Nested(ast) => write!(f, "({})", ast), Expr::Value(v) => write!(f, "{}", v), diff --git a/src/parser.rs b/src/parser.rs index b9368007..1ca493b9 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -423,6 +423,7 @@ impl<'a> Parser<'a> { Keyword::TRY_CAST => self.parse_try_cast_expr(), Keyword::EXISTS => self.parse_exists_expr(), Keyword::EXTRACT => self.parse_extract_expr(), + Keyword::POSITION => self.parse_position_expr(), Keyword::SUBSTRING => self.parse_substring_expr(), Keyword::TRIM => self.parse_trim_expr(), Keyword::INTERVAL => self.parse_literal_interval(), @@ -779,6 +780,24 @@ impl<'a> Parser<'a> { }) } + pub fn parse_position_expr(&mut self) -> Result { + // 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 { // PARSE SUBSTRING (EXPR [FROM 1] [FOR 3]) self.expect_token(&Token::LParen)?; diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 5d259743..1a1dee98 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -4588,3 +4588,16 @@ fn parse_time_functions() { // Validating Parenthesis 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)) + ); +}