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
3 changes: 2 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
Development Version
-------------------

Nothing yet.
* Preserve whitespace and line endings inside quoted values containing a
backslash followed by a newline when formatting SQL.


Release 0.6.0 (Aug 13, 2026)
Expand Down
2 changes: 1 addition & 1 deletion sqlparse/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
'(?:[^'\\]|\\.)*' # Match single quoted strings
)
)
""", re.VERBOSE)
""", re.VERBOSE | re.DOTALL)

LINE_MATCH = re.compile(r'(\r\n|\r|\n)')

Expand Down
24 changes: 24 additions & 0 deletions tests/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,30 @@ def test_notransform_of_quoted_crlf(self):
== "SELECT some_column LIKE 'value\\\\\\'\r' WHERE id = 1\n")


@pytest.mark.parametrize('quote', ["'", '"'])
@pytest.mark.parametrize('newline', ['\n', '\r', '\r\n'])
@pytest.mark.parametrize('options', [{}, {'strip_whitespace': True},
{'reindent': True}])
def test_preserve_quoted_newlines_after_backslash(quote, newline, options):
text = 'SELECT ' + quote + 'a\\' + newline + 'b \r\nc' + quote + ';'

assert sqlparse.format(text, **options) == text


@pytest.mark.parametrize('mode', ['strip_whitespace', 'reindent'])
def test_keyword_transform_preserves_multiple_literals(mode):
left = "'select a\\\nb \r\nc'"
right = "'from d\\\ne \r\nf'"
text = f'select {left} as x,\n{right} as y;'

actual = sqlparse.format(text, keyword_case='upper', **{mode: True})

assert actual.startswith('SELECT ')
assert actual.count(' AS ') == 2
assert left in actual
assert right in actual


class TestFormatReindentAligned:
@staticmethod
def formatter(sql):
Expand Down
11 changes: 11 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,14 @@
['`foo`', 'foo']))
def test_remove_quotes(value, expected):
assert utils.remove_quotes(value) == expected


@pytest.mark.parametrize('quote', ["'", '"'])
@pytest.mark.parametrize('newline', ['\n', '\r', '\r\n'])
@pytest.mark.parametrize('backslashes', [1, 2])
def test_split_unquoted_newlines_after_backslash(quote, newline, backslashes):
quoted = (quote + 'a' + '\\' * backslashes + newline
+ 'b \r\nc' + quote)
text = 'SELECT\r\n' + quoted + '\rFROM t'

assert utils.split_unquoted_newlines(text) == ['SELECT', quoted, 'FROM t']