Opened 5 months ago
Last modified 5 months ago
#36453 closed Bug
5.2.3 introduces a regression when using `Value(None, output_field=JSONField()` in a `When` clause. — at Initial Version
| Reported by: | Thomas | Owned by: | |
|---|---|---|---|
| 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
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.