Repository: tobymao/sqlglot

Issue:
Sqlglot parses out comments 
Hi,

Could you please help with this issue?

sqlglot==13.3.0


**Fully reproducible code snippet**
```python
query = """
SELECT
  'hotel1' AS hotel,
  *
FROM dw_1_dw_1_1.exactonline_1.transactionlines
/*
    UNION ALL
    SELECT
      'Thon Partner Hotel Jølster' AS hotel,
      name,
      date,
      CAST(identifier AS VARCHAR) AS identifier,
      value
    FROM d2o_889_oupjr_1348.public.accountvalues_forecast
*/
UNION ALL
SELECT
  'hotel2' AS hotel,
  *
FROM dw_1_dw_1_1.exactonline_2.transactionlines
"""

expression_tree = parse_one(query, read='postgres')

print(expression_tree)
```

Output:
```sql
SELECT 'hotel1' AS hotel, * FROM dw_1_dw_1_1.exactonline_1.transactionlines UNION ALL SELECT 'hotel2' AS hotel, * FROM dw_1_dw_1_1.exactonline_2.transactionlines
```


Discussion:
tobymao: damn i literally have the same code in my branch lol

Patch:
diff --git a/sqlglot/generator.py b/sqlglot/generator.py
index 2b09645e..d5aa54f7 100644
--- a/sqlglot/generator.py
+++ b/sqlglot/generator.py
@@ -347,6 +347,12 @@ class Generator:
         exp.With,
     )
 
+    # Expressions that should not have their comments generated in maybe_comment
+    EXCLUDE_COMMENTS: t.Tuple[t.Type[exp.Expression], ...] = (
+        exp.Binary,
+        exp.Union,
+    )
+
     # Expressions that can remain unwrapped when appearing in the context of an INTERVAL
     UNWRAPPED_INTERVAL_VALUES: t.Tuple[t.Type[exp.Expression], ...] = (
         exp.Column,
@@ -507,7 +513,7 @@ class Generator:
             else None
         )
 
-        if not comments or isinstance(expression, exp.Binary):
+        if not comments or isinstance(expression, self.EXCLUDE_COMMENTS):
             return sql
 
         comments_sql = " ".join(
@@ -2713,8 +2719,8 @@ class Generator:
             self.unsupported(f"Unsupported property {expression.__class__.__name__}")
         return f"{property_name} {self.sql(expression, 'this')}"
 
-    def set_operation(self, expression: exp.Expression, op: str) -> str:
-        this = self.sql(expression, "this")
+    def set_operation(self, expression: exp.Union, op: str) -> str:
+        this = self.maybe_comment(self.sql(expression, "this"), comments=expression.comments)
         op = self.seg(op)
         return self.query_modifiers(
             expression, f"{this}{op}{self.sep()}{self.sql(expression, 'expression')}"
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
index 3a6dfd6a..e0d32f13 100644
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -3160,6 +3160,7 @@ class Parser(metaclass=_Parser):
 
         return self.expression(
             expression,
+            comments=self._prev.comments,
             this=this,
             distinct=self._match(TokenType.DISTINCT) or not self._match(TokenType.ALL),
             by_name=self._match_text_seq("BY", "NAME"),


Test patch:
diff --git a/tests/test_transpile.py b/tests/test_transpile.py
index d588f07e..af2968c8 100644
--- a/tests/test_transpile.py
+++ b/tests/test_transpile.py
@@ -87,7 +87,18 @@ class TestTranspile(unittest.TestCase):
         self.validate("SELECT 3>=3", "SELECT 3 >= 3")
 
     def test_comments(self):
-        self.validate("SELECT\n  foo\n/* comments */\n;", "SELECT foo /* comments */")
+        self.validate(
+            "SELECT * FROM t1\n/*x*/\nUNION ALL SELECT * FROM t2",
+            "SELECT * FROM t1 /* x */ UNION ALL SELECT * FROM t2",
+        )
+        self.validate(
+            "SELECT * FROM t1\n/*x*/\nINTERSECT ALL SELECT * FROM t2",
+            "SELECT * FROM t1 /* x */ INTERSECT ALL SELECT * FROM t2",
+        )
+        self.validate(
+            "SELECT\n  foo\n/* comments */\n;",
+            "SELECT foo /* comments */",
+        )
         self.validate(
             "SELECT * FROM a INNER /* comments */ JOIN b",
             "SELECT * FROM a /* comments */ INNER JOIN b",
@@ -379,6 +390,47 @@ LEFT OUTER JOIN b""",
 FROM tbl""",
             pretty=True,
         )
+        self.validate(
+            """
+SELECT
+  'hotel1' AS hotel,
+  *
+FROM dw_1_dw_1_1.exactonline_1.transactionlines
+/*
+    UNION ALL
+    SELECT
+      'Thon Partner Hotel Jølster' AS hotel,
+      name,
+      date,
+      CAST(identifier AS VARCHAR) AS identifier,
+      value
+    FROM d2o_889_oupjr_1348.public.accountvalues_forecast
+*/
+UNION ALL
+SELECT
+  'hotel2' AS hotel,
+  *
+FROM dw_1_dw_1_1.exactonline_2.transactionlines""",
+            """SELECT
+  'hotel1' AS hotel,
+  *
+FROM dw_1_dw_1_1.exactonline_1.transactionlines /*
+    UNION ALL
+    SELECT
+      'Thon Partner Hotel Jølster' AS hotel,
+      name,
+      date,
+      CAST(identifier AS VARCHAR) AS identifier,
+      value
+    FROM d2o_889_oupjr_1348.public.accountvalues_forecast
+*/
+UNION ALL
+SELECT
+  'hotel2' AS hotel,
+  *
+FROM dw_1_dw_1_1.exactonline_2.transactionlines""",
+            pretty=True,
+        )
 
     def test_types(self):
         self.validate("INT 1", "CAST(1 AS INT)")