#34553: Can't create CheckConstraint with percent characters in values on
postgresql due to broken quoting
-------------------------------------+-------------------------------------
Reporter: Thomas | Owner: nobody
Kolar |
Type: Bug | Status: new
Component: Database | Version: 4.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 |
-------------------------------------+-------------------------------------
It is currently impossible to create check constraints that reference
values containing percent characters (`%`).
Consider the following model definition:
{{{#!python
from django.db import models
class Dolor(models.Model):
sit = models.CharField(max_length=42069)
class Meta:
constraints = (
models.CheckConstraint(
check=models.Q(sit="%"),
name="amet",
),
)
}}}
This will indeed result in a constraint being created. However, the
percent character will be doubled, and constrain `sit` to contain `%%`,
not `%`:
{{{#!python
>>> from ipsum.models import *
>>> Dolor.objects.create(sit="%")
Traceback (most recent call last):
(... snip ...)
psycopg2.errors.CheckViolation: new row for relation "ipsum_dolor"
violates check constraint "amet"
DETAIL: Failing row contains (1, %).
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
(... snip ...)
django.db.utils.IntegrityError: new row for relation "ipsum_dolor"
violates check constraint "amet"
DETAIL: Failing row contains (1, %).
>>> Dolor.objects.create(sit="%%")
<Dolor: Dolor object (2)>
>>>
}}}
This may be a super contrived example, but using an `__in` lookup in the
check with a list of allowed values also does not work (`choices` are not
a suitable alternative here as that isn't enforced at the DB level).
This was likely introduced with the fix for #30484 - here, the schema
editor's `quote_value` method was changed to always double percent
characters.
I'd also like to note that creating a `CheckConstraint` like this DOES
work in Django 2.2. Likely, that stopped being the case when #30060 was
fixed. I can attest that this is a serious roadblock when moving a project
from 2.2 to a modern and supported version of Django.
Honestly, I'm surprised that this doesn't break in way more instances.
"Quoting" like this should only be correct specifically for `LIKE` (and
the likes of it).
Suggested fix: remove the percentage character doubling from the general-
purpose escaping method, and reintroduce it in a targeted way where
needed.
I unfortunately don't know enough about the ORM's internals to make a more
detailed suggestion, or know for just how much headache creation I am to
apologize. But the current behavior is obviously incorrect.
Additional notes:
- This affects django 3.2 as well
- This almost certainly affects the oracle backend as well
- This works as expected on sqlite3
I have attached a sample django project that reproduces the issue.
Steps to reproduce (require docker installation):
- Spin up a postgres instance: `docker run -e POSTGRES_USER=lorem -e
POSTGRES_PASSWORD=lorem -e POSTGRES_DB=lorem -p 5432:5432 postgres`
- Extract `lorem.zip`
- Create a virtual environment
- Install `django==4.2.1`, `psycopg2-binary==2.9.6`
- Activate the virtual environment
- Extract `lorem.zip` and change into django directory
- `python -m manage migrate`
- `python -m manage shell`
- `from ipsum.models import *`
- `Dolor.objects.create(sit="%")`
- expected behavior: This should return a model instance
- actual behavior: exception (as described above)
- `Dolor.objects.create(sit="%%").sit`
- expected behavior: exception (as described above)
- actual behavior: returns "%%"
--
Ticket URL: <https://code.djangoproject.com/ticket/34553>
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/0107018800a80914-6bb2702a-174e-4072-96d6-c1d924738b6e-000000%40eu-central-1.amazonses.com.