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 logging
from collections import namedtuple
from contextlib import nullcontext
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.utils import tree
from django.utils.functional import cached_property
@ -130,14 +131,21 @@ class Q(tree.Node):
value = Value(value)
query.add_annotation(value, name, select=False)
query.add_annotation(Value(1), "_check")
connection = connections[using]
# 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())))
else:
query.add_q(self)
compiler = query.get_compiler(using=using)
context_manager = (
transaction.atomic(using=using)
if connection.in_atomic_block
else nullcontext()
)
try:
return compiler.execute_sql(SINGLE) is not None
with context_manager:
return compiler.execute_sql(SINGLE) is not None
except DatabaseError as e:
logger.warning("Got a database error calling check() on %r: %s", self, e)
return True

View File

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