Repository: tobymao/sqlglot

Issue:
[spark dialect] Parser doesn't work when column name or alias starts with digits AND contains _
maybe this commit https://github.com/tobymao/sqlglot/pull/923 not fix https://github.com/tobymao/sqlglot/issues/916 properly

reproduction:

1. column name starts with digits AND contains `_`

```python
>>> from sqlglot import parse_one
>>> sql = "select 1_a as a from test_table"
>>> parse_one(sql, read='spark')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/homebrew/lib/python3.8/site-packages/sqlglot/__init__.py", line 84, in parse_one
    result = dialect.parse(sql, **opts)
  File "/opt/homebrew/lib/python3.8/site-packages/sqlglot/dialects/dialect.py", line 150, in parse
    return self.parser(**opts).parse(self.tokenizer.tokenize(sql), sql)
  File "/opt/homebrew/lib/python3.8/site-packages/sqlglot/parser.py", line 667, in parse
    return self._parse(
  File "/opt/homebrew/lib/python3.8/site-packages/sqlglot/parser.py", line 731, in _parse
    self.raise_error("Invalid expression / Unexpected token")
  File "/opt/homebrew/lib/python3.8/site-packages/sqlglot/parser.py", line 774, in raise_error
    raise error
sqlglot.errors.ParseError: Invalid expression / Unexpected token. Line 1, Col: 12.
  select 1_a as a from test_table
```

2.  alias starts with digits AND contains `_`

reproduction:
```python
>>> from sqlglot import parse_one
>>> sql = """select a_b as a from test_table"""
>>> parse_one(sql, read='spark')
(SELECT expressions: 
  (ALIAS this: 
    (COLUMN this: 
      (IDENTIFIER this: a_b, quoted: False)), alias: 
    (IDENTIFIER this: a, quoted: False)), from: 
  (FROM expressions: 
    (TABLE this: 
      (IDENTIFIER this: test_table, quoted: False))))
>>> 
>>> sql = """select a_b as 1 from test_table"""
>>> parse_one(sql, read='spark')
(SELECT expressions: 
  (ALIAS this: 
    (COLUMN this: 
      (IDENTIFIER this: a_b, quoted: False)), alias: 
    (IDENTIFIER this: 1, quoted: False)), from: 
  (FROM expressions: 
    (TABLE this: 
      (IDENTIFIER this: test_table, quoted: False))))
>>> 
>>> sql = """select a_b as a_b from test_table"""
>>> parse_one(sql, read='spark')
(SELECT expressions: 
  (ALIAS this: 
    (COLUMN this: 
      (IDENTIFIER this: a_b, quoted: False)), alias: 
    (IDENTIFIER this: a_b, quoted: False)), from: 
  (FROM expressions: 
    (TABLE this: 
      (IDENTIFIER this: test_table, quoted: False))))
>>> 
>>> sql = """select a_b as a1_b from test_table"""
>>> parse_one(sql, read='spark')
(SELECT expressions: 
  (ALIAS this: 
    (COLUMN this: 
      (IDENTIFIER this: a_b, quoted: False)), alias: 
    (IDENTIFIER this: a1_b, quoted: False)), from: 
  (FROM expressions: 
    (TABLE this: 
      (IDENTIFIER this: test_table, quoted: False))))
>>> 
>>> sql = """select a_b as 1_a from test_table"""
>>> parse_one(sql, read='spark')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/homebrew/lib/python3.8/site-packages/sqlglot/__init__.py", line 84, in parse_one
    result = dialect.parse(sql, **opts)
  File "/opt/homebrew/lib/python3.8/site-packages/sqlglot/dialects/dialect.py", line 150, in parse
    return self.parser(**opts).parse(self.tokenizer.tokenize(sql), sql)
  File "/opt/homebrew/lib/python3.8/site-packages/sqlglot/parser.py", line 667, in parse
    return self._parse(
  File "/opt/homebrew/lib/python3.8/site-packages/sqlglot/parser.py", line 731, in _parse
    self.raise_error("Invalid expression / Unexpected token")
  File "/opt/homebrew/lib/python3.8/site-packages/sqlglot/parser.py", line 774, in raise_error
    raise error
sqlglot.errors.ParseError: Invalid expression / Unexpected token. Line 1, Col: 16.
  select a_b as 1_a from test_table
```

Discussion:

Patch:
diff --git a/sqlglot/tokens.py b/sqlglot/tokens.py
index 745152ff..8e312a7f 100644
--- a/sqlglot/tokens.py
+++ b/sqlglot/tokens.py
@@ -944,10 +944,10 @@ class Tokenizer(metaclass=_Tokenizer):
             elif self._peek.upper() == "E" and not scientific:  # type: ignore
                 scientific += 1
                 self._advance()
-            elif self._peek.isalpha():  # type: ignore
+            elif self._peek.isidentifier():  # type: ignore
                 number_text = self._text
                 literal = []
-                while self._peek.isalpha():  # type: ignore
+                while self._peek.isidentifier():  # type: ignore
                     literal.append(self._peek.upper())  # type: ignore
                     self._advance()
 


Test patch:
diff --git a/tests/dialects/test_hive.py b/tests/dialects/test_hive.py
index 41dc6cea..bbf00b1b 100644
--- a/tests/dialects/test_hive.py
+++ b/tests/dialects/test_hive.py
@@ -344,6 +344,18 @@ class TestHive(Validator):
                 "spark": "SELECT A.1a AS b FROM test_a AS A",
             },
         )
+        self.validate_all(
+            "SELECT 1_a AS a FROM test_table",
+            write={
+                "spark": "SELECT 1_a AS a FROM test_table",
+            },
+        )
+        self.validate_all(
+            "SELECT a_b AS 1_a FROM test_table",
+            write={
+                "spark": "SELECT a_b AS 1_a FROM test_table",
+            },
+        )
         self.validate_all(
             "PERCENTILE(x, 0.5)",
             write={