#33282: django.db.utils.ProgrammingError: more than one row returned by a 
subquery
used as an expression
-------------------------------------+-------------------------------------
               Reporter:  Antonio    |          Owner:  nobody
  Terceiro                           |
                   Type:  Bug        |         Status:  new
              Component:  Database   |        Version:  3.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          |
-------------------------------------+-------------------------------------
 Hi,

 I'm working on porting [https://lavasoftware.org lava] to Django 3.2. When
 I run the test suite, I find 2 issues. One is #32690, for which I have the
 corresponding patch backported locally. The other one is this is a bunch
 of crashes that look like this:

 E               django.db.utils.ProgrammingError: more than one row
 returned by a subquery used as an expression

 I wasn't able to produce a minimal reproducer app yet, but I will try to
 point to the relevant code.

 in lava we have a few special model managers for handling access control.
 They are here:
 
https://git.lavasoftware.org/lava/lava/-/blob/master/lava_scheduler_app/managers.py

 This issue can easily be reproduced in a shell session:

 {{{
 $ ./manage.py shell
 Python 3.9.8 (main, Nov  7 2021, 15:47:09)
 Type 'copyright', 'credits' or 'license' for more information
 IPython 7.27.0 -- An enhanced Interactive Python. Type '?' for help.

 In [1]: from lava_scheduler_app.models import TestJob, User

 In [2]: TestJob.objects.visible_by_user(User.objects.last())
 Out[2]:
 ---------------------------------------------------------------------------
 CardinalityViolation                      Traceback (most recent call
 last)
 /usr/lib/python3/dist-packages/django/db/backends/utils.py in
 _execute(self, sql, params, *ignored_wrapper_args)
      83             else:
 ---> 84                 return self.cursor.execute(sql, params)
      85

 CardinalityViolation: more than one row returned by a subquery used as an
 expression


 The above exception was the direct cause of the following exception:

 ProgrammingError                          Traceback (most recent call
 last)
 /usr/lib/python3/dist-packages/IPython/core/formatters.py in
 __call__(self, obj)
     700                 type_pprinters=self.type_printers,
     701                 deferred_pprinters=self.deferred_printers)
 --> 702             printer.pretty(obj)
     703             printer.flush()
     704             return stream.getvalue()

 /usr/lib/python3/dist-packages/IPython/lib/pretty.py in pretty(self, obj)
     392                         if cls is not object \
     393                                 and
 callable(cls.__dict__.get('__repr__')):
 --> 394                             return _repr_pprint(obj, self, cycle)
     395
     396             return _default_pprint(obj, self, cycle)

 /usr/lib/python3/dist-packages/IPython/lib/pretty.py in _repr_pprint(obj,
 p, cycle)
     698     """A pprint that just redirects to the normal repr
 function."""
     699     # Find newlines and replace them with p.break_()
 --> 700     output = repr(obj)
     701     lines = output.splitlines()
     702     with p.group():

 /usr/lib/python3/dist-packages/django/db/models/query.py in __repr__(self)
     254
     255     def __repr__(self):
 --> 256         data = list(self[:REPR_OUTPUT_SIZE + 1])
     257         if len(data) > REPR_OUTPUT_SIZE:
     258             data[-1] = "...(remaining elements truncated)..."

 /usr/lib/python3/dist-packages/django/db/models/query.py in __len__(self)
     260
     261     def __len__(self):
 --> 262         self._fetch_all()
     263         return len(self._result_cache)
     264

 /usr/lib/python3/dist-packages/django/db/models/query.py in
 _fetch_all(self)
    1322     def _fetch_all(self):
    1323         if self._result_cache is None:
 -> 1324             self._result_cache = list(self._iterable_class(self))
    1325         if self._prefetch_related_lookups and not
 self._prefetch_done:
    1326             self._prefetch_related_objects()

 /usr/lib/python3/dist-packages/django/db/models/query.py in __iter__(self)
      49         # Execute the query. This will also fill compiler.select,
 klass_info,
      50         # and annotations.
 ---> 51         results =
 compiler.execute_sql(chunked_fetch=self.chunked_fetch,
 chunk_size=self.chunk_size)
      52         select, klass_info, annotation_col_map = (compiler.select,
 compiler.klass_info,
      53
 compiler.annotation_col_map)

 /usr/lib/python3/dist-packages/django/db/models/sql/compiler.py in
 execute_sql(self, result_type, chunked_fetch, chunk_size)
    1173             cursor = self.connection.cursor()
    1174         try:
 -> 1175             cursor.execute(sql, params)
    1176         except Exception:
    1177             # Might fail for server-side cursors (e.g. connection
 closed)

 /usr/lib/python3/dist-packages/django/db/backends/utils.py in
 execute(self, sql, params)
      96     def execute(self, sql, params=None):
      97         with self.debug_sql(sql, params,
 use_last_executed_query=True):
 ---> 98             return super().execute(sql, params)
      99
     100     def executemany(self, sql, param_list):

 /usr/lib/python3/dist-packages/django/db/backends/utils.py in
 execute(self, sql, params)
      64
      65     def execute(self, sql, params=None):
 ---> 66         return self._execute_with_wrappers(sql, params,
 many=False, executor=self._execute)
      67
      68     def executemany(self, sql, param_list):

 /usr/lib/python3/dist-packages/django/db/backends/utils.py in
 _execute_with_wrappers(self, sql, params, many, executor)
      73         for wrapper in reversed(self.db.execute_wrappers):
      74             executor = functools.partial(wrapper, executor)
 ---> 75         return executor(sql, params, many, context)
      76
      77     def _execute(self, sql, params, *ignored_wrapper_args):

 /usr/lib/python3/dist-packages/django/db/backends/utils.py in
 _execute(self, sql, params, *ignored_wrapper_args)
      82                 return self.cursor.execute(sql)
      83             else:
 ---> 84                 return self.cursor.execute(sql, params)
      85
      86     def _executemany(self, sql, param_list,
 *ignored_wrapper_args):

 /usr/lib/python3/dist-packages/django/db/utils.py in __exit__(self,
 exc_type, exc_value, traceback)
      88                 if dj_exc_type not in (DataError, IntegrityError):
      89                     self.wrapper.errors_occurred = True
 ---> 90                 raise dj_exc_value.with_traceback(traceback) from
 exc_value
      91
      92     def __call__(self, func):

 /usr/lib/python3/dist-packages/django/db/backends/utils.py in
 _execute(self, sql, params, *ignored_wrapper_args)
      82                 return self.cursor.execute(sql)
      83             else:
 ---> 84                 return self.cursor.execute(sql, params)
      85
      86     def _executemany(self, sql, param_list,
 *ignored_wrapper_args):

 ProgrammingError: more than one row returned by a subquery used as an
 expression
 }}}

 If I downgrade Django to 2.2, that just works. This is reproducible with
 Django 3.2 and with the current main branch from git.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/33282>
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/051.845a36dab3cf13f9aab6be8dde8a32d4%40djangoproject.com.

Reply via email to