#33260: Crash when using query set select_for_update(of=(...)) with exists()
-------------------------------------+-------------------------------------
               Reporter:  Hannes     |          Owner:  Hannes Ljungberg
  Ljungberg                          |
                   Type:  Bug        |         Status:  assigned
              Component:  Database   |        Version:  dev
  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          |
-------------------------------------+-------------------------------------
 For example specifying `(self,)` as an argument to `of`:
 {{{
 Person.objects.select_for_update(of=("self",)).exists()
 }}}

 Will crash with the following traceback:
 {{{
 Traceback (most recent call last):
   File "/tests/django/django/test/testcases.py", line 1305, in
 skip_wrapper
     return test_func(*args, **kwargs)
   File "/tests/django/tests/select_for_update/tests.py", line 599, in
 test_select_for_update_with_exists
     self.assertIs(Person.objects.select_for_update(of=("self",)).exists(),
 True)
   File "/tests/django/django/db/models/query.py", line 818, in exists
     return self.query.has_results(using=self.db)
   File "/tests/django/django/db/models/sql/query.py", line 546, in
 has_results
     return compiler.has_results()
   File "/tests/django/django/db/models/sql/compiler.py", line 1174, in
 has_results
     return bool(self.execute_sql(SINGLE))
   File "/tests/django/django/db/models/sql/compiler.py", line 1191, in
 execute_sql
     sql, params = self.as_sql()
   File "/tests/django/django/db/models/sql/compiler.py", line 612, in
 as_sql
     of=self.get_select_for_update_of_arguments(),
   File "/tests/django/django/db/models/sql/compiler.py", line 1087, in
 get_select_for_update_of_arguments
     col = _get_first_selected_col_from_model(klass_info)
   File "/tests/django/django/db/models/sql/compiler.py", line 1053, in
 _get_first_selected_col_from_model
     concrete_model = klass_info['model']._meta.concrete_model
 TypeError: 'NoneType' object is not subscriptable
 }}}

 Selecting a related model like:
 {{{
 Person.objects.select_for_update(of=("born",)).exists()
 }}}

 Will crash with the following traceback:
 {{{
 Traceback (most recent call last):
   File "/tests/django/django/test/testcases.py", line 1305, in
 skip_wrapper
     return test_func(*args, **kwargs)
   File "/tests/django/tests/select_for_update/tests.py", line 599, in
 test_select_for_update_with_exists
     self.assertIs(Person.objects.select_for_update(of=("born")).exists(),
 True)
   File "/tests/django/django/db/models/query.py", line 818, in exists
     return self.query.has_results(using=self.db)
   File "/tests/django/django/db/models/sql/query.py", line 546, in
 has_results
     return compiler.has_results()
   File "/tests/django/django/db/models/sql/compiler.py", line 1174, in
 has_results
     return bool(self.execute_sql(SINGLE))
   File "/tests/django/django/db/models/sql/compiler.py", line 1191, in
 execute_sql
     sql, params = self.as_sql()
   File "/tests/django/django/db/models/sql/compiler.py", line 612, in
 as_sql
     of=self.get_select_for_update_of_arguments(),
   File "/tests/django/django/db/models/sql/compiler.py", line 1091, in
 get_select_for_update_of_arguments
     *klass_info.get('related_klass_infos', []),
 AttributeError: 'NoneType' object has no attribute 'get'
 }}}

 With https://code.djangoproject.com/ticket/32888 in consideration we
 should probably just drop locking anything as no table columns are
 selected.

 Thinking something like:
 {{{
 diff --git a/django/db/models/sql/compiler.py
 b/django/db/models/sql/compiler.py
 index d1009847e7..7f6251aa34 100644
 --- a/django/db/models/sql/compiler.py
 +++ b/django/db/models/sql/compiler.py
 @@ -1081,6 +1081,8 @@ class SQLCompiler:
          invalid_names = []
          for name in self.query.select_for_update_of:
              klass_info = self.klass_info
 +            if not klass_info:
 +                continue
              if name == 'self':
                  col = _get_first_selected_col_from_model(klass_info)
              else:
 }}}

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

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/052.5270c831d73fff5db89a530965d16a9e%40djangoproject.com.

Reply via email to