#31445 closed Bug (wontfix)
Chain of unions leads to incorrect SQL query on MySQL.
| Reported by: | Thodoris Sotiropoulos | Owned by: | |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 3.0 |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Accepted | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description (last modified by )
I have the following model
class Listing(models.Model): id = models.TextField(primary_key=True) foo = models.CharField(max_length=20) class Meta: managed = False db_table = 'listing'
Based on this model, I perform the following query in a MySQL backend.
ret1 = Listing.objects.using('mysql') ret2 = Listing.objects.using('mysql') ret3 = Listing.objects.using('mysql') ret4= ret2.union(ret3) ret5 = ret1.union(ret4) print(ret5.count())
Unfortunately, this query crashes with a ProgrammingError exception. The track trace is
Traceback (most recent call last):
File "/dir/.env/lib/python3.6/site-packages/django/db/backends/utils.py", line 86, in _execute
return self.cursor.execute(sql, params)
File "/dir/.env/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 74, in execute
return self.cursor.execute(query, args)
File "/dir/.env/lib/python3.6/site-packages/MySQLdb/cursors.py", line 209, in execute
res = self._query(query)
File "/dir/.env/lib/python3.6/site-packages/MySQLdb/cursors.py", line 315, in _query
db.query(q)
File "/dir/.env/lib/python3.6/site-packages/MySQLdb/connections.py", line 239, in query
_mysql.connection.query(self, query)
MySQLdb._exceptions.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION (SELECT `listing`.`id`, `listing`.`foo` FROM `listing`))) subquery' at line 1")
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "driver_mysql.py", line 27, in <module>
raise e
File "driver_mysql.py", line 24, in <module>
print(ret5.count())
File "/dir/.env/lib/python3.6/site-packages/django/db/models/query.py", line 397, in count
return self.query.get_count(using=self.db)
File "/dir/.env/lib/python3.6/site-packages/django/db/models/sql/query.py", line 517, in get_count
number = obj.get_aggregation(using, ['__count'])['__count']
File "/dir/.env/lib/python3.6/site-packages/django/db/models/sql/query.py", line 502, in get_aggregation
result = compiler.execute_sql(SINGLE)
File "/dir/.env/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1151, in execute_sql
cursor.execute(sql, params)
File "/dir/.env/lib/python3.6/site-packages/django/db/backends/utils.py", line 100, in execute
return super().execute(sql, params)
File "/dir/.env/lib/python3.6/site-packages/django/db/backends/utils.py", line 68, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/dir/.env/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/dir/.env/lib/python3.6/site-packages/django/db/backends/utils.py", line 86, in _execute
return self.cursor.execute(sql, params)
File "/dir/.env/lib/python3.6/site-packages/django/db/utils.py", line 90, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/dir/.env/lib/python3.6/site-packages/django/db/backends/utils.py", line 86, in _execute
return self.cursor.execute(sql, params)
File "/dir/.env/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 74, in execute
return self.cursor.execute(query, args)
File "/dir/.env/lib/python3.6/site-packages/MySQLdb/cursors.py", line 209, in execute
res = self._query(query)
File "/dir/.env/lib/python3.6/site-packages/MySQLdb/cursors.py", line 315, in _query
db.query(q)
File "/dir/.env/lib/python3.6/site-packages/MySQLdb/connections.py", line 239, in query
_mysql.connection.query(self, query)
django.db.utils.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION (SELECT `listing`.`id`, `listing`.`foo` FROM `listing`))) subquery' at line 1")
The generated query is
(SELECT `listing`.`id`, `listing`.`foo` FROM `listing`) UNION ((SELECT `listing`.`id`, `listing`.`foo` FROM `listing`) UNION (SELECT `listing`.`id`, `listing`.`foo` FROM `listing`))
Note that although MySQL crashes, chaining unions in SQLite or Postgres works as expected.
Django version: 3.0.4
MySQL version: 5.7.29
Change History (9)
comment:1 by , 6 years ago
| Type: | Uncategorized → Bug |
|---|
comment:2 by , 6 years ago
| Description: | modified (diff) |
|---|
comment:3 by , 6 years ago
| Description: | modified (diff) |
|---|
comment:4 by , 6 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
| Summary: | Chain of unions leads to incorrect SQL query (MySQL) → Chain of unions leads to incorrect SQL query on MariaDB < 10.4 and MySQL. |
| Triage Stage: | Unreviewed → Accepted |
comment:5 by , 5 years ago
Just stumbled across this trying to union three identical models together with MariaDB 10.3. Can't upgrade MariaDB to 10.4 yet (which added bracket support for unions: https://jira.mariadb.org/browse/MDEV-11953), so in case this is useful to anyone else, the workaround I have used is https://github.com/dracos/django/commit/e71c62b95e (probably has issues, but appears to work okay for my use case, which is to display a place's productions and all its children's productions in the same query/pagination with this change to use union(): https://github.com/dracos/Theatricalia/commit/423f8d5e , displayed as eg https://theatricalia.com/place/7c/birmingham-repertory-theatre-birmingham).
comment:6 by , 3 years ago
| Owner: | removed |
|---|---|
| Status: | assigned → new |
| Summary: | Chain of unions leads to incorrect SQL query on MariaDB < 10.4 and MySQL. → Chain of unions leads to incorrect SQL query on MySQL. |
MariaDB < 10.4 is not supported anymore.
comment:7 by , 3 years ago
This was fixed in MySQL 8.0.31, see release notes:
"Bodies of parenthesized query expressions can now be nested to in combination with
UNION. For example, the query shown here, previously rejected with errorER_NOT_SUPPORTED_YET, is now allowed"
I'm going to add a regression test and skip it on MySQL < 8.0.31
comment:8 by , 3 years ago
| Resolution: | → wontfix |
|---|---|
| Status: | new → closed |
I don't think it's worth juggling parentheses around UNION's to support this on MySQL < 8.0.31.
Thanks. I'm pretty confident that it's the same issue that I encounter in #29338 (see comment) related with using of parentheses. Unfortunately result depends on version of MySQL/MariaDB:
1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near...,1235, "This version of MySQL doesn't yet support 'nesting of unions at the right-hand side'",I will try to finally fix this.