1
0
mirror of https://github.com/django/django.git synced 2024-12-22 17:16:24 +00:00

Fixed #35712 -- Prevented Q.check() from leaving the connection in an unusable state.

Co-authored-by: Simon Charette <charette.s@gmail.com>
This commit is contained in:
Alex Fischer 2024-08-28 09:53:40 -06:00 committed by Sarah Boyce
parent 387475c5b2
commit c6a4f853c7
2 changed files with 15 additions and 3 deletions

View File

@ -10,9 +10,10 @@ import functools
import inspect import inspect
import logging import logging
from collections import namedtuple from collections import namedtuple
from contextlib import nullcontext
from django.core.exceptions import FieldError from django.core.exceptions import FieldError
from django.db import DEFAULT_DB_ALIAS, DatabaseError, connections from django.db import DEFAULT_DB_ALIAS, DatabaseError, connections, transaction
from django.db.models.constants import LOOKUP_SEP from django.db.models.constants import LOOKUP_SEP
from django.utils import tree from django.utils import tree
from django.utils.functional import cached_property from django.utils.functional import cached_property
@ -130,14 +131,21 @@ class Q(tree.Node):
value = Value(value) value = Value(value)
query.add_annotation(value, name, select=False) query.add_annotation(value, name, select=False)
query.add_annotation(Value(1), "_check") query.add_annotation(Value(1), "_check")
connection = connections[using]
# This will raise a FieldError if a field is missing in "against". # This will raise a FieldError if a field is missing in "against".
if connections[using].features.supports_comparing_boolean_expr: if connection.features.supports_comparing_boolean_expr:
query.add_q(Q(Coalesce(self, True, output_field=BooleanField()))) query.add_q(Q(Coalesce(self, True, output_field=BooleanField())))
else: else:
query.add_q(self) query.add_q(self)
compiler = query.get_compiler(using=using) compiler = query.get_compiler(using=using)
context_manager = (
transaction.atomic(using=using)
if connection.in_atomic_block
else nullcontext()
)
try: try:
return compiler.execute_sql(SINGLE) is not None with context_manager:
return compiler.execute_sql(SINGLE) is not None
except DatabaseError as e: except DatabaseError as e:
logger.warning("Got a database error calling check() on %r: %s", self, e) logger.warning("Got a database error calling check() on %r: %s", self, e)
return True return True

View File

@ -1,4 +1,5 @@
from django.core.exceptions import FieldError from django.core.exceptions import FieldError
from django.db import connection
from django.db.models import ( from django.db.models import (
BooleanField, BooleanField,
Exists, Exists,
@ -327,3 +328,6 @@ class QCheckTests(TestCase):
f"Got a database error calling check() on {q!r}: ", f"Got a database error calling check() on {q!r}: ",
cm.records[0].getMessage(), cm.records[0].getMessage(),
) )
# We must leave the connection in a usable state (#35712).
self.assertTrue(connection.is_usable())