Repository: tobymao/sqlglot

Issue:
valid duckdb query fails to parse
**Fully reproducible code snippet**

This query cannot be parsed by sqlglot, but it is a valid duckdb query:

```
In [18]: import sqlglot as sg, sqlglot.expressions as sge

In [19]: import duckdb

In [20]: sql = """
    ...: SELECT
    ...:   LIST_APPLY(
    ...:     RANGE(
    ...:       1,
    ...:       GREATEST(
    ...:         LENGTH(LIST_VALUE(CAST(1 AS TINYINT), CAST(2 AS TINYINT), CAST(3 AS TINYINT))),
    ...:         LENGTH(LIST_VALUE(CAST(1 AS TINYINT), CAST(2 AS TINYINT), CAST(3 AS TINYINT)))
    ...:       ) + 1
    ...:     ),
    ...:     i -> {'f1': LIST_VALUE(CAST(1 AS TINYINT), CAST(2 AS TINYINT), CAST(3 AS TINYINT))[i], 'f2': LIST_VALUE(CAST(1 AS TINYINT), CAST(2 AS TINYINT), CAST(3 AS TINYINT))[i]}
    ...:   ) AS "ArrayZip()"
    ...: """

In [21]: duckdb.execute(sql).df()
Out[21]:
                                          ArrayZip()
0  [{'f1': 1, 'f2': 1}, {'f1': 2, 'f2': 2}, {'f1'...

In [22]: sg.parse_one(sql, read="duckdb")
...
ParseError: Expected }. Line 12, Col: 2.
  AS TINYINT))[i], 'f2': LIST_VALUE(CAST(1 AS TINYINT), CAST(2 AS TINYINT), CAST(3 AS TINYINT))[i]}
  ) AS "ArrayZip()"
```


Discussion:
A smaller example to reproduce this issue `{x: arr[i]}`.
Ah, thanks!

Resolving patch:
diff --git a/sqlglot/dialects/duckdb.py b/sqlglot/dialects/duckdb.py
--- a/sqlglot/dialects/duckdb.py
+++ b/sqlglot/dialects/duckdb.py
@@ -571,3 +571,9 @@ def generateseries_sql(self, expression: exp.GenerateSeries) -> str:
                 return rename_func("RANGE")(self, expression)
 
             return super().generateseries_sql(expression)
+
+        def bracket_sql(self, expression: exp.Bracket) -> str:
+            if isinstance(expression.this, exp.Array):
+                expression.this.replace(exp.paren(expression.this))
+
+            return super().bracket_sql(expression)
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -4316,7 +4316,7 @@ def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expr
 
                 if not isinstance(e, exp.PropertyEQ):
                     e = self.expression(
-                        exp.PropertyEQ, this=exp.to_identifier(e.name), expression=e.expression
+                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
                     )
 
                 if isinstance(e.this, exp.Column):
@@ -4735,9 +4735,9 @@ def _parse_bracket(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Exp
             lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
         )
 
-        if not self._match(TokenType.R_BRACKET) and bracket_kind == TokenType.L_BRACKET:
+        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
             self.raise_error("Expected ]")
-        elif not self._match(TokenType.R_BRACE) and bracket_kind == TokenType.L_BRACE:
+        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
             self.raise_error("Expected }")
 
         # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs


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
@@ -699,7 +699,19 @@ def test_array_index(self):
                 },
             )
             self.validate_identity(
-                "[x.STRING_SPLIT(' ')[1] FOR x IN ['1', '2', 3] IF x.CONTAINS('1')]"
+                "[x.STRING_SPLIT(' ')[i] FOR x IN ['1', '2', 3] IF x.CONTAINS('1')]"
+            )
+            self.validate_identity(
+                """SELECT LIST_VALUE(1)[i]""",
+                """SELECT ([1])[i]""",
+            )
+            self.validate_identity(
+                """{'x': LIST_VALUE(1)[i]}""",
+                """{'x': ([1])[i]}""",
+            )
+            self.validate_identity(
+                """SELECT LIST_APPLY(RANGE(1, 4), i -> {'f1': LIST_VALUE(1, 2, 3)[i], 'f2': LIST_VALUE(1, 2, 3)[i]})""",
+                """SELECT LIST_APPLY(RANGE(1, 4), i -> {'f1': ([1, 2, 3])[i], 'f2': ([1, 2, 3])[i]})""",
             )
 
             self.assertEqual(
@@ -709,8 +721,6 @@ def test_array_index(self):
                     "WARNING:sqlglot:Applying array index offset (1)",
                     "WARNING:sqlglot:Applying array index offset (1)",
                     "WARNING:sqlglot:Applying array index offset (1)",
-                    "WARNING:sqlglot:Applying array index offset (-1)",
-                    "WARNING:sqlglot:Applying array index offset (1)",
                 ],
             )