Repository: tobymao/sqlglot

Issue:
Parsing DuckDB escape string literals throws error
Trying to parse escape string literals like `E'\n'` fails with `sqlglot.errors.ParseError: Invalid expression / Unexpected token`. Can be worked around by using character codes and string concatenation.

**Fully reproducible code snippet**
```python
import sqlglot

sql = r"SELECT E'\n'"
ast = sqlglot.parse_one(sql, dialect="duckdb")
print(repr(ast))
```

**Official Documentation**
- Docs for escape string literals: https://duckdb.org/docs/sql/data_types/literal_types.html#escape-string-literals
- General info about how to handle special characters: https://duckdb.org/docs/sql/data_types/text#strings-with-special-characters

Hints from issue comments:
@georgesittas: @VaggelisD we probably need to add `BYTE_STRINGS` in DuckDB too, similar to Postgres.

Solution patch:
diff --git a/sqlglot/dialects/duckdb.py b/sqlglot/dialects/duckdb.py
index 946410f5bf..33a9366029 100644
--- a/sqlglot/dialects/duckdb.py
+++ b/sqlglot/dialects/duckdb.py
@@ -297,6 +297,7 @@ def to_json_path(self, path: t.Optional[exp.Expression]) -> t.Optional[exp.Expre
         return super().to_json_path(path)
 
     class Tokenizer(tokens.Tokenizer):
+        BYTE_STRINGS = [("e'", "'"), ("E'", "'")]
         HEREDOC_STRINGS = ["$"]
 
         HEREDOC_TAG_IS_IDENTIFIER = True


Test patch:
diff --git a/tests/dialects/test_duckdb.py b/tests/dialects/test_duckdb.py
index a9d6330228..09f0134dbc 100644
--- a/tests/dialects/test_duckdb.py
+++ b/tests/dialects/test_duckdb.py
@@ -899,6 +899,16 @@ def test_duckdb(self):
             "NOT a ILIKE b",
         )
 
+        self.validate_all(
+            "SELECT e'Hello\nworld'",
+            read={
+                "duckdb": "SELECT E'Hello\nworld'",
+            },
+            write={
+                "duckdb": "SELECT e'Hello\nworld'",
+            },
+        )
+
     def test_array_index(self):
         with self.assertLogs(helper_logger) as cm:
             self.validate_all(