#30408: CheckConstraint with lookup using LIKE & % and PostgreSQL results in
exception
-------------------------------------+-------------------------------------
               Reporter:  David      |          Owner:  nobody
  Sanders                            |
                   Type:  Bug        |         Status:  new
              Component:  Database   |        Version:  master
  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          |
-------------------------------------+-------------------------------------
 Given the following model:

 {{{
 class Foo(models.Model):
     bar = models.CharField(max_length=255)

     class Meta:
         constraints = (
             models.CheckConstraint(
                 check=models.Q(bar__startswith='BAR'),
                 name='check_bar_starts_with_BAR',
             ),
         )
 }}}

 Running migrate with PostgreSQL will result in an exception:

 {{{
 davids ~/projects/test_startswith_constraint $ ./manage.py migrate
 Operations to perform:
   Apply all migrations: admin, auth, contenttypes, sample, sessions
 Running migrations:
   Applying contenttypes.0001_initial... OK
   Applying auth.0001_initial... OK
   Applying admin.0001_initial... OK
   Applying admin.0002_logentry_remove_auto_add... OK
   Applying admin.0003_logentry_add_action_flag_choices... OK
   Applying contenttypes.0002_remove_content_type_name... OK
   Applying auth.0002_alter_permission_name_max_length... OK
   Applying auth.0003_alter_user_email_max_length... OK
   Applying auth.0004_alter_user_username_opts... OK
   Applying auth.0005_alter_user_last_login_null... OK
   Applying auth.0006_require_contenttypes_0002... OK
   Applying auth.0007_alter_validators_add_error_messages... OK
   Applying auth.0008_alter_user_username_max_length... OK
   Applying auth.0009_alter_user_last_name_max_length... OK
   Applying auth.0010_alter_group_name_max_length... OK
   Applying auth.0011_update_proxy_permissions... OK
   Applying sample.0001_initial...Traceback (most recent call last):
   File "./manage.py", line 21, in <module>
     main()
   File "./manage.py", line 17, in main
     execute_from_command_line(sys.argv)
   File "/Users/davids/src/django/django/core/management/__init__.py", line
 381, in execute_from_command_line
     utility.execute()
   File "/Users/davids/src/django/django/core/management/__init__.py", line
 375, in execute
     self.fetch_command(subcommand).run_from_argv(self.argv)
   File "/Users/davids/src/django/django/core/management/base.py", line
 323, in run_from_argv
     self.execute(*args, **cmd_options)
   File "/Users/davids/src/django/django/core/management/base.py", line
 364, in execute
     output = self.handle(*args, **options)
   File "/Users/davids/src/django/django/core/management/base.py", line 83,
 in wrapped
     res = handle_func(*args, **kwargs)
   File
 "/Users/davids/src/django/django/core/management/commands/migrate.py",
 line 233, in handle
     fake_initial=fake_initial,
   File "/Users/davids/src/django/django/db/migrations/executor.py", line
 117, in migrate
     state = self._migrate_all_forwards(state, plan, full_plan, fake=fake,
 fake_initial=fake_initial)
   File "/Users/davids/src/django/django/db/migrations/executor.py", line
 147, in _migrate_all_forwards
     state = self.apply_migration(state, migration, fake=fake,
 fake_initial=fake_initial)
   File "/Users/davids/src/django/django/db/migrations/executor.py", line
 245, in apply_migration
     state = migration.apply(state, schema_editor)
   File "/Users/davids/src/django/django/db/migrations/migration.py", line
 124, in apply
     operation.database_forwards(self.app_label, schema_editor, old_state,
 project_state)
   File
 "/Users/davids/src/django/django/db/migrations/operations/models.py", line
 827, in database_forwards
     schema_editor.add_constraint(model, self.constraint)
   File "/Users/davids/src/django/django/db/backends/base/schema.py", line
 346, in add_constraint
     self.execute(sql)
   File "/Users/davids/src/django/django/db/backends/base/schema.py", line
 138, in execute
     cursor.execute(sql, params)
   File "/Users/davids/src/django/django/db/backends/utils.py", line 99, in
 execute
     return super().execute(sql, params)
   File "/Users/davids/src/django/django/db/backends/utils.py", line 67, in
 execute
     return self._execute_with_wrappers(sql, params, many=False,
 executor=self._execute)
   File "/Users/davids/src/django/django/db/backends/utils.py", line 76, in
 _execute_with_wrappers
     return executor(sql, params, many, context)
   File "/Users/davids/src/django/django/db/backends/utils.py", line 84, in
 _execute
     return self.cursor.execute(sql, params)
 IndexError: tuple index out of range
 }}}

 This is due to the SQL being passed to `execute()` has an unescaped `%`:

 {{{
 > /Users/davids/src/django/django/db/backends/utils.py(85)_execute()
      84                 import ipdb; ipdb.set_trace()
 ---> 85                 return self.cursor.execute(sql, params)
      86

 ipdb> sql
 'ALTER TABLE "sample_foo" ADD CONSTRAINT "check_bar_starts_with_BAR" CHECK
 ("bar"::text LIKE \'BAR%\')'
 }}}

 Note that this runs fine with SQLite but is problematic for PostgreSQL.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/30408>
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 post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/051.21a088e931de429271c639cd719bd6f3%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to