#31390: Using Q as rhs value in filter causes SQL Syntax error
-------------------------------------+-------------------------------------
               Reporter:             |          Owner:  nobody
  MarcinWieczorek                    |
                   Type:  Bug        |         Status:  new
              Component:  Database   |        Version:  3.0
  layer (models, ORM)                |
               Severity:  Normal     |       Keywords:  Q filter SQL
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 Hello. I discovered this issue by accident. I couldn't find what
 documentation says about undefined behaviour of filter, so I assume it is
 a bug.
 When a Q object is passed as right hand side value to filter it is treated
 as allowed, but in the end serializes to empty string. I assume that a one
 "word" AND is simplified to that word, (q AND nothing = q) and also two
 "nothings" ANDed get simplified to empty string. This results in something
 like "pk = LIMIT" in the example.

 The model is trivial, it works for anything.
 {{{
 class A(models.Model):
     pass
 }}}

 Steps to reproduce
 {{{
 ./manage.py shell
 >>> from app.models import *
 >>> from django.db.models import Q
 >>> A.objects.filter(pk=Q())
 Traceback (most recent call last):
   File "/secret/venv37/lib/python3.7/site-
 packages/django/db/backends/utils.py", line 86, in _execute
     return self.cursor.execute(sql, params)
   File "/secret/venv37/lib/python3.7/site-
 packages/django/db/backends/sqlite3/base.py", line 396, in execute
     return Database.Cursor.execute(self, query, params)
 sqlite3.OperationalError: near "LIMIT": syntax error

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

 Traceback (most recent call last):
   File "<console>", line 1, in <module>
   File "/secret/venv37/lib/python3.7/site-
 packages/django/db/models/query.py", line 252, in __repr__
     data = list(self[:REPR_OUTPUT_SIZE + 1])
   File "/secret/venv37/lib/python3.7/site-
 packages/django/db/models/query.py", line 276, in __iter__
     self._fetch_all()
   File "/secret/venv37/lib/python3.7/site-
 packages/django/db/models/query.py", line 1261, in _fetch_all
     self._result_cache = list(self._iterable_class(self))
   File "/secret/venv37/lib/python3.7/site-
 packages/django/db/models/query.py", line 57, in __iter__
     results = compiler.execute_sql(chunked_fetch=self.chunked_fetch,
 chunk_size=self.chunk_size)
   File "/secret/venv37/lib/python3.7/site-
 packages/django/db/models/sql/compiler.py", line 1151, in execute_sql
     cursor.execute(sql, params)
   File "/secret/venv37/lib/python3.7/site-
 packages/django/db/backends/utils.py", line 100, in execute
     return super().execute(sql, params)
   File "/secret/venv37/lib/python3.7/site-
 packages/django/db/backends/utils.py", line 68, in execute
     return self._execute_with_wrappers(sql, params, many=False,
 executor=self._execute)
   File "/secret/venv37/lib/python3.7/site-
 packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
     return executor(sql, params, many, context)
   File "/secret/venv37/lib/python3.7/site-
 packages/django/db/backends/utils.py", line 86, in _execute
     return self.cursor.execute(sql, params)
   File "/secret/venv37/lib/python3.7/site-packages/django/db/utils.py",
 line 90, in __exit__
     raise dj_exc_value.with_traceback(traceback) from exc_value
   File "/secret/venv37/lib/python3.7/site-
 packages/django/db/backends/utils.py", line 86, in _execute
     return self.cursor.execute(sql, params)
   File "/secret/venv37/lib/python3.7/site-
 packages/django/db/backends/sqlite3/base.py", line 396, in execute
     return Database.Cursor.execute(self, query, params)
 django.db.utils.OperationalError: near "LIMIT": syntax error
 }}}

 Bonus:
 {{{
 >>> A.objects.filter(pk=Q()).query.__str__()
 'SELECT "app_a"."id" FROM "app_a" WHERE "app_a"."id" = '
 }}}


 Notes:
 If this gets confirmed I'm willing to try to do a fix (plenty of time
 nowadays, right?), or at least provide a failing test, because as far as I
 dug into the code, the query interfaces are fairly complicated.

 This example was made on sqlite, but the issue was originally discovered
 on postgres. I assume the bug is not on db backend level.

 As absurd as this code might look, I created it by adding an inline if
 statemement to the filter (pk=1 if flag else Q()), which wasn't an obvious
 error.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/31390>
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/058.63b43bdb538c64441db9ede7f6d04b0b%40djangoproject.com.

Reply via email to