Repository: tobymao/sqlglot

Issue:
Support for parsing `timestamp with/without time zone[]` and `time with/without time zone[]` with postgres
**Is your feature request related to a problem? Please describe.**

Not related to a problem.

**Describe the solution you'd like**

I'd like sqlglot to support parsing the `timestamp without time zone[]` and `time without time zone[]` types for the postgres dialect.

**Describe alternatives you've considered**

I haven't considered any alternatives

**Additional context**

Proof that this is a thing :)

```
ibis_testing> create table t (x timestamp without time zone []);
CREATE TABLE
Time: 0.009s
```


Discussion:
can you share the docs for this @cpcloud 
```select cast('2022-01-01' as timestamp without time zone [])``` this is a syntax error
```
ibis_testing> select cast(array['2022-01-01'] as timestamp without time zone[]);
+-------------------------+
| array                   |
|-------------------------|
| ['2022-01-01 00:00:00'] |
+-------------------------+
```

You need to wrap it in the array constructor :)
The [arrays docs](https://www.postgresql.org/docs/current/arrays.html) say

> PostgreSQL allows columns of a table to be defined as variable-length multidimensional arrays. Arrays of any built-in or user-defined base type, enum type, composite type, range type, or domain can be created.

Since `timestamp without time zone` is a built in type, it would follow that `timestamp without time zone[]` is a valid array type.

After the first example there's:

> As shown, an array data type is named by appending square brackets ([]) to the data type name of the array elements.

Resolving patch:
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -3139,29 +3139,9 @@ def _parse_types(
 
             maybe_func = True
 
-        if self._match_pair(TokenType.L_BRACKET, TokenType.R_BRACKET):
-            this = exp.DataType(
-                this=exp.DataType.Type.ARRAY,
-                expressions=[
-                    exp.DataType(
-                        this=exp.DataType.Type[type_token.value],
-                        expressions=expressions,
-                        nested=nested,
-                    )
-                ],
-                nested=True,
-            )
-
-            while self._match_pair(TokenType.L_BRACKET, TokenType.R_BRACKET):
-                this = exp.DataType(this=exp.DataType.Type.ARRAY, expressions=[this], nested=True)
-
-            return this
-
-        if self._match(TokenType.L_BRACKET):
-            self._retreat(index)
-            return None
-
+        this: t.Optional[exp.Expression] = None
         values: t.Optional[t.List[t.Optional[exp.Expression]]] = None
+
         if nested and self._match(TokenType.LT):
             if is_struct:
                 expressions = self._parse_csv(self._parse_struct_types)
@@ -3177,14 +3157,13 @@ def _parse_types(
                 values = self._parse_csv(self._parse_conjunction)
                 self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
 
-        value: t.Optional[exp.Expression] = None
         if type_token in self.TIMESTAMPS:
             if self._match_text_seq("WITH", "TIME", "ZONE"):
                 maybe_func = False
-                value = exp.DataType(this=exp.DataType.Type.TIMESTAMPTZ, expressions=expressions)
+                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPTZ, expressions=expressions)
             elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
                 maybe_func = False
-                value = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
+                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
             elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
                 maybe_func = False
         elif type_token == TokenType.INTERVAL:
@@ -3197,11 +3176,11 @@ def _parse_types(
 
             unit = not span and self._parse_var()
             if not unit:
-                value = self.expression(
+                this = self.expression(
                     exp.DataType, this=exp.DataType.Type.INTERVAL, expressions=span
                 )
             else:
-                value = self.expression(exp.Interval, unit=unit)
+                this = self.expression(exp.Interval, unit=unit)
 
         if maybe_func and check_func:
             index2 = self._index
@@ -3213,16 +3192,19 @@ def _parse_types(
 
             self._retreat(index2)
 
-        if value:
-            return value
+        if not this:
+            this = exp.DataType(
+                this=exp.DataType.Type[type_token.value],
+                expressions=expressions,
+                nested=nested,
+                values=values,
+                prefix=prefix,
+            )
+
+        while self._match_pair(TokenType.L_BRACKET, TokenType.R_BRACKET):
+            this = exp.DataType(this=exp.DataType.Type.ARRAY, expressions=[this], nested=True)
 
-        return exp.DataType(
-            this=exp.DataType.Type[type_token.value],
-            expressions=expressions,
-            nested=nested,
-            values=values,
-            prefix=prefix,
-        )
+        return this
 
     def _parse_struct_types(self) -> t.Optional[exp.Expression]:
         this = self._parse_type() or self._parse_id_var()


Test patch:
diff --git a/tests/dialects/test_postgres.py b/tests/dialects/test_postgres.py
--- a/tests/dialects/test_postgres.py
+++ b/tests/dialects/test_postgres.py
@@ -9,6 +9,10 @@ class TestPostgres(Validator):
     dialect = "postgres"
 
     def test_ddl(self):
+        self.validate_identity(
+            "CREATE TABLE test (x TIMESTAMP WITHOUT TIME ZONE[][])",
+            "CREATE TABLE test (x TIMESTAMP[][])",
+        )
         self.validate_identity("CREATE TABLE test (elems JSONB[])")
         self.validate_identity("CREATE TABLE public.y (x TSTZRANGE NOT NULL)")
         self.validate_identity("CREATE TABLE test (foo HSTORE)")