[Django] #34604: On databases lacking XOR, Q(…) ^ Q(…) ^ Q(…) wrongly interpreted as exactly-one rather than parity

11 views
Skip to first unread message

Django

unread,
May 30, 2023, 12:19:57 AM5/30/23
to django-...@googlegroups.com
#34604: On databases lacking XOR, Q(…) ^ Q(…) ^ Q(…) wrongly interpreted as
exactly-one rather than parity
-------------------------------------+-------------------------------------
Reporter: Anders | Owner: nobody
Kaseorg |
Type: Bug | Status: new
Component: Database | Version: 4.2
layer (models, ORM) |
Severity: Normal | Keywords:
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
On databases that don’t natively support `XOR`, such as PostgreSQL, Django
generates incorrect fallback SQL for `Q(…) ^ Q(…) ^ Q(…)` with more than 2
arguments. The [https://en.wikipedia.org/wiki/Exclusive_or correct
interpretation], and the interpretation of databases natively supporting
`XOR` (e.g. [https://dev.mysql.com/doc/refman/8.0/en/logical-
operators.html#operator_xor MySQL]), is that `a ^ b ^ c` is true when an
''odd number'' of the arguments are true. But Django’s fallback
interpretation is that `a ^ b ^ c` is true when ''exactly one'' argument
is true:

{{{
>>> from django.db.models import Q
>>> from my_app.models import Client
>>> Client.objects.filter(Q(id=37)).count()
1
>>> Client.objects.filter(Q(id=37) ^ Q(id=37)).count()
0
>>> Client.objects.filter(Q(id=37) ^ Q(id=37) ^ Q(id=37)).count()
0
>>> Client.objects.filter(Q(id=37) ^ Q(id=37) ^ Q(id=37) ^
Q(id=37)).count()
0
>>> Client.objects.filter(Q(id=37) ^ Q(id=37) ^ Q(id=37) ^ Q(id=37) ^
Q(id=37)).count()
0
}}}

(Expected: `1`, `0`, `1`, `0`, `1`.)

This was introduced in #29865.

--
Ticket URL: <https://code.djangoproject.com/ticket/34604>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
May 30, 2023, 1:09:55 AM5/30/23
to django-...@googlegroups.com
#34604: On databases lacking XOR, Q(…) ^ Q(…) ^ Q(…) wrongly interpreted as
exactly-one rather than parity
-------------------------------------+-------------------------------------
Reporter: Anders Kaseorg | Owner: Anders
| Kaseorg
Type: Bug | Status: assigned
Component: Database layer | Version: 4.2
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage:
| Unreviewed
Has patch: 1 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Anders Kaseorg):

* owner: nobody => Anders Kaseorg
* status: new => assigned
* has_patch: 0 => 1


Comment:

Submitted a patch at https://github.com/django/django/pull/16736.

--
Ticket URL: <https://code.djangoproject.com/ticket/34604#comment:1>

Django

unread,
May 30, 2023, 5:06:14 AM5/30/23
to django-...@googlegroups.com
#34604: On databases lacking XOR, Q(…) ^ Q(…) ^ Q(…) wrongly interpreted as
exactly-one rather than parity
-------------------------------------+-------------------------------------
Reporter: Anders Kaseorg | Owner: Anders
| Kaseorg
Type: Bug | Status: assigned
Component: Database layer | Version: 4.2
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 1
Needs tests: 0 | Patch needs improvement: 1

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

* cc: Ryan Heard (added)
* needs_better_patch: 0 => 1
* stage: Unreviewed => Accepted
* needs_docs: 0 => 1


Comment:

Thanks for the report.

[https://github.com/django/django/pull/16901 PR]

--
Ticket URL: <https://code.djangoproject.com/ticket/34604#comment:2>

Django

unread,
Jun 8, 2023, 5:03:13 AM6/8/23
to django-...@googlegroups.com
#34604: On databases lacking XOR, Q(…) ^ Q(…) ^ Q(…) wrongly interpreted as
exactly-one rather than parity
-------------------------------------+-------------------------------------
Reporter: Anders Kaseorg | Owner: Anders
| Kaseorg
Type: Bug | Status: assigned
Component: Database layer | Version: 4.2
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

* needs_better_patch: 1 => 0
* stage: Accepted => Ready for checkin
* needs_docs: 1 => 0


--
Ticket URL: <https://code.djangoproject.com/ticket/34604#comment:3>

Django

unread,
Jun 9, 2023, 12:31:16 AM6/9/23
to django-...@googlegroups.com
#34604: On databases lacking XOR, Q(…) ^ Q(…) ^ Q(…) wrongly interpreted as
exactly-one rather than parity
-------------------------------------+-------------------------------------
Reporter: Anders Kaseorg | Owner: Anders
| Kaseorg
Type: Bug | Status: closed

Component: Database layer | Version: 4.2
(models, ORM) |
Severity: Normal | Resolution: fixed

Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak <felisiak.mariusz@…>):

* status: assigned => closed
* resolution: => fixed


Comment:

In [changeset:"b81e974e9ea16bd693b194a728f77fb825ec8e54" b81e974]:
{{{
#!CommitTicketReference repository=""
revision="b81e974e9ea16bd693b194a728f77fb825ec8e54"
Fixed #34604 -- Corrected fallback SQL for n-ary logical XOR.

An n-ary logical XOR Q(…) ^ Q(…) ^ … ^ Q(…) should evaluate to true
when an odd number of its operands evaluate to true, not when exactly
one operand evaluates to true.
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/34604#comment:4>

Reply all
Reply to author
Forward
0 new messages