Opened 6 years ago
Last modified 6 years ago
#31246 closed Bug
select_for_update() with "of" uses wrong tables from (multi-level) model inheritance. — at Version 6
| Reported by: | Abhijeet Viswa | Owned by: | Abhijeet Viswa | 
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 2.2 | 
| Severity: | Release blocker | Keywords: | select_for_update mti relations | 
| Cc: | Triage Stage: | Ready for checkin | |
| Has patch: | yes | Needs documentation: | no | 
| Needs tests: | no | Patch needs improvement: | no | 
| Easy pickings: | no | UI/UX: | no | 
Description (last modified by )
Two different bugs related to model inheritance:
1.
Consider the following models:
class A(models.Model):
    field1 = models.IntegerField()
class B(A):
    field2 = models.IntegerField()
class C(models.Model):
    b = models.ForeignKey(B, on_delete=models.CASCADE)
queryset = C.objects.select_related('b').select_for_update(of=('b'))
The above queryet generates the following query:
SELECT "selectforupdate_c"."id",
       "selectforupdate_c"."b_id",
       "selectforupdate_a"."id",
       "selectforupdate_a"."field1",
       "selectforupdate_b"."a_ptr_id",
       "selectforupdate_b"."field2"
FROM   "selectforupdate_c"
       INNER JOIN "selectforupdate_b"
               ON ( "selectforupdate_c"."b_id" =
                  "selectforupdate_b"."a_ptr_id" )
       INNER JOIN "selectforupdate_a"
               ON ( "selectforupdate_b"."a_ptr_id" = "selectforupdate_a"."id" )
FOR UPDATE OF "selectforupdate_a"
The of clause in the generated SQL references the model a instead of b
2.
Consider the following models:
 
class A(models.Model):
    field1 = models.IntegerField()
class B(A):
     field2 = models.IntegerField()
 
class C(B):
    field_c = models.IntegerField()
queryset = C.objects.all().select_for_update(of=('b_ptr', 'b_ptr__a_ptr'))
 
The above queryset crashes with the following crashlog: 
Traceback (most recent call last):
  File "/home/abhijeet/git-repos/django/django/core/management/base.py", line 328, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/abhijeet/git-repos/django/django/core/management/base.py", line 369, in execute
   output = self.handle(*args, **options)
  File "/home/abhijeet/django_contrib/selectforupdate/management/commands/debug.py", line 12, in handle
    print(queryset.query)
  File "/home/abhijeet/git-repos/django/django/db/models/sql/query.py", line 257, in __str__
    sql, params = self.sql_with_params()
  File "/home/abhijeet/git-repos/django/django/db/models/sql/query.py", line 265, in sql_with_params
    return self.get_compiler(DEFAULT_DB_ALIAS).as_sql()
  File "/home/abhijeet/git-repos/django/django/db/models/sql/compiler.py", line 555, in as_sql
    of=self.get_select_for_update_of_arguments(),
  File "/home/abhijeet/git-repos/django/django/db/models/sql/compiler.py", line 1036, in get_select_for_update_of_arguments
    select_index = klass_info['select_fields'][0]
IndexError: list index out of range
This is related to #30953
Change History (6)
comment:1 by , 6 years ago
| Description: | modified (diff) | 
|---|
comment:2 by , 6 years ago
| Keywords: | select_for_update; mti; relations; → select_for_update mti relations | 
|---|---|
| Severity: | Normal → Release blocker | 
| Triage Stage: | Unreviewed → Accepted | 
comment:3 by , 6 years ago
| Version: | master → 2.2 | 
|---|
comment:4 by , 6 years ago
| Has patch: | set | 
|---|
comment:5 by , 6 years ago
| Needs tests: | set | 
|---|---|
| Patch needs improvement: | set | 
| Summary: | Related Model with inheritance generates wrong select_for_update 'of' → select_for_update() with "of" uses wrong tables from (multi-level) model inheritance. | 
It is a data loss issue introduced in 0107e3d1058f653f66032f7fd3a0bd61e96bf782 (Django 2.2.8).
comment:6 by , 6 years ago
| Description: | modified (diff) | 
|---|
  Note:
 See   TracTickets
 for help on using tickets.
    
I forgot to link to my PR:
PR