mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-23 07:24:10 +00:00
Snowflake: support position with normal function call syntax (#1341)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
This commit is contained in:
parent
7fdb2ec5d1
commit
c3ba2f33c6
3 changed files with 39 additions and 27 deletions
|
@ -1038,7 +1038,7 @@ impl<'a> Parser<'a> {
|
||||||
Keyword::CEIL => self.parse_ceil_floor_expr(true),
|
Keyword::CEIL => self.parse_ceil_floor_expr(true),
|
||||||
Keyword::FLOOR => self.parse_ceil_floor_expr(false),
|
Keyword::FLOOR => self.parse_ceil_floor_expr(false),
|
||||||
Keyword::POSITION if self.peek_token().token == Token::LParen => {
|
Keyword::POSITION if self.peek_token().token == Token::LParen => {
|
||||||
self.parse_position_expr()
|
self.parse_position_expr(w.to_ident())
|
||||||
}
|
}
|
||||||
Keyword::SUBSTRING => self.parse_substring_expr(),
|
Keyword::SUBSTRING => self.parse_substring_expr(),
|
||||||
Keyword::OVERLAY => self.parse_overlay_expr(),
|
Keyword::OVERLAY => self.parse_overlay_expr(),
|
||||||
|
@ -1707,24 +1707,26 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_position_expr(&mut self) -> Result<Expr, ParserError> {
|
pub fn parse_position_expr(&mut self, ident: Ident) -> Result<Expr, ParserError> {
|
||||||
// PARSE SELECT POSITION('@' in field)
|
let position_expr = self.maybe_parse(|p| {
|
||||||
self.expect_token(&Token::LParen)?;
|
// PARSE SELECT POSITION('@' in field)
|
||||||
|
p.expect_token(&Token::LParen)?;
|
||||||
|
|
||||||
// Parse the subexpr till the IN keyword
|
// Parse the subexpr till the IN keyword
|
||||||
let expr = self.parse_subexpr(Self::BETWEEN_PREC)?;
|
let expr = p.parse_subexpr(Self::BETWEEN_PREC)?;
|
||||||
if self.parse_keyword(Keyword::IN) {
|
p.expect_keyword(Keyword::IN)?;
|
||||||
let from = self.parse_expr()?;
|
let from = p.parse_expr()?;
|
||||||
self.expect_token(&Token::RParen)?;
|
p.expect_token(&Token::RParen)?;
|
||||||
Ok(Expr::Position {
|
Ok(Expr::Position {
|
||||||
expr: Box::new(expr),
|
expr: Box::new(expr),
|
||||||
r#in: Box::new(from),
|
r#in: Box::new(from),
|
||||||
})
|
})
|
||||||
} else {
|
});
|
||||||
parser_err!(
|
match position_expr {
|
||||||
"Position function must include IN keyword".to_string(),
|
Some(expr) => Ok(expr),
|
||||||
self.peek_token().location
|
// Snowflake supports `position` as an ordinary function call
|
||||||
)
|
// without the special `IN` syntax.
|
||||||
|
None => self.parse_function(ObjectName(vec![ident])),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4151,7 +4151,7 @@ fn parse_scalar_function_in_projection() {
|
||||||
|
|
||||||
for function_name in names {
|
for function_name in names {
|
||||||
// like SELECT sqrt(id) FROM foo
|
// like SELECT sqrt(id) FROM foo
|
||||||
let sql = dbg!(format!("SELECT {function_name}(id) FROM foo"));
|
let sql = format!("SELECT {function_name}(id) FROM foo");
|
||||||
let select = verified_only_select(&sql);
|
let select = verified_only_select(&sql);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&call(function_name, [Expr::Identifier(Ident::new("id"))]),
|
&call(function_name, [Expr::Identifier(Ident::new("id"))]),
|
||||||
|
@ -8254,30 +8254,34 @@ fn parse_time_functions() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_position() {
|
fn parse_position() {
|
||||||
let sql = "SELECT POSITION('@' IN field)";
|
|
||||||
let select = verified_only_select(sql);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&Expr::Position {
|
Expr::Position {
|
||||||
expr: Box::new(Expr::Value(Value::SingleQuotedString("@".to_string()))),
|
expr: Box::new(Expr::Value(Value::SingleQuotedString("@".to_string()))),
|
||||||
r#in: Box::new(Expr::Identifier(Ident::new("field"))),
|
r#in: Box::new(Expr::Identifier(Ident::new("field"))),
|
||||||
},
|
},
|
||||||
expr_from_projection(only(&select.projection))
|
verified_expr("POSITION('@' IN field)"),
|
||||||
|
);
|
||||||
|
|
||||||
|
// some dialects (e.g. snowflake) support position as a function call (i.e. without IN)
|
||||||
|
assert_eq!(
|
||||||
|
call(
|
||||||
|
"position",
|
||||||
|
[
|
||||||
|
Expr::Value(Value::SingleQuotedString("an".to_owned())),
|
||||||
|
Expr::Value(Value::SingleQuotedString("banana".to_owned())),
|
||||||
|
Expr::Value(number("1")),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
verified_expr("position('an', 'banana', 1)")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_position_negative() {
|
fn parse_position_negative() {
|
||||||
let sql = "SELECT POSITION(foo) from bar";
|
|
||||||
let res = parse_sql_statements(sql);
|
|
||||||
assert_eq!(
|
|
||||||
ParserError::ParserError("Position function must include IN keyword".to_string()),
|
|
||||||
res.unwrap_err()
|
|
||||||
);
|
|
||||||
|
|
||||||
let sql = "SELECT POSITION(foo IN) from bar";
|
let sql = "SELECT POSITION(foo IN) from bar";
|
||||||
let res = parse_sql_statements(sql);
|
let res = parse_sql_statements(sql);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParserError::ParserError("Expected: an expression:, found: )".to_string()),
|
ParserError::ParserError("Expected: (, found: )".to_string()),
|
||||||
res.unwrap_err()
|
res.unwrap_err()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2256,3 +2256,9 @@ fn asof_joins() {
|
||||||
"ORDER BY s.observed",
|
"ORDER BY s.observed",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_position() {
|
||||||
|
snowflake().verified_query("SELECT position('an', 'banana', 1)");
|
||||||
|
snowflake().verified_query("SELECT n, h, POSITION(n IN h) FROM pos");
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue