From 3be47a712dc31e00fa8d080183e3842a80291f03 Mon Sep 17 00:00:00 2001 From: Rami Abdelrazzaq Date: Sat, 12 Sep 2026 16:12:25 -0500 Subject: [PATCH] feat: make grouping token limit configurable --- sqlparse/__init__.py | 11 +++++++++++ tests/test_grouping_limits.py | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/test_grouping_limits.py diff --git a/sqlparse/__init__.py b/sqlparse/__init__.py index 8411f5a3..7a0c3467 100644 --- a/sqlparse/__init__.py +++ b/sqlparse/__init__.py @@ -17,6 +17,17 @@ __all__ = ["cli", "engine", "filters", "formatter", "sql", "tokens"] +def set_max_grouping_tokens(limit: int | None) -> None: + """Set the maximum token count allowed during grouping. + + Set *limit* to ``None`` to disable the token-count guard. Disabling or + increasing this limit is not recommended for SQL from untrusted sources. + """ + if limit is not None and limit < 1: + raise ValueError("Grouping token limit must be a positive integer or None") + engine.grouping.MAX_GROUPING_TOKENS = limit + + def parse( sql: str, encoding: str | None = None ) -> tuple[sql.Statement, ...]: diff --git a/tests/test_grouping_limits.py b/tests/test_grouping_limits.py new file mode 100644 index 00000000..00c14f8c --- /dev/null +++ b/tests/test_grouping_limits.py @@ -0,0 +1,37 @@ +import pytest + +import sqlparse +from sqlparse.engine import grouping +from sqlparse.exceptions import SQLParseError + + +def test_set_max_grouping_tokens_updates_grouping_limit(): + original_limit = grouping.MAX_GROUPING_TOKENS + try: + sqlparse.set_max_grouping_tokens(20000) + assert grouping.MAX_GROUPING_TOKENS == 20000 + + sqlparse.set_max_grouping_tokens(None) + assert grouping.MAX_GROUPING_TOKENS is None + finally: + grouping.MAX_GROUPING_TOKENS = original_limit + + +def test_set_max_grouping_tokens_rejects_nonpositive_limit(): + with pytest.raises(ValueError, match="positive integer or None"): + sqlparse.set_max_grouping_tokens(0) + + +def test_set_max_grouping_tokens_controls_parser_guard(): + original_limit = grouping.MAX_GROUPING_TOKENS + statement = "SELECT " + ", ".join(f"column_{i}" for i in range(20)) + + try: + sqlparse.set_max_grouping_tokens(5) + with pytest.raises(SQLParseError, match="Maximum number of tokens exceeded"): + sqlparse.parse(statement) + + sqlparse.set_max_grouping_tokens(100) + assert len(sqlparse.parse(statement)) == 1 + finally: + grouping.MAX_GROUPING_TOKENS = original_limit