Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/dialect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,12 @@ pub trait Dialect: Debug + Any {
false
}

// Does the Dialect support concatenating of string literal
// Example: SELECT 'Hello ' "world" => SELECT 'Hello world'
fn supports_string_literal_concatenation(&self) -> bool {
false
}

/// Does the dialect support trailing commas in the projection list?
fn supports_projection_trailing_commas(&self) -> bool {
self.supports_trailing_commas()
Expand Down
5 changes: 5 additions & 0 deletions src/dialect/mysql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ impl Dialect for MySqlDialect {
true
}

/// see <https://dev.mysql.com/doc/refman/8.4/en/string-functions.html#function_concat>
fn supports_string_literal_concatenation(&self) -> bool {
true
}

fn ignores_wildcard_escapes(&self) -> bool {
true
}
Expand Down
20 changes: 18 additions & 2 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9808,8 +9808,12 @@ impl<'a> Parser<'a> {
// bigdecimal feature is enabled, and is otherwise a no-op
// (i.e., it returns the input string).
Token::Number(n, l) => ok_value(Value::Number(Self::parse(n, span.start)?, l)),
Token::SingleQuotedString(ref s) => ok_value(Value::SingleQuotedString(s.to_string())),
Token::DoubleQuotedString(ref s) => ok_value(Value::DoubleQuotedString(s.to_string())),
Token::SingleQuotedString(ref s) => ok_value(Value::SingleQuotedString(
self.maybe_concat_string_literal(s.to_string()),
)),
Token::DoubleQuotedString(ref s) => ok_value(Value::DoubleQuotedString(
self.maybe_concat_string_literal(s.to_string()),
)),
Token::TripleSingleQuotedString(ref s) => {
ok_value(Value::TripleSingleQuotedString(s.to_string()))
}
Expand Down Expand Up @@ -9879,6 +9883,18 @@ impl<'a> Parser<'a> {
}
}

fn maybe_concat_string_literal(&mut self, mut str: String) -> String {
if self.dialect.supports_string_literal_concatenation() {
while let Token::SingleQuotedString(ref s) | Token::DoubleQuotedString(ref s) =
self.peek_token_ref().token
{
str.push_str(s.clone().as_str());
self.advance_token();
}
}
str
}

/// Parse an unsigned numeric literal
pub fn parse_number_value(&mut self) -> Result<ValueWithSpan, ParserError> {
let value_wrapper = self.parse_value()?;
Expand Down
10 changes: 10 additions & 0 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17027,3 +17027,13 @@ fn test_parse_semantic_view_table_factor() {
_ => panic!("Expected Query statement"),
}
}

#[test]
fn parse_adjacent_string_literal_concatenation() {
let sql = r#"SELECT 'M' "y" 'S' "q" 'l'"#;
let dialects = all_dialects_where(|d| d.supports_string_literal_concatenation());
dialects.one_statement_parses_to(sql, r"SELECT 'MySql'");

let sql = "SELECT * FROM t WHERE col = 'Hello' \n ' ' \t 'World!'";
dialects.one_statement_parses_to(sql, r"SELECT * FROM t WHERE col = 'Hello World!'");
}
Loading