Repository: tobymao/sqlglot

Issue:
Enum types not parsed correctly in duckdb sql
DuckDB supports enum data type definitions at table creation, but sqlgot fails to parse this.

```python
>>> import sqlglot
... sqlglot.transpile("CREATE TABLE color ( name ENUM('RED','GREEN','BLUE'));", read="duckdb", write="sqlite")
```

```pytb
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File ".a/lib/python3.11/site-packages/sqlglot/__init__.py", line 164, in transpile
    for expression in parse(sql, read, error_level=error_level)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "./lib/python3.11/site-packages/sqlglot/__init__.py", line 87, in parse
    return Dialect.get_or_raise(read or dialect).parse(sql, **opts)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "./lib/python3.11/site-packages/sqlglot/dialects/dialect.py", line 469, in parse
    return self.parser(**opts).parse(self.tokenize(sql), sql)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "./lib/python3.11/site-packages/sqlglot/parser.py", line 1086, in parse
    return self._parse(
           ^^^^^^^^^^^^
  File "./lib/python3.11/site-packages/sqlglot/parser.py", line 1152, in _parse
    expressions.append(parse_method(self))
                       ^^^^^^^^^^^^^^^^^^
  File "./lib/python3.11/site-packages/sqlglot/parser.py", line 1354, in _parse_statement
    return self.STATEMENT_PARSERS[self._prev.token_type](self)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "./lib/python3.11/site-packages/sqlglot/parser.py", line 616, in <lambda>
    TokenType.CREATE: lambda self: self._parse_create(),
                                   ^^^^^^^^^^^^^^^^^^^^
  File "./lib/python3.11/site-packages/sqlglot/parser.py", line 1474, in _parse_create
    this = self._parse_schema(this=table_parts)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "./lib/python3.11/site-packages/sqlglot/parser.py", line 4275, in _parse_schema
    self._match_r_paren()
  File "./lib/python3.11/site-packages/sqlglot/parser.py", line 5891, in _match_r_paren
    self.raise_error("Expecting )")
  File "./lib/python3.11/site-packages/sqlglot/parser.py", line 1196, in raise_error
    raise error
sqlglot.errors.ParseError: Expecting ). Line 1, Col: 30.
  CREATE TABLE color ( name ENUM('RED','GREEN','BLUE'));
```

Defining ENUM types at table creation appears to work fine in duckdb v0.10.0:

```duckdb
D CREATE TABLE color ( name ENUM('RED', 'GREEN', 'BLUE'));
D SELECT column_name, data_type FROM duckdb_columns() where table_name = 'color';
┌─────────────┬──────────────────────────────┐
│ column_name │          data_type           │
│   varchar   │           varchar            │
├─────────────┼──────────────────────────────┤
│ name        │ ENUM('RED', 'GREEN', 'BLUE') │
└─────────────┴──────────────────────────────┘
```



Discussion:

Resolving patch:
diff --git a/sqlglot/dialects/clickhouse.py b/sqlglot/dialects/clickhouse.py
--- a/sqlglot/dialects/clickhouse.py
+++ b/sqlglot/dialects/clickhouse.py
@@ -68,7 +68,6 @@ class Tokenizer(tokens.Tokenizer):
             "DATE32": TokenType.DATE32,
             "DATETIME64": TokenType.DATETIME64,
             "DICTIONARY": TokenType.DICTIONARY,
-            "ENUM": TokenType.ENUM,
             "ENUM8": TokenType.ENUM8,
             "ENUM16": TokenType.ENUM16,
             "FINAL": TokenType.FINAL,
diff --git a/sqlglot/dialects/mysql.py b/sqlglot/dialects/mysql.py
--- a/sqlglot/dialects/mysql.py
+++ b/sqlglot/dialects/mysql.py
@@ -185,7 +185,6 @@ class Tokenizer(tokens.Tokenizer):
         KEYWORDS = {
             **tokens.Tokenizer.KEYWORDS,
             "CHARSET": TokenType.CHARACTER_SET,
-            "ENUM": TokenType.ENUM,
             "FORCE": TokenType.FORCE,
             "IGNORE": TokenType.IGNORE,
             "LOCK TABLES": TokenType.COMMAND,
diff --git a/sqlglot/tokens.py b/sqlglot/tokens.py
--- a/sqlglot/tokens.py
+++ b/sqlglot/tokens.py
@@ -661,6 +661,7 @@ class Tokenizer(metaclass=_Tokenizer):
         "DROP": TokenType.DROP,
         "ELSE": TokenType.ELSE,
         "END": TokenType.END,
+        "ENUM": TokenType.ENUM,
         "ESCAPE": TokenType.ESCAPE,
         "EXCEPT": TokenType.EXCEPT,
         "EXECUTE": TokenType.EXECUTE,


Test patch:
diff --git a/tests/dialects/test_duckdb.py b/tests/dialects/test_duckdb.py
--- a/tests/dialects/test_duckdb.py
+++ b/tests/dialects/test_duckdb.py
@@ -7,6 +7,7 @@ class TestDuckDB(Validator):
     dialect = "duckdb"
 
     def test_duckdb(self):
+        self.validate_identity("CREATE TABLE color (name ENUM('RED', 'GREEN', 'BLUE'))")
         self.validate_identity(
             "SELECT * FROM x LEFT JOIN UNNEST(y)", "SELECT * FROM x LEFT JOIN UNNEST(y) ON TRUE"
         )
diff --git a/tests/fixtures/identity.sql b/tests/fixtures/identity.sql
--- a/tests/fixtures/identity.sql
+++ b/tests/fixtures/identity.sql
@@ -853,4 +853,5 @@ SELECT values
 SELECT values AS values FROM t WHERE values + 1 > 3
 SELECT truncate
 SELECT only
-TRUNCATE(a, b)
\ No newline at end of file
+TRUNCATE(a, b)
+SELECT enum