{{{
b = B.objects.filter(pk=1).select_for_update(of=('self'))
b = b[0] # Evaluate the query
b.some_field_of_b = b.some_field_of_b + 1
b.save()
}}}
This will cause race conditions. The generated SQL will only lock the
table of A (the super-model) and not of B. As you can see, the field being
updated is of B and not of A. Even though the `SELECT .. FOR UPDATE OF`
might block, the queryset returned will not contain the updated data of
the table of B because the snapshot will not include the updated data
(before a lock is even acquired).
When the `of` parameter for `select_for_update` is supplied, the tables
locked should include those of the sub-models of the `of` fields.
--
Ticket URL: <https://code.djangoproject.com/ticket/30953>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* owner: nobody => Abhijeet
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/30953#comment:1>
* keywords: race conditions, psql, concurrency, db => select_for_update
mti model inheritance
* version: 2.2 => master
* stage: Unreviewed => Accepted
Comment:
> The generated SQL will only lock the table of A (the super-model) and
not of B.
I confirmed this is the case, `self` always use the parent model table
instead of the current one.
I'm not convinced we should make `select_for_update(of=('self',))` select
'''all''' inherited tables though as that would prevents selecting only
the current ''leaf'' model table. IMO the code should only be changed to
make `self` point to the queryset's model table as documented.
I suggest we also enhance the documentation to mention that parent links
should be included in `of` when this is desired instead.
In your case that would mean `of=('self', 'a_ptr')` to select both tables
for update.
--
Ticket URL: <https://code.djangoproject.com/ticket/30953#comment:2>
* cc: Abhijeet (added)
* has_patch: 0 => 1
--
Ticket URL: <https://code.djangoproject.com/ticket/30953#comment:3>
Comment (by Abhijeet):
Created a patch pull request on GitHub. ([PR
#12082](https://github.com/django/django/pull/12082)).
I believe this bug qualifies under data loss bugs as the unexpected
behavior caused due to this bug could cause race conditions (as was my
case). I've added release notes to 2.2.8. However, I'm not sure if it
should be added to 3.0 or 3.1 and should be backported to 2.1. Please
guide me on this so that I can modify the patch appropriately.
--
Ticket URL: <https://code.djangoproject.com/ticket/30953#comment:4>
* version: master => 2.1
* severity: Normal => Release blocker
Comment:
I agree this qualifies for a backport as a data loss bug.
--
Ticket URL: <https://code.djangoproject.com/ticket/30953#comment:5>
* needs_better_patch: 0 => 1
* needs_tests: 0 => 1
--
Ticket URL: <https://code.djangoproject.com/ticket/30953#comment:6>
* owner: Abhijeet => felixxm
* needs_better_patch: 1 => 0
* needs_tests: 1 => 0
Comment:
[https://github.com/django/django/pull/12154 PR]
--
Ticket URL: <https://code.djangoproject.com/ticket/30953#comment:7>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"0107e3d1058f653f66032f7fd3a0bd61e96bf782" 0107e3d1]:
{{{
#!CommitTicketReference repository=""
revision="0107e3d1058f653f66032f7fd3a0bd61e96bf782"
Fixed #30953 -- Made select_for_update() lock queryset's model when using
"self" with multi-table inheritance.
Thanks Abhijeet Viswa for the report and initial patch.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30953#comment:8>
Comment (by Mariusz Felisiak <felisiak.mariusz@…>):
In [changeset:"f4ed6800bd5de576816861931699ddd8377d338d" f4ed6800]:
{{{
#!CommitTicketReference repository=""
revision="f4ed6800bd5de576816861931699ddd8377d338d"
[3.0.x] Fixed #30953 -- Made select_for_update() lock queryset's model
when using "self" with multi-table inheritance.
Thanks Abhijeet Viswa for the report and initial patch.
Backport of 0107e3d1058f653f66032f7fd3a0bd61e96bf782 from master
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30953#comment:9>
Comment (by Mariusz Felisiak <felisiak.mariusz@…>):
In [changeset:"6cf3b6f5cf0cc3b11e86e511ec5201999913286f" 6cf3b6f5]:
{{{
#!CommitTicketReference repository=""
revision="6cf3b6f5cf0cc3b11e86e511ec5201999913286f"
[2.2.x] Fixed #30953 -- Made select_for_update() lock queryset's model
when using "self" with multi-table inheritance.
Thanks Abhijeet Viswa for the report and initial patch.
Backport of 0107e3d1058f653f66032f7fd3a0bd61e96bf782 from master
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30953#comment:10>
Comment (by Mariusz Felisiak <felisiak.mariusz@…>):
In [changeset:"39e39d0ac1b720e7460ec8ccf45926c78edb2047" 39e39d0a]:
{{{
#!CommitTicketReference repository=""
revision="39e39d0ac1b720e7460ec8ccf45926c78edb2047"
Refs #30953 -- Added 2.1.15 release note for
0107e3d1058f653f66032f7fd3a0bd61e96bf782.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30953#comment:11>
Comment (by Mariusz Felisiak <felisiak.mariusz@…>):
In [changeset:"db0cc4ae96c4752d10d98a3c7f2c48f813bf8a7f" db0cc4a]:
{{{
#!CommitTicketReference repository=""
revision="db0cc4ae96c4752d10d98a3c7f2c48f813bf8a7f"
[3.0.x] Refs #30953 -- Added 2.1.15 release note for
0107e3d1058f653f66032f7fd3a0bd61e96bf782.
Backport of 39e39d0ac1b720e7460ec8ccf45926c78edb2047 from master
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30953#comment:12>
Comment (by Mariusz Felisiak <felisiak.mariusz@…>):
In [changeset:"70311e1d00ef5b6bbbc8961eac81b5c814396a43" 70311e1]:
{{{
#!CommitTicketReference repository=""
revision="70311e1d00ef5b6bbbc8961eac81b5c814396a43"
[2.2.x] Refs #30953 -- Added 2.1.15 release note for
0107e3d1058f653f66032f7fd3a0bd61e96bf782.
Backport of 39e39d0ac1b720e7460ec8ccf45926c78edb2047 from master
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30953#comment:13>
Comment (by Mariusz Felisiak <felisiak.mariusz@…>):
In [changeset:"f57f81a7fe9da5116a9892d7f32aa055771b99c0" f57f81a7]:
{{{
#!CommitTicketReference repository=""
revision="f57f81a7fe9da5116a9892d7f32aa055771b99c0"
[2.1.x] Refs #30953 -- Added 2.1.15 release note for
0107e3d1058f653f66032f7fd3a0bd61e96bf782.
Backport of 39e39d0ac1b720e7460ec8ccf45926c78edb2047 from master
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30953#comment:15>
Comment (by Mariusz Felisiak <felisiak.mariusz@…>):
In [changeset:"015fab76ad7f91562d2323657a6b5d7b4ff15e28" 015fab76]:
{{{
#!CommitTicketReference repository=""
revision="015fab76ad7f91562d2323657a6b5d7b4ff15e28"
[2.1.x] Fixed #30953 -- Made select_for_update() lock queryset's model
when using "self" with multi-table inheritance.
Thanks Abhijeet Viswa for the report and initial patch.
Backport of 0107e3d1058f653f66032f7fd3a0bd61e96bf782 from master.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30953#comment:14>