diff --git a/sqlparse/filters/aligned_indent.py b/sqlparse/filters/aligned_indent.py index 6ac99d62..abf369ef 100644 --- a/sqlparse/filters/aligned_indent.py +++ b/sqlparse/filters/aligned_indent.py @@ -80,9 +80,16 @@ def _process_case(self, tlist): # cond is None when 'else or end' stmt = cond[0] if cond else value[0] + # Malformed CASE expressions can yield case fragments that are no + # longer direct children of this token list. Aligned indentation is + # best-effort for such input, so do not try to insert relative to a + # token that token_index() cannot resolve. + if stmt not in tlist.tokens: + continue + if i > 0: tlist.insert_before(stmt, self.nl(offset_ - len(str(stmt)))) - if cond: + if cond and cond[-1] in tlist.tokens: ws = sql.Token(T.Whitespace, self.char * ( max_cond_width - condition_width[i])) tlist.insert_after(cond[-1], ws) diff --git a/tests/test_issue886.py b/tests/test_issue886.py new file mode 100644 index 00000000..6c7503ee --- /dev/null +++ b/tests/test_issue886.py @@ -0,0 +1,12 @@ +import sqlparse + + +def test_reindent_aligned_malformed_case_does_not_crash(): + sql = "CASE 'a' := WHERE END SELECT GO # ->>" + + formatted = sqlparse.format(sql, reindent_aligned=True) + + assert isinstance(formatted, str) + assert "CASE" in formatted + assert "END" in formatted + assert "SELECT" in formatted