#25517 closed Bug (fixed)
Concat() database function is not idempotent in SQLite
Reported by: | Warren Smith | Owned by: | Josh Smeaton |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.8 |
Severity: | Release blocker | Keywords: | concat coalesce sqlite |
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 )
When running on sqlite, with a Concat()
expression used in the query, the ConcatPair.coalesce()
method is called every time the SQL is generated. This is normal, expected, and AFAIK, correct behavior.
The problem is that ConcatPair.coalesce()
is not idempotent. So, every time the SQL is generated, each expression within the ConcatPair
instance is wrapped with an additional COALESCE()
SQL function. If generated enough times, the SQL can reach a point where it will crash the sqlite query parser.
This problem may not manifest itself in a typical request/response context, as the SQL with the additional COALESCE()
calls will work identically to the original and the SQL may not be re-generated a sufficient number of times to crash the parser.
However, in a long-running process (where this bug was found), it can be easily triggered. For example, say I have a "base" queryset with a Concat()
within an .annotate()
. I never actually evaluate this queryset, but I use it to construct other querysets which I do evaluate. Because all of these querysets share the same instance of Query._annotations
, evaluating ANY of these querysets will add an additional level of COALESCE()
to the SQL generated by the others.
Change History (15)
comment:1 by , 9 years ago
Description: | modified (diff) |
---|
comment:2 by , 9 years ago
Description: | modified (diff) |
---|
comment:3 by , 9 years ago
Description: | modified (diff) |
---|---|
Owner: | changed from | to
Status: | new → assigned |
comment:4 by , 9 years ago
Has patch: | set |
---|
comment:5 by , 9 years ago
Triage Stage: | Unreviewed → Ready for checkin |
---|
comment:6 by , 9 years ago
Triage Stage: | Ready for checkin → Unreviewed |
---|
comment:8 by , 9 years ago
Patch needs improvement: | set |
---|---|
Triage Stage: | Unreviewed → Accepted |
Could you give a queryset that reproduces the issue and use that in the test rather than reproducing with the low level APIs like SQLCompiler
? I think that will make the issue more understandable, at least to me.
comment:9 by , 9 years ago
Owner: | removed |
---|---|
Status: | assigned → new |
comment:10 by , 9 years ago
Owner: | set to |
---|---|
Patch needs improvement: | unset |
Status: | new → assigned |
Triage Stage: | Accepted → Ready for checkin |
I think this should probably be backported to 1.8. It's a crashing bug if Concat is reused on sqlite.
comment:14 by , 9 years ago
Has patch: | unset |
---|---|
Severity: | Normal → Release blocker |
Triage Stage: | Ready for checkin → Accepted |
Version: | master → 1.8 |
Oops, I didn't check if the tests passed when backporting to 1.8 and there are a few test failures there. We can solve the SQLite failures by backporting BaseExpression.flatten()
from 134ca4d438bd7cbe8f0f287a00d545f96fa04a01 but there are also some MySQL two failures in tests/db_functions
.
Thanks for the report and patch, however, it's not appropriate to triage your own tickets, see https://docs.djangoproject.com/en/dev/internals/contributing/triaging-tickets/#triage-workflow. Thanks!