#36453 closed Bug (fixed)
5.2.3 introduces a regression when using `Value(None, output_field=JSONField()` in a `When` clause.
Reported by: | Thomas | Owned by: | Clifford Gama |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 5.2 |
Severity: | Release blocker | Keywords: | |
Cc: | Thomas | Triage Stage: | Ready for checkin |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
We've tried to upgrade to 5.2.3 and several of our tests started failing. We've pinpointed the problem to one query which uses Value(None, output_field=JSONField()
in a When
clause. Here's a minimal reproducible example (with a WHERE
clause too, to highlight the difference in behavior):
from django.db import connection from django.db.models import ( BigIntegerField, Case, F, JSONField, Model, Value, When, ) from django.db.models.functions import Cast class Foo(Model): bar = BigIntegerField(blank=True, null=True) json_field = JSONField(blank=True, null=True) if __name__ == '__main__': Foo.objects.filter( json_field__key_1=Value(None, output_field=JSONField()) ).update( bar=Case( When( json_field__key_2=Value(None, output_field=JSONField()), then=None ), default=Cast(F('json_field__key_2'), BigIntegerField()), output_field=BigIntegerField(), ), ) print(connection.queries[-1]['sql'])
We ran this code with 5.2.2 (with this version our test suite passes) and 5.2.3 (with this version our test suite fails) and got this:
-- Generated with Django 5.2.2 UPDATE "polls_foo" SET "bar" = CASE WHEN ( ("polls_foo"."json_field" -> 'key_2') = 'null'::jsonb -- JSON "null" ) THEN NULL ELSE (("polls_foo"."json_field" -> 'key_2'))::bigint END WHERE ("polls_foo"."json_field" -> 'key_1') = 'null'::jsonb; -- Generated with Django 5.2.3 UPDATE "polls_foo" SET "bar" = CASE WHEN ( ("polls_foo"."json_field" -> 'key_2') = NULL -- SQL NULL ) THEN NULL ELSE (("polls_foo"."json_field" -> 'key_2'))::bigint END WHERE ("polls_foo"."json_field" -> 'key_1') = 'null'::jsonb;
Notice how the WHEN
clause differs, but the WHERE
clause stays the same, despite both using the same Value(None, output_field=JSONField())
syntax.
Edit: If that makes any difference, we're using PostgreSQL as a backend.
Change History (10)
comment:1 by , 3 months ago
Description: | modified (diff) |
---|
comment:2 by , 3 months ago
Resolution: | → duplicate |
---|---|
Status: | new → closed |
comment:3 by , 3 months ago
I guess this was closed as duplicate because the cause might be the same, but then I don't understand how the other ticket claims it isn't a regression. The code I posted has been working since 4.x at least. It only breaks with 5.2.3 (released June 10th), which I guess was released with a known bug/regression (#36445, June 6th).
comment:4 by , 3 months ago
Resolution: | duplicate |
---|---|
Severity: | Normal → Release blocker |
Status: | closed → new |
Triage Stage: | Unreviewed → Accepted |
This is indeed a regression in c1fa3fdd040718356e5a3b9a0fe699d73f47a940.
I think the problem is that we are now passing on for_save=True
from the update to Case
's source expressions, which ends up resolving When.condition
with for_save=True
.
The issue is related to #36445 in that they both expose problems related to the use of Value(None, JSONField())
to mean JSON null
and None to mean NULL
, and how that is implemented depending on whether JSONFIeld.get_db_prep_save
is called. I think these set of tickets should be an argument in favour of introducing a JSONNull
value as outlined in ticket:35381#comment:5.
comment:5 by , 3 months ago
Has patch: | set |
---|
comment:7 by , 3 months ago
Owner: | set to |
---|---|
Status: | new → assigned |
comment:8 by , 3 months ago
Triage Stage: | Accepted → Ready for checkin |
---|
Duplicate of #36445 👍