Skip to content

Commit 939fbdd

Browse files
authored
Parse SUBSTR as alias for SUBSTRING (#1769)
1 parent f487cbe commit 939fbdd

File tree

7 files changed

+32
-4
lines changed

7 files changed

+32
-4
lines changed

src/ast/mod.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,10 @@ pub enum Expr {
890890
/// true if the expression is represented using the `SUBSTRING(expr, start, len)` syntax
891891
/// This flag is used for formatting.
892892
special: bool,
893+
894+
/// true if the expression is represented using the `SUBSTR` shorthand
895+
/// This flag is used for formatting.
896+
shorthand: bool,
893897
},
894898
/// ```sql
895899
/// TRIM([BOTH | LEADING | TRAILING] [<expr> FROM] <expr>)
@@ -1719,8 +1723,13 @@ impl fmt::Display for Expr {
17191723
substring_from,
17201724
substring_for,
17211725
special,
1726+
shorthand,
17221727
} => {
1723-
write!(f, "SUBSTRING({expr}")?;
1728+
f.write_str("SUBSTR")?;
1729+
if !*shorthand {
1730+
f.write_str("ING")?;
1731+
}
1732+
write!(f, "({expr}")?;
17241733
if let Some(from_part) = substring_from {
17251734
if *special {
17261735
write!(f, ", {from_part}")?;

src/ast/spans.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1503,6 +1503,7 @@ impl Spanned for Expr {
15031503
substring_from,
15041504
substring_for,
15051505
special: _,
1506+
shorthand: _,
15061507
} => union_spans(
15071508
core::iter::once(expr.span())
15081509
.chain(substring_from.as_ref().map(|i| i.span()))

src/keywords.rs

+1
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,7 @@ define_keywords!(
841841
STRING,
842842
STRUCT,
843843
SUBMULTISET,
844+
SUBSTR,
844845
SUBSTRING,
845846
SUBSTRING_REGEX,
846847
SUCCEEDS,

src/parser/mod.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -1302,7 +1302,10 @@ impl<'a> Parser<'a> {
13021302
Keyword::POSITION if self.peek_token_ref().token == Token::LParen => {
13031303
Ok(Some(self.parse_position_expr(w.clone().into_ident(w_span))?))
13041304
}
1305-
Keyword::SUBSTRING => Ok(Some(self.parse_substring_expr()?)),
1305+
Keyword::SUBSTR | Keyword::SUBSTRING => {
1306+
self.prev_token();
1307+
Ok(Some(self.parse_substring()?))
1308+
}
13061309
Keyword::OVERLAY => Ok(Some(self.parse_overlay_expr()?)),
13071310
Keyword::TRIM => Ok(Some(self.parse_trim_expr()?)),
13081311
Keyword::INTERVAL => Ok(Some(self.parse_interval()?)),
@@ -2412,8 +2415,16 @@ impl<'a> Parser<'a> {
24122415
}
24132416
}
24142417

2415-
pub fn parse_substring_expr(&mut self) -> Result<Expr, ParserError> {
2416-
// PARSE SUBSTRING (EXPR [FROM 1] [FOR 3])
2418+
// { SUBSTRING | SUBSTR } (<EXPR> [FROM 1] [FOR 3])
2419+
pub fn parse_substring(&mut self) -> Result<Expr, ParserError> {
2420+
let shorthand = match self.expect_one_of_keywords(&[Keyword::SUBSTR, Keyword::SUBSTRING])? {
2421+
Keyword::SUBSTR => true,
2422+
Keyword::SUBSTRING => false,
2423+
_ => {
2424+
self.prev_token();
2425+
return self.expected("SUBSTR or SUBSTRING", self.peek_token());
2426+
}
2427+
};
24172428
self.expect_token(&Token::LParen)?;
24182429
let expr = self.parse_expr()?;
24192430
let mut from_expr = None;
@@ -2433,6 +2444,7 @@ impl<'a> Parser<'a> {
24332444
substring_from: from_expr.map(Box::new),
24342445
substring_for: to_expr.map(Box::new),
24352446
special,
2447+
shorthand,
24362448
})
24372449
}
24382450

tests/sqlparser_common.rs

+3
Original file line numberDiff line numberDiff line change
@@ -7607,6 +7607,9 @@ fn parse_substring() {
76077607
verified_stmt("SELECT SUBSTRING('1', 1, 3)");
76087608
verified_stmt("SELECT SUBSTRING('1', 1)");
76097609
verified_stmt("SELECT SUBSTRING('1' FOR 3)");
7610+
verified_stmt("SELECT SUBSTRING('foo' FROM 1 FOR 2) FROM t");
7611+
verified_stmt("SELECT SUBSTR('foo' FROM 1 FOR 2) FROM t");
7612+
verified_stmt("SELECT SUBSTR('foo', 1, 2) FROM t");
76107613
}
76117614

76127615
#[test]

tests/sqlparser_mssql.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,7 @@ fn parse_substring_in_select() {
11331133
(number("1")).with_empty_span()
11341134
))),
11351135
special: true,
1136+
shorthand: false,
11361137
})],
11371138
into: None,
11381139
from: vec![TableWithJoins {

tests/sqlparser_mysql.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2590,6 +2590,7 @@ fn parse_substring_in_select() {
25902590
(number("1")).with_empty_span()
25912591
))),
25922592
special: true,
2593+
shorthand: false,
25932594
})],
25942595
into: None,
25952596
from: vec![TableWithJoins {

0 commit comments

Comments
 (0)