#34840: Django 4.2 casts text fields when testing IS NULL, preventing use of
partial indexes
-------------------------------------+-------------------------------------
Reporter: Alex Vandiver | Owner: Mariusz
| Felisiak
Type: Bug | Status: assigned
Component: Database layer | Version: 4.2
(models, ORM) |
Severity: Release blocker | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):
* owner: murtatah => Mariusz Felisiak
Comment:
I wonder if we could extend Simon's solution for #34754
(3434dbd39d373df7193ad006b970c09c1a909ea3). The following patch passes all
tests (with and without server side binding parameters):
{{{#!diff
diff --git a/django/db/backends/postgresql/operations.py
b/django/db/backends/postgresql/operations.py
index 93eb982f4b..e536681914 100644
--- a/django/db/backends/postgresql/operations.py
+++ b/django/db/backends/postgresql/operations.py
@@ -155,13 +155,6 @@ class DatabaseOperations(BaseDatabaseOperations):
def lookup_cast(self, lookup_type, internal_type=None):
lookup = "%s"
- if lookup_type == "isnull" and internal_type in (
- "CharField",
- "EmailField",
- "TextField",
- ):
- return "%s::text"
-
# Cast text lookups to text to allow things like
filter(x__contains=4)
if lookup_type in (
"iexact",
diff --git a/django/db/models/lookups.py b/django/db/models/lookups.py
index 896d3eee44..eb887f5548 100644
--- a/django/db/models/lookups.py
+++ b/django/db/models/lookups.py
@@ -624,11 +624,17 @@ class IsNull(BuiltinLookup):
raise ValueError(
"The QuerySet value for an isnull lookup must be True or
False."
)
- if isinstance(self.lhs, Value) and self.lhs.value is None:
+ if isinstance(self.lhs, Value):
if self.rhs:
- raise FullResultSet
+ if self.lhs.value is None:
+ raise FullResultSet
+ else:
+ raise EmptyResultSet
else:
- raise EmptyResultSet
+ if self.lhs.value is None:
+ raise EmptyResultSet
+ else:
+ raise FullResultSet
sql, params = self.process_lhs(compiler, connection)
if self.rhs:
return "%s IS NULL" % sql, params
diff --git a/django/db/models/query_utils.py
b/django/db/models/query_utils.py
index 4f3358eb8d..830a7fdb6f 100644
--- a/django/db/models/query_utils.py
+++ b/django/db/models/query_utils.py
@@ -10,7 +10,7 @@ import inspect
import logging
from collections import namedtuple
-from django.core.exceptions import FieldError
+from django.core.exceptions import EmptyResultSet, FieldError
from django.db import DEFAULT_DB_ALIAS, DatabaseError, connections
from django.db.models.constants import LOOKUP_SEP
from django.utils import tree
@@ -140,6 +140,8 @@ class Q(tree.Node):
except DatabaseError as e:
logger.warning("Got a database error calling check() on %r:
%s", self, e)
return True
+ except EmptyResultSet:
+ return False
def deconstruct(self):
path = "%s.%s" % (self.__class__.__module__,
self.__class__.__name__)
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/34840#comment:16>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/0107018aac965e91-0d765c1b-bbaa-45cd-b1b3-621de4e7016d-000000%40eu-central-1.amazonses.com.