Opened 2 years ago

Closed 2 years ago

Last modified 2 years ago

#33820 closed Bug (fixed)

Querying "null" on key transforms for JSONField returns wrong results on SQLite.

Reported by: Johnny Metz Owned by: Mariusz Felisiak
Component: Database layer (models, ORM) Version: 4.0
Severity: Release blocker Keywords: JSONField
Cc: Matthew Cornell, Sage Abdullah Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Let's say I have a Django model with a JSONField:

class Event(models.Model):
    data = models.JSONField()

And I create the following objects:

event1 = Event.objects.create(data={"key": None})
event2 = Event.objects.create(data={"key": "null"})

In Django 3.2.13, the following queries return some results:

Event.objects.filter(data__key=Value("null"))
# [event1]

Event.objects.filter(data__key="null")
# [event2]

In Django 4.0.5, the same queries return different results:

Event.objects.filter(data__key=Value("null"))
# [event1, event2]

Event.objects.filter(data__key="null")
# [event1, event2]

The Django docs aren't clear which results are correct. I would lean towards the v3 results.

I'm happy to work on a patch if people think this is a bug in v4.

Attachments (1)

regression-tests-33820.diff (1.7 KB ) - added by Mariusz Felisiak 2 years ago.

Download all attachments as: .zip

Change History (12)

comment:1 by Mariusz Felisiak, 2 years ago

Cc: Matthew Cornell added
Severity: NormalRelease blocker
Summary: Querying null in JSONField is different between 3.2 and 4.0Querying "null" on key transforms for JSONField returns wrong results on SQLite.
Triage Stage: UnreviewedAccepted

Thanks for the report. Regression in 71ec102b01fcc85acae3819426a4e02ef423b0fa. This is also inconsistent with other backends.

comment:2 by Gregory, 2 years ago

Seems like a type-juggling routine introduced in 4.0.0
I am totally into type-juggling but this case, and actually blocking issue is a great example of the general confusion that a seemingly *simplification* - may lead to hold back on tech dev.

TL;DR:

  • consider removing type juggling
  • keep principles up, regarding data type comparison

by Mariusz Felisiak, 2 years ago

Attachment: regression-tests-33820.diff added

comment:3 by Mariusz Felisiak, 2 years ago

I tried to fix this few times in the last two weeks, unfortunately, I don't see a proper way to distinguish between {"x": "null"} and {"x": NULL} extracted from the JSON field (the same for boolean values). Mainly due to the lack of proper database types in SQLite. In 71ec102b01fcc85acae3819426a4e02ef423b0fa we tried to use

CASE
    WHEN JSON_TYPE("model"."json_field", $."key") IN ('null', 'false', 'true')
         THEN JSON_TYPE("model"."json_field", $."key")
    ELSE JSON_EXTRACT("model"."json_field", $."key")
END

which fixed #32483 but also introduced this regression because for both NULL and "null" it returns 'null'.

Quo vadis? 🤷 We have two options:

comment:4 by Carlton Gibson, 2 years ago

document this as a SQLite caveat,

I'd go with this. I think storing "null" is quite niche, and easily worked around.

in reply to:  4 comment:5 by Mariusz Felisiak, 2 years ago

Replying to Carlton Gibson:

I'd go with this. I think storing "null" is quite niche, and easily worked around.

Just to be clear, this issue is for all three "true", "false", and "null".

comment:6 by Carlton Gibson, 2 years ago

Sure, yes. My feeling is that it's better to resolve #32483, which was 71ec102b01fcc85acae3819426a4e02ef423b0fa. Most times I want True/False/None, and I can serialise those if I need to. (That's just a +1 towards option 1 in response to the What to do?)

comment:7 by Mariusz Felisiak, 2 years ago

Cc: Sage Abdullah added

comment:8 by Mariusz Felisiak, 2 years ago

Has patch: set
Owner: changed from nobody to Mariusz Felisiak
Status: newassigned

comment:9 by GitHub <noreply@…>, 2 years ago

Resolution: fixed
Status: assignedclosed

In e20e5d1:

Fixed #33820 -- Doc'd "true"/"false"/"null" caveat for JSONField key transforms on SQLite.

Thanks Johnny Metz for the report.

Regression in 71ec102b01fcc85acae3819426a4e02ef423b0fa.

comment:10 by Mariusz Felisiak <felisiak.mariusz@…>, 2 years ago

In 265c3eb:

[4.1.x] Fixed #33820 -- Doc'd "true"/"false"/"null" caveat for JSONField key transforms on SQLite.

Thanks Johnny Metz for the report.

Regression in 71ec102b01fcc85acae3819426a4e02ef423b0fa.
Backport of e20e5d1557785ba71e8ef0ceb8ccb85bdc13840a from main

comment:11 by Mariusz Felisiak <felisiak.mariusz@…>, 2 years ago

In f78b18f9:

[4.0.x] Fixed #33820 -- Doc'd "true"/"false"/"null" caveat for JSONField key transforms on SQLite.

Thanks Johnny Metz for the report.

Regression in 71ec102b01fcc85acae3819426a4e02ef423b0fa.
Backport of e20e5d1557785ba71e8ef0ceb8ccb85bdc13840a from main

Note: See TracTickets for help on using tickets.
Back to Top