We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Erroneous handling of redshift's JSON_PARSE
**sqlglot version: 18.16.1**

**Fully reproducible code snippet**
```python
import sqlglot
sql = "SELECT JSON_PARSE('[10001,10002,\"abc\"]');"
parsed = sqlglot.parse_one(sql,dialect="redshift")
parsed.sql(dialect="redshift")
#'SELECT PARSE_JSON(\'[10001,10002,"abc"]\')'
```
The generated sql triggers an error when executed in redshift

>Failed to execute query: ERROR: function parse_json("unknown") does not exist
  Hint: No function matches the given name and argument types. You may need to add explicit type casts.

**Official Documentation**
https://docs.aws.amazon.com/redshift/latest/dg/JSON_PARSE.html


--- 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     concat_to_dpipe_sql,
8     concat_ws_to_dpipe_sql,
9     generatedasidentitycolumnconstraint_sql,
10     rename_func,
11     ts_or_ds_to_date_sql,
12 )
13 from sqlglot.dialects.postgres import Postgres
14 from sqlglot.helper import seq_get
15 from sqlglot.tokens import TokenType
16 
17 
18 def _json_sql(self: Redshift.Generator, expression: exp.JSONExtract | exp.JSONExtractScalar) -> str:
19     return f'{self.sql(expression, "this")}."{expression.expression.name}"'
20 
21 
22 def _parse_date_add(args: t.List) -> exp.DateAdd:
23     return exp.DateAdd(
24         this=exp.TsOrDsToDate(this=seq_get(args, 2)),
25         expression=seq_get(args, 1),
26         unit=seq_get(args, 0),
27     )
28 
29 
30 class Redshift(Postgres):
31     # https://docs.aws.amazon.com/redshift/latest/dg/r_names.html
32     RESOLVES_IDENTIFIERS_AS_UPPERCASE = None
33 
34     SUPPORTS_USER_DEFINED_TYPES = False
35     INDEX_OFFSET = 0
36 
37     TIME_FORMAT = "'YYYY-MM-DD HH:MI:SS'"
38     TIME_MAPPING = {
39         **Postgres.TIME_MAPPING,
40         "MON": "%b",
41         "HH": "%H",
42     }
43 
44     class Parser(Postgres.Parser):
45         FUNCTIONS = {
46             **Postgres.Parser.FUNCTIONS,
47             "ADD_MONTHS": lambda args: exp.DateAdd(
48                 this=exp.TsOrDsToDate(this=seq_get(args, 0)),
49                 expression=seq_get(args, 1),
50                 unit=exp.var("month"),
51             ),
52             "DATEADD": _parse_date_add,
53             "DATE_ADD": _parse_date_add,
54             "DATEDIFF": lambda args: exp.DateDiff(
55                 this=exp.TsOrDsToDate(this=seq_get(args, 2)),
56                 expression=exp.TsOrDsToDate(this=seq_get(args, 1)),
57                 unit=seq_get(args, 0),
58             ),
59             "STRTOL": exp.FromBase.from_arg_list,
60         }
61 
62         NO_PAREN_FUNCTION_PARSERS = {
63             **Postgres.Parser.NO_PAREN_FUNCTION_PARSERS,
64             "APPROXIMATE": lambda self: self._parse_approximate_count(),
65         }
66 
67         def _parse_table(
68             self,
69             schema: bool = False,
70             joins: bool = False,
71             alias_tokens: t.Optional[t.Collection[TokenType]] = None,
72             parse_bracket: bool = False,
73         ) -> t.Optional[exp.Expression]:
74             # Redshift supports UNPIVOTing SUPER objects, e.g. `UNPIVOT foo.obj[0] AS val AT attr`
75             unpivot = self._match(TokenType.UNPIVOT)
76             table = super()._parse_table(
77                 schema=schema,
78                 joins=joins,
79                 alias_tokens=alias_tokens,
80                 parse_bracket=parse_bracket,
81             )
82 
83             return self.expression(exp.Pivot, this=table, unpivot=True) if unpivot else table
84 
85         def _parse_types(
86             self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
87         ) -> t.Optional[exp.Expression]:
88             this = super()._parse_types(
89                 check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
90             )
91 
92             if (
93                 isinstance(this, exp.DataType)
94                 and this.is_type("varchar")
95                 and this.expressions
96                 and this.expressions[0].this == exp.column("MAX")
97             ):
98                 this.set("expressions", [exp.var("MAX")])
99 
100             return this
101 
102         def _parse_convert(
103             self, strict: bool, safe: t.Optional[bool] = None
104         ) -> t.Optional[exp.Expression]:
105             to = self._parse_types()
106             self._match(TokenType.COMMA)
107             this = self._parse_bitwise()
108             return self.expression(exp.TryCast, this=this, to=to, safe=safe)
109 
110         def _parse_approximate_count(self) -> t.Optional[exp.ApproxDistinct]:
111             index = self._index - 1
112             func = self._parse_function()
113 
114             if isinstance(func, exp.Count) and isinstance(func.this, exp.Distinct):
115                 return self.expression(exp.ApproxDistinct, this=seq_get(func.this.expressions, 0))
116             self._retreat(index)
117             return None
118 
119     class Tokenizer(Postgres.Tokenizer):
120         BIT_STRINGS = []
121         HEX_STRINGS = []
122         STRING_ESCAPES = ["\\", "'"]
123 
124         KEYWORDS = {
125             **Postgres.Tokenizer.KEYWORDS,
126             "HLLSKETCH": TokenType.HLLSKETCH,
127             "SUPER": TokenType.SUPER,
128             "SYSDATE": TokenType.CURRENT_TIMESTAMP,
129             "TOP": TokenType.TOP,
130             "UNLOAD": TokenType.COMMAND,
131             "VARBYTE": TokenType.VARBINARY,
132         }
133 
134         # Redshift allows # to appear as a table identifier prefix
135         SINGLE_TOKENS = Postgres.Tokenizer.SINGLE_TOKENS.copy()
136         SINGLE_TOKENS.pop("#")
137 
138     class Generator(Postgres.Generator):
139         LOCKING_READS_SUPPORTED = False
140         RENAME_TABLE_WITH_DB = False
141         QUERY_HINTS = False
142         VALUES_AS_TABLE = False
143         TZ_TO_WITH_TIME_ZONE = True
144         NVL2_SUPPORTED = True
145 
146         TYPE_MAPPING = {
147             **Postgres.Generator.TYPE_MAPPING,
148             exp.DataType.Type.BINARY: "VARBYTE",
149             exp.DataType.Type.INT: "INTEGER",
150             exp.DataType.Type.TIMETZ: "TIME",
151             exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP",
152             exp.DataType.Type.VARBINARY: "VARBYTE",
153         }
154 
155         PROPERTIES_LOCATION = {
156             **Postgres.Generator.PROPERTIES_LOCATION,
157             exp.LikeProperty: exp.Properties.Location.POST_WITH,
158         }
159 
160         TRANSFORMS = {
161             **Postgres.Generator.TRANSFORMS,
162             exp.Concat: concat_to_dpipe_sql,
163             exp.ConcatWs: concat_ws_to_dpipe_sql,
164             exp.ApproxDistinct: lambda self, e: f"APPROXIMATE COUNT(DISTINCT {self.sql(e, 'this')})",
165             exp.CurrentTimestamp: lambda self, e: "SYSDATE",
166             exp.DateAdd: lambda self, e: self.func(
167                 "DATEADD", exp.var(e.text("unit") or "day"), e.expression, e.this
168             ),
169             exp.DateDiff: lambda self, e: self.func(
170                 "DATEDIFF", exp.var(e.text("unit") or "day"), e.expression, e.this
171             ),
172             exp.DistKeyProperty: lambda self, e: f"DISTKEY({e.name})",
173             exp.DistStyleProperty: lambda self, e: self.naked_property(e),
174             exp.FromBase: rename_func("STRTOL"),
175             exp.GeneratedAsIdentityColumnConstraint: generatedasidentitycolumnconstraint_sql,
176             exp.JSONExtract: _json_sql,
177             exp.JSONExtractScalar: _json_sql,
178             exp.SafeConcat: concat_to_dpipe_sql,
179             exp.Select: transforms.preprocess(
180                 [transforms.eliminate_distinct_on, transforms.eliminate_semi_and_anti_joins]
181             ),
182             exp.SortKeyProperty: lambda self, e: f"{'COMPOUND ' if e.args['compound'] else ''}SORTKEY({self.format_args(*e.this)})",
183             exp.TsOrDsToDate: ts_or_ds_to_date_sql("redshift"),
184         }
185 
186         # Postgres maps exp.Pivot to no_pivot_sql, but Redshift support pivots
187         TRANSFORMS.pop(exp.Pivot)
188 
189         # Redshift uses the POW | POWER (expr1, expr2) syntax instead of expr1 ^ expr2 (postgres)
190         TRANSFORMS.pop(exp.Pow)
191 
192         # Redshift supports ANY_VALUE(..)
193         TRANSFORMS.pop(exp.AnyValue)
194 
195         RESERVED_KEYWORDS = {*Postgres.Generator.RESERVED_KEYWORDS, "snapshot", "type"}
196 
197         def with_properties(self, properties: exp.Properties) -> str:
198             """Redshift doesn't have `WITH` as part of their with_properties so we remove it"""
199             return self.properties(properties, prefix=" ", suffix="")
200 
201         def datatype_sql(self, expression: exp.DataType) -> str:
202             """
203             Redshift converts the `TEXT` data type to `VARCHAR(255)` by default when people more generally mean
204             VARCHAR of max length which is `VARCHAR(max)` in Redshift. Therefore if we get a `TEXT` data type
205             without precision we convert it to `VARCHAR(max)` and if it does have precision then we just convert
206             `TEXT` to `VARCHAR`.
207             """
208             if expression.is_type("text"):
209                 expression = expression.copy()
210                 expression.set("this", exp.DataType.Type.VARCHAR)
211                 precision = expression.args.get("expressions")
212 
213                 if not precision:
214                     expression.append("expressions", exp.var("MAX"))
215 
216             return super().datatype_sql(expression)
217
```
--- 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
@@ -175,6 +175,7 @@
             exp.GeneratedAsIdentityColumnConstraint: generatedasidentitycolumnconstraint_sql,
             exp.JSONExtract: _json_sql,
             exp.JSONExtractScalar: _json_sql,
+            exp.ParseJSON: rename_func("JSON_PARSE"),
             exp.SafeConcat: concat_to_dpipe_sql,
             exp.Select: transforms.preprocess(
                 [transforms.eliminate_distinct_on, transforms.eliminate_semi_and_anti_joins]

{"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@@ -175,6 +175,7 @@\n             exp.GeneratedAsIdentityColumnConstraint: generatedasidentitycolumnconstraint_sql,\n             exp.JSONExtract: _json_sql,\n             exp.JSONExtractScalar: _json_sql,\n+            exp.ParseJSON: rename_func(\"JSON_PARSE\"),\n             exp.SafeConcat: concat_to_dpipe_sql,\n             exp.Select: transforms.preprocess(\n                 [transforms.eliminate_distinct_on, transforms.eliminate_semi_and_anti_joins]\n", "issue": "Erroneous handling of redshift's JSON_PARSE\n**sqlglot version: 18.16.1**\r\n\r\n**Fully reproducible code snippet**\r\n```python\r\nimport sqlglot\r\nsql = \"SELECT JSON_PARSE('[10001,10002,\\\"abc\\\"]');\"\r\nparsed = sqlglot.parse_one(sql,dialect=\"redshift\")\r\nparsed.sql(dialect=\"redshift\")\r\n#'SELECT PARSE_JSON(\\'[10001,10002,\"abc\"]\\')'\r\n```\r\nThe generated sql triggers an error when executed in redshift\r\n\r\n>Failed to execute query: ERROR: function parse_json(\"unknown\") does not exist\r\n  Hint: No function matches the given name and argument types. You may need to add explicit type casts.\r\n\r\n**Official Documentation**\r\nhttps://docs.aws.amazon.com/redshift/latest/dg/JSON_PARSE.html\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    concat_to_dpipe_sql,\n    concat_ws_to_dpipe_sql,\n    generatedasidentitycolumnconstraint_sql,\n    rename_func,\n    ts_or_ds_to_date_sql,\n)\nfrom sqlglot.dialects.postgres import Postgres\nfrom sqlglot.helper import seq_get\nfrom sqlglot.tokens import TokenType\n\n\ndef _json_sql(self: Redshift.Generator, expression: exp.JSONExtract | exp.JSONExtractScalar) -> str:\n    return f'{self.sql(expression, \"this\")}.\"{expression.expression.name}\"'\n\n\ndef _parse_date_add(args: t.List) -> exp.DateAdd:\n    return exp.DateAdd(\n        this=exp.TsOrDsToDate(this=seq_get(args, 2)),\n        expression=seq_get(args, 1),\n        unit=seq_get(args, 0),\n    )\n\n\nclass Redshift(Postgres):\n    # https://docs.aws.amazon.com/redshift/latest/dg/r_names.html\n    RESOLVES_IDENTIFIERS_AS_UPPERCASE = None\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.DateAdd(\n                this=exp.TsOrDsToDate(this=seq_get(args, 0)),\n                expression=seq_get(args, 1),\n                unit=exp.var(\"month\"),\n            ),\n            \"DATEADD\": _parse_date_add,\n            \"DATE_ADD\": _parse_date_add,\n            \"DATEDIFF\": lambda args: exp.DateDiff(\n                this=exp.TsOrDsToDate(this=seq_get(args, 2)),\n                expression=exp.TsOrDsToDate(this=seq_get(args, 1)),\n                unit=seq_get(args, 0),\n            ),\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        }\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        ) -> 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            )\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    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            \"SYSDATE\": TokenType.CURRENT_TIMESTAMP,\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        RENAME_TABLE_WITH_DB = False\n        QUERY_HINTS = False\n        VALUES_AS_TABLE = False\n        TZ_TO_WITH_TIME_ZONE = True\n        NVL2_SUPPORTED = True\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        PROPERTIES_LOCATION = {\n            **Postgres.Generator.PROPERTIES_LOCATION,\n            exp.LikeProperty: exp.Properties.Location.POST_WITH,\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, e: f\"APPROXIMATE COUNT(DISTINCT {self.sql(e, 'this')})\",\n            exp.CurrentTimestamp: lambda self, e: \"SYSDATE\",\n            exp.DateAdd: lambda self, e: self.func(\n                \"DATEADD\", exp.var(e.text(\"unit\") or \"day\"), e.expression, e.this\n            ),\n            exp.DateDiff: lambda self, e: self.func(\n                \"DATEDIFF\", exp.var(e.text(\"unit\") or \"day\"), e.expression, e.this\n            ),\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_sql,\n            exp.JSONExtractScalar: _json_sql,\n            exp.SafeConcat: concat_to_dpipe_sql,\n            exp.Select: transforms.preprocess(\n                [transforms.eliminate_distinct_on, transforms.eliminate_semi_and_anti_joins]\n            ),\n            exp.SortKeyProperty: lambda self, e: f\"{'COMPOUND ' if e.args['compound'] else ''}SORTKEY({self.format_args(*e.this)})\",\n            exp.TsOrDsToDate: ts_or_ds_to_date_sql(\"redshift\"),\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        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 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 = expression.copy()\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    concat_to_dpipe_sql,\n    concat_ws_to_dpipe_sql,\n    generatedasidentitycolumnconstraint_sql,\n    rename_func,\n    ts_or_ds_to_date_sql,\n)\nfrom sqlglot.dialects.postgres import Postgres\nfrom sqlglot.helper import seq_get\nfrom sqlglot.tokens import TokenType\n\n\ndef _json_sql(self: Redshift.Generator, expression: exp.JSONExtract | exp.JSONExtractScalar) -> str:\n    return f'{self.sql(expression, \"this\")}.\"{expression.expression.name}\"'\n\n\ndef _parse_date_add(args: t.List) -> exp.DateAdd:\n    return exp.DateAdd(\n        this=exp.TsOrDsToDate(this=seq_get(args, 2)),\n        expression=seq_get(args, 1),\n        unit=seq_get(args, 0),\n    )\n\n\nclass Redshift(Postgres):\n    # https://docs.aws.amazon.com/redshift/latest/dg/r_names.html\n    RESOLVES_IDENTIFIERS_AS_UPPERCASE = None\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.DateAdd(\n                this=exp.TsOrDsToDate(this=seq_get(args, 0)),\n                expression=seq_get(args, 1),\n                unit=exp.var(\"month\"),\n            ),\n            \"DATEADD\": _parse_date_add,\n            \"DATE_ADD\": _parse_date_add,\n            \"DATEDIFF\": lambda args: exp.DateDiff(\n                this=exp.TsOrDsToDate(this=seq_get(args, 2)),\n                expression=exp.TsOrDsToDate(this=seq_get(args, 1)),\n                unit=seq_get(args, 0),\n            ),\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        }\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        ) -> 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            )\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    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            \"SYSDATE\": TokenType.CURRENT_TIMESTAMP,\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        RENAME_TABLE_WITH_DB = False\n        QUERY_HINTS = False\n        VALUES_AS_TABLE = False\n        TZ_TO_WITH_TIME_ZONE = True\n        NVL2_SUPPORTED = True\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        PROPERTIES_LOCATION = {\n            **Postgres.Generator.PROPERTIES_LOCATION,\n            exp.LikeProperty: exp.Properties.Location.POST_WITH,\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, e: f\"APPROXIMATE COUNT(DISTINCT {self.sql(e, 'this')})\",\n            exp.CurrentTimestamp: lambda self, e: \"SYSDATE\",\n            exp.DateAdd: lambda self, e: self.func(\n                \"DATEADD\", exp.var(e.text(\"unit\") or \"day\"), e.expression, e.this\n            ),\n            exp.DateDiff: lambda self, e: self.func(\n                \"DATEDIFF\", exp.var(e.text(\"unit\") or \"day\"), e.expression, e.this\n            ),\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_sql,\n            exp.JSONExtractScalar: _json_sql,\n            exp.ParseJSON: rename_func(\"JSON_PARSE\"),\n            exp.SafeConcat: concat_to_dpipe_sql,\n            exp.Select: transforms.preprocess(\n                [transforms.eliminate_distinct_on, transforms.eliminate_semi_and_anti_joins]\n            ),\n            exp.SortKeyProperty: lambda self, e: f\"{'COMPOUND ' if e.args['compound'] else ''}SORTKEY({self.format_args(*e.this)})\",\n            exp.TsOrDsToDate: ts_or_ds_to_date_sql(\"redshift\"),\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        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 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 = expression.copy()\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"}]}