Repository: tobymao/sqlglot

Issue:
Decimal numbers ending with a `.` and a closing parenthesis throw a ParseError in Snowflake ❄️ 
The following query works in Snowflake:
```sql
SELECT (5.)
```

But throws a ParseError when parsed:
```py
parse_one("SELECT (5.)", read=dialects.Snowflake)
```

<details><summary>Here is the traceback</summary>
<p>

```py
Traceback (most recent call last):
  File "/Users/florian.ernst/Library/Application Support/JetBrains/Toolbox/apps/PyCharm-P/ch-0/231.9011.38/PyCharm.app/Contents/plugins/python/helpers/pydev/pydevconsole.py", line 364, in runcode
    coro = func()
  File "<input>", line 1, in <module>
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/__init__.py", line 158, in parse_one
    result = dialect.parse(sql, **opts)
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/dialects/dialect.py", line 217, in parse
    return self.parser(**opts).parse(self.tokenize(sql), sql)
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 856, in parse
    return self._parse(
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 922, in _parse
    expressions.append(parse_method(self))
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 1112, in _parse_statement
    expression = self._parse_set_operations(expression) if expression else self._parse_select()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 1877, in _parse_select
    expressions = self._parse_csv(self._parse_expression)
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 4135, in _parse_csv
    parse_result = parse_method()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2722, in _parse_expression
    return self._parse_alias(self._parse_conjunction())
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2725, in _parse_conjunction
    return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 4149, in _parse_tokens
    this = parse_method()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2728, in _parse_equality
    return self._parse_tokens(self._parse_comparison, self.EQUALITY)
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 4149, in _parse_tokens
    this = parse_method()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2731, in _parse_comparison
    return self._parse_tokens(self._parse_range, self.COMPARISON)
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 4149, in _parse_tokens
    this = parse_method()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2734, in _parse_range
    this = self._parse_bitwise()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2831, in _parse_bitwise
    this = self._parse_term()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2852, in _parse_term
    return self._parse_tokens(self._parse_factor, self.TERM)
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 4149, in _parse_tokens
    this = parse_method()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2855, in _parse_factor
    return self._parse_tokens(self._parse_unary, self.FACTOR)
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 4149, in _parse_tokens
    this = parse_method()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2860, in _parse_unary
    return self._parse_at_time_zone(self._parse_type())
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2869, in _parse_type
    this = self._parse_column()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 3020, in _parse_column
    this = self._parse_field()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 3123, in _parse_field
    self._parse_primary()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 3095, in _parse_primary
    expressions = self._parse_csv(self._parse_expression)
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 4135, in _parse_csv
    parse_result = parse_method()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2722, in _parse_expression
    return self._parse_alias(self._parse_conjunction())
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2725, in _parse_conjunction
    return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 4149, in _parse_tokens
    this = parse_method()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2728, in _parse_equality
    return self._parse_tokens(self._parse_comparison, self.EQUALITY)
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 4149, in _parse_tokens
    this = parse_method()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2731, in _parse_comparison
    return self._parse_tokens(self._parse_range, self.COMPARISON)
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 4149, in _parse_tokens
    this = parse_method()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2734, in _parse_range
    this = self._parse_bitwise()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2831, in _parse_bitwise
    this = self._parse_term()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2852, in _parse_term
    return self._parse_tokens(self._parse_factor, self.TERM)
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 4149, in _parse_tokens
    this = parse_method()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2855, in _parse_factor
    return self._parse_tokens(self._parse_unary, self.FACTOR)
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 4149, in _parse_tokens
    this = parse_method()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2860, in _parse_unary
    return self._parse_at_time_zone(self._parse_type())
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 2869, in _parse_type
    this = self._parse_column()
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 3025, in _parse_column
    return self._parse_column_ops(this)
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 3058, in _parse_column_ops
    this = self.expression(
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 986, in expression
    return self.validate_expression(instance)
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 1006, in validate_expression
    self.raise_error(error_message)
  File "/Users/florian.ernst/Alan/alan-jobs/env/lib/python3.10/site-packages/sqlglot/parser.py", line 966, in raise_error
    raise error
sqlglot.errors.ParseError: Required keyword: 'this' missing for <class 'sqlglot.expressions.Column'>. Line 1, Col: 11.
  SELECT (5.)
```

</p>
</details> 


Discussion:
Thanks for the reports, I'll have a look.

Resolving patch:
diff --git a/sqlglot/tokens.py b/sqlglot/tokens.py
--- a/sqlglot/tokens.py
+++ b/sqlglot/tokens.py
@@ -995,7 +995,7 @@ def _scan_number(self) -> None:
                 self._advance()
             elif self._peek == "." and not decimal:
                 after = self.peek(1)
-                if after.isdigit() or not after.strip():
+                if after.isdigit() or not after.isalpha():
                     decimal = True
                     self._advance()
                 else:


Test patch:
diff --git a/tests/fixtures/identity.sql b/tests/fixtures/identity.sql
--- a/tests/fixtures/identity.sql
+++ b/tests/fixtures/identity.sql
@@ -1,7 +1,11 @@
 SUM(1)
 SUM(CASE WHEN x > 1 THEN 1 ELSE 0 END) / y
 1
+(1)
+1.
+(1.)
 1.0
+(1.0)
 1E2
 1E+2
 1E-2