Repository: tobymao/sqlglot

Issue:
Bigquery parse_one a subquery with "-" hangs
**Fully reproducible code snippet**
version: 25.30.0 and 25.33.0
```
sql = """
WITH _stanford AS (
  SELECT unitid
  FROM colleges_ipeds_institution_dim
  WHERE inst_name = 'Stanford University'
),
_stanford_grad_rates AS (
  SELECT DISTINCT
    g.year,
    SAFE_DIVIDE(SUM(g.completers_150pct), SUM(g.cohort_adj_150pct)) AS graduation_rate
  FROM
    colleges_ipeds_grad-rates g
    JOIN _stanford s ON g.unitid = s.unitid
  WHERE
    g.subcohort = 99
  GROUP BY
    g.year
)
SELECT
  sgr.year,
  sgr.graduation_rate
FROM
  _stanford_grad_rates sgr
WHERE
  sgr.year >= (SELECT MAX(year) FROM colleges_ipeds_grad-rates) - 20
ORDER BY
  sgr.year DESC;
"""
parsed_query = parse_one(sql, read="bigquery")
>>> hangs
```
Primary issue is the clause `WHERE sgr.year >= (SELECT MAX(year) FROM colleges_ipeds_grad-rates) - 20`, likely due to the hyphen. If we wrap the table name in backticks it does work properly and will not hang

Hints from issue comments:
@georgesittas: Thanks, we'll take a look.

Solution patch:
diff --git a/sqlglot/dialects/bigquery.py b/sqlglot/dialects/bigquery.py
index ec8188bb7c..390e1aacf0 100644
--- a/sqlglot/dialects/bigquery.py
+++ b/sqlglot/dialects/bigquery.py
@@ -589,6 +589,8 @@ class Parser(parser.Parser):
 
         NULL_TOKENS = {TokenType.NULL, TokenType.UNKNOWN}
 
+        DASHED_TABLE_PART_FOLLOW_TOKENS = {TokenType.DOT, TokenType.L_PAREN, TokenType.R_PAREN}
+
         STATEMENT_PARSERS = {
             **parser.Parser.STATEMENT_PARSERS,
             TokenType.ELSE: lambda self: self._parse_as_command(self._prev),
@@ -615,11 +617,13 @@ def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
             if isinstance(this, exp.Identifier):
                 table_name = this.name
                 while self._match(TokenType.DASH, advance=False) and self._next:
-                    text = ""
-                    while self._is_connected() and self._curr.token_type != TokenType.DOT:
+                    start = self._curr
+                    while self._is_connected() and not self._match_set(
+                        self.DASHED_TABLE_PART_FOLLOW_TOKENS, advance=False
+                    ):
                         self._advance()
-                        text += self._prev.text
-                    table_name += text
+
+                    table_name += self._find_sql(start, self._prev)
 
                 this = exp.Identifier(this=table_name, quoted=this.args.get("quoted"))
             elif isinstance(this, exp.Literal):


Test patch:
diff --git a/tests/dialects/test_bigquery.py b/tests/dialects/test_bigquery.py
index 09f7673cef..80a5dcc387 100644
--- a/tests/dialects/test_bigquery.py
+++ b/tests/dialects/test_bigquery.py
@@ -200,24 +200,7 @@ def test_bigquery(self):
         self.validate_identity("CAST(x AS NVARCHAR)", "CAST(x AS STRING)")
         self.validate_identity("CAST(x AS TIMESTAMPTZ)", "CAST(x AS TIMESTAMP)")
         self.validate_identity("CAST(x AS RECORD)", "CAST(x AS STRUCT)")
-        self.validate_all(
-            "EDIT_DISTANCE(col1, col2, max_distance => 3)",
-            write={
-                "bigquery": "EDIT_DISTANCE(col1, col2, max_distance => 3)",
-                "clickhouse": UnsupportedError,
-                "databricks": UnsupportedError,
-                "drill": UnsupportedError,
-                "duckdb": UnsupportedError,
-                "hive": UnsupportedError,
-                "postgres": "LEVENSHTEIN_LESS_EQUAL(col1, col2, 3)",
-                "presto": UnsupportedError,
-                "snowflake": "EDITDISTANCE(col1, col2, 3)",
-                "spark": UnsupportedError,
-                "spark2": UnsupportedError,
-                "sqlite": UnsupportedError,
-            },
-        )
-
+        self.validate_identity("SELECT * FROM x WHERE x.y >= (SELECT MAX(a) FROM b-c) - 20")
         self.validate_identity(
             "MERGE INTO dataset.NewArrivals USING (SELECT * FROM UNNEST([('microwave', 10, 'warehouse #1'), ('dryer', 30, 'warehouse #1'), ('oven', 20, 'warehouse #2')])) ON FALSE WHEN NOT MATCHED THEN INSERT ROW WHEN NOT MATCHED BY SOURCE THEN DELETE"
         )
@@ -332,6 +315,23 @@ def test_bigquery(self):
             "SELECT CAST(1 AS INT64)",
         )
 
+        self.validate_all(
+            "EDIT_DISTANCE(col1, col2, max_distance => 3)",
+            write={
+                "bigquery": "EDIT_DISTANCE(col1, col2, max_distance => 3)",
+                "clickhouse": UnsupportedError,
+                "databricks": UnsupportedError,
+                "drill": UnsupportedError,
+                "duckdb": UnsupportedError,
+                "hive": UnsupportedError,
+                "postgres": "LEVENSHTEIN_LESS_EQUAL(col1, col2, 3)",
+                "presto": UnsupportedError,
+                "snowflake": "EDITDISTANCE(col1, col2, 3)",
+                "spark": UnsupportedError,
+                "spark2": UnsupportedError,
+                "sqlite": UnsupportedError,
+            },
+        )
         self.validate_all(
             "EDIT_DISTANCE(a, b)",
             write={