Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
Development Version
-------------------

Nothing yet.
Bug Fixes

* `identifier_case` no longer changes the case of identifiers quoted with
backticks, acute accents or square brackets. Only double-quoted identifiers
were exempt before, although the lexer recognizes all four quoting styles
(issue433).


Release 0.6.0 (Aug 13, 2026)
Expand Down
8 changes: 7 additions & 1 deletion sqlparse/filters/tokens.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,15 @@ class KeywordCaseFilter(_CaseFilter):
class IdentifierCaseFilter(_CaseFilter):
ttype = T.Name, T.String.Symbol

# Opening delimiters of a quoted identifier. SQL_REGEX recognizes four
# quoting styles, and only the double-quoted one reaches this filter as
# T.String.Symbol; the backtick, acute-accent and [bracket] forms arrive
# as plain T.Name, indistinguishable from a bare identifier here.
QUOTES = '"`´['

def process(self, stream):
for ttype, value in stream:
if ttype in self.ttype and value.strip()[0] != '"':
if ttype in self.ttype and value.strip()[0] not in self.QUOTES:
value = self.convert(value)
yield ttype, value

Expand Down
12 changes: 12 additions & 0 deletions tests/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ def test_identifiercase_quotes(self):
res = sqlparse.format(sql, identifier_case="upper")
assert res == 'select * from "foo"."bar"'

@pytest.mark.parametrize('sql', [
'select * from `myS`.`Tbl`', # MySQL
'select * from ´myS´.´Tbl´',
'select * from [myS].[Tbl]', # T-SQL / SQLite
])
@pytest.mark.parametrize('case', ['upper', 'lower', 'capitalize'])
def test_identifiercase_non_ansi_quotes(self, sql, case):
# issue433: a delimited identifier keeps its case whichever of the
# four quoting styles SQL_REGEX recognizes was used. The mixed-case
# names make every one of the three conversions observable.
assert sqlparse.format(sql, identifier_case=case) == sql

def test_strip_comments_single(self):
sql = 'select *-- statement starts here\nfrom foo'
res = sqlparse.format(sql, strip_comments=True)
Expand Down