#36122: Add sanity check against updating non-composite field with composite
expression
-------------------------------------+-------------------------------------
Reporter: Jacob Walls | Type: Bug
Status: new | Component: Database
| layer (models, ORM)
Version: 5.2 | Severity: Release
| blocker
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Attempting to update a non-composite field via `.update()` with a
composite expression fails at the db level with an invalid query:
Rough test:
{{{#!diff
diff --git a/tests/composite_pk/test_update.py
b/tests/composite_pk/test_update.py
index ec770230fc..c5deac6d4b 100644
--- a/tests/composite_pk/test_update.py
+++ b/tests/composite_pk/test_update.py
@@ -1,4 +1,5 @@
from django.db import connection
+from django.db.models import F
from django.test import TestCase
from .models import Comment, Tenant, TimeStamped, Token, User
@@ -175,3 +176,9 @@ class CompositePKUpdateTests(TestCase):
with self.assertRaisesMessage(ValueError, msg):
Comment.objects.update(user=User())
+
+ def test_update_lhs_not_composite(self):
+ qs = Comment.objects.filter(user__email=self.user_1.email)
+ msg = "Composite expressions only work with composite fields."
+ with self.assertRaisesMessage(ValueError, msg):
+ qs.update(text=F("pk"))
}}}
----
{{{#!py
======================================================================
ERROR: test_update_lhs_not_composite
(composite_pk.test_update.CompositePKUpdateTests.test_update_lhs_not_composite)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/source/django/django/db/backends/utils.py", line 105, in
_execute
return self.cursor.execute(sql, params)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "/Users/source/django/django/db/backends/sqlite3/base.py", line
360, in execute
return super().execute(query, params)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
sqlite3.OperationalError: near ".": syntax error
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/source/django/tests/composite_pk/test_update.py", line 184,
in test_update_lhs_not_composite
qs.update(text=F("pk"))
~~~~~~~~~^^^^^^^^^^^^^^
File "/Users/source/django/django/db/models/query.py", line 1254, in
update
rows = query.get_compiler(self.db).execute_sql(ROW_COUNT)
File "/Users/source/django/django/db/models/sql/compiler.py", line 2068,
in execute_sql
row_count = super().execute_sql(result_type)
File "/Users/source/django/django/db/models/sql/compiler.py", line 1623,
in execute_sql
cursor.execute(sql, params)
~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "/Users/source/django/django/db/backends/utils.py", line 122, in
execute
return super().execute(sql, params)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "/Users/source/django/django/db/backends/utils.py", line 79, in
execute
return self._execute_with_wrappers(
~~~~~~~~~~~~~~~~~~~~~~~~~~~^
sql, params, many=False, executor=self._execute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "/Users/source/django/django/db/backends/utils.py", line 92, in
_execute_with_wrappers
return executor(sql, params, many, context)
File "/Users/source/django/django/db/backends/utils.py", line 100, in
_execute
with self.db.wrap_database_errors:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/source/django/django/db/utils.py", line 91, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/Users/source/django/django/db/backends/utils.py", line 105, in
_execute
return self.cursor.execute(sql, params)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "/Users/source/django/django/db/backends/sqlite3/base.py", line
360, in execute
return super().execute(query, params)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
django.db.utils.OperationalError: near ".": syntax error
----------------------------------------------------------------------
(0.000) UPDATE "composite_pk_comment"
SET "text" = "composite_pk_comment"."tenant_id",
"composite_pk_comment"."comment_id"
WHERE ("composite_pk_comment"."tenant_id",
"composite_pk_comment"."comment_id") IN
(SELECT U0."tenant_id" AS "tenant",
U0."comment_id" AS "id"
FROM "composite_pk_comment" U0
INNER JOIN "composite_pk_user" U1 ON (U0."tenant_id" = U1."tenant_id"
AND U0."user_id" = U1."id")
WHERE U1."email" = '
user...@example.com');
args=('
user...@example.com',); alias=default
----------------------------------------------------------------------
Ran 1 test in 0.014s
FAILED (errors=1)
}}}
--
Ticket URL: <
https://code.djangoproject.com/ticket/36122>
Django <
https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.