#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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/052.5270c831d73fff5db89a530965d16a9e%40djangoproject.com.

Reply via email to