Repository: tobymao/sqlglot

Issue:
Interval parsing on postgres broken since 23.4.0
Recently my test suite started failing because it couldn't parse this query:

```python
Python 3.12.2 (main, Feb 25 2024, 04:38:01) [Clang 17.0.6 ] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sqlglot
>>> query = 'UPDATE "tests_duration" SET "duration" = \'0 days 60.000000 seconds\'::interval WHERE "tests_duration"."id" IN (2, 3)'
>>> sqlglot.parse_one(query, read="postgres")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/lily/work/sqlglot/sqlglot/__init__.py", line 139, in parse_one
    result = dialect.parse(sql, **opts)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lily/work/sqlglot/sqlglot/dialects/dialect.py", line 503, in parse
    return self.parser(**opts).parse(self.tokenize(sql), sql)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lily/work/sqlglot/sqlglot/parser.py", line 1166, in parse
    return self._parse(
           ^^^^^^^^^^^^
  File "/home/lily/work/sqlglot/sqlglot/parser.py", line 1235, in _parse
    self.raise_error("Invalid expression / Unexpected token")
  File "/home/lily/work/sqlglot/sqlglot/parser.py", line 1276, in raise_error
    raise error
sqlglot.errors.ParseError: Invalid expression / Unexpected token. Line 1, Col: 100.
  UPDATE "tests_duration" SET "duration" = '0 days 60.000000 seconds'::interval WHERE "tests_duration"."id" IN (2, 3)
```

I was able to bisect to find that this broke at https://github.com/tobymao/sqlglot/commit/a630c50737bb9deb6f44e1afd374b113612a1d24.

On `v23.3.0`, this was the output:

```python
>>> import sqlglot
>>> query = 'UPDATE "tests_duration" SET "duration" = \'0 days 60.000000 seconds\'::interval WHERE "tests_duration"."id" IN (2, 3)'
>>> sqlglot.parse_one(query, read="postgres")
Update(
  this=Table(
    this=Identifier(this=tests_duration, quoted=True)),
  expressions=[
    EQ(
      this=Column(
        this=Identifier(this=duration, quoted=True)),
      expression=Cast(
        this=Literal(this=0 days 60.000000 seconds, is_string=True),
        to=DataType(this=Type.INTERVAL)))],
  where=Where(
    this=In(
      this=Column(
        this=Identifier(this=id, quoted=True),
        table=Identifier(this=tests_duration, quoted=True)),
      expressions=[
        Literal(this=2, is_string=False),
        Literal(this=3, is_string=False)])))
```


Discussion:
Taking a look, thanks for report this 👍

Resolving patch:
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -4100,14 +4100,11 @@ def _parse_types(
             elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
                 maybe_func = False
         elif type_token == TokenType.INTERVAL:
-            unit = self._parse_var(any_token=True, upper=True)
-
-            if self._match_text_seq("TO"):
-                unit = exp.IntervalSpan(
-                    this=unit, expression=self._parse_var(any_token=True, upper=True)
-                )
-
+            unit = self._parse_var(upper=True)
             if unit:
+                if self._match_text_seq("TO"):
+                    unit = exp.IntervalSpan(this=unit, expression=self._parse_var(upper=True))
+
                 this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
             else:
                 this = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)


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
@@ -63,6 +63,9 @@ def test_postgres(self):
         self.validate_identity("EXEC AS myfunc @id = 123", check_command_warning=True)
         self.validate_identity("SELECT CURRENT_USER")
         self.validate_identity("SELECT * FROM ONLY t1")
+        self.validate_identity(
+            """UPDATE "x" SET "y" = CAST('0 days 60.000000 seconds' AS INTERVAL) WHERE "x"."id" IN (2, 3)"""
+        )
         self.validate_identity(
             "WITH t1 AS MATERIALIZED (SELECT 1), t2 AS NOT MATERIALIZED (SELECT 2) SELECT * FROM t1, t2"
         )