From e488bb47e4bd21ff0a09ce23e1adf00ba64d5d57 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Tue, 8 Oct 2013 20:06:58 -0400 Subject: [PATCH] A :func:`.select` that is made to refer to itself in its FROM clause, typically via in-place mutation, will raise an informative error message rather than causing a recursion overflow. [ticket:2815] Conflicts: lib/sqlalchemy/sql/selectable.py --- doc/build/changelog/changelog_08.rst | 9 +++++++++ lib/sqlalchemy/sql/expression.py | 3 +++ test/sql/test_selectable.py | 12 ++++++++++++ 3 files changed, 24 insertions(+) diff --git a/doc/build/changelog/changelog_08.rst b/doc/build/changelog/changelog_08.rst index 70521ecbf6..0937aaad57 100644 --- a/doc/build/changelog/changelog_08.rst +++ b/doc/build/changelog/changelog_08.rst @@ -10,6 +10,15 @@ .. changelog:: :version: 0.8.3 + .. change:: + :tags: bug, sql + :tickets: 2815 + :versions: 0.9.0 + + A :func:`.select` that is made to refer to itself in its FROM clause, + typically via in-place mutation, will raise an informative error + message rather than causing a recursion overflow. + .. change:: :tags: bug, orm :tickets: 2813 diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index b2f957bd02..5a97c2222b 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -5288,6 +5288,9 @@ class Select(HasPrefixes, SelectBase): def add(items): for item in items: + if item is self: + raise exc.InvalidRequestError( + "select() construct refers to itself as a FROM") if translate and item in translate: item = translate[item] if not seen.intersection(item._cloned_set): diff --git a/test/sql/test_selectable.py b/test/sql/test_selectable.py index 649490ef30..8289a783d8 100644 --- a/test/sql/test_selectable.py +++ b/test/sql/test_selectable.py @@ -514,6 +514,18 @@ class SelectableTest(fixtures.TestBase, AssertsExecutionResults, AssertsCompiled "SELECT c FROM (SELECT (SELECT (SELECT table1.col1 AS a FROM table1) AS b) AS c)" ) + def test_self_referential_select_raises(self): + t = table('t', column('x')) + + s = select([t]) + + s.append_whereclause(s.c.x > 5) + assert_raises_message( + exc.InvalidRequestError, + r"select\(\) construct refers to itself as a FROM", + s.compile + ) + def test_unusual_column_elements_text(self): """test that .c excludes text().""" -- 2.47.2