Repository: tobymao/sqlglot
Pull request: fix(clickhouse): Allow TokenType.SELECT as a Tuple field identifier
Fixes #3763


Docs
-------
[Clickhouse Tuple](https://clickhouse.com/docs/en/sql-reference/data-types/tuple)

Problem statement:
ClickHouse tuple field named `select` fails to parse without quotes
```
In [7]: import sqlglot as sg, sqlglot.expressions as sge

In [8]: sg.__version__
Out[8]: '25.5.1'

In [9]: sg.parse_one('Tuple(select Int64)', into=sge.DataType, dialect="clickhouse")
```

Unfortunately I don't have control over the input here, this is coming directly from a clickhouse `DESCRIBE t` query that returns the string `Tuple(select Int64)`, without quoting the `select` field.

Hints from issue discussion:

Commit message: fix(clickhouse): Allow TokenType.SELECT as a Tuple identifier

Patch to review:
diff --git a/sqlglot/dialects/clickhouse.py b/sqlglot/dialects/clickhouse.py
index 3841ea6480..adf7b446ea 100644
--- a/sqlglot/dialects/clickhouse.py
+++ b/sqlglot/dialects/clickhouse.py
@@ -332,6 +332,8 @@ class Parser(parser.Parser):
             TokenType.SET,
         }
 
+        RESERVED_TOKENS = {*parser.Parser.RESERVED_TOKENS} - {TokenType.SELECT}
+
         AGG_FUNC_MAPPING = (
             lambda functions, suffixes: {
                 f"{f}{sfx}": (f, sfx) for sfx in (suffixes + [""]) for f in functions
diff --git a/tests/dialects/test_clickhouse.py b/tests/dialects/test_clickhouse.py
index a31cc24a85..8f8c7f0b8c 100644
--- a/tests/dialects/test_clickhouse.py
+++ b/tests/dialects/test_clickhouse.py
@@ -451,6 +451,10 @@ def test_clickhouse(self):
         self.validate_identity("ALTER TABLE visits REPLACE PARTITION ID '201901' FROM visits_tmp")
         self.validate_identity("ALTER TABLE visits ON CLUSTER test_cluster DROP COLUMN col1")
 
+        self.assertIsInstance(
+            parse_one("Tuple(select Int64)", into=exp.DataType, read="clickhouse"), exp.DataType
+        )
+
     def test_cte(self):
         self.validate_identity("WITH 'x' AS foo SELECT foo")
         self.validate_identity("WITH ['c'] AS field_names SELECT field_names")
@@ -548,6 +552,7 @@ def test_ddl(self):
         self.validate_identity(
             "CREATE TABLE foo (x UInt32) TTL time_column + INTERVAL '1' MONTH DELETE WHERE column = 'value'"
         )
+        self.validate_identity("CREATE TABLE named_tuples (a Tuple(select String, i Int64))")
 
         self.validate_all(
             """


Code review comments:
diff_hunk: @@ -332,6 +332,8 @@ class Parser(parser.Parser):
             TokenType.SET,
         }
 
+        RESERVED_TOKENS = {*parser.Parser.RESERVED_TOKENS} - {TokenType.SELECT}
path: sqlglot/dialects/clickhouse.py
text: @user1:
you don't need to make a copy just to RESERVED_TOKENS - ...

@author:
Good catch, thanks