We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
FROM_UNIXTIME has different types in Trino and SparkSQL
```FROM_UNIXTIME(`created`)``` in Trino SQL returns a datetime, but ```FROM_UNIXTIME(`created`)``` in SparkSQL returns a string, which can cause queries to fail.

I would expect:
```select FROM_UNIXTIME(`created`) from a``` # (read='trino') 
to convert to
```select CAST(FROM_UNIXTIME('created') as timestamp) from a``` # (write='spark')

https://docs.databricks.com/sql/language-manual/functions/from_unixtime.html
https://spark.apache.org/docs/3.0.0/api/sql/#from_unixtime


--- 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/spark2.py`
Content:
```
1 from __future__ import annotations
2 
3 import typing as t
4 
5 from sqlglot import exp, parser
6 from sqlglot.dialects.dialect import create_with_partitions_sql, rename_func, trim_sql
7 from sqlglot.dialects.hive import Hive
8 from sqlglot.helper import seq_get
9 
10 
11 def _create_sql(self: Hive.Generator, e: exp.Create) -> str:
12     kind = e.args["kind"]
13     properties = e.args.get("properties")
14 
15     if kind.upper() == "TABLE" and any(
16         isinstance(prop, exp.TemporaryProperty)
17         for prop in (properties.expressions if properties else [])
18     ):
19         return f"CREATE TEMPORARY VIEW {self.sql(e, 'this')} AS {self.sql(e, 'expression')}"
20     return create_with_partitions_sql(self, e)
21 
22 
23 def _map_sql(self: Hive.Generator, expression: exp.Map) -> str:
24     keys = self.sql(expression.args["keys"])
25     values = self.sql(expression.args["values"])
26     return f"MAP_FROM_ARRAYS({keys}, {values})"
27 
28 
29 def _parse_as_cast(to_type: str) -> t.Callable[[t.Sequence], exp.Expression]:
30     return lambda args: exp.Cast(this=seq_get(args, 0), to=exp.DataType.build(to_type))
31 
32 
33 def _str_to_date(self: Hive.Generator, expression: exp.StrToDate) -> str:
34     this = self.sql(expression, "this")
35     time_format = self.format_time(expression)
36     if time_format == Hive.date_format:
37         return f"TO_DATE({this})"
38     return f"TO_DATE({this}, {time_format})"
39 
40 
41 def _unix_to_time_sql(self: Hive.Generator, expression: exp.UnixToTime) -> str:
42     scale = expression.args.get("scale")
43     timestamp = self.sql(expression, "this")
44     if scale is None:
45         return f"FROM_UNIXTIME({timestamp})"
46     if scale == exp.UnixToTime.SECONDS:
47         return f"TIMESTAMP_SECONDS({timestamp})"
48     if scale == exp.UnixToTime.MILLIS:
49         return f"TIMESTAMP_MILLIS({timestamp})"
50     if scale == exp.UnixToTime.MICROS:
51         return f"TIMESTAMP_MICROS({timestamp})"
52 
53     raise ValueError("Improper scale for timestamp")
54 
55 
56 class Spark2(Hive):
57     class Parser(Hive.Parser):
58         FUNCTIONS = {
59             **Hive.Parser.FUNCTIONS,  # type: ignore
60             "MAP_FROM_ARRAYS": exp.Map.from_arg_list,
61             "TO_UNIX_TIMESTAMP": exp.StrToUnix.from_arg_list,
62             "LEFT": lambda args: exp.Substring(
63                 this=seq_get(args, 0),
64                 start=exp.Literal.number(1),
65                 length=seq_get(args, 1),
66             ),
67             "SHIFTLEFT": lambda args: exp.BitwiseLeftShift(
68                 this=seq_get(args, 0),
69                 expression=seq_get(args, 1),
70             ),
71             "SHIFTRIGHT": lambda args: exp.BitwiseRightShift(
72                 this=seq_get(args, 0),
73                 expression=seq_get(args, 1),
74             ),
75             "RIGHT": lambda args: exp.Substring(
76                 this=seq_get(args, 0),
77                 start=exp.Sub(
78                     this=exp.Length(this=seq_get(args, 0)),
79                     expression=exp.Add(this=seq_get(args, 1), expression=exp.Literal.number(1)),
80                 ),
81                 length=seq_get(args, 1),
82             ),
83             "APPROX_PERCENTILE": exp.ApproxQuantile.from_arg_list,
84             "IIF": exp.If.from_arg_list,
85             "AGGREGATE": exp.Reduce.from_arg_list,
86             "DAYOFWEEK": lambda args: exp.DayOfWeek(
87                 this=exp.TsOrDsToDate(this=seq_get(args, 0)),
88             ),
89             "DAYOFMONTH": lambda args: exp.DayOfMonth(
90                 this=exp.TsOrDsToDate(this=seq_get(args, 0)),
91             ),
92             "DAYOFYEAR": lambda args: exp.DayOfYear(
93                 this=exp.TsOrDsToDate(this=seq_get(args, 0)),
94             ),
95             "WEEKOFYEAR": lambda args: exp.WeekOfYear(
96                 this=exp.TsOrDsToDate(this=seq_get(args, 0)),
97             ),
98             "DATE": lambda args: exp.Cast(this=seq_get(args, 0), to=exp.DataType.build("date")),
99             "DATE_TRUNC": lambda args: exp.TimestampTrunc(
100                 this=seq_get(args, 1),
101                 unit=exp.var(seq_get(args, 0)),
102             ),
103             "TRUNC": lambda args: exp.DateTrunc(unit=seq_get(args, 1), this=seq_get(args, 0)),
104             "BOOLEAN": _parse_as_cast("boolean"),
105             "DOUBLE": _parse_as_cast("double"),
106             "FLOAT": _parse_as_cast("float"),
107             "INT": _parse_as_cast("int"),
108             "STRING": _parse_as_cast("string"),
109             "TIMESTAMP": _parse_as_cast("timestamp"),
110         }
111 
112         FUNCTION_PARSERS = {
113             **parser.Parser.FUNCTION_PARSERS,  # type: ignore
114             "BROADCAST": lambda self: self._parse_join_hint("BROADCAST"),
115             "BROADCASTJOIN": lambda self: self._parse_join_hint("BROADCASTJOIN"),
116             "MAPJOIN": lambda self: self._parse_join_hint("MAPJOIN"),
117             "MERGE": lambda self: self._parse_join_hint("MERGE"),
118             "SHUFFLEMERGE": lambda self: self._parse_join_hint("SHUFFLEMERGE"),
119             "MERGEJOIN": lambda self: self._parse_join_hint("MERGEJOIN"),
120             "SHUFFLE_HASH": lambda self: self._parse_join_hint("SHUFFLE_HASH"),
121             "SHUFFLE_REPLICATE_NL": lambda self: self._parse_join_hint("SHUFFLE_REPLICATE_NL"),
122         }
123 
124         def _parse_add_column(self) -> t.Optional[exp.Expression]:
125             return self._match_text_seq("ADD", "COLUMNS") and self._parse_schema()
126 
127         def _parse_drop_column(self) -> t.Optional[exp.Expression]:
128             return self._match_text_seq("DROP", "COLUMNS") and self.expression(
129                 exp.Drop,
130                 this=self._parse_schema(),
131                 kind="COLUMNS",
132             )
133 
134         def _pivot_column_names(self, pivot_columns: t.List[exp.Expression]) -> t.List[str]:
135             # Spark doesn't add a suffix to the pivot columns when there's a single aggregation
136             if len(pivot_columns) == 1:
137                 return [""]
138 
139             names = []
140             for agg in pivot_columns:
141                 if isinstance(agg, exp.Alias):
142                     names.append(agg.alias)
143                 else:
144                     """
145                     This case corresponds to aggregations without aliases being used as suffixes
146                     (e.g. col_avg(foo)). We need to unquote identifiers because they're going to
147                     be quoted in the base parser's `_parse_pivot` method, due to `to_identifier`.
148                     Otherwise, we'd end up with `col_avg(`foo`)` (notice the double quotes).
149 
150                     Moreover, function names are lowercased in order to mimic Spark's naming scheme.
151                     """
152                     agg_all_unquoted = agg.transform(
153                         lambda node: exp.Identifier(this=node.name, quoted=False)
154                         if isinstance(node, exp.Identifier)
155                         else node
156                     )
157                     names.append(agg_all_unquoted.sql(dialect="spark", normalize_functions="lower"))
158 
159             return names
160 
161     class Generator(Hive.Generator):
162         TYPE_MAPPING = {
163             **Hive.Generator.TYPE_MAPPING,  # type: ignore
164             exp.DataType.Type.TINYINT: "BYTE",
165             exp.DataType.Type.SMALLINT: "SHORT",
166             exp.DataType.Type.BIGINT: "LONG",
167         }
168 
169         PROPERTIES_LOCATION = {
170             **Hive.Generator.PROPERTIES_LOCATION,  # type: ignore
171             exp.EngineProperty: exp.Properties.Location.UNSUPPORTED,
172             exp.AutoIncrementProperty: exp.Properties.Location.UNSUPPORTED,
173             exp.CharacterSetProperty: exp.Properties.Location.UNSUPPORTED,
174             exp.CollateProperty: exp.Properties.Location.UNSUPPORTED,
175         }
176 
177         TRANSFORMS = {
178             **Hive.Generator.TRANSFORMS,  # type: ignore
179             exp.ApproxDistinct: rename_func("APPROX_COUNT_DISTINCT"),
180             exp.FileFormatProperty: lambda self, e: f"USING {e.name.upper()}",
181             exp.ArraySum: lambda self, e: f"AGGREGATE({self.sql(e, 'this')}, 0, (acc, x) -> acc + x, acc -> acc)",
182             exp.BitwiseLeftShift: rename_func("SHIFTLEFT"),
183             exp.BitwiseRightShift: rename_func("SHIFTRIGHT"),
184             exp.DateTrunc: lambda self, e: self.func("TRUNC", e.this, e.args.get("unit")),
185             exp.Hint: lambda self, e: f" /*+ {self.expressions(e).strip()} */",
186             exp.StrToDate: _str_to_date,
187             exp.StrToTime: lambda self, e: f"TO_TIMESTAMP({self.sql(e, 'this')}, {self.format_time(e)})",
188             exp.UnixToTime: _unix_to_time_sql,
189             exp.Create: _create_sql,
190             exp.Map: _map_sql,
191             exp.Reduce: rename_func("AGGREGATE"),
192             exp.StructKwarg: lambda self, e: f"{self.sql(e, 'this')}: {self.sql(e, 'expression')}",
193             exp.TimestampTrunc: lambda self, e: self.func(
194                 "DATE_TRUNC", exp.Literal.string(e.text("unit")), e.this
195             ),
196             exp.Trim: trim_sql,
197             exp.VariancePop: rename_func("VAR_POP"),
198             exp.DateFromParts: rename_func("MAKE_DATE"),
199             exp.LogicalOr: rename_func("BOOL_OR"),
200             exp.LogicalAnd: rename_func("BOOL_AND"),
201             exp.DayOfWeek: rename_func("DAYOFWEEK"),
202             exp.DayOfMonth: rename_func("DAYOFMONTH"),
203             exp.DayOfYear: rename_func("DAYOFYEAR"),
204             exp.WeekOfYear: rename_func("WEEKOFYEAR"),
205             exp.AtTimeZone: lambda self, e: f"FROM_UTC_TIMESTAMP({self.sql(e, 'this')}, {self.sql(e, 'zone')})",
206         }
207         TRANSFORMS.pop(exp.ArraySort)
208         TRANSFORMS.pop(exp.ILike)
209 
210         WRAP_DERIVED_VALUES = False
211         CREATE_FUNCTION_RETURN_AS = False
212 
213         def cast_sql(self, expression: exp.Cast) -> str:
214             if isinstance(expression.this, exp.Cast) and expression.this.is_type(
215                 exp.DataType.Type.JSON
216             ):
217                 schema = f"'{self.sql(expression, 'to')}'"
218                 return self.func("FROM_JSON", expression.this.this, schema)
219             if expression.to.is_type(exp.DataType.Type.JSON):
220                 return self.func("TO_JSON", expression.this)
221 
222             return super(Hive.Generator, self).cast_sql(expression)
223 
224     class Tokenizer(Hive.Tokenizer):
225         HEX_STRINGS = [("X'", "'")]
226
```
--- 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/spark2.py b/sqlglot/dialects/spark2.py
--- a/sqlglot/dialects/spark2.py
+++ b/sqlglot/dialects/spark2.py
@@ -42,7 +42,7 @@
     scale = expression.args.get("scale")
     timestamp = self.sql(expression, "this")
     if scale is None:
-        return f"FROM_UNIXTIME({timestamp})"
+        return f"CAST(FROM_UNIXTIME({timestamp}) AS TIMESTAMP)"
     if scale == exp.UnixToTime.SECONDS:
         return f"TIMESTAMP_SECONDS({timestamp})"
     if scale == exp.UnixToTime.MILLIS:

{"golden_diff": "diff --git a/sqlglot/dialects/spark2.py b/sqlglot/dialects/spark2.py\n--- a/sqlglot/dialects/spark2.py\n+++ b/sqlglot/dialects/spark2.py\n@@ -42,7 +42,7 @@\n     scale = expression.args.get(\"scale\")\n     timestamp = self.sql(expression, \"this\")\n     if scale is None:\n-        return f\"FROM_UNIXTIME({timestamp})\"\n+        return f\"CAST(FROM_UNIXTIME({timestamp}) AS TIMESTAMP)\"\n     if scale == exp.UnixToTime.SECONDS:\n         return f\"TIMESTAMP_SECONDS({timestamp})\"\n     if scale == exp.UnixToTime.MILLIS:\n", "issue": "FROM_UNIXTIME has different types in Trino and SparkSQL\n```FROM_UNIXTIME(`created`)``` in Trino SQL returns a datetime, but ```FROM_UNIXTIME(`created`)``` in SparkSQL returns a string, which can cause queries to fail.\r\n\r\nI would expect:\r\n```select FROM_UNIXTIME(`created`) from a``` # (read='trino') \r\nto convert to\r\n```select CAST(FROM_UNIXTIME('created') as timestamp) from a``` # (write='spark')\r\n\r\nhttps://docs.databricks.com/sql/language-manual/functions/from_unixtime.html\r\nhttps://spark.apache.org/docs/3.0.0/api/sql/#from_unixtime\r\n\n", "before_files": [{"content": "from __future__ import annotations\n\nimport typing as t\n\nfrom sqlglot import exp, parser\nfrom sqlglot.dialects.dialect import create_with_partitions_sql, rename_func, trim_sql\nfrom sqlglot.dialects.hive import Hive\nfrom sqlglot.helper import seq_get\n\n\ndef _create_sql(self: Hive.Generator, e: exp.Create) -> str:\n    kind = e.args[\"kind\"]\n    properties = e.args.get(\"properties\")\n\n    if kind.upper() == \"TABLE\" and any(\n        isinstance(prop, exp.TemporaryProperty)\n        for prop in (properties.expressions if properties else [])\n    ):\n        return f\"CREATE TEMPORARY VIEW {self.sql(e, 'this')} AS {self.sql(e, 'expression')}\"\n    return create_with_partitions_sql(self, e)\n\n\ndef _map_sql(self: Hive.Generator, expression: exp.Map) -> str:\n    keys = self.sql(expression.args[\"keys\"])\n    values = self.sql(expression.args[\"values\"])\n    return f\"MAP_FROM_ARRAYS({keys}, {values})\"\n\n\ndef _parse_as_cast(to_type: str) -> t.Callable[[t.Sequence], exp.Expression]:\n    return lambda args: exp.Cast(this=seq_get(args, 0), to=exp.DataType.build(to_type))\n\n\ndef _str_to_date(self: Hive.Generator, expression: exp.StrToDate) -> str:\n    this = self.sql(expression, \"this\")\n    time_format = self.format_time(expression)\n    if time_format == Hive.date_format:\n        return f\"TO_DATE({this})\"\n    return f\"TO_DATE({this}, {time_format})\"\n\n\ndef _unix_to_time_sql(self: Hive.Generator, expression: exp.UnixToTime) -> str:\n    scale = expression.args.get(\"scale\")\n    timestamp = self.sql(expression, \"this\")\n    if scale is None:\n        return f\"FROM_UNIXTIME({timestamp})\"\n    if scale == exp.UnixToTime.SECONDS:\n        return f\"TIMESTAMP_SECONDS({timestamp})\"\n    if scale == exp.UnixToTime.MILLIS:\n        return f\"TIMESTAMP_MILLIS({timestamp})\"\n    if scale == exp.UnixToTime.MICROS:\n        return f\"TIMESTAMP_MICROS({timestamp})\"\n\n    raise ValueError(\"Improper scale for timestamp\")\n\n\nclass Spark2(Hive):\n    class Parser(Hive.Parser):\n        FUNCTIONS = {\n            **Hive.Parser.FUNCTIONS,  # type: ignore\n            \"MAP_FROM_ARRAYS\": exp.Map.from_arg_list,\n            \"TO_UNIX_TIMESTAMP\": exp.StrToUnix.from_arg_list,\n            \"LEFT\": lambda args: exp.Substring(\n                this=seq_get(args, 0),\n                start=exp.Literal.number(1),\n                length=seq_get(args, 1),\n            ),\n            \"SHIFTLEFT\": lambda args: exp.BitwiseLeftShift(\n                this=seq_get(args, 0),\n                expression=seq_get(args, 1),\n            ),\n            \"SHIFTRIGHT\": lambda args: exp.BitwiseRightShift(\n                this=seq_get(args, 0),\n                expression=seq_get(args, 1),\n            ),\n            \"RIGHT\": lambda args: exp.Substring(\n                this=seq_get(args, 0),\n                start=exp.Sub(\n                    this=exp.Length(this=seq_get(args, 0)),\n                    expression=exp.Add(this=seq_get(args, 1), expression=exp.Literal.number(1)),\n                ),\n                length=seq_get(args, 1),\n            ),\n            \"APPROX_PERCENTILE\": exp.ApproxQuantile.from_arg_list,\n            \"IIF\": exp.If.from_arg_list,\n            \"AGGREGATE\": exp.Reduce.from_arg_list,\n            \"DAYOFWEEK\": lambda args: exp.DayOfWeek(\n                this=exp.TsOrDsToDate(this=seq_get(args, 0)),\n            ),\n            \"DAYOFMONTH\": lambda args: exp.DayOfMonth(\n                this=exp.TsOrDsToDate(this=seq_get(args, 0)),\n            ),\n            \"DAYOFYEAR\": lambda args: exp.DayOfYear(\n                this=exp.TsOrDsToDate(this=seq_get(args, 0)),\n            ),\n            \"WEEKOFYEAR\": lambda args: exp.WeekOfYear(\n                this=exp.TsOrDsToDate(this=seq_get(args, 0)),\n            ),\n            \"DATE\": lambda args: exp.Cast(this=seq_get(args, 0), to=exp.DataType.build(\"date\")),\n            \"DATE_TRUNC\": lambda args: exp.TimestampTrunc(\n                this=seq_get(args, 1),\n                unit=exp.var(seq_get(args, 0)),\n            ),\n            \"TRUNC\": lambda args: exp.DateTrunc(unit=seq_get(args, 1), this=seq_get(args, 0)),\n            \"BOOLEAN\": _parse_as_cast(\"boolean\"),\n            \"DOUBLE\": _parse_as_cast(\"double\"),\n            \"FLOAT\": _parse_as_cast(\"float\"),\n            \"INT\": _parse_as_cast(\"int\"),\n            \"STRING\": _parse_as_cast(\"string\"),\n            \"TIMESTAMP\": _parse_as_cast(\"timestamp\"),\n        }\n\n        FUNCTION_PARSERS = {\n            **parser.Parser.FUNCTION_PARSERS,  # type: ignore\n            \"BROADCAST\": lambda self: self._parse_join_hint(\"BROADCAST\"),\n            \"BROADCASTJOIN\": lambda self: self._parse_join_hint(\"BROADCASTJOIN\"),\n            \"MAPJOIN\": lambda self: self._parse_join_hint(\"MAPJOIN\"),\n            \"MERGE\": lambda self: self._parse_join_hint(\"MERGE\"),\n            \"SHUFFLEMERGE\": lambda self: self._parse_join_hint(\"SHUFFLEMERGE\"),\n            \"MERGEJOIN\": lambda self: self._parse_join_hint(\"MERGEJOIN\"),\n            \"SHUFFLE_HASH\": lambda self: self._parse_join_hint(\"SHUFFLE_HASH\"),\n            \"SHUFFLE_REPLICATE_NL\": lambda self: self._parse_join_hint(\"SHUFFLE_REPLICATE_NL\"),\n        }\n\n        def _parse_add_column(self) -> t.Optional[exp.Expression]:\n            return self._match_text_seq(\"ADD\", \"COLUMNS\") and self._parse_schema()\n\n        def _parse_drop_column(self) -> t.Optional[exp.Expression]:\n            return self._match_text_seq(\"DROP\", \"COLUMNS\") and self.expression(\n                exp.Drop,\n                this=self._parse_schema(),\n                kind=\"COLUMNS\",\n            )\n\n        def _pivot_column_names(self, pivot_columns: t.List[exp.Expression]) -> t.List[str]:\n            # Spark doesn't add a suffix to the pivot columns when there's a single aggregation\n            if len(pivot_columns) == 1:\n                return [\"\"]\n\n            names = []\n            for agg in pivot_columns:\n                if isinstance(agg, exp.Alias):\n                    names.append(agg.alias)\n                else:\n                    \"\"\"\n                    This case corresponds to aggregations without aliases being used as suffixes\n                    (e.g. col_avg(foo)). We need to unquote identifiers because they're going to\n                    be quoted in the base parser's `_parse_pivot` method, due to `to_identifier`.\n                    Otherwise, we'd end up with `col_avg(`foo`)` (notice the double quotes).\n\n                    Moreover, function names are lowercased in order to mimic Spark's naming scheme.\n                    \"\"\"\n                    agg_all_unquoted = agg.transform(\n                        lambda node: exp.Identifier(this=node.name, quoted=False)\n                        if isinstance(node, exp.Identifier)\n                        else node\n                    )\n                    names.append(agg_all_unquoted.sql(dialect=\"spark\", normalize_functions=\"lower\"))\n\n            return names\n\n    class Generator(Hive.Generator):\n        TYPE_MAPPING = {\n            **Hive.Generator.TYPE_MAPPING,  # type: ignore\n            exp.DataType.Type.TINYINT: \"BYTE\",\n            exp.DataType.Type.SMALLINT: \"SHORT\",\n            exp.DataType.Type.BIGINT: \"LONG\",\n        }\n\n        PROPERTIES_LOCATION = {\n            **Hive.Generator.PROPERTIES_LOCATION,  # type: ignore\n            exp.EngineProperty: exp.Properties.Location.UNSUPPORTED,\n            exp.AutoIncrementProperty: exp.Properties.Location.UNSUPPORTED,\n            exp.CharacterSetProperty: exp.Properties.Location.UNSUPPORTED,\n            exp.CollateProperty: exp.Properties.Location.UNSUPPORTED,\n        }\n\n        TRANSFORMS = {\n            **Hive.Generator.TRANSFORMS,  # type: ignore\n            exp.ApproxDistinct: rename_func(\"APPROX_COUNT_DISTINCT\"),\n            exp.FileFormatProperty: lambda self, e: f\"USING {e.name.upper()}\",\n            exp.ArraySum: lambda self, e: f\"AGGREGATE({self.sql(e, 'this')}, 0, (acc, x) -> acc + x, acc -> acc)\",\n            exp.BitwiseLeftShift: rename_func(\"SHIFTLEFT\"),\n            exp.BitwiseRightShift: rename_func(\"SHIFTRIGHT\"),\n            exp.DateTrunc: lambda self, e: self.func(\"TRUNC\", e.this, e.args.get(\"unit\")),\n            exp.Hint: lambda self, e: f\" /*+ {self.expressions(e).strip()} */\",\n            exp.StrToDate: _str_to_date,\n            exp.StrToTime: lambda self, e: f\"TO_TIMESTAMP({self.sql(e, 'this')}, {self.format_time(e)})\",\n            exp.UnixToTime: _unix_to_time_sql,\n            exp.Create: _create_sql,\n            exp.Map: _map_sql,\n            exp.Reduce: rename_func(\"AGGREGATE\"),\n            exp.StructKwarg: lambda self, e: f\"{self.sql(e, 'this')}: {self.sql(e, 'expression')}\",\n            exp.TimestampTrunc: lambda self, e: self.func(\n                \"DATE_TRUNC\", exp.Literal.string(e.text(\"unit\")), e.this\n            ),\n            exp.Trim: trim_sql,\n            exp.VariancePop: rename_func(\"VAR_POP\"),\n            exp.DateFromParts: rename_func(\"MAKE_DATE\"),\n            exp.LogicalOr: rename_func(\"BOOL_OR\"),\n            exp.LogicalAnd: rename_func(\"BOOL_AND\"),\n            exp.DayOfWeek: rename_func(\"DAYOFWEEK\"),\n            exp.DayOfMonth: rename_func(\"DAYOFMONTH\"),\n            exp.DayOfYear: rename_func(\"DAYOFYEAR\"),\n            exp.WeekOfYear: rename_func(\"WEEKOFYEAR\"),\n            exp.AtTimeZone: lambda self, e: f\"FROM_UTC_TIMESTAMP({self.sql(e, 'this')}, {self.sql(e, 'zone')})\",\n        }\n        TRANSFORMS.pop(exp.ArraySort)\n        TRANSFORMS.pop(exp.ILike)\n\n        WRAP_DERIVED_VALUES = False\n        CREATE_FUNCTION_RETURN_AS = False\n\n        def cast_sql(self, expression: exp.Cast) -> str:\n            if isinstance(expression.this, exp.Cast) and expression.this.is_type(\n                exp.DataType.Type.JSON\n            ):\n                schema = f\"'{self.sql(expression, 'to')}'\"\n                return self.func(\"FROM_JSON\", expression.this.this, schema)\n            if expression.to.is_type(exp.DataType.Type.JSON):\n                return self.func(\"TO_JSON\", expression.this)\n\n            return super(Hive.Generator, self).cast_sql(expression)\n\n    class Tokenizer(Hive.Tokenizer):\n        HEX_STRINGS = [(\"X'\", \"'\")]\n", "path": "sqlglot/dialects/spark2.py"}], "after_files": [{"content": "from __future__ import annotations\n\nimport typing as t\n\nfrom sqlglot import exp, parser\nfrom sqlglot.dialects.dialect import create_with_partitions_sql, rename_func, trim_sql\nfrom sqlglot.dialects.hive import Hive\nfrom sqlglot.helper import seq_get\n\n\ndef _create_sql(self: Hive.Generator, e: exp.Create) -> str:\n    kind = e.args[\"kind\"]\n    properties = e.args.get(\"properties\")\n\n    if kind.upper() == \"TABLE\" and any(\n        isinstance(prop, exp.TemporaryProperty)\n        for prop in (properties.expressions if properties else [])\n    ):\n        return f\"CREATE TEMPORARY VIEW {self.sql(e, 'this')} AS {self.sql(e, 'expression')}\"\n    return create_with_partitions_sql(self, e)\n\n\ndef _map_sql(self: Hive.Generator, expression: exp.Map) -> str:\n    keys = self.sql(expression.args[\"keys\"])\n    values = self.sql(expression.args[\"values\"])\n    return f\"MAP_FROM_ARRAYS({keys}, {values})\"\n\n\ndef _parse_as_cast(to_type: str) -> t.Callable[[t.Sequence], exp.Expression]:\n    return lambda args: exp.Cast(this=seq_get(args, 0), to=exp.DataType.build(to_type))\n\n\ndef _str_to_date(self: Hive.Generator, expression: exp.StrToDate) -> str:\n    this = self.sql(expression, \"this\")\n    time_format = self.format_time(expression)\n    if time_format == Hive.date_format:\n        return f\"TO_DATE({this})\"\n    return f\"TO_DATE({this}, {time_format})\"\n\n\ndef _unix_to_time_sql(self: Hive.Generator, expression: exp.UnixToTime) -> str:\n    scale = expression.args.get(\"scale\")\n    timestamp = self.sql(expression, \"this\")\n    if scale is None:\n        return f\"CAST(FROM_UNIXTIME({timestamp}) AS TIMESTAMP)\"\n    if scale == exp.UnixToTime.SECONDS:\n        return f\"TIMESTAMP_SECONDS({timestamp})\"\n    if scale == exp.UnixToTime.MILLIS:\n        return f\"TIMESTAMP_MILLIS({timestamp})\"\n    if scale == exp.UnixToTime.MICROS:\n        return f\"TIMESTAMP_MICROS({timestamp})\"\n\n    raise ValueError(\"Improper scale for timestamp\")\n\n\nclass Spark2(Hive):\n    class Parser(Hive.Parser):\n        FUNCTIONS = {\n            **Hive.Parser.FUNCTIONS,  # type: ignore\n            \"MAP_FROM_ARRAYS\": exp.Map.from_arg_list,\n            \"TO_UNIX_TIMESTAMP\": exp.StrToUnix.from_arg_list,\n            \"LEFT\": lambda args: exp.Substring(\n                this=seq_get(args, 0),\n                start=exp.Literal.number(1),\n                length=seq_get(args, 1),\n            ),\n            \"SHIFTLEFT\": lambda args: exp.BitwiseLeftShift(\n                this=seq_get(args, 0),\n                expression=seq_get(args, 1),\n            ),\n            \"SHIFTRIGHT\": lambda args: exp.BitwiseRightShift(\n                this=seq_get(args, 0),\n                expression=seq_get(args, 1),\n            ),\n            \"RIGHT\": lambda args: exp.Substring(\n                this=seq_get(args, 0),\n                start=exp.Sub(\n                    this=exp.Length(this=seq_get(args, 0)),\n                    expression=exp.Add(this=seq_get(args, 1), expression=exp.Literal.number(1)),\n                ),\n                length=seq_get(args, 1),\n            ),\n            \"APPROX_PERCENTILE\": exp.ApproxQuantile.from_arg_list,\n            \"IIF\": exp.If.from_arg_list,\n            \"AGGREGATE\": exp.Reduce.from_arg_list,\n            \"DAYOFWEEK\": lambda args: exp.DayOfWeek(\n                this=exp.TsOrDsToDate(this=seq_get(args, 0)),\n            ),\n            \"DAYOFMONTH\": lambda args: exp.DayOfMonth(\n                this=exp.TsOrDsToDate(this=seq_get(args, 0)),\n            ),\n            \"DAYOFYEAR\": lambda args: exp.DayOfYear(\n                this=exp.TsOrDsToDate(this=seq_get(args, 0)),\n            ),\n            \"WEEKOFYEAR\": lambda args: exp.WeekOfYear(\n                this=exp.TsOrDsToDate(this=seq_get(args, 0)),\n            ),\n            \"DATE\": lambda args: exp.Cast(this=seq_get(args, 0), to=exp.DataType.build(\"date\")),\n            \"DATE_TRUNC\": lambda args: exp.TimestampTrunc(\n                this=seq_get(args, 1),\n                unit=exp.var(seq_get(args, 0)),\n            ),\n            \"TRUNC\": lambda args: exp.DateTrunc(unit=seq_get(args, 1), this=seq_get(args, 0)),\n            \"BOOLEAN\": _parse_as_cast(\"boolean\"),\n            \"DOUBLE\": _parse_as_cast(\"double\"),\n            \"FLOAT\": _parse_as_cast(\"float\"),\n            \"INT\": _parse_as_cast(\"int\"),\n            \"STRING\": _parse_as_cast(\"string\"),\n            \"TIMESTAMP\": _parse_as_cast(\"timestamp\"),\n        }\n\n        FUNCTION_PARSERS = {\n            **parser.Parser.FUNCTION_PARSERS,  # type: ignore\n            \"BROADCAST\": lambda self: self._parse_join_hint(\"BROADCAST\"),\n            \"BROADCASTJOIN\": lambda self: self._parse_join_hint(\"BROADCASTJOIN\"),\n            \"MAPJOIN\": lambda self: self._parse_join_hint(\"MAPJOIN\"),\n            \"MERGE\": lambda self: self._parse_join_hint(\"MERGE\"),\n            \"SHUFFLEMERGE\": lambda self: self._parse_join_hint(\"SHUFFLEMERGE\"),\n            \"MERGEJOIN\": lambda self: self._parse_join_hint(\"MERGEJOIN\"),\n            \"SHUFFLE_HASH\": lambda self: self._parse_join_hint(\"SHUFFLE_HASH\"),\n            \"SHUFFLE_REPLICATE_NL\": lambda self: self._parse_join_hint(\"SHUFFLE_REPLICATE_NL\"),\n        }\n\n        def _parse_add_column(self) -> t.Optional[exp.Expression]:\n            return self._match_text_seq(\"ADD\", \"COLUMNS\") and self._parse_schema()\n\n        def _parse_drop_column(self) -> t.Optional[exp.Expression]:\n            return self._match_text_seq(\"DROP\", \"COLUMNS\") and self.expression(\n                exp.Drop,\n                this=self._parse_schema(),\n                kind=\"COLUMNS\",\n            )\n\n        def _pivot_column_names(self, pivot_columns: t.List[exp.Expression]) -> t.List[str]:\n            # Spark doesn't add a suffix to the pivot columns when there's a single aggregation\n            if len(pivot_columns) == 1:\n                return [\"\"]\n\n            names = []\n            for agg in pivot_columns:\n                if isinstance(agg, exp.Alias):\n                    names.append(agg.alias)\n                else:\n                    \"\"\"\n                    This case corresponds to aggregations without aliases being used as suffixes\n                    (e.g. col_avg(foo)). We need to unquote identifiers because they're going to\n                    be quoted in the base parser's `_parse_pivot` method, due to `to_identifier`.\n                    Otherwise, we'd end up with `col_avg(`foo`)` (notice the double quotes).\n\n                    Moreover, function names are lowercased in order to mimic Spark's naming scheme.\n                    \"\"\"\n                    agg_all_unquoted = agg.transform(\n                        lambda node: exp.Identifier(this=node.name, quoted=False)\n                        if isinstance(node, exp.Identifier)\n                        else node\n                    )\n                    names.append(agg_all_unquoted.sql(dialect=\"spark\", normalize_functions=\"lower\"))\n\n            return names\n\n    class Generator(Hive.Generator):\n        TYPE_MAPPING = {\n            **Hive.Generator.TYPE_MAPPING,  # type: ignore\n            exp.DataType.Type.TINYINT: \"BYTE\",\n            exp.DataType.Type.SMALLINT: \"SHORT\",\n            exp.DataType.Type.BIGINT: \"LONG\",\n        }\n\n        PROPERTIES_LOCATION = {\n            **Hive.Generator.PROPERTIES_LOCATION,  # type: ignore\n            exp.EngineProperty: exp.Properties.Location.UNSUPPORTED,\n            exp.AutoIncrementProperty: exp.Properties.Location.UNSUPPORTED,\n            exp.CharacterSetProperty: exp.Properties.Location.UNSUPPORTED,\n            exp.CollateProperty: exp.Properties.Location.UNSUPPORTED,\n        }\n\n        TRANSFORMS = {\n            **Hive.Generator.TRANSFORMS,  # type: ignore\n            exp.ApproxDistinct: rename_func(\"APPROX_COUNT_DISTINCT\"),\n            exp.FileFormatProperty: lambda self, e: f\"USING {e.name.upper()}\",\n            exp.ArraySum: lambda self, e: f\"AGGREGATE({self.sql(e, 'this')}, 0, (acc, x) -> acc + x, acc -> acc)\",\n            exp.BitwiseLeftShift: rename_func(\"SHIFTLEFT\"),\n            exp.BitwiseRightShift: rename_func(\"SHIFTRIGHT\"),\n            exp.DateTrunc: lambda self, e: self.func(\"TRUNC\", e.this, e.args.get(\"unit\")),\n            exp.Hint: lambda self, e: f\" /*+ {self.expressions(e).strip()} */\",\n            exp.StrToDate: _str_to_date,\n            exp.StrToTime: lambda self, e: f\"TO_TIMESTAMP({self.sql(e, 'this')}, {self.format_time(e)})\",\n            exp.UnixToTime: _unix_to_time_sql,\n            exp.Create: _create_sql,\n            exp.Map: _map_sql,\n            exp.Reduce: rename_func(\"AGGREGATE\"),\n            exp.StructKwarg: lambda self, e: f\"{self.sql(e, 'this')}: {self.sql(e, 'expression')}\",\n            exp.TimestampTrunc: lambda self, e: self.func(\n                \"DATE_TRUNC\", exp.Literal.string(e.text(\"unit\")), e.this\n            ),\n            exp.Trim: trim_sql,\n            exp.VariancePop: rename_func(\"VAR_POP\"),\n            exp.DateFromParts: rename_func(\"MAKE_DATE\"),\n            exp.LogicalOr: rename_func(\"BOOL_OR\"),\n            exp.LogicalAnd: rename_func(\"BOOL_AND\"),\n            exp.DayOfWeek: rename_func(\"DAYOFWEEK\"),\n            exp.DayOfMonth: rename_func(\"DAYOFMONTH\"),\n            exp.DayOfYear: rename_func(\"DAYOFYEAR\"),\n            exp.WeekOfYear: rename_func(\"WEEKOFYEAR\"),\n            exp.AtTimeZone: lambda self, e: f\"FROM_UTC_TIMESTAMP({self.sql(e, 'this')}, {self.sql(e, 'zone')})\",\n        }\n        TRANSFORMS.pop(exp.ArraySort)\n        TRANSFORMS.pop(exp.ILike)\n\n        WRAP_DERIVED_VALUES = False\n        CREATE_FUNCTION_RETURN_AS = False\n\n        def cast_sql(self, expression: exp.Cast) -> str:\n            if isinstance(expression.this, exp.Cast) and expression.this.is_type(\n                exp.DataType.Type.JSON\n            ):\n                schema = f\"'{self.sql(expression, 'to')}'\"\n                return self.func(\"FROM_JSON\", expression.this.this, schema)\n            if expression.to.is_type(exp.DataType.Type.JSON):\n                return self.func(\"TO_JSON\", expression.this)\n\n            return super(Hive.Generator, self).cast_sql(expression)\n\n    class Tokenizer(Hive.Tokenizer):\n        HEX_STRINGS = [(\"X'\", \"'\")]\n", "path": "sqlglot/dialects/spark2.py"}]}