diff --git a/debug_toolbar/panels/sql/utils.py b/debug_toolbar/panels/sql/utils.py index 03b390d2b..3fa6eb5d9 100644 --- a/debug_toolbar/panels/sql/utils.py +++ b/debug_toolbar/panels/sql/utils.py @@ -93,10 +93,26 @@ def is_select_query(sql): def reformat_sql(sql, *, with_toggle=False): - formatted = parse_sql(sql) + import logging + + logger = logging.getLogger(__name__) + + # Try to format the full SQL + try: + formatted = parse_sql(sql) + except (sqlparse.exceptions.SQLParseError, RecursionError) as e: + logger.warning(f"Failed to format SQL query: {e}") + formatted = f"-- SQL formatting failed (query too large)\n{sql}" + if not with_toggle: return formatted - simplified = parse_sql(sql, simplify=True) + + try: + simplified = parse_sql(sql, simplify=True) + except (sqlparse.exceptions.SQLParseError, RecursionError) as e: + logger.warning(f"Failed to simplify SQL query: {e}") + simplified = f"-- Simplified formatting failed\n{sql}" + uncollapsed = f'{simplified}' collapsed = f'{formatted}' return collapsed + uncollapsed diff --git a/tests/test_sql_large_query.py b/tests/test_sql_large_query.py new file mode 100644 index 000000000..2f49a3a73 --- /dev/null +++ b/tests/test_sql_large_query.py @@ -0,0 +1,42 @@ +import pytest + +from debug_toolbar.panels.sql.utils import reformat_sql + + +def test_reformat_sql_with_huge_in_clause(): + """Test that huge IN clauses don't cause crashes""" + # Create a SQL with a huge IN clause (5000 items) + items = [f"'{i}'" for i in range(5000)] + sql = f"SELECT * FROM table WHERE id IN ({','.join(items)})" + + # This should not raise an exception + try: + result = reformat_sql(sql, with_toggle=False) + assert isinstance(result, str) + assert len(result) > 0 + except Exception as e: + pytest.fail(f"reformat_sql raised {type(e).__name__}: {e}") + + +def test_reformat_sql_with_toggle_and_huge_in_clause(): + """Test with_toggle=True with huge IN clause""" + items = [f"'{i}'" for i in range(5000)] + sql = f"SELECT * FROM table WHERE id IN ({','.join(items)})" + + try: + result = reformat_sql(sql, with_toggle=True) + assert isinstance(result, str) + assert "djDebugUncollapsed" in result + assert "djDebugCollapsed" in result + except Exception as e: + pytest.fail(f"reformat_sql (with_toggle) raised {type(e).__name__}: {e}") + + +def test_reformat_sql_with_invalid_sql(): + """Test that invalid SQL is handled gracefully""" + sql = "SELECT * FROM WHERE" # Invalid SQL + + result = reformat_sql(sql, with_toggle=False) + assert isinstance(result, str) + # Should either contain the SQL or an error message + assert len(result) > 0