Repository: tobymao/sqlglot

Issue:
Unable to Parse VALUES clause with named table alias (Presto -> Spark)
Getting an error trying to parse the following query
```
q = """
SELECT zoo, animal
FROM (VALUES
        ('OaklandZoo', ARRAY['dog', 'cat', 'tiger']),
        ('SanFranciscoZoo', ARRAY['dog', 'cat'])
) AS t(zoo,animals)
"""

sqlglot.transpile(q, 'presto', 'spark')
```

```
ParseError: Invalid expression / Unexpected token. Line 5, Col: 7.
  'OaklandZoo', ARRAY['dog', 'cat', 'tiger']),
        ('SanFranciscoZoo', ARRAY['dog', 'cat'])
) AS t(zoo,animals)
```

Token List
```
[<Token token_type: TokenType.SELECT, text: SELECT, line: 1, col: 1>,
...,
 <Token token_type: TokenType.FROM, text: FROM, line: 2, col: 1>,
 <Token token_type: TokenType.L_PAREN, text: (, line: 2, col: 6>,
 <Token token_type: TokenType.VALUES, text: VALUES, line: 2, col: 7>,
 <Token token_type: TokenType.L_PAREN, text: (, line: 3, col: 9>,
 ...,
 <Token token_type: TokenType.R_PAREN, text: ), line: 5, col: 1>,
 <Token token_type: TokenType.ALIAS, text: AS, line: 5, col: 3>,
 <Token token_type: TokenType.VAR, text: t, line: 5, col: 6>,
 **<Token token_type: TokenType.L_PAREN, text: (, line: 5, col: 7>,**
 <Token token_type: TokenType.VAR, text: zoo, line: 5, col: 8>,
 <Token token_type: TokenType.COMMA, text: ,, line: 5, col: 11>,
 <Token token_type: TokenType.VAR, text: animals, line: 5, col: 12>,
 <Token token_type: TokenType.R_PAREN, text: ), line: 5, col: 19>]
```


Discussion:
The following query gets transpiled correctly. Key difference is using the alias **(zoo, animals)** vs **t(zoo, animals)**
```
q = """SELECT zoo, animal
FROM (VALUES
        ('OaklandZoo', ARRAY['dog', 'cat', 'tiger']),
        ('SanFranciscoZoo', ARRAY['dog', 'cat'])
) AS (zoo,animals)"""

sqlglot.transpile(q, 'presto', 'spark')
```
@tobymao this seems similar to the `CTEAlias` introduced in this PR: https://github.com/tobymao/sqlglot/pull/96
Maybe we should rename `CTEAlias` to `TableAlias` and use it here as well?
sure, want to tackle it? in parse_table we do 

```
        if alias is None:
            this = expression
        elif alias:
            this = self.expression(exp.Alias, this=expression, alias=alias)
        else:
            print("coming here")
            this = self._parse_alias(expression)
            print(this)
```

and parse_alias isn't picking this up

one thing tricky about this issue is spark and hive i don't think support table constructions, meaning 

AS TABLE_IDENTIFIER(column_a, column_b)
when this is detected in hive/spark or things don't don't support value table constructions, we'll have to expand this into 

select 'oakland' AS zoo, ARRAY('dog') AS animals
UNION ALL
select 'san fran' AS zoo, ARRAY('dog', cat) AS animals

Resolving patch:
diff --git a/sqlglot/expressions.py b/sqlglot/expressions.py
--- a/sqlglot/expressions.py
+++ b/sqlglot/expressions.py
@@ -973,7 +973,7 @@ def with_(
 
     def subquery(self, alias=None, copy=True):
         """
-        Convert this expression to an aliased expression that can be used as a subquery.
+        Convert this expression to an aliased expression that can be used as a Subquery.
 
         Example:
             >>> subquery = Select().select("x").from_("tbl").subquery()
@@ -988,7 +988,7 @@ def subquery(self, alias=None, copy=True):
             Alias: the subquery
         """
         instance = _maybe_copy(self, copy)
-        return Alias(
+        return Subquery(
             this=instance,
             alias=alias,
         )
@@ -1035,6 +1035,10 @@ def ctas(self, table, properties=None, dialect=None, parser_opts=None, copy=True
         )
 
 
+class Subquery(Expression):
+    arg_types = {"this": True, "alias": False}
+
+
 class TableSample(Expression):
     arg_types = {
         "this": True,
diff --git a/sqlglot/generator.py b/sqlglot/generator.py
--- a/sqlglot/generator.py
+++ b/sqlglot/generator.py
@@ -37,18 +37,6 @@ class Generator:
             unsupported expressions. Default ErrorLevel.WARN.
     """
 
-    BODY_EXP = (
-        exp.Select,
-        exp.From,
-        exp.Join,
-        exp.Where,
-        exp.Group,
-        exp.Having,
-        exp.Order,
-        exp.Union,
-        exp.CTE,
-    )
-
     TRANSFORMS = {
         exp.DateAdd: lambda self, e: f"DATE_ADD({self.sql(e, 'this')}, {self.sql(e, 'expression')}, {self.sql(e, 'unit')})",
         exp.DateDiff: lambda self, e: f"DATE_DIFF({self.sql(e, 'this')}, {self.sql(e, 'expression')})",
@@ -357,7 +345,7 @@ def except_sql(self, expression):
 
     def exists_sql(self, expression):
         exists = "NOT EXISTS" if expression.args.get("not") else "EXISTS"
-        return f"{exists} {self.wrap(expression)}"
+        return f"{exists} {self.sql(expression, 'this')}"
 
     def hint_sql(self, expression):
         if self.sql(expression, "this"):
@@ -547,6 +535,13 @@ def star_sql(self, expression):
         # pylint: disable=unused-argument
         return "*"
 
+    def subquery_sql(self, expression):
+        alias = self.sql(expression, "alias")
+        alias = f" AS {alias}" if alias else ""
+        if self.pretty:
+            return f"{self.wrap(expression)}{alias}"
+        return f"({self.sql(expression, 'this')}){alias}"
+
     def union_sql(self, expression):
         return self.set_operation(
             expression, f"UNION{'' if expression.args.get('distinct') else ' ALL'}"
@@ -667,11 +662,6 @@ def not_sql(self, expression):
     def alias_sql(self, expression):
         to_sql = self.sql(expression, "alias")
         to_sql = f" AS {to_sql}" if to_sql else ""
-
-        if isinstance(expression.args["this"], self.BODY_EXP):
-            if self.pretty:
-                return f"{self.wrap(expression)}{to_sql}"
-            return f"({self.sql(expression, 'this')}){to_sql}"
         return f"{self.sql(expression, 'this')}{to_sql}"
 
     def aliases_sql(self, expression):
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -189,6 +189,18 @@ def _parse_decimal(args):
         TokenType.CROSS,
     }
 
+    BODY_EXPRESSIONS = (
+        exp.Select,
+        exp.From,
+        exp.Join,
+        exp.Where,
+        exp.Group,
+        exp.Having,
+        exp.Order,
+        exp.Union,
+        exp.CTE,
+    )
+
     __slots__ = (
         "functions",
         "error_level",
@@ -422,7 +434,7 @@ def _parse_drop(self):
         return self.expression(
             exp.Drop,
             exists=self._parse_exists(),
-            this=self._parse_table(None, schema=True),
+            this=self._parse_table(schema=True),
             kind=kind,
         )
 
@@ -443,7 +455,7 @@ def _parse_create(self):
             self.raise_error("Expected TABLE or View")
 
         exists = self._parse_exists(not_=True)
-        this = self._parse_table(alias=None, schema=True)
+        this = self._parse_table(schema=True)
         expression = None
         properties = None
 
@@ -581,7 +593,7 @@ def _parse_insert(self):
 
         return self.expression(
             exp.Insert,
-            this=self._parse_table(alias=None, schema=True),
+            this=self._parse_table(schema=True),
             exists=self._parse_exists(),
             partition=self._parse_partition(),
             expression=self._parse_select(),
@@ -593,7 +605,7 @@ def _parse_delete(self):
 
         return self.expression(
             exp.Delete,
-            this=self._parse_table(alias=None, schema=True),
+            this=self._parse_table(schema=True),
             where=self._parse_where(),
         )
 
@@ -601,7 +613,7 @@ def _parse_update(self):
         return self.expression(
             exp.Update,
             **{
-                "this": self._parse_table(alias=None, schema=True),
+                "this": self._parse_table(schema=True),
                 "expressions": self._match(TokenType.SET)
                 and self._parse_csv(self._parse_equality),
                 "from": self._parse_from(),
@@ -621,7 +633,7 @@ def _parse_uncache(self):
     def _parse_cache(self):
         lazy = self._match(TokenType.LAZY)
         self._match(TokenType.TABLE)
-        table = self._parse_table(alias=None, schema=True)
+        table = self._parse_table(schema=True)
         options = []
 
         if self._match(TokenType.OPTIONS):
@@ -720,6 +732,7 @@ def _parse_cte(self):
         )
 
     def _parse_table_alias(self):
+        self._match(TokenType.ALIAS)
         alias = self._parse_id_var()
         columns = None
 
@@ -742,9 +755,13 @@ def _parse_select(self):
         if self._match(TokenType.L_PAREN):
             this = self._parse_select()
             self._match_r_paren()
-            this = self._parse_alias(this)
+            this = self.expression(
+                exp.Subquery,
+                this=this,
+                alias=self._parse_table_alias(),
+            )
 
-        if isinstance(this, exp.Alias) or self._match(TokenType.SELECT):
+        if isinstance(this, exp.Subquery) or self._match(TokenType.SELECT):
             this = self.expression(
                 exp.Select,
                 hint=self._parse_hint(),
@@ -834,14 +851,14 @@ def _parse_join(self):
             on=self._parse_conjunction() if self._match(TokenType.ON) else None,
         )
 
-    def _parse_table(self, alias=False, schema=False):
+    def _parse_table(self, schema=False):
         unnest = self._parse_unnest()
 
         if unnest:
             return unnest
 
         if self._match(TokenType.L_PAREN):
-            expression = self._parse_with()
+            this = self._parse_with()
             self._match_r_paren()
         else:
             catalog = None
@@ -855,22 +872,18 @@ def _parse_table(self, alias=False, schema=False):
                 if not table:
                     self.raise_error("Expected table name")
 
-            expression = self.expression(exp.Table, this=table, db=db, catalog=catalog)
-
-        expression = self._parse_table_sample(expression)
+            this = self.expression(exp.Table, this=table, db=db, catalog=catalog)
 
-        if alias is None:
-            this = expression
-        elif alias:
-            this = self.expression(exp.Alias, this=expression, alias=alias)
-        else:
-            this = self._parse_alias(expression)
+        if schema:
+            return self._parse_schema(this=this)
 
-        if not isinstance(this, (exp.Alias, exp.Table)):
-            this = self.expression(exp.Alias, this=this, alias=None)
+        this = self._parse_table_sample(this)
+        alias = self._parse_table_alias()
 
-        if schema:
-            return self._parse_schema(this=expression)
+        if isinstance(this, self.BODY_EXPRESSIONS):
+            return self.expression(exp.Subquery, this=this, alias=alias)
+        if alias:
+            return self.expression(exp.Alias, this=this, alias=alias)
         return this
 
     def _parse_unnest(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
@@ -232,12 +232,15 @@ SELECT 1 EXCEPT DISTINCT SELECT 2
 SELECT 1 INTERSECT SELECT 2
 SELECT 1 INTERSECT DISTINCT SELECT 2
 SELECT 1 AS delete, 2 AS alter
+SELECT * FROM ((SELECT 1))
 SELECT * FROM (SELECT 1) AS x
 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 1) UNION (SELECT 2)
 (SELECT 1) UNION SELECT 2
 SELECT 1 UNION (SELECT 2)
diff --git a/tests/test_transpile.py b/tests/test_transpile.py
--- a/tests/test_transpile.py
+++ b/tests/test_transpile.py
@@ -27,11 +27,6 @@ def test_custom_transform(self):
         )
 
     def test_paren(self):
-        self.validate(
-            "SELECT * FROM ((SELECT 1))",
-            "SELECT * FROM (SELECT 1)",
-        )
-
         with self.assertRaises(ParseError):
             transpile("1 + (2 + 3")
             transpile("select f(")