We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Table incorrectly parsed as column
# Description
Table of format `<schema>.<table>` in a join gets mis-parsed as a column. In the attached example, the table `"usage"."company_names"` gets misparsed as a column. 

### Version details
- Dialect is 'redshift'
- The issue exists on the latest pip version of sqlglot (21.0.2)
- The issue doesn't exist on the latest pip version of sqlglot (20.4.0)

### Correct output with sqlglot==20.4.0
```
Python 3.11.7 (main, Dec  4 2023, 18:10:11) [Clang 15.0.0 (clang-1500.1.0.2.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sqlglot
from sqlglot import parse_one
sqlglot.__version__>>> from sqlglot import parse_one
>>> sqlglot.__version__
'20.4.0'
>>> dialect = 'redshift'
>>> query = 'SELECT * FROM "usage"."usage" JOIN "usage"."company_names" ON "company_names"."id" = "usage"."customerid"'
>>> parse_one(query, dialect=dialect)
(SELECT expressions: 
  (STAR ), from: 
  (FROM this: 
    (TABLE this: 
      (IDENTIFIER this: usage, quoted: True), db: 
      (IDENTIFIER this: usage, quoted: True))), joins: 
  (JOIN this: 
    (TABLE this: 
      (IDENTIFIER this: company_names, quoted: True), db: 
      (IDENTIFIER this: usage, quoted: True)), on: 
    (EQ this: 
      (COLUMN this: 
        (IDENTIFIER this: id, quoted: True), table: 
        (IDENTIFIER this: company_names, quoted: True)), expression: 
      (COLUMN this: 
        (IDENTIFIER this: customerid, quoted: True), table: 
        (IDENTIFIER this: usage, quoted: True)))))
```        

### Incorrect output with sqlglot==21.0.2
```
Python 3.11.7 (main, Dec  4 2023, 18:10:11) [Clang 15.0.0 (clang-1500.1.0.2.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sqlglot
from sqlglot import parse_one
sqlglot.__version__>>> from sqlglot import parse_one
>>> sqlglot.__version__
'21.0.2'
>>> dialect = 'redshift'
>>> query = 'SELECT * FROM "usage"."usage" JOIN "usage"."company_names" ON "company_names"."id" = "usage"."customerid"'
>>> parse_one(query, dialect=dialect)
Select(
  expressions=[
    Star()],
  from=From(
    this=Table(
      this=Identifier(this=usage, quoted=True),
      db=Identifier(this=usage, quoted=True))),
  joins=[
    Join(
      this=Column(
        this=Identifier(this=company_names, quoted=True),
        table=Identifier(this=usage, quoted=True)),
      on=EQ(
        this=Column(
          this=Identifier(this=id, quoted=True),
          table=Identifier(this=company_names, quoted=True)),
        expression=Column(
          this=Identifier(this=customerid, quoted=True),
          table=Identifier(this=usage, quoted=True))))])
```
      


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sqlglot/dialects/redshift.py`
Content:
```
1 from __future__ import annotations
2 
3 import typing as t
4 
5 from sqlglot import exp, transforms
6 from sqlglot.dialects.dialect import (
7     NormalizationStrategy,
8     concat_to_dpipe_sql,
9     concat_ws_to_dpipe_sql,
10     date_delta_sql,
11     generatedasidentitycolumnconstraint_sql,
12     json_extract_segments,
13     no_tablesample_sql,
14     rename_func,
15 )
16 from sqlglot.dialects.postgres import Postgres
17 from sqlglot.helper import seq_get
18 from sqlglot.tokens import TokenType
19 
20 if t.TYPE_CHECKING:
21     from sqlglot._typing import E
22 
23 
24 def _parse_date_delta(expr_type: t.Type[E]) -> t.Callable[[t.List], E]:
25     def _parse_delta(args: t.List) -> E:
26         expr = expr_type(this=seq_get(args, 2), expression=seq_get(args, 1), unit=seq_get(args, 0))
27         if expr_type is exp.TsOrDsAdd:
28             expr.set("return_type", exp.DataType.build("TIMESTAMP"))
29 
30         return expr
31 
32     return _parse_delta
33 
34 
35 class Redshift(Postgres):
36     # https://docs.aws.amazon.com/redshift/latest/dg/r_names.html
37     NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE
38 
39     SUPPORTS_USER_DEFINED_TYPES = False
40     INDEX_OFFSET = 0
41 
42     TIME_FORMAT = "'YYYY-MM-DD HH:MI:SS'"
43     TIME_MAPPING = {
44         **Postgres.TIME_MAPPING,
45         "MON": "%b",
46         "HH": "%H",
47     }
48 
49     class Parser(Postgres.Parser):
50         FUNCTIONS = {
51             **Postgres.Parser.FUNCTIONS,
52             "ADD_MONTHS": lambda args: exp.TsOrDsAdd(
53                 this=seq_get(args, 0),
54                 expression=seq_get(args, 1),
55                 unit=exp.var("month"),
56                 return_type=exp.DataType.build("TIMESTAMP"),
57             ),
58             "DATEADD": _parse_date_delta(exp.TsOrDsAdd),
59             "DATE_ADD": _parse_date_delta(exp.TsOrDsAdd),
60             "DATEDIFF": _parse_date_delta(exp.TsOrDsDiff),
61             "DATE_DIFF": _parse_date_delta(exp.TsOrDsDiff),
62             "GETDATE": exp.CurrentTimestamp.from_arg_list,
63             "LISTAGG": exp.GroupConcat.from_arg_list,
64             "STRTOL": exp.FromBase.from_arg_list,
65         }
66 
67         NO_PAREN_FUNCTION_PARSERS = {
68             **Postgres.Parser.NO_PAREN_FUNCTION_PARSERS,
69             "APPROXIMATE": lambda self: self._parse_approximate_count(),
70             "SYSDATE": lambda self: self.expression(exp.CurrentTimestamp, transaction=True),
71         }
72 
73         def _parse_table(
74             self,
75             schema: bool = False,
76             joins: bool = False,
77             alias_tokens: t.Optional[t.Collection[TokenType]] = None,
78             parse_bracket: bool = False,
79             is_db_reference: bool = False,
80         ) -> t.Optional[exp.Expression]:
81             # Redshift supports UNPIVOTing SUPER objects, e.g. `UNPIVOT foo.obj[0] AS val AT attr`
82             unpivot = self._match(TokenType.UNPIVOT)
83             table = super()._parse_table(
84                 schema=schema,
85                 joins=joins,
86                 alias_tokens=alias_tokens,
87                 parse_bracket=parse_bracket,
88                 is_db_reference=is_db_reference,
89             )
90 
91             return self.expression(exp.Pivot, this=table, unpivot=True) if unpivot else table
92 
93         def _parse_types(
94             self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
95         ) -> t.Optional[exp.Expression]:
96             this = super()._parse_types(
97                 check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
98             )
99 
100             if (
101                 isinstance(this, exp.DataType)
102                 and this.is_type("varchar")
103                 and this.expressions
104                 and this.expressions[0].this == exp.column("MAX")
105             ):
106                 this.set("expressions", [exp.var("MAX")])
107 
108             return this
109 
110         def _parse_convert(
111             self, strict: bool, safe: t.Optional[bool] = None
112         ) -> t.Optional[exp.Expression]:
113             to = self._parse_types()
114             self._match(TokenType.COMMA)
115             this = self._parse_bitwise()
116             return self.expression(exp.TryCast, this=this, to=to, safe=safe)
117 
118         def _parse_approximate_count(self) -> t.Optional[exp.ApproxDistinct]:
119             index = self._index - 1
120             func = self._parse_function()
121 
122             if isinstance(func, exp.Count) and isinstance(func.this, exp.Distinct):
123                 return self.expression(exp.ApproxDistinct, this=seq_get(func.this.expressions, 0))
124             self._retreat(index)
125             return None
126 
127         def _parse_query_modifiers(
128             self, this: t.Optional[exp.Expression]
129         ) -> t.Optional[exp.Expression]:
130             this = super()._parse_query_modifiers(this)
131 
132             if this:
133                 refs = set()
134 
135                 for i, join in enumerate(this.args.get("joins", [])):
136                     refs.add(
137                         (
138                             this.args["from"] if i == 0 else this.args["joins"][i - 1]
139                         ).alias_or_name.lower()
140                     )
141                     table = join.this
142 
143                     if isinstance(table, exp.Table):
144                         if table.parts[0].name.lower() in refs:
145                             table.replace(table.to_column())
146             return this
147 
148     class Tokenizer(Postgres.Tokenizer):
149         BIT_STRINGS = []
150         HEX_STRINGS = []
151         STRING_ESCAPES = ["\\", "'"]
152 
153         KEYWORDS = {
154             **Postgres.Tokenizer.KEYWORDS,
155             "HLLSKETCH": TokenType.HLLSKETCH,
156             "SUPER": TokenType.SUPER,
157             "TOP": TokenType.TOP,
158             "UNLOAD": TokenType.COMMAND,
159             "VARBYTE": TokenType.VARBINARY,
160         }
161 
162         # Redshift allows # to appear as a table identifier prefix
163         SINGLE_TOKENS = Postgres.Tokenizer.SINGLE_TOKENS.copy()
164         SINGLE_TOKENS.pop("#")
165 
166     class Generator(Postgres.Generator):
167         LOCKING_READS_SUPPORTED = False
168         QUERY_HINTS = False
169         VALUES_AS_TABLE = False
170         TZ_TO_WITH_TIME_ZONE = True
171         NVL2_SUPPORTED = True
172         LAST_DAY_SUPPORTS_DATE_PART = False
173 
174         TYPE_MAPPING = {
175             **Postgres.Generator.TYPE_MAPPING,
176             exp.DataType.Type.BINARY: "VARBYTE",
177             exp.DataType.Type.INT: "INTEGER",
178             exp.DataType.Type.TIMETZ: "TIME",
179             exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP",
180             exp.DataType.Type.VARBINARY: "VARBYTE",
181         }
182 
183         TRANSFORMS = {
184             **Postgres.Generator.TRANSFORMS,
185             exp.Concat: concat_to_dpipe_sql,
186             exp.ConcatWs: concat_ws_to_dpipe_sql,
187             exp.ApproxDistinct: lambda self,
188             e: f"APPROXIMATE COUNT(DISTINCT {self.sql(e, 'this')})",
189             exp.CurrentTimestamp: lambda self, e: (
190                 "SYSDATE" if e.args.get("transaction") else "GETDATE()"
191             ),
192             exp.DateAdd: date_delta_sql("DATEADD"),
193             exp.DateDiff: date_delta_sql("DATEDIFF"),
194             exp.DistKeyProperty: lambda self, e: f"DISTKEY({e.name})",
195             exp.DistStyleProperty: lambda self, e: self.naked_property(e),
196             exp.FromBase: rename_func("STRTOL"),
197             exp.GeneratedAsIdentityColumnConstraint: generatedasidentitycolumnconstraint_sql,
198             exp.JSONExtract: json_extract_segments("JSON_EXTRACT_PATH_TEXT"),
199             exp.GroupConcat: rename_func("LISTAGG"),
200             exp.ParseJSON: rename_func("JSON_PARSE"),
201             exp.Select: transforms.preprocess(
202                 [transforms.eliminate_distinct_on, transforms.eliminate_semi_and_anti_joins]
203             ),
204             exp.SortKeyProperty: lambda self,
205             e: f"{'COMPOUND ' if e.args['compound'] else ''}SORTKEY({self.format_args(*e.this)})",
206             exp.TableSample: no_tablesample_sql,
207             exp.TsOrDsAdd: date_delta_sql("DATEADD"),
208             exp.TsOrDsDiff: date_delta_sql("DATEDIFF"),
209         }
210 
211         # Postgres maps exp.Pivot to no_pivot_sql, but Redshift support pivots
212         TRANSFORMS.pop(exp.Pivot)
213 
214         # Redshift uses the POW | POWER (expr1, expr2) syntax instead of expr1 ^ expr2 (postgres)
215         TRANSFORMS.pop(exp.Pow)
216 
217         # Redshift supports ANY_VALUE(..)
218         TRANSFORMS.pop(exp.AnyValue)
219 
220         # Redshift supports LAST_DAY(..)
221         TRANSFORMS.pop(exp.LastDay)
222 
223         RESERVED_KEYWORDS = {*Postgres.Generator.RESERVED_KEYWORDS, "snapshot", "type"}
224 
225         def with_properties(self, properties: exp.Properties) -> str:
226             """Redshift doesn't have `WITH` as part of their with_properties so we remove it"""
227             return self.properties(properties, prefix=" ", suffix="")
228 
229         def cast_sql(self, expression: exp.Cast, safe_prefix: t.Optional[str] = None) -> str:
230             if expression.is_type(exp.DataType.Type.JSON):
231                 # Redshift doesn't support a JSON type, so casting to it is treated as a noop
232                 return self.sql(expression, "this")
233 
234             return super().cast_sql(expression, safe_prefix=safe_prefix)
235 
236         def datatype_sql(self, expression: exp.DataType) -> str:
237             """
238             Redshift converts the `TEXT` data type to `VARCHAR(255)` by default when people more generally mean
239             VARCHAR of max length which is `VARCHAR(max)` in Redshift. Therefore if we get a `TEXT` data type
240             without precision we convert it to `VARCHAR(max)` and if it does have precision then we just convert
241             `TEXT` to `VARCHAR`.
242             """
243             if expression.is_type("text"):
244                 expression.set("this", exp.DataType.Type.VARCHAR)
245                 precision = expression.args.get("expressions")
246 
247                 if not precision:
248                     expression.append("expressions", exp.var("MAX"))
249 
250             return super().datatype_sql(expression)
251
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/sqlglot/dialects/redshift.py b/sqlglot/dialects/redshift.py
--- a/sqlglot/dialects/redshift.py
+++ b/sqlglot/dialects/redshift.py
@@ -136,11 +136,11 @@
                     refs.add(
                         (
                             this.args["from"] if i == 0 else this.args["joins"][i - 1]
-                        ).alias_or_name.lower()
+                        ).this.alias.lower()
                     )
-                    table = join.this
 
-                    if isinstance(table, exp.Table):
+                    table = join.this
+                    if isinstance(table, exp.Table) and not join.args.get("on"):
                         if table.parts[0].name.lower() in refs:
                             table.replace(table.to_column())
             return this

{"golden_diff": "diff --git a/sqlglot/dialects/redshift.py b/sqlglot/dialects/redshift.py\n--- a/sqlglot/dialects/redshift.py\n+++ b/sqlglot/dialects/redshift.py\n@@ -136,11 +136,11 @@\n                     refs.add(\n                         (\n                             this.args[\"from\"] if i == 0 else this.args[\"joins\"][i - 1]\n-                        ).alias_or_name.lower()\n+                        ).this.alias.lower()\n                     )\n-                    table = join.this\n \n-                    if isinstance(table, exp.Table):\n+                    table = join.this\n+                    if isinstance(table, exp.Table) and not join.args.get(\"on\"):\n                         if table.parts[0].name.lower() in refs:\n                             table.replace(table.to_column())\n             return this\n", "issue": "Table incorrectly parsed as column\n# Description\r\nTable of format `<schema>.<table>` in a join gets mis-parsed as a column. In the attached example, the table `\"usage\".\"company_names\"` gets misparsed as a column. \r\n\r\n### Version details\r\n- Dialect is 'redshift'\r\n- The issue exists on the latest pip version of sqlglot (21.0.2)\r\n- The issue doesn't exist on the latest pip version of sqlglot (20.4.0)\r\n\r\n### Correct output with sqlglot==20.4.0\r\n```\r\nPython 3.11.7 (main, Dec  4 2023, 18:10:11) [Clang 15.0.0 (clang-1500.1.0.2.5)] on darwin\r\nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\r\n>>> import sqlglot\r\nfrom sqlglot import parse_one\r\nsqlglot.__version__>>> from sqlglot import parse_one\r\n>>> sqlglot.__version__\r\n'20.4.0'\r\n>>> dialect = 'redshift'\r\n>>> query = 'SELECT * FROM \"usage\".\"usage\" JOIN \"usage\".\"company_names\" ON \"company_names\".\"id\" = \"usage\".\"customerid\"'\r\n>>> parse_one(query, dialect=dialect)\r\n(SELECT expressions: \r\n  (STAR ), from: \r\n  (FROM this: \r\n    (TABLE this: \r\n      (IDENTIFIER this: usage, quoted: True), db: \r\n      (IDENTIFIER this: usage, quoted: True))), joins: \r\n  (JOIN this: \r\n    (TABLE this: \r\n      (IDENTIFIER this: company_names, quoted: True), db: \r\n      (IDENTIFIER this: usage, quoted: True)), on: \r\n    (EQ this: \r\n      (COLUMN this: \r\n        (IDENTIFIER this: id, quoted: True), table: \r\n        (IDENTIFIER this: company_names, quoted: True)), expression: \r\n      (COLUMN this: \r\n        (IDENTIFIER this: customerid, quoted: True), table: \r\n        (IDENTIFIER this: usage, quoted: True)))))\r\n```        \r\n\r\n### Incorrect output with sqlglot==21.0.2\r\n```\r\nPython 3.11.7 (main, Dec  4 2023, 18:10:11) [Clang 15.0.0 (clang-1500.1.0.2.5)] on darwin\r\nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\r\n>>> import sqlglot\r\nfrom sqlglot import parse_one\r\nsqlglot.__version__>>> from sqlglot import parse_one\r\n>>> sqlglot.__version__\r\n'21.0.2'\r\n>>> dialect = 'redshift'\r\n>>> query = 'SELECT * FROM \"usage\".\"usage\" JOIN \"usage\".\"company_names\" ON \"company_names\".\"id\" = \"usage\".\"customerid\"'\r\n>>> parse_one(query, dialect=dialect)\r\nSelect(\r\n  expressions=[\r\n    Star()],\r\n  from=From(\r\n    this=Table(\r\n      this=Identifier(this=usage, quoted=True),\r\n      db=Identifier(this=usage, quoted=True))),\r\n  joins=[\r\n    Join(\r\n      this=Column(\r\n        this=Identifier(this=company_names, quoted=True),\r\n        table=Identifier(this=usage, quoted=True)),\r\n      on=EQ(\r\n        this=Column(\r\n          this=Identifier(this=id, quoted=True),\r\n          table=Identifier(this=company_names, quoted=True)),\r\n        expression=Column(\r\n          this=Identifier(this=customerid, quoted=True),\r\n          table=Identifier(this=usage, quoted=True))))])\r\n```\r\n      \r\n\n", "before_files": [{"content": "from __future__ import annotations\n\nimport typing as t\n\nfrom sqlglot import exp, transforms\nfrom sqlglot.dialects.dialect import (\n    NormalizationStrategy,\n    concat_to_dpipe_sql,\n    concat_ws_to_dpipe_sql,\n    date_delta_sql,\n    generatedasidentitycolumnconstraint_sql,\n    json_extract_segments,\n    no_tablesample_sql,\n    rename_func,\n)\nfrom sqlglot.dialects.postgres import Postgres\nfrom sqlglot.helper import seq_get\nfrom sqlglot.tokens import TokenType\n\nif t.TYPE_CHECKING:\n    from sqlglot._typing import E\n\n\ndef _parse_date_delta(expr_type: t.Type[E]) -> t.Callable[[t.List], E]:\n    def _parse_delta(args: t.List) -> E:\n        expr = expr_type(this=seq_get(args, 2), expression=seq_get(args, 1), unit=seq_get(args, 0))\n        if expr_type is exp.TsOrDsAdd:\n            expr.set(\"return_type\", exp.DataType.build(\"TIMESTAMP\"))\n\n        return expr\n\n    return _parse_delta\n\n\nclass Redshift(Postgres):\n    # https://docs.aws.amazon.com/redshift/latest/dg/r_names.html\n    NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE\n\n    SUPPORTS_USER_DEFINED_TYPES = False\n    INDEX_OFFSET = 0\n\n    TIME_FORMAT = \"'YYYY-MM-DD HH:MI:SS'\"\n    TIME_MAPPING = {\n        **Postgres.TIME_MAPPING,\n        \"MON\": \"%b\",\n        \"HH\": \"%H\",\n    }\n\n    class Parser(Postgres.Parser):\n        FUNCTIONS = {\n            **Postgres.Parser.FUNCTIONS,\n            \"ADD_MONTHS\": lambda args: exp.TsOrDsAdd(\n                this=seq_get(args, 0),\n                expression=seq_get(args, 1),\n                unit=exp.var(\"month\"),\n                return_type=exp.DataType.build(\"TIMESTAMP\"),\n            ),\n            \"DATEADD\": _parse_date_delta(exp.TsOrDsAdd),\n            \"DATE_ADD\": _parse_date_delta(exp.TsOrDsAdd),\n            \"DATEDIFF\": _parse_date_delta(exp.TsOrDsDiff),\n            \"DATE_DIFF\": _parse_date_delta(exp.TsOrDsDiff),\n            \"GETDATE\": exp.CurrentTimestamp.from_arg_list,\n            \"LISTAGG\": exp.GroupConcat.from_arg_list,\n            \"STRTOL\": exp.FromBase.from_arg_list,\n        }\n\n        NO_PAREN_FUNCTION_PARSERS = {\n            **Postgres.Parser.NO_PAREN_FUNCTION_PARSERS,\n            \"APPROXIMATE\": lambda self: self._parse_approximate_count(),\n            \"SYSDATE\": lambda self: self.expression(exp.CurrentTimestamp, transaction=True),\n        }\n\n        def _parse_table(\n            self,\n            schema: bool = False,\n            joins: bool = False,\n            alias_tokens: t.Optional[t.Collection[TokenType]] = None,\n            parse_bracket: bool = False,\n            is_db_reference: bool = False,\n        ) -> t.Optional[exp.Expression]:\n            # Redshift supports UNPIVOTing SUPER objects, e.g. `UNPIVOT foo.obj[0] AS val AT attr`\n            unpivot = self._match(TokenType.UNPIVOT)\n            table = super()._parse_table(\n                schema=schema,\n                joins=joins,\n                alias_tokens=alias_tokens,\n                parse_bracket=parse_bracket,\n                is_db_reference=is_db_reference,\n            )\n\n            return self.expression(exp.Pivot, this=table, unpivot=True) if unpivot else table\n\n        def _parse_types(\n            self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True\n        ) -> t.Optional[exp.Expression]:\n            this = super()._parse_types(\n                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers\n            )\n\n            if (\n                isinstance(this, exp.DataType)\n                and this.is_type(\"varchar\")\n                and this.expressions\n                and this.expressions[0].this == exp.column(\"MAX\")\n            ):\n                this.set(\"expressions\", [exp.var(\"MAX\")])\n\n            return this\n\n        def _parse_convert(\n            self, strict: bool, safe: t.Optional[bool] = None\n        ) -> t.Optional[exp.Expression]:\n            to = self._parse_types()\n            self._match(TokenType.COMMA)\n            this = self._parse_bitwise()\n            return self.expression(exp.TryCast, this=this, to=to, safe=safe)\n\n        def _parse_approximate_count(self) -> t.Optional[exp.ApproxDistinct]:\n            index = self._index - 1\n            func = self._parse_function()\n\n            if isinstance(func, exp.Count) and isinstance(func.this, exp.Distinct):\n                return self.expression(exp.ApproxDistinct, this=seq_get(func.this.expressions, 0))\n            self._retreat(index)\n            return None\n\n        def _parse_query_modifiers(\n            self, this: t.Optional[exp.Expression]\n        ) -> t.Optional[exp.Expression]:\n            this = super()._parse_query_modifiers(this)\n\n            if this:\n                refs = set()\n\n                for i, join in enumerate(this.args.get(\"joins\", [])):\n                    refs.add(\n                        (\n                            this.args[\"from\"] if i == 0 else this.args[\"joins\"][i - 1]\n                        ).alias_or_name.lower()\n                    )\n                    table = join.this\n\n                    if isinstance(table, exp.Table):\n                        if table.parts[0].name.lower() in refs:\n                            table.replace(table.to_column())\n            return this\n\n    class Tokenizer(Postgres.Tokenizer):\n        BIT_STRINGS = []\n        HEX_STRINGS = []\n        STRING_ESCAPES = [\"\\\\\", \"'\"]\n\n        KEYWORDS = {\n            **Postgres.Tokenizer.KEYWORDS,\n            \"HLLSKETCH\": TokenType.HLLSKETCH,\n            \"SUPER\": TokenType.SUPER,\n            \"TOP\": TokenType.TOP,\n            \"UNLOAD\": TokenType.COMMAND,\n            \"VARBYTE\": TokenType.VARBINARY,\n        }\n\n        # Redshift allows # to appear as a table identifier prefix\n        SINGLE_TOKENS = Postgres.Tokenizer.SINGLE_TOKENS.copy()\n        SINGLE_TOKENS.pop(\"#\")\n\n    class Generator(Postgres.Generator):\n        LOCKING_READS_SUPPORTED = False\n        QUERY_HINTS = False\n        VALUES_AS_TABLE = False\n        TZ_TO_WITH_TIME_ZONE = True\n        NVL2_SUPPORTED = True\n        LAST_DAY_SUPPORTS_DATE_PART = False\n\n        TYPE_MAPPING = {\n            **Postgres.Generator.TYPE_MAPPING,\n            exp.DataType.Type.BINARY: \"VARBYTE\",\n            exp.DataType.Type.INT: \"INTEGER\",\n            exp.DataType.Type.TIMETZ: \"TIME\",\n            exp.DataType.Type.TIMESTAMPTZ: \"TIMESTAMP\",\n            exp.DataType.Type.VARBINARY: \"VARBYTE\",\n        }\n\n        TRANSFORMS = {\n            **Postgres.Generator.TRANSFORMS,\n            exp.Concat: concat_to_dpipe_sql,\n            exp.ConcatWs: concat_ws_to_dpipe_sql,\n            exp.ApproxDistinct: lambda self,\n            e: f\"APPROXIMATE COUNT(DISTINCT {self.sql(e, 'this')})\",\n            exp.CurrentTimestamp: lambda self, e: (\n                \"SYSDATE\" if e.args.get(\"transaction\") else \"GETDATE()\"\n            ),\n            exp.DateAdd: date_delta_sql(\"DATEADD\"),\n            exp.DateDiff: date_delta_sql(\"DATEDIFF\"),\n            exp.DistKeyProperty: lambda self, e: f\"DISTKEY({e.name})\",\n            exp.DistStyleProperty: lambda self, e: self.naked_property(e),\n            exp.FromBase: rename_func(\"STRTOL\"),\n            exp.GeneratedAsIdentityColumnConstraint: generatedasidentitycolumnconstraint_sql,\n            exp.JSONExtract: json_extract_segments(\"JSON_EXTRACT_PATH_TEXT\"),\n            exp.GroupConcat: rename_func(\"LISTAGG\"),\n            exp.ParseJSON: rename_func(\"JSON_PARSE\"),\n            exp.Select: transforms.preprocess(\n                [transforms.eliminate_distinct_on, transforms.eliminate_semi_and_anti_joins]\n            ),\n            exp.SortKeyProperty: lambda self,\n            e: f\"{'COMPOUND ' if e.args['compound'] else ''}SORTKEY({self.format_args(*e.this)})\",\n            exp.TableSample: no_tablesample_sql,\n            exp.TsOrDsAdd: date_delta_sql(\"DATEADD\"),\n            exp.TsOrDsDiff: date_delta_sql(\"DATEDIFF\"),\n        }\n\n        # Postgres maps exp.Pivot to no_pivot_sql, but Redshift support pivots\n        TRANSFORMS.pop(exp.Pivot)\n\n        # Redshift uses the POW | POWER (expr1, expr2) syntax instead of expr1 ^ expr2 (postgres)\n        TRANSFORMS.pop(exp.Pow)\n\n        # Redshift supports ANY_VALUE(..)\n        TRANSFORMS.pop(exp.AnyValue)\n\n        # Redshift supports LAST_DAY(..)\n        TRANSFORMS.pop(exp.LastDay)\n\n        RESERVED_KEYWORDS = {*Postgres.Generator.RESERVED_KEYWORDS, \"snapshot\", \"type\"}\n\n        def with_properties(self, properties: exp.Properties) -> str:\n            \"\"\"Redshift doesn't have `WITH` as part of their with_properties so we remove it\"\"\"\n            return self.properties(properties, prefix=\" \", suffix=\"\")\n\n        def cast_sql(self, expression: exp.Cast, safe_prefix: t.Optional[str] = None) -> str:\n            if expression.is_type(exp.DataType.Type.JSON):\n                # Redshift doesn't support a JSON type, so casting to it is treated as a noop\n                return self.sql(expression, \"this\")\n\n            return super().cast_sql(expression, safe_prefix=safe_prefix)\n\n        def datatype_sql(self, expression: exp.DataType) -> str:\n            \"\"\"\n            Redshift converts the `TEXT` data type to `VARCHAR(255)` by default when people more generally mean\n            VARCHAR of max length which is `VARCHAR(max)` in Redshift. Therefore if we get a `TEXT` data type\n            without precision we convert it to `VARCHAR(max)` and if it does have precision then we just convert\n            `TEXT` to `VARCHAR`.\n            \"\"\"\n            if expression.is_type(\"text\"):\n                expression.set(\"this\", exp.DataType.Type.VARCHAR)\n                precision = expression.args.get(\"expressions\")\n\n                if not precision:\n                    expression.append(\"expressions\", exp.var(\"MAX\"))\n\n            return super().datatype_sql(expression)\n", "path": "sqlglot/dialects/redshift.py"}], "after_files": [{"content": "from __future__ import annotations\n\nimport typing as t\n\nfrom sqlglot import exp, transforms\nfrom sqlglot.dialects.dialect import (\n    NormalizationStrategy,\n    concat_to_dpipe_sql,\n    concat_ws_to_dpipe_sql,\n    date_delta_sql,\n    generatedasidentitycolumnconstraint_sql,\n    json_extract_segments,\n    no_tablesample_sql,\n    rename_func,\n)\nfrom sqlglot.dialects.postgres import Postgres\nfrom sqlglot.helper import seq_get\nfrom sqlglot.tokens import TokenType\n\nif t.TYPE_CHECKING:\n    from sqlglot._typing import E\n\n\ndef _parse_date_delta(expr_type: t.Type[E]) -> t.Callable[[t.List], E]:\n    def _parse_delta(args: t.List) -> E:\n        expr = expr_type(this=seq_get(args, 2), expression=seq_get(args, 1), unit=seq_get(args, 0))\n        if expr_type is exp.TsOrDsAdd:\n            expr.set(\"return_type\", exp.DataType.build(\"TIMESTAMP\"))\n\n        return expr\n\n    return _parse_delta\n\n\nclass Redshift(Postgres):\n    # https://docs.aws.amazon.com/redshift/latest/dg/r_names.html\n    NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE\n\n    SUPPORTS_USER_DEFINED_TYPES = False\n    INDEX_OFFSET = 0\n\n    TIME_FORMAT = \"'YYYY-MM-DD HH:MI:SS'\"\n    TIME_MAPPING = {\n        **Postgres.TIME_MAPPING,\n        \"MON\": \"%b\",\n        \"HH\": \"%H\",\n    }\n\n    class Parser(Postgres.Parser):\n        FUNCTIONS = {\n            **Postgres.Parser.FUNCTIONS,\n            \"ADD_MONTHS\": lambda args: exp.TsOrDsAdd(\n                this=seq_get(args, 0),\n                expression=seq_get(args, 1),\n                unit=exp.var(\"month\"),\n                return_type=exp.DataType.build(\"TIMESTAMP\"),\n            ),\n            \"DATEADD\": _parse_date_delta(exp.TsOrDsAdd),\n            \"DATE_ADD\": _parse_date_delta(exp.TsOrDsAdd),\n            \"DATEDIFF\": _parse_date_delta(exp.TsOrDsDiff),\n            \"DATE_DIFF\": _parse_date_delta(exp.TsOrDsDiff),\n            \"GETDATE\": exp.CurrentTimestamp.from_arg_list,\n            \"LISTAGG\": exp.GroupConcat.from_arg_list,\n            \"STRTOL\": exp.FromBase.from_arg_list,\n        }\n\n        NO_PAREN_FUNCTION_PARSERS = {\n            **Postgres.Parser.NO_PAREN_FUNCTION_PARSERS,\n            \"APPROXIMATE\": lambda self: self._parse_approximate_count(),\n            \"SYSDATE\": lambda self: self.expression(exp.CurrentTimestamp, transaction=True),\n        }\n\n        def _parse_table(\n            self,\n            schema: bool = False,\n            joins: bool = False,\n            alias_tokens: t.Optional[t.Collection[TokenType]] = None,\n            parse_bracket: bool = False,\n            is_db_reference: bool = False,\n        ) -> t.Optional[exp.Expression]:\n            # Redshift supports UNPIVOTing SUPER objects, e.g. `UNPIVOT foo.obj[0] AS val AT attr`\n            unpivot = self._match(TokenType.UNPIVOT)\n            table = super()._parse_table(\n                schema=schema,\n                joins=joins,\n                alias_tokens=alias_tokens,\n                parse_bracket=parse_bracket,\n                is_db_reference=is_db_reference,\n            )\n\n            return self.expression(exp.Pivot, this=table, unpivot=True) if unpivot else table\n\n        def _parse_types(\n            self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True\n        ) -> t.Optional[exp.Expression]:\n            this = super()._parse_types(\n                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers\n            )\n\n            if (\n                isinstance(this, exp.DataType)\n                and this.is_type(\"varchar\")\n                and this.expressions\n                and this.expressions[0].this == exp.column(\"MAX\")\n            ):\n                this.set(\"expressions\", [exp.var(\"MAX\")])\n\n            return this\n\n        def _parse_convert(\n            self, strict: bool, safe: t.Optional[bool] = None\n        ) -> t.Optional[exp.Expression]:\n            to = self._parse_types()\n            self._match(TokenType.COMMA)\n            this = self._parse_bitwise()\n            return self.expression(exp.TryCast, this=this, to=to, safe=safe)\n\n        def _parse_approximate_count(self) -> t.Optional[exp.ApproxDistinct]:\n            index = self._index - 1\n            func = self._parse_function()\n\n            if isinstance(func, exp.Count) and isinstance(func.this, exp.Distinct):\n                return self.expression(exp.ApproxDistinct, this=seq_get(func.this.expressions, 0))\n            self._retreat(index)\n            return None\n\n        def _parse_query_modifiers(\n            self, this: t.Optional[exp.Expression]\n        ) -> t.Optional[exp.Expression]:\n            this = super()._parse_query_modifiers(this)\n\n            if this:\n                refs = set()\n\n                for i, join in enumerate(this.args.get(\"joins\", [])):\n                    refs.add(\n                        (\n                            this.args[\"from\"] if i == 0 else this.args[\"joins\"][i - 1]\n                        ).this.alias.lower()\n                    )\n\n                    table = join.this\n                    if isinstance(table, exp.Table) and not join.args.get(\"on\"):\n                        if table.parts[0].name.lower() in refs:\n                            table.replace(table.to_column())\n            return this\n\n    class Tokenizer(Postgres.Tokenizer):\n        BIT_STRINGS = []\n        HEX_STRINGS = []\n        STRING_ESCAPES = [\"\\\\\", \"'\"]\n\n        KEYWORDS = {\n            **Postgres.Tokenizer.KEYWORDS,\n            \"HLLSKETCH\": TokenType.HLLSKETCH,\n            \"SUPER\": TokenType.SUPER,\n            \"TOP\": TokenType.TOP,\n            \"UNLOAD\": TokenType.COMMAND,\n            \"VARBYTE\": TokenType.VARBINARY,\n        }\n\n        # Redshift allows # to appear as a table identifier prefix\n        SINGLE_TOKENS = Postgres.Tokenizer.SINGLE_TOKENS.copy()\n        SINGLE_TOKENS.pop(\"#\")\n\n    class Generator(Postgres.Generator):\n        LOCKING_READS_SUPPORTED = False\n        QUERY_HINTS = False\n        VALUES_AS_TABLE = False\n        TZ_TO_WITH_TIME_ZONE = True\n        NVL2_SUPPORTED = True\n        LAST_DAY_SUPPORTS_DATE_PART = False\n\n        TYPE_MAPPING = {\n            **Postgres.Generator.TYPE_MAPPING,\n            exp.DataType.Type.BINARY: \"VARBYTE\",\n            exp.DataType.Type.INT: \"INTEGER\",\n            exp.DataType.Type.TIMETZ: \"TIME\",\n            exp.DataType.Type.TIMESTAMPTZ: \"TIMESTAMP\",\n            exp.DataType.Type.VARBINARY: \"VARBYTE\",\n        }\n\n        TRANSFORMS = {\n            **Postgres.Generator.TRANSFORMS,\n            exp.Concat: concat_to_dpipe_sql,\n            exp.ConcatWs: concat_ws_to_dpipe_sql,\n            exp.ApproxDistinct: lambda self,\n            e: f\"APPROXIMATE COUNT(DISTINCT {self.sql(e, 'this')})\",\n            exp.CurrentTimestamp: lambda self, e: (\n                \"SYSDATE\" if e.args.get(\"transaction\") else \"GETDATE()\"\n            ),\n            exp.DateAdd: date_delta_sql(\"DATEADD\"),\n            exp.DateDiff: date_delta_sql(\"DATEDIFF\"),\n            exp.DistKeyProperty: lambda self, e: f\"DISTKEY({e.name})\",\n            exp.DistStyleProperty: lambda self, e: self.naked_property(e),\n            exp.FromBase: rename_func(\"STRTOL\"),\n            exp.GeneratedAsIdentityColumnConstraint: generatedasidentitycolumnconstraint_sql,\n            exp.JSONExtract: json_extract_segments(\"JSON_EXTRACT_PATH_TEXT\"),\n            exp.GroupConcat: rename_func(\"LISTAGG\"),\n            exp.ParseJSON: rename_func(\"JSON_PARSE\"),\n            exp.Select: transforms.preprocess(\n                [transforms.eliminate_distinct_on, transforms.eliminate_semi_and_anti_joins]\n            ),\n            exp.SortKeyProperty: lambda self,\n            e: f\"{'COMPOUND ' if e.args['compound'] else ''}SORTKEY({self.format_args(*e.this)})\",\n            exp.TableSample: no_tablesample_sql,\n            exp.TsOrDsAdd: date_delta_sql(\"DATEADD\"),\n            exp.TsOrDsDiff: date_delta_sql(\"DATEDIFF\"),\n        }\n\n        # Postgres maps exp.Pivot to no_pivot_sql, but Redshift support pivots\n        TRANSFORMS.pop(exp.Pivot)\n\n        # Redshift uses the POW | POWER (expr1, expr2) syntax instead of expr1 ^ expr2 (postgres)\n        TRANSFORMS.pop(exp.Pow)\n\n        # Redshift supports ANY_VALUE(..)\n        TRANSFORMS.pop(exp.AnyValue)\n\n        # Redshift supports LAST_DAY(..)\n        TRANSFORMS.pop(exp.LastDay)\n\n        RESERVED_KEYWORDS = {*Postgres.Generator.RESERVED_KEYWORDS, \"snapshot\", \"type\"}\n\n        def with_properties(self, properties: exp.Properties) -> str:\n            \"\"\"Redshift doesn't have `WITH` as part of their with_properties so we remove it\"\"\"\n            return self.properties(properties, prefix=\" \", suffix=\"\")\n\n        def cast_sql(self, expression: exp.Cast, safe_prefix: t.Optional[str] = None) -> str:\n            if expression.is_type(exp.DataType.Type.JSON):\n                # Redshift doesn't support a JSON type, so casting to it is treated as a noop\n                return self.sql(expression, \"this\")\n\n            return super().cast_sql(expression, safe_prefix=safe_prefix)\n\n        def datatype_sql(self, expression: exp.DataType) -> str:\n            \"\"\"\n            Redshift converts the `TEXT` data type to `VARCHAR(255)` by default when people more generally mean\n            VARCHAR of max length which is `VARCHAR(max)` in Redshift. Therefore if we get a `TEXT` data type\n            without precision we convert it to `VARCHAR(max)` and if it does have precision then we just convert\n            `TEXT` to `VARCHAR`.\n            \"\"\"\n            if expression.is_type(\"text\"):\n                expression.set(\"this\", exp.DataType.Type.VARCHAR)\n                precision = expression.args.get(\"expressions\")\n\n                if not precision:\n                    expression.append(\"expressions\", exp.var(\"MAX\"))\n\n            return super().datatype_sql(expression)\n", "path": "sqlglot/dialects/redshift.py"}]}