diff --git a/sqlparse/filters/reindent.py b/sqlparse/filters/reindent.py index ea41ac6b..303c2e7e 100644 --- a/sqlparse/filters/reindent.py +++ b/sqlparse/filters/reindent.py @@ -91,8 +91,8 @@ def _split_statements(self, tlist): if prev_ and prev_.is_whitespace: del tlist.tokens[pidx] tidx -= 1 - # only break if it's not the first token - if prev_: + _, before = tlist.token_prev(tidx, skip_ws=True) + if before is not None: tlist.insert_before(tidx, self.nl()) tidx += 1 tidx, token = tlist.token_next_by(t=ttypes, idx=tidx) diff --git a/tests/test_format.py b/tests/test_format.py index 0cdbcf88..8ffb4522 100644 --- a/tests/test_format.py +++ b/tests/test_format.py @@ -649,6 +649,37 @@ def test_insert_values(self): ' , (3, 4)', ' , (5, 6)']) + def test_multi_statement_idempotent(self): + # Reformatting should not add accumulating blank lines + # between statements. + f = lambda sql: sqlparse.format(sql, reindent=True) + sql = 'select a from b; select c from d' + once = f(sql) + twice = f(once) + assert once == twice, f'not idempotent:\n {once!r}\n {twice!r}' + + # Also with keyword_case + f2 = lambda sql: sqlparse.format( + sql, reindent=True, keyword_case='upper') + once = f2(sql) + twice = f2(once) + assert once == twice + + # And with comma_first + f3 = lambda sql: sqlparse.format( + sql, reindent=True, comma_first=True) + once = f3(sql) + twice = f3(once) + assert once == twice + + def test_union_idempotent(self): + # UNION within a single statement should also be idempotent + f = lambda sql: sqlparse.format(sql, reindent=True) + sql = 'select a from b union select c from d' + once = f(sql) + twice = f(once) + assert once == twice, f'not idempotent:\n {once!r}\n {twice!r}' + class TestOutputFormat: def test_python(self):