Repository: tobymao/sqlglot

Issue:
Regression in 25.1.0 when the write dialect is postgres and the read dialect is omitted
Hi, we ran into the following change of behaviour in 25.1.0.

```
>>> from sqlglot import parse_one

>>> parse_one("SELECT unnest(ARRAY[1, 2, 3])").sql()
'SELECT UNNEST(1, 2, 3)'

>>> parse_one("SELECT unnest(ARRAY[1, 2, 3])").sql(dialect="postgres")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/ronan/.virtualenvs/insitu/lib/python3.9/site-packages/sqlglot/expressions.py", line 597, in sql
    return Dialect.get_or_raise(dialect).generate(self, **opts)
  File "/home/ronan/.virtualenvs/insitu/lib/python3.9/site-packages/sqlglot/dialects/dialect.py", line 538, in generate
    return self.generator(**opts).generate(expression, copy=copy)
  File "/home/ronan/.virtualenvs/insitu/lib/python3.9/site-packages/sqlglot/generator.py", line 623, in generate
    sql = self.sql(expression).strip()
  File "/home/ronan/.virtualenvs/insitu/lib/python3.9/site-packages/sqlglot/generator.py", line 777, in sql
    sql = transform(self, expression)
  File "/home/ronan/.virtualenvs/insitu/lib/python3.9/site-packages/sqlglot/transforms.py", line 650, in _to_sql
    return _sql_handler(expression)
  File "/home/ronan/.virtualenvs/insitu/lib/python3.9/site-packages/sqlglot/generator.py", line 2302, in select_sql
    expressions = self.expressions(expression)
  File "/home/ronan/.virtualenvs/insitu/lib/python3.9/site-packages/sqlglot/generator.py", line 3371, in expressions
    sql = self.sql(e, comment=False)
  File "/home/ronan/.virtualenvs/insitu/lib/python3.9/site-packages/sqlglot/generator.py", line 782, in sql
    sql = getattr(self, exp_handler_name)(expression)
  File "/home/ronan/.virtualenvs/insitu/lib/python3.9/site-packages/sqlglot/dialects/postgres.py", line 584, in unnest_sql
    if len(expression.expressions) == 1:
TypeError: object of type 'Array' has no len()

>>> parse_one("SELECT unnest(ARRAY[1, 2, 3])", dialect="postgres").sql(dialect="postgres")
'SELECT UNNEST(ARRAY[1, 2, 3])'
```

I realized that this only occurs when the read dialect is not specified, so the workaround for us was to make sure that we added the dialect parameter to `parse_one()`, but I thought I would file the issue in case it would be useful.


Discussion:

Patch:
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
index cf5cc9d4..cbce4b7a 100644
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -150,6 +150,7 @@ class Parser(metaclass=_Parser):
             to=exp.DataType(this=exp.DataType.Type.TEXT),
         ),
         "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
+        "HEX": build_hex,
         "JSON_EXTRACT": build_extract_json_with_path(exp.JSONExtract),
         "JSON_EXTRACT_SCALAR": build_extract_json_with_path(exp.JSONExtractScalar),
         "JSON_EXTRACT_PATH_TEXT": build_extract_json_with_path(exp.JSONExtractScalar),
@@ -157,11 +158,13 @@ class Parser(metaclass=_Parser):
         "LOG": build_logarithm,
         "LOG2": lambda args: exp.Log(this=exp.Literal.number(2), expression=seq_get(args, 0)),
         "LOG10": lambda args: exp.Log(this=exp.Literal.number(10), expression=seq_get(args, 0)),
+        "LOWER": build_lower,
         "MOD": build_mod,
         "TIME_TO_TIME_STR": lambda args: exp.Cast(
             this=seq_get(args, 0),
             to=exp.DataType(this=exp.DataType.Type.TEXT),
         ),
+        "TO_HEX": build_hex,
         "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
             this=exp.Cast(
                 this=seq_get(args, 0),
@@ -170,11 +173,9 @@ class Parser(metaclass=_Parser):
             start=exp.Literal.number(1),
             length=exp.Literal.number(10),
         ),
-        "VAR_MAP": build_var_map,
-        "LOWER": build_lower,
+        "UNNEST": lambda args: exp.Unnest(expressions=ensure_list(seq_get(args, 0))),
         "UPPER": build_upper,
-        "HEX": build_hex,
-        "TO_HEX": build_hex,
+        "VAR_MAP": build_var_map,
     }
 
     NO_PAREN_FUNCTIONS = {


Test patch:
diff --git a/tests/test_parser.py b/tests/test_parser.py
index d6849c3d..d6be7ae3 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -102,6 +102,13 @@ class TestParser(unittest.TestCase):
     def test_float(self):
         self.assertEqual(parse_one(".2"), parse_one("0.2"))
 
+    def test_unnest(self):
+        unnest_sql = "UNNEST(foo)"
+        expr = parse_one(unnest_sql)
+        self.assertIsInstance(expr, exp.Unnest)
+        self.assertIsInstance(expr.expressions, list)
+        self.assertEqual(expr.sql(), unnest_sql)
+
     def test_unnest_projection(self):
         expr = parse_one("SELECT foo IN UNNEST(bla) AS bar")
         self.assertIsInstance(expr.selects[0], exp.Alias)