Repository: tobymao/sqlglot

Issue:
Parentheses at union doesn't work inside CTE
This isn't working:

```
WITH
  cte AS (
    (
      SELECT
        table_1.id AS id,
        table_1.name AS name
      FROM
        table_1
    )
    UNION ALL
    (
      SELECT
        table_2.id AS id,
        table_2.name AS name
      FROM
        table_2
    )
  )
SELECT
  *
FROM
  cte

```

This works: 

```
WITH
  cte AS (
    SELECT
      table_1.id AS id,
      table_1.name AS name
    FROM
      table_1
    UNION ALL
    SELECT
      table_2.id AS id,
      table_2.name AS name
    FROM
      table_2
  )
SELECT
  *
FROM
  cte
```




Discussion:
thanks for all these edge cases. will have a fix soon. just woke up. curious if you have a large amount of user contributed sql. it’s very helpful!

Resolving patch:
diff --git a/sqlglot/expressions.py b/sqlglot/expressions.py
--- a/sqlglot/expressions.py
+++ b/sqlglot/expressions.py
@@ -1116,12 +1116,10 @@ def join(
         except ParseError:
             expression = _maybe_parse(expression, into=(Join, Expression), **parse_args)
 
-        if isinstance(expression, Join):
-            join = expression
-        else:
-            if isinstance(expression, Select):
-                expression = expression.subquery()
-            join = Join(this=expression)
+        join = expression if isinstance(expression, Join) else Join(this=expression)
+
+        if isinstance(join.this, Select):
+            join.this.replace(join.this.subquery())
 
         if join_type:
             side, kind = _maybe_parse(join_type, into="JOIN_TYPE", **parse_args)
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -83,7 +83,6 @@ class Parser:
         TokenType.ESCAPE,
         TokenType.EXPLAIN,
         TokenType.FALSE,
-        TokenType.FILTER,
         TokenType.FOLLOWING,
         TokenType.FUNCTION,
         TokenType.IF,
@@ -92,7 +91,6 @@ class Parser:
         TokenType.OPTIMIZE,
         TokenType.OPTIONS,
         TokenType.ORDINALITY,
-        TokenType.OVER,
         TokenType.PERCENT,
         TokenType.PRECEDING,
         TokenType.QUALIFY,
@@ -111,8 +109,6 @@ class Parser:
         *TYPE_TOKENS,
     }
 
-    LAMBDA_TOKENS = ID_VAR_TOKENS | {TokenType.LEFT, TokenType.RIGHT}
-
     CASTS = {
         TokenType.CAST,
         TokenType.TRY_CAST,
@@ -198,19 +194,6 @@ class Parser:
         TokenType.DOT,
     }
 
-    BODY_EXPRESSIONS = (
-        exp.Select,
-        exp.From,
-        exp.Join,
-        exp.Where,
-        exp.Group,
-        exp.Having,
-        exp.Order,
-        exp.Union,
-        exp.CTE,
-        exp.Values,
-    )
-
     CREATABLES = {TokenType.TABLE, TokenType.VIEW, TokenType.FUNCTION}
 
     __slots__ = (
@@ -765,12 +748,12 @@ def _parse_cte(self):
         )
 
     def _parse_table_alias(self):
-        self._match(TokenType.ALIAS)
-        alias = self._parse_id_var()
+        explicit = self._match(TokenType.ALIAS)
+        alias = self._parse_id_var(explicit)
         columns = None
 
         if self._match(TokenType.L_PAREN):
-            columns = self._parse_csv(self._parse_id_var)
+            columns = self._parse_csv(lambda: self._parse_id_var(explicit))
             self._match_r_paren()
 
         if not alias and not columns:
@@ -794,7 +777,7 @@ def _parse_select(self):
                 alias=self._parse_table_alias(),
             )
 
-        if isinstance(this, exp.Subquery) or self._match(TokenType.SELECT):
+        if self._match(TokenType.SELECT):
             hint = self._parse_hint()
             all_ = self._match(TokenType.ALL)
             distinct = self._match(TokenType.DISTINCT)
@@ -913,25 +896,23 @@ def _parse_table(self, schema=False):
         if unnest:
             return unnest
 
-        is_body = False
+        subquery = self._parse_with()
 
-        if self._match(TokenType.L_PAREN):
-            this = self._parse_with()
-            is_body = isinstance(this, self.BODY_EXPRESSIONS)
-            self._match_r_paren()
-        else:
-            catalog = None
-            db = None
-            table = (not schema and self._parse_function()) or self._parse_id_var()
+        if subquery:
+            return subquery
+
+        catalog = None
+        db = None
+        table = (not schema and self._parse_function()) or self._parse_id_var()
 
-            while self._match(TokenType.DOT):
-                catalog = db
-                db = table
-                table = self._parse_id_var()
-                if not table:
-                    self.raise_error("Expected table name")
+        while self._match(TokenType.DOT):
+            catalog = db
+            db = table
+            table = self._parse_id_var()
+            if not table:
+                self.raise_error("Expected table name")
 
-            this = self.expression(exp.Table, this=table, db=db, catalog=catalog)
+        this = self.expression(exp.Table, this=table, db=db, catalog=catalog)
 
         if schema:
             return self._parse_schema(this=this)
@@ -939,8 +920,6 @@ def _parse_table(self, schema=False):
         this = self._parse_table_sample(this)
         alias = self._parse_table_alias()
 
-        if is_body:
-            return self.expression(exp.Subquery, this=this, alias=alias)
         if alias:
             return self.expression(exp.Alias, this=this, alias=alias)
         return this
@@ -1073,14 +1052,14 @@ def _parse_set_operations(self, this):
                 this=this,
                 distinct=self._match(TokenType.DISTINCT)
                 or not self._match(TokenType.ALL),
-                expression=self._parse_expression() or self._parse_select(),
+                expression=self._parse_with(),
             )
 
         return self.expression(
             exp.Except if token_type == TokenType.EXCEPT else exp.Intersect,
             this=this,
             distinct=self._match(TokenType.DISTINCT),
-            expression=self._parse_expression() or self._parse_select(),
+            expression=self._parse_with(),
         )
 
     def _parse_expression(self):
@@ -1278,7 +1257,7 @@ def _parse_primary(self):
             return this
 
         if self._match(TokenType.L_PAREN):
-            this = self._parse_conjunction() or self._parse_select()
+            this = self._parse_conjunction() or self._parse_with()
             self._match_r_paren()
             return self.expression(exp.Paren, this=this)
 
@@ -1337,12 +1316,10 @@ def _parse_lambda(self):
         index = self._index
 
         if self._match(TokenType.L_PAREN):
-            expressions = self._parse_csv(
-                lambda: self._parse_id_var(self.LAMBDA_TOKENS)
-            )
+            expressions = self._parse_csv(lambda: self._parse_id_var(True))
             self._match(TokenType.R_PAREN)
         else:
-            expressions = [self._parse_id_var()]
+            expressions = [self._parse_id_var(True)]
 
         if not self._match(TokenType.LAMBDA):
             self._retreat(index)
@@ -1568,27 +1545,35 @@ def _parse_window_spec(self):
         }
 
     def _parse_alias(self, this):
-        self._match(TokenType.ALIAS)
+        explicit = self._match(TokenType.ALIAS)
 
         if self._match(TokenType.L_PAREN):
             aliases = self.expression(
                 exp.Aliases,
                 this=this,
-                expressions=self._parse_csv(self._parse_id_var),
+                expressions=self._parse_csv(lambda: self._parse_id_var(explicit)),
             )
             self._match_r_paren()
             return aliases
 
-        alias = self._parse_id_var()
+        alias = self._parse_id_var(explicit)
+
         if alias:
             return self.expression(exp.Alias, this=this, alias=alias)
 
         return this
 
-    def _parse_id_var(self, tokens=None):
-        return self._parse_identifier() or (
-            self._match_set(tokens or self.ID_VAR_TOKENS)
-            and exp.Identifier(this=self._prev.text, quoted=False)
+    def _parse_id_var(self, explicit=False):
+        identifier = self._parse_identifier()
+
+        if identifier:
+            return identifier
+
+        if explicit:
+            return self._advance() or exp.Identifier(this=self._prev.text, quoted=False)
+
+        return self._match_set(self.ID_VAR_TOKENS) and exp.Identifier(
+            this=self._prev.text, quoted=False
         )
 
     def _parse_string(self):


Test patch:
diff --git a/tests/fixtures/identity.sql b/tests/fixtures/identity.sql
--- a/tests/fixtures/identity.sql
+++ b/tests/fixtures/identity.sql
@@ -260,7 +260,6 @@ SELECT * FROM (SELECT 1 UNION SELECT 2) AS x
 SELECT * FROM (SELECT 1 UNION ALL SELECT 2) AS x
 SELECT * FROM (SELECT 1 UNION ALL SELECT 2)
 SELECT * FROM ((SELECT 1) AS a UNION ALL (SELECT 2) AS b)
-SELECT 1 FROM ((SELECT 1) AS a JOIN (SELECT 1) AS b)
 SELECT * FROM ((SELECT 1) AS a(b))
 SELECT * FROM x AS y(a, b)
 SELECT zoo, animals FROM (VALUES ('oakland', ARRAY('a', 'b')), ('sf', ARRAY('b', 'c'))) AS t(zoo, animals)
@@ -405,3 +404,6 @@ WITH a AS (SELECT * FROM b) UPDATE a SET col = 1
 WITH a AS (SELECT * FROM b) CREATE TABLE b AS SELECT * FROM a
 WITH a AS (SELECT * FROM b) DELETE FROM a
 WITH a AS (SELECT * FROM b) CACHE TABLE a
+WITH a AS ((SELECT b.foo AS foo, b.bar AS bar FROM b) UNION ALL (SELECT c.foo AS foo, c.bar AS bar FROM c)) SELECT * FROM a
+WITH a AS ((SELECT 1 AS b) UNION ALL (SELECT 1 AS b)) SELECT * FROM a
+SELECT (WITH x AS (SELECT 1 AS y) SELECT * FROM x) AS z
diff --git a/tests/fixtures/pretty.sql b/tests/fixtures/pretty.sql
--- a/tests/fixtures/pretty.sql
+++ b/tests/fixtures/pretty.sql
@@ -3,6 +3,22 @@ SELECT
   *
 FROM test;
 
+WITH a AS ((SELECT 1 AS b) UNION ALL (SELECT 2 AS b)) SELECT * FROM a;
+WITH a AS (
+  (
+    SELECT
+      1 AS b
+  )
+  UNION ALL
+  (
+    SELECT
+      2 AS b
+  )
+)
+SELECT
+  *
+FROM a;
+
 WITH cte1 AS (
     SELECT a, z and e AS b
     FROM cte
diff --git a/tests/test_transpile.py b/tests/test_transpile.py
--- a/tests/test_transpile.py
+++ b/tests/test_transpile.py
@@ -15,6 +15,15 @@ class TestTranspile(unittest.TestCase):
     def validate(self, sql, target, **kwargs):
         self.assertEqual(transpile(sql, **kwargs)[0], target)
 
+    def test_alias(self):
+        for key in ("union", "filter", "over", "from", "join"):
+            with self.subTest(f"alias {key}"):
+                self.validate(f"SELECT x AS {key}", f"SELECT x AS {key}")
+                self.validate(f'SELECT x "{key}"', f'SELECT x AS "{key}"')
+
+                with self.assertRaises(ParseError):
+                    self.validate(f"SELECT x {key}", "")
+
     def test_asc(self):
         self.validate("SELECT x FROM y ORDER BY x ASC", "SELECT x FROM y ORDER BY x")