Refs #27149 -- Based recursive nested subquery detection on sys.getrecursionlimit().

This makes sure the test_avoid_infinite_loop_on_too_many_subqueries test
doesn't fail on systems with a non-default recursion limit.
This commit is contained in:
Simon Charette 2019-04-05 00:37:58 -04:00 committed by Mariusz Felisiak
parent 9ac8520fcd
commit c0969ee227
2 changed files with 9 additions and 3 deletions

View File

@ -9,6 +9,7 @@ all about the internals of models in order to get the information it needs.
import difflib import difflib
import functools import functools
import inspect import inspect
import sys
import warnings import warnings
from collections import Counter, namedtuple from collections import Counter, namedtuple
from collections.abc import Iterator, Mapping from collections.abc import Iterator, Mapping
@ -883,7 +884,11 @@ class Query(BaseExpression):
# No clashes between self and outer query should be possible. # No clashes between self and outer query should be possible.
return return
local_recursion_limit = 67 # explicitly avoid infinite loop # Explicitly avoid infinite loop. The constant divider is based on how
# much depth recursive subquery references add to the stack. This value
# might need to be adjusted when adding or removing function calls from
# the code path in charge of performing these operations.
local_recursion_limit = sys.getrecursionlimit() // 16
for pos, prefix in enumerate(prefix_gen()): for pos, prefix in enumerate(prefix_gen()):
if prefix not in self.subq_aliases: if prefix not in self.subq_aliases:
self.alias_prefix = prefix self.alias_prefix = prefix

View File

@ -1,5 +1,6 @@
import datetime import datetime
import pickle import pickle
import sys
import unittest import unittest
from operator import attrgetter from operator import attrgetter
@ -402,10 +403,10 @@ class Queries1Tests(TestCase):
def test_avoid_infinite_loop_on_too_many_subqueries(self): def test_avoid_infinite_loop_on_too_many_subqueries(self):
x = Tag.objects.filter(pk=1) x = Tag.objects.filter(pk=1)
local_recursion_limit = 67 local_recursion_limit = sys.getrecursionlimit() // 16
msg = 'Maximum recursion depth exceeded: too many subqueries.' msg = 'Maximum recursion depth exceeded: too many subqueries.'
with self.assertRaisesMessage(RuntimeError, msg): with self.assertRaisesMessage(RuntimeError, msg):
for i in range(local_recursion_limit * 2): for i in range(local_recursion_limit + 2):
x = Tag.objects.filter(pk__in=x) x = Tag.objects.filter(pk__in=x)
def test_reasonable_number_of_subq_aliases(self): def test_reasonable_number_of_subq_aliases(self):