mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-23 15:34:09 +00:00
Parse SUBSTR
as alias for SUBSTRING
(#1769)
This commit is contained in:
parent
f487cbe004
commit
939fbdd4f6
7 changed files with 32 additions and 4 deletions
|
@ -890,6 +890,10 @@ pub enum Expr {
|
||||||
/// true if the expression is represented using the `SUBSTRING(expr, start, len)` syntax
|
/// true if the expression is represented using the `SUBSTRING(expr, start, len)` syntax
|
||||||
/// This flag is used for formatting.
|
/// This flag is used for formatting.
|
||||||
special: bool,
|
special: bool,
|
||||||
|
|
||||||
|
/// true if the expression is represented using the `SUBSTR` shorthand
|
||||||
|
/// This flag is used for formatting.
|
||||||
|
shorthand: bool,
|
||||||
},
|
},
|
||||||
/// ```sql
|
/// ```sql
|
||||||
/// TRIM([BOTH | LEADING | TRAILING] [<expr> FROM] <expr>)
|
/// TRIM([BOTH | LEADING | TRAILING] [<expr> FROM] <expr>)
|
||||||
|
@ -1719,8 +1723,13 @@ impl fmt::Display for Expr {
|
||||||
substring_from,
|
substring_from,
|
||||||
substring_for,
|
substring_for,
|
||||||
special,
|
special,
|
||||||
|
shorthand,
|
||||||
} => {
|
} => {
|
||||||
write!(f, "SUBSTRING({expr}")?;
|
f.write_str("SUBSTR")?;
|
||||||
|
if !*shorthand {
|
||||||
|
f.write_str("ING")?;
|
||||||
|
}
|
||||||
|
write!(f, "({expr}")?;
|
||||||
if let Some(from_part) = substring_from {
|
if let Some(from_part) = substring_from {
|
||||||
if *special {
|
if *special {
|
||||||
write!(f, ", {from_part}")?;
|
write!(f, ", {from_part}")?;
|
||||||
|
|
|
@ -1503,6 +1503,7 @@ impl Spanned for Expr {
|
||||||
substring_from,
|
substring_from,
|
||||||
substring_for,
|
substring_for,
|
||||||
special: _,
|
special: _,
|
||||||
|
shorthand: _,
|
||||||
} => union_spans(
|
} => union_spans(
|
||||||
core::iter::once(expr.span())
|
core::iter::once(expr.span())
|
||||||
.chain(substring_from.as_ref().map(|i| i.span()))
|
.chain(substring_from.as_ref().map(|i| i.span()))
|
||||||
|
|
|
@ -841,6 +841,7 @@ define_keywords!(
|
||||||
STRING,
|
STRING,
|
||||||
STRUCT,
|
STRUCT,
|
||||||
SUBMULTISET,
|
SUBMULTISET,
|
||||||
|
SUBSTR,
|
||||||
SUBSTRING,
|
SUBSTRING,
|
||||||
SUBSTRING_REGEX,
|
SUBSTRING_REGEX,
|
||||||
SUCCEEDS,
|
SUCCEEDS,
|
||||||
|
|
|
@ -1302,7 +1302,10 @@ impl<'a> Parser<'a> {
|
||||||
Keyword::POSITION if self.peek_token_ref().token == Token::LParen => {
|
Keyword::POSITION if self.peek_token_ref().token == Token::LParen => {
|
||||||
Ok(Some(self.parse_position_expr(w.clone().into_ident(w_span))?))
|
Ok(Some(self.parse_position_expr(w.clone().into_ident(w_span))?))
|
||||||
}
|
}
|
||||||
Keyword::SUBSTRING => Ok(Some(self.parse_substring_expr()?)),
|
Keyword::SUBSTR | Keyword::SUBSTRING => {
|
||||||
|
self.prev_token();
|
||||||
|
Ok(Some(self.parse_substring()?))
|
||||||
|
}
|
||||||
Keyword::OVERLAY => Ok(Some(self.parse_overlay_expr()?)),
|
Keyword::OVERLAY => Ok(Some(self.parse_overlay_expr()?)),
|
||||||
Keyword::TRIM => Ok(Some(self.parse_trim_expr()?)),
|
Keyword::TRIM => Ok(Some(self.parse_trim_expr()?)),
|
||||||
Keyword::INTERVAL => Ok(Some(self.parse_interval()?)),
|
Keyword::INTERVAL => Ok(Some(self.parse_interval()?)),
|
||||||
|
@ -2412,8 +2415,16 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_substring_expr(&mut self) -> Result<Expr, ParserError> {
|
// { SUBSTRING | SUBSTR } (<EXPR> [FROM 1] [FOR 3])
|
||||||
// PARSE SUBSTRING (EXPR [FROM 1] [FOR 3])
|
pub fn parse_substring(&mut self) -> Result<Expr, ParserError> {
|
||||||
|
let shorthand = match self.expect_one_of_keywords(&[Keyword::SUBSTR, Keyword::SUBSTRING])? {
|
||||||
|
Keyword::SUBSTR => true,
|
||||||
|
Keyword::SUBSTRING => false,
|
||||||
|
_ => {
|
||||||
|
self.prev_token();
|
||||||
|
return self.expected("SUBSTR or SUBSTRING", self.peek_token());
|
||||||
|
}
|
||||||
|
};
|
||||||
self.expect_token(&Token::LParen)?;
|
self.expect_token(&Token::LParen)?;
|
||||||
let expr = self.parse_expr()?;
|
let expr = self.parse_expr()?;
|
||||||
let mut from_expr = None;
|
let mut from_expr = None;
|
||||||
|
@ -2433,6 +2444,7 @@ impl<'a> Parser<'a> {
|
||||||
substring_from: from_expr.map(Box::new),
|
substring_from: from_expr.map(Box::new),
|
||||||
substring_for: to_expr.map(Box::new),
|
substring_for: to_expr.map(Box::new),
|
||||||
special,
|
special,
|
||||||
|
shorthand,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7607,6 +7607,9 @@ fn parse_substring() {
|
||||||
verified_stmt("SELECT SUBSTRING('1', 1, 3)");
|
verified_stmt("SELECT SUBSTRING('1', 1, 3)");
|
||||||
verified_stmt("SELECT SUBSTRING('1', 1)");
|
verified_stmt("SELECT SUBSTRING('1', 1)");
|
||||||
verified_stmt("SELECT SUBSTRING('1' FOR 3)");
|
verified_stmt("SELECT SUBSTRING('1' FOR 3)");
|
||||||
|
verified_stmt("SELECT SUBSTRING('foo' FROM 1 FOR 2) FROM t");
|
||||||
|
verified_stmt("SELECT SUBSTR('foo' FROM 1 FOR 2) FROM t");
|
||||||
|
verified_stmt("SELECT SUBSTR('foo', 1, 2) FROM t");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1133,6 +1133,7 @@ fn parse_substring_in_select() {
|
||||||
(number("1")).with_empty_span()
|
(number("1")).with_empty_span()
|
||||||
))),
|
))),
|
||||||
special: true,
|
special: true,
|
||||||
|
shorthand: false,
|
||||||
})],
|
})],
|
||||||
into: None,
|
into: None,
|
||||||
from: vec![TableWithJoins {
|
from: vec![TableWithJoins {
|
||||||
|
|
|
@ -2590,6 +2590,7 @@ fn parse_substring_in_select() {
|
||||||
(number("1")).with_empty_span()
|
(number("1")).with_empty_span()
|
||||||
))),
|
))),
|
||||||
special: true,
|
special: true,
|
||||||
|
shorthand: false,
|
||||||
})],
|
})],
|
||||||
into: None,
|
into: None,
|
||||||
from: vec![TableWithJoins {
|
from: vec![TableWithJoins {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue