#35028: psycopg3: distinct query iteration causes
psycopg.errors.InvalidColumnReference: for SELECT DISTINCT, ORDER BY
expressions must appear in select list
-------------------------------------+-------------------------------------
               Reporter:  Richard    |          Owner:  nobody
  Ebeling                            |
                   Type:  Bug        |         Status:  new
              Component:  Database   |        Version:  5.0
  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          |
-------------------------------------+-------------------------------------
 Using PostgreSQL, after upgrading from psycopg2 to psycopg3
 (`psycopg[binary]==3.1.14`), iterating a distinct queryset of a model with
 an ordering that uses `Value` expressions causes
 `psycopg.errors.InvalidColumnReference` error saying that the `ORDER BY`
 expression must appear in the select list.

 This is a minimal reproducible example:
 {{{
 ### MODELS

 from django.db import models

 class TestModel(models.Model):
     test_field = models.CharField()

     class Meta:
         ordering = [NullIf("test_field", Value(""))]

 ### TEST

 from name.models import TestModel
 from django.test import TestCase

 class TestTestModel(TestCase):
     def test_iterating(self):
         for el in TestModel.objects.all().distinct().iterator():
             pass
 }}}

 which gives this output when running:
 {{{
 $ ./manage.py test -k test_iterating
 Found 1 test(s).
 Creating test database for alias 'default'...
 System check identified no issues (0 silenced).
 E
 ======================================================================
 ERROR: test_iterating (name.tests.test_models.TestTestModel)
 ----------------------------------------------------------------------
 Traceback (most recent call last):
   File "/.../venv/lib/python3.10/site-
 packages/django/db/backends/utils.py", line 105, in _execute
     return self.cursor.execute(sql, params)
   File "/.../venv/lib/python3.10/site-packages/psycopg/server_cursor.py",
 line 294, in execute
     raise ex.with_traceback(None)
 psycopg.errors.InvalidColumnReference: for SELECT DISTINCT, ORDER BY
 expressions must appear in select list
 LINE 1: ..._field", $1) FROM "evaluation_testmodel" ORDER BY NULLIF("ev...
                                                              ^

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

 Traceback (most recent call last):
   File ".../tests/test_models.py", line 43, in test_iterating
     for el in TestModel.objects.all().distinct().iterator():
   File "/.../venv/lib/python3.10/site-packages/django/db/models/query.py",
 line 516, in _iterator
     yield from iterable
   File "/.../venv/lib/python3.10/site-packages/django/db/models/query.py",
 line 91, in __iter__
     results = compiler.execute_sql(
   File "/.../venv/lib/python3.10/site-
 packages/django/db/models/sql/compiler.py", line 1562, in execute_sql
     cursor.execute(sql, params)
   File "/.../venv/lib/python3.10/site-
 packages/django/db/backends/utils.py", line 79, in execute
     return self._execute_with_wrappers(
   File "/.../venv/lib/python3.10/site-
 packages/django/db/backends/utils.py", line 92, in _execute_with_wrappers
     return executor(sql, params, many, context)
   File "/.../venv/lib/python3.10/site-
 packages/django/db/backends/utils.py", line 100, in _execute
     with self.db.wrap_database_errors:
   File "/.../venv/lib/python3.10/site-packages/django/db/utils.py", line
 91, in __exit__
     raise dj_exc_value.with_traceback(traceback) from exc_value
   File "/.../venv/lib/python3.10/site-
 packages/django/db/backends/utils.py", line 105, in _execute
     return self.cursor.execute(sql, params)
   File "/.../venv/lib/python3.10/site-packages/psycopg/server_cursor.py",
 line 294, in execute
     raise ex.with_traceback(None)
 django.db.utils.ProgrammingError: for SELECT DISTINCT, ORDER BY
 expressions must appear in select list
 LINE 1: ..._field", $1) FROM "evaluation_testmodel" ORDER BY NULLIF("ev...
                                                              ^

 ----------------------------------------------------------------------
 Ran 1 test in 0.010s

 FAILED (errors=1)
 Destroying test database for alias 'default'...
 }}}

 Removing the `.distinct()` call prevents the error.

 This is the relevant excerpt from the postgres log:
 {{{
 2023-12-11 19:15:15.900 UTC [18994] name@test_name ERROR:  for SELECT
 DISTINCT, ORDER BY expressions must appear in select list at character 235
 2023-12-11 19:15:15.900 UTC [18994] name@test_name STATEMENT:  DECLARE
 "_django_curs_139772156350464_sync_1" NO SCROLL CURSOR FOR SELECT DISTINCT
 "name_testmodel"."id", "name_testmodel"."test_field",
 NULLIF("name_testmodel"."test_field", $1) FROM "name_testmodel" ORDER BY
 NULLIF("name_testmodel"."test_field", $2) ASC
 }}}

 When using psycopg2, this is the resulting postgres log (without errors):
 {{{
 2023-12-11 19:19:32.456 UTC [19038] name@test_name LOG:  statement:
 DECLARE "_django_curs_140476300926976_sync_1" NO SCROLL CURSOR WITHOUT
 HOLD FOR SELECT DISTINCT "name_testmodel"."id",
 "name_testmodel"."test_field", NULLIF("name_testmodel"."test_field", '')
 FROM "name_testmodel" ORDER BY NULLIF("name_testmodel"."test_field", '')
 ASC
 2023-12-11 19:19:32.456 UTC [19038] name@test_name LOG:  statement: FETCH
 FORWARD 2000 FROM "_django_curs_140476300926976_sync_1"
 2023-12-11 19:19:32.456 UTC [19038] name@test_name LOG:  statement: CLOSE
 "_django_curs_140476300926976_sync_1"
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/35028>
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/0107018c5a5a8308-b74657b3-5465-453c-86b2-1cd6eaee9a19-000000%40eu-central-1.amazonses.com.

Reply via email to