Skip to content

Commit cff2833

Browse files
etgarperetsiffyio
andauthored
Add support for string literal concatenation (#2003)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
1 parent eca6574 commit cff2833

File tree

4 files changed

+39
-2
lines changed

4 files changed

+39
-2
lines changed

src/dialect/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,12 @@ pub trait Dialect: Debug + Any {
476476
false
477477
}
478478

479+
/// Returns true if the dialect supports concatenating of string literal
480+
/// Example: `SELECT 'Hello ' "world" => SELECT 'Hello world'`
481+
fn supports_string_literal_concatenation(&self) -> bool {
482+
false
483+
}
484+
479485
/// Does the dialect support trailing commas in the projection list?
480486
fn supports_projection_trailing_commas(&self) -> bool {
481487
self.supports_trailing_commas()

src/dialect/mysql.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ impl Dialect for MySqlDialect {
7171
true
7272
}
7373

74+
/// see <https://dev.mysql.com/doc/refman/8.4/en/string-functions.html#function_concat>
75+
fn supports_string_literal_concatenation(&self) -> bool {
76+
true
77+
}
78+
7479
fn ignores_wildcard_escapes(&self) -> bool {
7580
true
7681
}

src/parser/mod.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9914,8 +9914,12 @@ impl<'a> Parser<'a> {
99149914
// bigdecimal feature is enabled, and is otherwise a no-op
99159915
// (i.e., it returns the input string).
99169916
Token::Number(n, l) => ok_value(Value::Number(Self::parse(n, span.start)?, l)),
9917-
Token::SingleQuotedString(ref s) => ok_value(Value::SingleQuotedString(s.to_string())),
9918-
Token::DoubleQuotedString(ref s) => ok_value(Value::DoubleQuotedString(s.to_string())),
9917+
Token::SingleQuotedString(ref s) => ok_value(Value::SingleQuotedString(
9918+
self.maybe_concat_string_literal(s.to_string()),
9919+
)),
9920+
Token::DoubleQuotedString(ref s) => ok_value(Value::DoubleQuotedString(
9921+
self.maybe_concat_string_literal(s.to_string()),
9922+
)),
99199923
Token::TripleSingleQuotedString(ref s) => {
99209924
ok_value(Value::TripleSingleQuotedString(s.to_string()))
99219925
}
@@ -9985,6 +9989,18 @@ impl<'a> Parser<'a> {
99859989
}
99869990
}
99879991

9992+
fn maybe_concat_string_literal(&mut self, mut str: String) -> String {
9993+
if self.dialect.supports_string_literal_concatenation() {
9994+
while let Token::SingleQuotedString(ref s) | Token::DoubleQuotedString(ref s) =
9995+
self.peek_token_ref().token
9996+
{
9997+
str.push_str(s.clone().as_str());
9998+
self.advance_token();
9999+
}
10000+
}
10001+
str
10002+
}
10003+
998810004
/// Parse an unsigned numeric literal
998910005
pub fn parse_number_value(&mut self) -> Result<ValueWithSpan, ParserError> {
999010006
let value_wrapper = self.parse_value()?;

tests/sqlparser_common.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17150,3 +17150,13 @@ fn test_parse_semantic_view_table_factor() {
1715017150
_ => panic!("Expected Query statement"),
1715117151
}
1715217152
}
17153+
17154+
#[test]
17155+
fn parse_adjacent_string_literal_concatenation() {
17156+
let sql = r#"SELECT 'M' "y" 'S' "q" 'l'"#;
17157+
let dialects = all_dialects_where(|d| d.supports_string_literal_concatenation());
17158+
dialects.one_statement_parses_to(sql, r"SELECT 'MySql'");
17159+
17160+
let sql = "SELECT * FROM t WHERE col = 'Hello' \n ' ' \t 'World!'";
17161+
dialects.one_statement_parses_to(sql, r"SELECT * FROM t WHERE col = 'Hello World!'");
17162+
}

0 commit comments

Comments
 (0)