This is an automated email from the ASF dual-hosted git repository.

LucaCappelletti94 pushed a commit to branch byte-string-display-escaping
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git

commit f2e1d68108e7bf6e49f46d5fcb59697da27467a5
Author: LucaCappelletti94 <[email protected]>
AuthorDate: Mon Sep 21 22:47:39 2026 +0200

    Generic: Fix quote escaping when displaying byte and raw string literals
---
 src/ast/value.rs            | 53 +++++++++++++++++++++++++++++++++++++++++----
 tests/sqlparser_bigquery.rs | 27 +++++++++++++++++++++++
 tests/sqlparser_mysql.rs    |  6 +++++
 tests/sqlparser_postgres.rs |  6 +++++
 4 files changed, 88 insertions(+), 4 deletions(-)

diff --git a/src/ast/value.rs b/src/ast/value.rs
index a906c4b3..967e6477 100644
--- a/src/ast/value.rs
+++ b/src/ast/value.rs
@@ -278,12 +278,20 @@ impl fmt::Display for Value {
             Value::NationalQuoteDelimitedStringLiteral(v) => write!(f, "N{v}"),
             Value::HexStringLiteral(v) => write!(f, "X'{v}'"),
             Value::Boolean(v) => write!(f, "{v}"),
-            Value::SingleQuotedByteStringLiteral(v) => write!(f, "B'{v}'"),
-            Value::DoubleQuotedByteStringLiteral(v) => write!(f, "B\"{v}\""),
+            Value::SingleQuotedByteStringLiteral(v) => {
+                write!(f, "B'{}'", escape_single_quote_string(v))
+            }
+            Value::DoubleQuotedByteStringLiteral(v) => {
+                write!(f, "B\"{}\"", escape_double_quote_string(v))
+            }
             Value::TripleSingleQuotedByteStringLiteral(v) => write!(f, 
"B'''{v}'''"),
             Value::TripleDoubleQuotedByteStringLiteral(v) => write!(f, 
r#"B"""{v}""""#),
-            Value::SingleQuotedRawStringLiteral(v) => write!(f, "R'{v}'"),
-            Value::DoubleQuotedRawStringLiteral(v) => write!(f, "R\"{v}\""),
+            Value::SingleQuotedRawStringLiteral(v) => {
+                write!(f, "R'{}'", escape_single_quote_string(v))
+            }
+            Value::DoubleQuotedRawStringLiteral(v) => {
+                write!(f, "R\"{}\"", escape_double_quote_string(v))
+            }
             Value::TripleSingleQuotedRawStringLiteral(v) => write!(f, 
"R'''{v}'''"),
             Value::TripleDoubleQuotedRawStringLiteral(v) => write!(f, 
r#"R"""{v}""""#),
             Value::Null => write!(f, "NULL"),
@@ -717,3 +725,40 @@ fn test_escape_quoted_string_with_multibyte_quote_char() {
         "a🦀🦀b🦀🦀c"
     );
 }
+
+#[cfg(test)]
+#[test]
+fn test_byte_and_raw_string_literal_display_escaping() {
+    assert_eq!(
+        Value::SingleQuotedByteStringLiteral("'".to_string()).to_string(),
+        "B''''"
+    );
+    assert_eq!(
+        Value::SingleQuotedByteStringLiteral("it's".to_string()).to_string(),
+        "B'it''s'"
+    );
+    assert_eq!(
+        Value::DoubleQuotedByteStringLiteral("\"".to_string()).to_string(),
+        "B\"\"\"\""
+    );
+    assert_eq!(
+        Value::DoubleQuotedByteStringLiteral("it\"s".to_string()).to_string(),
+        "B\"it\"\"s\""
+    );
+    assert_eq!(
+        Value::SingleQuotedRawStringLiteral("'".to_string()).to_string(),
+        "R''''"
+    );
+    assert_eq!(
+        Value::SingleQuotedRawStringLiteral("it's".to_string()).to_string(),
+        "R'it''s'"
+    );
+    assert_eq!(
+        Value::DoubleQuotedRawStringLiteral("\"".to_string()).to_string(),
+        "R\"\"\"\""
+    );
+    assert_eq!(
+        Value::DoubleQuotedRawStringLiteral("it\"s".to_string()).to_string(),
+        "R\"it\"\"s\""
+    );
+}
diff --git a/tests/sqlparser_bigquery.rs b/tests/sqlparser_bigquery.rs
index 97f71cfe..d6ae192e 100644
--- a/tests/sqlparser_bigquery.rs
+++ b/tests/sqlparser_bigquery.rs
@@ -2957,3 +2957,30 @@ fn parse_from_first_select() {
     bigquery().verified_stmt("FROM t SELECT a, b");
     bigquery().verified_stmt("FROM t |> WHERE a > 1 |> SELECT a");
 }
+
+#[test]
+fn test_byte_and_raw_string_quote_escaping() {
+    let generic = TestedDialects::new(vec![Box::new(GenericDialect {})]);
+    generic.verified_stmt("SELECT B''''");
+    generic.verified_stmt("SELECT B'it''s'");
+    generic.verified_stmt("SELECT B\"\"\"\"");
+    generic.verified_stmt(r#"SELECT B"it""s""#);
+    generic.verified_stmt("SELECT R'it''s'");
+    generic.verified_stmt(r#"SELECT R"it""s""#);
+    generic.verified_stmt("SELECT COUNSELECT AS name, B''''");
+
+    bigquery_and_generic().verified_stmt("SELECT B'it''s'");
+    bigquery_and_generic().verified_stmt(r#"SELECT B"it""s""#);
+    bigquery_and_generic().verified_stmt("SELECT R'it''s'");
+    bigquery_and_generic().verified_stmt(r#"SELECT R"it""s""#);
+
+    let err = generic
+        .parse_sql_statements("SELECT B'unterminated")
+        .unwrap_err();
+    assert_eq!(
+        ParserError::TokenizerError(
+            "Unterminated string literal at Line: 1, Column: 9".to_string(),
+        ),
+        err
+    );
+}
diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs
index 97f21374..ffa2e47a 100644
--- a/tests/sqlparser_mysql.rs
+++ b/tests/sqlparser_mysql.rs
@@ -5052,3 +5052,9 @@ fn parse_is_distinct_from_json_arrow_precedence() {
         mysql_and_generic().verified_expr("a IS NOT DISTINCT FROM b ->> 'k'")
     );
 }
+
+#[test]
+fn parse_bitstring_literal_escaping() {
+    mysql_and_generic().verified_stmt("SELECT B''''");
+    mysql_and_generic().verified_stmt("SELECT B'it''s'");
+}
diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs
index ab2d4b8e..e097ca63 100644
--- a/tests/sqlparser_postgres.rs
+++ b/tests/sqlparser_postgres.rs
@@ -9984,3 +9984,9 @@ fn parse_unary_minus_before_pg_prefix_operators() {
     pg().verified_stmt("SELECT - @ 2");
     pg().one_statement_parses_to("SELECT - #x", "SELECT - # x");
 }
+
+#[test]
+fn parse_bitstring_literal_escaping() {
+    pg_and_generic().verified_stmt("SELECT B''''");
+    pg_and_generic().verified_stmt("SELECT B'it''s'");
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to