Opened 8 years ago
Closed 8 years ago
#26908 closed Bug (fixed)
jsonfield__key__isnull lookup crashes on PostgreSQL 9.4
Reported by: | Luca Simone Sigfrido Percich | Owned by: | PREMANAND |
---|---|---|---|
Component: | contrib.postgres | Version: | 1.9 |
Severity: | Normal | Keywords: | jsonb, postgresql |
Cc: | Marc Tamlyn | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Given this model:
class MyModel(models.Model): jsonbfield = JSONField(null=True, blank=True, default=dict)
The following filter will always result in a "ProgrammingError: operator does not exist jsonb -> boolean":
MyModel.objects.filter(jsonbfield__key__isnull=True)
That's because this is beng translated in the following SQL expression:
... where myapp_mymodel.jsonbfield -> 'key' is null
which does not yield the desired result because in postgres the ->, ->> or #> operators have no precedence over is.
Fix: enclose mapping in parenthesis
(myapp_mymodel.jsonbfield -> 'key') is null
Relevant code:
File: django/contrib/postgres/fields/jsonb.py
row 76 and 83:
return "{} #> %s".format(lhs), [key_transforms] + params ... return "%s -> %s" % (lhs, lookup), params
Should become:
return "({} #> %s)".format(lhs), [key_transforms] + params ... return "(%s -> %s)" % (lhs, lookup), params
Change History (9)
comment:1 by , 8 years ago
Has patch: | set |
---|---|
Summary: | jsonb field: error with __isnull lookup → jsonfield__key__isnull lookup crashes |
Triage Stage: | Unreviewed → Accepted |
comment:2 by , 8 years ago
You're right, I didn't notice:
(('{"key": null}' :: jsonb) -> 'key') = 'null'::jsonb -- which is different from SQL null, thus: (('{"key": null}' :: jsonb) -> 'key') is null = false -- but: (('{"key": null}' :: jsonb) ->> 'key') is null = true
so after the fix, I believe the isnull lookup would behave exactly as has_key.
I won't expect that. There would be no way to find instances having a {'key':null}.
On the other hand, on PG docs they say that jsonb 'null' and SQL NULL have different meaning. Should we introduce a new lookup is_null_json maybe?
comment:3 by , 8 years ago
Easy pickings: | unset |
---|---|
Has patch: | unset |
I'm not certain, but I guess it might be better to override the isnull
lookup to work as you expect. I'll withdraw my patch.
comment:4 by , 8 years ago
Owner: | set to |
---|---|
Status: | new → assigned |
comment:5 by , 8 years ago
@sigfrid/@tim
Im unable to recreate this issue using the dev version of the Django code.
>>> MyModel.objects.filter(jsonbfield__key__isnull=True) <QuerySet []>
and here is my model.
class MyModel(models.Model): jsonbfield = JSONField(null=True, blank=True, default=dict)
follow-up: 7 comment:6 by , 8 years ago
Summary: | jsonfield__key__isnull lookup crashes → jsonfield__key__isnull lookup crashes on PostgreSQL 9.4 |
---|
Looks like the crash happens on PostgreSQL 9.4 but not 9.5. The test on my PR passes on 9.5 which could make it more difficult to change the behavior since it would change the behavior of possibly working code.
comment:7 by , 8 years ago
ok,got it. I'm using 9.5 as expected. How do we proceed on these issues?
Replying to timgraham:
Looks like the crash happens on PostgreSQL 9.4 but not 9.5. The test on my PR passes on 9.5 which could make it more difficult to change the behavior since it would change the behavior of possibly working code.
comment:8 by , 8 years ago
Cc: | added |
---|---|
Has patch: | set |
I guess we might proceed with my PR unless anyone feels like we should change the behavior of the isnull
lookup. We could then open a new ticket to add a way to query for keys that have a 'null' value, if one doesn't exist.
I agree that Django shouldn't crash. Is this expected to give the same semantics as
has_key
? Is there any advantage of using one form over the other that might be worth documenting? PR