Commit b9a670b2 authored by Markus Holtermann's avatar Markus Holtermann Committed by Tim Graham
Browse files

Fixed #23426 -- Don't require double percent sign in RunSQL without parameters

parent 0aca91cf
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -66,14 +66,14 @@ class RunSQL(Operation):
    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        statements = schema_editor.connection.ops.prepare_sql_script(self.sql)
        for statement in statements:
            schema_editor.execute(statement)
            schema_editor.execute(statement, params=None)

    def database_backwards(self, app_label, schema_editor, from_state, to_state):
        if self.reverse_sql is None:
            raise NotImplementedError("You cannot reverse this operation")
        statements = schema_editor.connection.ops.prepare_sql_script(self.reverse_sql)
        for statement in statements:
            schema_editor.execute(statement)
            schema_editor.execute(statement, params=None)

    def describe(self):
        return "Raw SQL operation"
+5 −0
Original line number Diff line number Diff line
@@ -192,6 +192,11 @@ operation here so that the autodetector still has an up-to-date state of the
model (otherwise, when you next run ``makemigrations``, it won't see any
operation that adds that field and so will try to run it again).

.. versionchanged:: 1.7.1

    If you want to include literal percent signs in the query you don't need to
    double them anymore.

.. _sqlparse: https://pypi.python.org/pypi/sqlparse

RunPython
+3 −0
Original line number Diff line number Diff line
@@ -67,3 +67,6 @@ Bugfixes
  :meth:`~django.contrib.admin.InlineModelAdmin.get_min_num()` hooks to
  :class:`~django.contrib.contenttypes.admin.GenericInlineModelAdmin`
  (:ticket:`23539`).

* Made ``migrations.RunSQL`` no longer require percent sign escaping. This is
  now consistent with ``cursor.execute()`` (:ticket:`23426`).
+15 −3
Original line number Diff line number Diff line
@@ -1156,10 +1156,18 @@ class OperationTests(OperationTestBase):
        # Create the operation
        operation = migrations.RunSQL(
            # Use a multi-line string with a comment to test splitting on SQLite and MySQL respectively
            "CREATE TABLE i_love_ponies (id int, special_thing int);\n"
            "INSERT INTO i_love_ponies (id, special_thing) VALUES (1, 42); -- this is magic!\n"
            "INSERT INTO i_love_ponies (id, special_thing) VALUES (2, 51);\n",
            "CREATE TABLE i_love_ponies (id int, special_thing varchar(15));\n"
            "INSERT INTO i_love_ponies (id, special_thing) VALUES (1, 'i love ponies'); -- this is magic!\n"
            "INSERT INTO i_love_ponies (id, special_thing) VALUES (2, 'i love django');\n"
            "UPDATE i_love_ponies SET special_thing = 'Ponies' WHERE special_thing LIKE '%%ponies';"
            "UPDATE i_love_ponies SET special_thing = 'Django' WHERE special_thing LIKE '%django';",

            # Run delete queries to test for parameter substitution failure
            # reported in #23426
            "DELETE FROM i_love_ponies WHERE special_thing LIKE '%Django%';"
            "DELETE FROM i_love_ponies WHERE special_thing LIKE '%%Ponies%%';"
            "DROP TABLE i_love_ponies",

            state_operations=[migrations.CreateModel("SomethingElse", [("id", models.AutoField(primary_key=True))])],
        )
        self.assertEqual(operation.describe(), "Raw SQL operation")
@@ -1177,6 +1185,10 @@ class OperationTests(OperationTestBase):
        with connection.cursor() as cursor:
            cursor.execute("SELECT COUNT(*) FROM i_love_ponies")
            self.assertEqual(cursor.fetchall()[0][0], 2)
            cursor.execute("SELECT COUNT(*) FROM i_love_ponies WHERE special_thing = 'Django'")
            self.assertEqual(cursor.fetchall()[0][0], 1)
            cursor.execute("SELECT COUNT(*) FROM i_love_ponies WHERE special_thing = 'Ponies'")
            self.assertEqual(cursor.fetchall()[0][0], 1)
        # And test reversal
        self.assertTrue(operation.reversible)
        with connection.schema_editor() as editor: