Repository: tobymao/sqlglot
Pull request: fix(hive)!: support STRUCT(*) and MAP(*)
Fixes #4871

This PR adds support for `STRUCT(*)` and `MAP(*)` for hive, spark, spark2, databricks dialects. 

Problem statement:
Spark support for map(*) and struct(*)
Theres a few ways to covert columns to json in spark depending on the use case, typically using map or struct. While its common to specify the schema, thats not required and sometimes not desired. 
```python
import sqlglot

sql = """
select
    to_json(map(*)),
    to_json(struct(*))
from data
"""
print(sqlglot.parse_one(sql, dialect='spark').sql(dialect='spark', pretty=True))
```
outputs:
```
SELECT
  TO_JSON(STAR_MAP(*)),
  TO_JSON(STRUCT(* AS col1))
FROM data
```
I'd expect this to not modify the query. The `to_json` part likely isn't relevant.

1.  `star_map` isn't a function in spark
2.  `struct(* as col1)` throws: `AnalysisException: Invalid use of '*' in expression 'alias'`

Hints from issue discussion:

Commit message: fix(hive)!: support STRUCT(*) and MAP(*)

Patch to review:
diff --git a/sqlglot/dialects/hive.py b/sqlglot/dialects/hive.py
index 587fee3482..2d702c068a 100644
--- a/sqlglot/dialects/hive.py
+++ b/sqlglot/dialects/hive.py
@@ -446,6 +446,9 @@ def _parse_parameter(self) -> exp.Parameter:
             return self.expression(exp.Parameter, this=this, expression=expression)
 
         def _to_prop_eq(self, expression: exp.Expression, index: int) -> exp.Expression:
+            if isinstance(expression, exp.Star):
+                return expression
+
             if isinstance(expression, exp.Column):
                 key = expression.this
             else:
@@ -577,6 +580,7 @@ class Generator(generator.Generator):
             exp.StrToTime: _str_to_time_sql,
             exp.StrToUnix: _str_to_unix_sql,
             exp.StructExtract: struct_extract_sql,
+            exp.StarMap: rename_func("MAP"),
             exp.Table: transforms.preprocess([transforms.unnest_generate_series]),
             exp.TimeStrToDate: rename_func("TO_DATE"),
             exp.TimeStrToTime: timestrtotime_sql,
diff --git a/tests/dialects/test_hive.py b/tests/dialects/test_hive.py
index 7caf9f9091..343be09a95 100644
--- a/tests/dialects/test_hive.py
+++ b/tests/dialects/test_hive.py
@@ -810,6 +810,21 @@ def test_hive(self):
 
         self.validate_identity("SELECT 1_2")
 
+        self.validate_all(
+            "SELECT MAP(*), STRUCT(*) FROM t",
+            read={
+                "hive": "SELECT MAP(*), STRUCT(*) FROM t",
+                "spark2": "SELECT MAP(*), STRUCT(*) FROM t",
+                "spark": "SELECT MAP(*), STRUCT(*) FROM t",
+                "databricks": "SELECT MAP(*), STRUCT(*) FROM t",
+            },
+            write={
+                "spark2": "SELECT MAP(*), STRUCT(*) FROM t",
+                "spark": "SELECT MAP(*), STRUCT(*) FROM t",
+                "databricks": "SELECT MAP(*), STRUCT(*) FROM t",
+            },
+        )
+
     def test_escapes(self) -> None:
         self.validate_identity("'\n'", "'\\n'")
         self.validate_identity("'\\n'")


Code review comments:
diff_hunk: @@ -446,6 +446,9 @@ def _parse_parameter(self) -> exp.Parameter:
             return self.expression(exp.Parameter, this=this, expression=expression)
 
         def _to_prop_eq(self, expression: exp.Expression, index: int) -> exp.Expression:
+            if isinstance(expression, exp.Star):
path: sqlglot/dialects/hive.py
text: @user1:
```suggestion
            if expression.is_star:
```