diff --git a/CHANGELOG b/CHANGELOG index edfedb4f..4d396900 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -33,6 +33,8 @@ Bug Fixes * Fix statement splitting (issue845). * Fix a late-binding closure bug in `TokenList.token_not_matching`. +* Fix keyword before a leading-dot float being lexed as a name, e.g. in + ``BETWEEN .03 AND .06`` (issue601). Release 0.5.5 (Dec 19, 2025) diff --git a/sqlparse/keywords.py b/sqlparse/keywords.py index 4bafcda1..5f9f7a08 100644 --- a/sqlparse/keywords.py +++ b/sqlparse/keywords.py @@ -49,7 +49,7 @@ # see issue #39 # Spaces around period `schema . name` are valid identifier # TODO: Spaces before period not implemented - (r'[A-ZÀ-Ü]\w*(?=\s*\.)', tokens.Name), # 'Name'. + (r'[A-ZÀ-Ü]\w*(?=\s*\.(?!\d))', tokens.Name), # 'Name'. # FIXME(atronah): never match, # because `re.match` doesn't work with look-behind regexp feature (r'(?<=\.)[A-ZÀ-Ü]\w*', tokens.Name), # .'Name' diff --git a/tests/test_regressions.py b/tests/test_regressions.py index 15ac9ee9..6addfae8 100644 --- a/tests/test_regressions.py +++ b/tests/test_regressions.py @@ -465,3 +465,16 @@ def limit_recursion(): def test_max_recursion(limit_recursion): with pytest.raises(SQLParseError): sqlparse.parse('[' * 1000 + ']' * 1000) + + +def test_between_leading_dot_float_issue601(): + # a leading-dot float must not turn the preceding word into a Name + # by mistaking the decimal point for a qualified-name separator + p = sqlparse.parse('a between .03 and .06')[0] + tokens = [t for t in p.flatten() if not t.is_whitespace] + assert tokens[1].ttype is T.Keyword + assert tokens[1].value == 'between' + assert tokens[2].ttype is T.Number.Float + assert tokens[3].ttype is T.Keyword + assert tokens[3].value == 'and' + assert tokens[4].ttype is T.Number.Float