summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2023-05-08 19:34:30 +0200
committerGitHub <noreply@github.com>2023-05-08 19:34:30 +0200
commit1586a09b7949bbb7b0d84cb74ce1cadc25cbb355 (patch)
treefdafc3d7dca2ac33acf08e5b311843809f960ac5
parentaaf8c76c567e8311f4a85cf74c82fc3d70cc6f12 (diff)
downloaddjango-1586a09b7949bbb7b0d84cb74ce1cadc25cbb355.tar.gz
Fixed #34544 -- Avoided DBMS_LOB.SUBSTR() wrapping with IS NULL condition on Oracle.
Regression in 09ffc5c1212d4ced58b708cbbf3dfbfb77b782ca. Thanks Michael Smith for the report. This also reverts commit 1e4da439556cdd69eb9f91e07f99cf77997e70d2.
-rw-r--r--django/db/backends/oracle/operations.py10
-rw-r--r--django/db/backends/postgresql/features.py3
-rw-r--r--docs/releases/4.2.2.txt4
-rw-r--r--tests/lookup/models.py12
-rw-r--r--tests/lookup/tests.py9
5 files changed, 18 insertions, 20 deletions
diff --git a/django/db/backends/oracle/operations.py b/django/db/backends/oracle/operations.py
index d34ca23bae..64b1f82071 100644
--- a/django/db/backends/oracle/operations.py
+++ b/django/db/backends/oracle/operations.py
@@ -296,12 +296,6 @@ END;
columns.append(value[0])
return tuple(columns)
- def field_cast_sql(self, db_type, internal_type):
- if db_type and db_type.endswith("LOB") and internal_type != "JSONField":
- return "DBMS_LOB.SUBSTR(%s)"
- else:
- return "%s"
-
def no_limit_value(self):
return None
@@ -344,7 +338,9 @@ END;
def lookup_cast(self, lookup_type, internal_type=None):
if lookup_type in ("iexact", "icontains", "istartswith", "iendswith"):
return "UPPER(%s)"
- if internal_type == "JSONField" and lookup_type == "exact":
+ if (
+ lookup_type != "isnull" and internal_type in ("BinaryField", "TextField")
+ ) or (lookup_type == "exact" and internal_type == "JSONField"):
return "DBMS_LOB.SUBSTR(%s)"
return "%s"
diff --git a/django/db/backends/postgresql/features.py b/django/db/backends/postgresql/features.py
index aa68465df9..732b30b0a4 100644
--- a/django/db/backends/postgresql/features.py
+++ b/django/db/backends/postgresql/features.py
@@ -82,6 +82,9 @@ class DatabaseFeatures(BaseDatabaseFeatures):
"indexes.tests.SchemaIndexesNotPostgreSQLTests."
"test_create_index_ignores_opclasses",
},
+ "PostgreSQL requires casting to text.": {
+ "lookup.tests.LookupTests.test_textfield_exact_null",
+ },
}
@cached_property
diff --git a/docs/releases/4.2.2.txt b/docs/releases/4.2.2.txt
index 31f854b004..9d16e7ef6f 100644
--- a/docs/releases/4.2.2.txt
+++ b/docs/releases/4.2.2.txt
@@ -9,4 +9,6 @@ Django 4.2.2 fixes several bugs in 4.2.1.
Bugfixes
========
-* ...
+* Fixed a regression in Django 4.2 that caused an unnecessary
+ ``DBMS_LOB.SUBSTR()`` wrapping in the ``__isnull`` and ``__exact=None``
+ lookups for ``TextField()``/``BinaryField()`` on Oracle (:ticket:`34544`).
diff --git a/tests/lookup/models.py b/tests/lookup/models.py
index 9bb3412c33..75f3e3b6ba 100644
--- a/tests/lookup/models.py
+++ b/tests/lookup/models.py
@@ -19,6 +19,7 @@ class Alarm(models.Model):
class Author(models.Model):
name = models.CharField(max_length=100)
alias = models.CharField(max_length=50, null=True, blank=True)
+ bio = models.TextField(null=True)
class Meta:
ordering = ("name",)
@@ -50,22 +51,11 @@ class NulledTextField(models.TextField):
return None if value == "" else value
-class NullField(models.Field):
- pass
-
-
-NullField.register_lookup(IsNull)
-
-
@NulledTextField.register_lookup
class NulledTransform(models.Transform):
lookup_name = "nulled"
template = "NULL"
- @property
- def output_field(self):
- return NullField()
-
@NulledTextField.register_lookup
class IsNullWithNoneAsRHS(IsNull):
diff --git a/tests/lookup/tests.py b/tests/lookup/tests.py
index 2dddd826e3..c639fe073e 100644
--- a/tests/lookup/tests.py
+++ b/tests/lookup/tests.py
@@ -49,7 +49,7 @@ class LookupTests(TestCase):
@classmethod
def setUpTestData(cls):
# Create a few Authors.
- cls.au1 = Author.objects.create(name="Author 1", alias="a1")
+ cls.au1 = Author.objects.create(name="Author 1", alias="a1", bio="x" * 4001)
cls.au2 = Author.objects.create(name="Author 2", alias="a2")
# Create a few Articles.
cls.a1 = Article.objects.create(
@@ -1029,6 +1029,13 @@ class LookupTests(TestCase):
Season.objects.create(year=2012, gt=None)
self.assertQuerySetEqual(Season.objects.filter(gt__regex=r"^$"), [])
+ def test_textfield_exact_null(self):
+ with self.assertNumQueries(1) as ctx:
+ self.assertSequenceEqual(Author.objects.filter(bio=None), [self.au2])
+ # Columns with IS NULL condition are not wrapped (except PostgreSQL).
+ bio_column = connection.ops.quote_name(Author._meta.get_field("bio").column)
+ self.assertIn(f"{bio_column} IS NULL", ctx.captured_queries[0]["sql"])
+
def test_regex_non_string(self):
"""
A regex lookup does not fail on non-string fields