Repository: tobymao/sqlglot

Issue:
Failure to parse nested SELECT in ARRAY [Dialect: BigQuery]
sqlglot 10.1.3 fails to parse this query:

```sql
SELECT ARRAY(SELECT x * 2 FROM UNNEST([0, 1]) AS x)
```

The inner `SELECT` makes it fail.
(My actual query is of course more complex than this, but I trimmed it down to the essentials)

Full code:

```python
from sqlglot import parse_one
content = "SELECT ARRAY(SELECT x FROM UNNEST([0, 1]) AS x)"
print(repr(parse_one(content, read="bigquery")))
```

Error:

```
sqlglot.errors.ParseError: Expecting ). Line 1, Col: 14.
  SELECT ARRAY(_SELECT_ x FROM UNNEST([0, 1]) AS x)
```

(Underscores used to highlight the part highlighted in the terminal)

Full error:

<details>

```
Traceback (most recent call last):
  File "/home/jer/py-sql-extract/bug.py", line 6, in <module>
    print(repr(parse_one(content, read="bigquery")))
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/__init__.py", line 82, in parse_one
    result = dialect.parse(sql, **opts)
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/dialects/dialect.py", line 150, in parse
    return self.parser(**opts).parse(self.tokenizer.tokenize(sql), sql)
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 622, in parse
    return self._parse(
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 660, in _parse
    expressions.append(parse_method(self))
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 772, in _parse_statement
    expression = self._parse_set_operations(expression) if expression else self._parse_select()
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 1119, in _parse_select
    expressions = self._parse_csv(self._parse_expression)
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 2541, in _parse_csv
    parse_result = parse_method()
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 1642, in _parse_expression
    return self._parse_alias(self._parse_conjunction())
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 1645, in _parse_conjunction
    return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 2555, in _parse_tokens
    this = parse_method()
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 1648, in _parse_equality
    return self._parse_tokens(self._parse_comparison, self.EQUALITY)
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 2555, in _parse_tokens
    this = parse_method()
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 1651, in _parse_comparison
    return self._parse_tokens(self._parse_range, self.COMPARISON)
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 2555, in _parse_tokens
    this = parse_method()
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 1654, in _parse_range
    this = self._parse_bitwise()
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 1716, in _parse_bitwise
    this = self._parse_term()
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 1739, in _parse_term
    return self._parse_tokens(self._parse_factor, self.TERM)
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 2555, in _parse_tokens
    this = parse_method()
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 1742, in _parse_factor
    return self._parse_tokens(self._parse_unary, self.FACTOR)
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 2555, in _parse_tokens
    this = parse_method()
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 1747, in _parse_unary
    return self._parse_at_time_zone(self._parse_type())
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 1755, in _parse_type
    this = self._parse_column()
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 1864, in _parse_column
    this = self._parse_field()
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 1935, in _parse_field
    return self._parse_primary() or self._parse_function() or self._parse_id_var(any_token)
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 1982, in _parse_function
    self._match_r_paren(this)
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 2698, in _match_r_paren
    self.raise_error("Expecting )")
  File "/home/jer/py-sql-extract/.venv/lib/python3.10/site-packages/sqlglot/parser.py", line 697, in raise_error
    raise error
sqlglot.errors.ParseError: Expecting ). Line 1, Col: 14.
  SELECT ARRAY([4mSELECT[0m x FROM UNNEST([0, 1]) AS x)
```

</details>

Discussion:

Patch:
diff --git a/sqlglot/dialects/bigquery.py b/sqlglot/dialects/bigquery.py
index 5b44912a..0ab32188 100644
--- a/sqlglot/dialects/bigquery.py
+++ b/sqlglot/dialects/bigquery.py
@@ -144,6 +144,7 @@ class BigQuery(Dialect):
 
         FUNCTION_PARSERS = {
             **parser.Parser.FUNCTION_PARSERS,
+            "ARRAY": lambda self: self.expression(exp.Array, expressions=[self._parse_statement()]),
         }
         FUNCTION_PARSERS.pop("TRIM")
 
@@ -161,7 +162,6 @@ class BigQuery(Dialect):
     class Generator(generator.Generator):
         TRANSFORMS = {
             **generator.Generator.TRANSFORMS,
-            exp.Array: inline_array_sql,
             exp.ArraySize: rename_func("ARRAY_LENGTH"),
             exp.DateAdd: _date_add_sql("DATE", "ADD"),
             exp.DateSub: _date_add_sql("DATE", "SUB"),
@@ -210,24 +210,31 @@ class BigQuery(Dialect):
 
         EXPLICIT_UNION = True
 
-        def transaction_sql(self, *_):
+        def array_sql(self, expression: exp.Array) -> str:
+            first_arg = seq_get(expression.expressions, 0)
+            if isinstance(first_arg, exp.Subqueryable):
+                return f"ARRAY{self.wrap(self.sql(first_arg))}"
+
+            return inline_array_sql(self, expression)
+
+        def transaction_sql(self, *_) -> str:
             return "BEGIN TRANSACTION"
 
-        def commit_sql(self, *_):
+        def commit_sql(self, *_) -> str:
             return "COMMIT TRANSACTION"
 
-        def rollback_sql(self, *_):
+        def rollback_sql(self, *_) -> str:
             return "ROLLBACK TRANSACTION"
 
-        def in_unnest_op(self, unnest):
-            return self.sql(unnest)
+        def in_unnest_op(self, expression: exp.Unnest) -> str:
+            return self.sql(expression)
 
-        def except_op(self, expression):
+        def except_op(self, expression: exp.Except) -> str:
             if not expression.args.get("distinct", False):
                 self.unsupported("EXCEPT without DISTINCT is not supported in BigQuery")
             return f"EXCEPT{' DISTINCT' if expression.args.get('distinct') else ' ALL'}"
 
-        def intersect_op(self, expression):
+        def intersect_op(self, expression: exp.Intersect) -> str:
             if not expression.args.get("distinct", False):
                 self.unsupported("INTERSECT without DISTINCT is not supported in BigQuery")
             return f"INTERSECT{' DISTINCT' if expression.args.get('distinct') else ' ALL'}"


Test patch:
diff --git a/tests/dialects/test_bigquery.py b/tests/dialects/test_bigquery.py
index cc443114..5c5a7713 100644
--- a/tests/dialects/test_bigquery.py
+++ b/tests/dialects/test_bigquery.py
@@ -94,6 +94,20 @@ class TestBigQuery(Validator):
                 "spark": "SELECT * FROM UNNEST(ARRAY('7', '14')) AS (x)",
             },
         )
+        self.validate_all(
+            "SELECT ARRAY(SELECT x FROM UNNEST([0, 1]) AS x)",
+            write={"bigquery": "SELECT ARRAY(SELECT x FROM UNNEST([0, 1]) AS x)"},
+        )
+        self.validate_all(
+            "SELECT ARRAY(SELECT DISTINCT x FROM UNNEST(some_numbers) AS x) AS unique_numbers",
+            write={
+                "bigquery": "SELECT ARRAY(SELECT DISTINCT x FROM UNNEST(some_numbers) AS x) AS unique_numbers"
+            },
+        )
+        self.validate_all(
+            "SELECT ARRAY(SELECT * FROM foo JOIN bla ON x = y)",
+            write={"bigquery": "SELECT ARRAY(SELECT * FROM foo JOIN bla ON x = y)"},
+        )
 
         self.validate_all(
             "x IS unknown",