From: Andi Albrecht <albrecht.andi@gmail.com>
Date: Sat, 13 Apr 2024 13:59:00 +0200
Subject: Raise SQLParseError instead of RecursionError.

Origin: https://github.com/andialbrecht/sqlparse/commit/b4a39d9850969b4e1d6940d32094ee0b42a2cf03
Origin: https://github.com/andialbrecht/sqlparse/commit/29f2e0a6609ddc1fa248faef1bc41616043c544e
Bug: https://github.com/advisories/GHSA-2m57-hf25-phgg
Bug-Debian: https://security-tracker.debian.org/tracker/CVE-2024-4340
Bug-Debian: https://bugs.debian.org/1070148
---
 sqlparse/sql.py           | 14 +++++++++-----
 tests/test_regressions.py | 16 ++++++++++++++++
 2 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/sqlparse/sql.py b/sqlparse/sql.py
index 6a32c26..ffffc77 100644
--- a/sqlparse/sql.py
+++ b/sqlparse/sql.py
@@ -10,6 +10,7 @@
 import re
 
 from sqlparse import tokens as T
+from sqlparse.exceptions import SQLParseError
 from sqlparse.utils import imt, remove_quotes
 
 
@@ -209,11 +210,14 @@ class TokenList(Token):
 
         This method is recursively called for all child tokens.
         """
-        for token in self.tokens:
-            if token.is_group:
-                yield from token.flatten()
-            else:
-                yield token
+        try:
+            for token in self.tokens:
+                if token.is_group:
+                    yield from token.flatten()
+                else:
+                    yield token
+        except RecursionError as err:
+            raise SQLParseError('Maximum recursion depth exceeded') from err
 
     def get_sublists(self):
         for token in self.tokens:
diff --git a/tests/test_regressions.py b/tests/test_regressions.py
index 38d1840..29311ea 100644
--- a/tests/test_regressions.py
+++ b/tests/test_regressions.py
@@ -1,7 +1,10 @@
+import sys
+
 import pytest
 
 import sqlparse
 from sqlparse import sql, tokens as T
+from sqlparse.exceptions import SQLParseError
 
 
 def test_issue9():
@@ -418,3 +421,16 @@ def test_splitting_at_and_backticks_issue588():
         'grant foo to user1@`myhost`; grant bar to user1@`myhost`;')
     assert len(splitted) == 2
     assert splitted[-1] == 'grant bar to user1@`myhost`;'
+
+
+@pytest.fixture
+def limit_recursion():
+    curr_limit = sys.getrecursionlimit()
+    sys.setrecursionlimit(100)
+    yield
+    sys.setrecursionlimit(curr_limit)
+
+
+def test_max_recursion(limit_recursion):
+    with pytest.raises(SQLParseError):
+        sqlparse.parse('[' * 1000 + ']' * 1000)
