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 Tim Graham, 8 years ago

Has patch: set
Summary: jsonb field: error with __isnull lookupjsonfield__key__isnull lookup crashes
Triage Stage: UnreviewedAccepted

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

comment:2 by Luca Simone Sigfrido Percich, 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 Tim Graham, 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 PREMANAND, 8 years ago

Owner: set to PREMANAND
Status: newassigned

comment:5 by PREMANAND, 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)


comment:6 by Tim Graham, 8 years ago

Summary: jsonfield__key__isnull lookup crashesjsonfield__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.

in reply to:  6 comment:7 by PREMANAND, 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 Tim Graham, 8 years ago

Cc: Marc Tamlyn 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.

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

Resolution: fixed
Status: assignedclosed

In 2eb7d6e6:

Fixed #26908 -- Fixed crash with jsonfieldkeyisnull lookup.

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