Repository: tobymao/sqlglot

Issue:
BigQuery `SELECT AS STRUCT` fails to parse
Reproducer:

```python
import sqlglot
sqlglot.transpile("SELECT AS STRUCT 1 a, 2 b", read="bigquery")
```

> sqlglot.errors.ParseError: Required keyword: 'this' missing for <class 'sqlglot.expressions.Alias'>. Line 1, Col: 18.
  SELECT AS STRUCT 1 a, 2 b

Note that the more general `SELECT AS VALUE` has the same issue.

Ref: https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_as_struct
Ref: https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_as_value

Discussion:

Patch:
diff --git a/sqlglot/dialects/mysql.py b/sqlglot/dialects/mysql.py
index 1e2cfa32..1e8f694f 100644
--- a/sqlglot/dialects/mysql.py
+++ b/sqlglot/dialects/mysql.py
@@ -303,7 +303,13 @@ class MySQL(Dialect):
                 db = None
             else:
                 position = None
-                db = self._parse_id_var() if self._match_text_seq("FROM") else None
+                db = None
+
+                if self._match(TokenType.FROM):
+                    db = self._parse_id_var()
+                elif self._match(TokenType.DOT):
+                    db = target_id
+                    target_id = self._parse_id_var()
 
             channel = self._parse_id_var() if self._match_text_seq("FOR", "CHANNEL") else None
 
diff --git a/sqlglot/expressions.py b/sqlglot/expressions.py
index b9da4cc4..5a1dd3ec 100644
--- a/sqlglot/expressions.py
+++ b/sqlglot/expressions.py
@@ -2058,6 +2058,7 @@ class Lock(Expression):
 class Select(Subqueryable):
     arg_types = {
         "with": False,
+        "kind": False,
         "expressions": False,
         "hint": False,
         "distinct": False,
diff --git a/sqlglot/generator.py b/sqlglot/generator.py
index a6f47728..69c81599 100644
--- a/sqlglot/generator.py
+++ b/sqlglot/generator.py
@@ -1323,6 +1323,8 @@ class Generator:
         )
 
     def select_sql(self, expression: exp.Select) -> str:
+        kind = expression.args.get("kind")
+        kind = f" AS {kind}" if kind else ""
         hint = self.sql(expression, "hint")
         distinct = self.sql(expression, "distinct")
         distinct = f" {distinct}" if distinct else ""
@@ -1330,7 +1332,7 @@ class Generator:
         expressions = f"{self.sep()}{expressions}" if expressions else expressions
         sql = self.query_modifiers(
             expression,
-            f"SELECT{hint}{distinct}{expressions}",
+            f"SELECT{kind}{hint}{distinct}{expressions}",
             self.sql(expression, "into", comment=False),
             self.sql(expression, "from", comment=False),
         )
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
index a36251ea..1c29a8a0 100644
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -1704,6 +1704,11 @@ class Parser(metaclass=_Parser):
         elif self._match(TokenType.SELECT):
             comments = self._prev_comments
 
+            kind = (
+                self._match(TokenType.ALIAS)
+                and self._match_texts(("STRUCT", "VALUE"))
+                and self._prev.text
+            )
             hint = self._parse_hint()
             all_ = self._match(TokenType.ALL)
             distinct = self._match(TokenType.DISTINCT)
@@ -1722,6 +1727,7 @@ class Parser(metaclass=_Parser):
 
             this = self.expression(
                 exp.Select,
+                kind=kind,
                 hint=hint,
                 distinct=distinct,
                 expressions=expressions,


Test patch:
diff --git a/tests/dialects/test_bigquery.py b/tests/dialects/test_bigquery.py
index e731b50f..1e912584 100644
--- a/tests/dialects/test_bigquery.py
+++ b/tests/dialects/test_bigquery.py
@@ -6,6 +6,8 @@ class TestBigQuery(Validator):
     dialect = "bigquery"
 
     def test_bigquery(self):
+        self.validate_identity("SELECT AS STRUCT 1 AS a, 2 AS b")
+        self.validate_identity("SELECT AS VALUE STRUCT(1 AS a, 2 AS b)")
         self.validate_identity("SELECT STRUCT<ARRAY<STRING>>(['2023-01-17'])")
         self.validate_identity("SELECT * FROM q UNPIVOT(values FOR quarter IN (b, c))")
         self.validate_identity(
@@ -13,6 +15,12 @@ class TestBigQuery(Validator):
         )
 
         self.validate_all("LEAST(x, y)", read={"sqlite": "MIN(x, y)"})
+        self.validate_all(
+            "SELECT ARRAY(SELECT AS STRUCT 1 a, 2 b)",
+            write={
+                "bigquery": "SELECT ARRAY(SELECT AS STRUCT 1 AS a, 2 AS b)",
+            },
+        )
         self.validate_all(
             "REGEXP_CONTAINS('foo', '.*')",
             read={"bigquery": "REGEXP_CONTAINS('foo', '.*')"},
diff --git a/tests/dialects/test_mysql.py b/tests/dialects/test_mysql.py
index 5f8560a0..a0f62d8d 100644
--- a/tests/dialects/test_mysql.py
+++ b/tests/dialects/test_mysql.py
@@ -424,6 +424,10 @@ COMMENT='客户账户表'"""
         show = self.validate_identity("SHOW INDEX FROM foo FROM bar")
         self.assertEqual(show.text("db"), "bar")
 
+        self.validate_all(
+            "SHOW INDEX FROM bar.foo", write={"mysql": "SHOW INDEX FROM foo FROM bar"}
+        )
+
     def test_show_db_like_or_where_sql(self):
         for key in [
             "OPEN TABLES",