diff --git a/django/db/backends/oracle/operations.py b/django/db/backends/oracle/operations.py index 672a02d664..b044adadda 100644 --- a/django/db/backends/oracle/operations.py +++ b/django/db/backends/oracle/operations.py @@ -309,14 +309,15 @@ END; # `statement` doesn't contain the query parameters. Substitute # parameters manually. if isinstance(params, (tuple, list)): - for i, param in enumerate(params): + for i, param in enumerate(reversed(params), start=1): + param_num = len(params) - i statement = statement.replace( - ":arg%d" % i, force_str(param, errors="replace") + ":arg%d" % param_num, force_str(param, errors="replace") ) elif isinstance(params, dict): - for key, param in params.items(): + for key in sorted(params, key=len, reverse=True): statement = statement.replace( - ":%s" % key, force_str(param, errors="replace") + ":%s" % key, force_str(params[key], errors="replace") ) return statement diff --git a/tests/backends/tests.py b/tests/backends/tests.py index 9303089b51..c6980058ca 100644 --- a/tests/backends/tests.py +++ b/tests/backends/tests.py @@ -101,6 +101,7 @@ class LastExecutedQueryTest(TestCase): pk=1, reporter__pk=9, ).exclude(reporter__pk__in=[2, 1]), + Article.objects.filter(pk__in=list(range(20, 31))), ): sql, params = qs.query.sql_with_params() with qs.query.get_compiler(DEFAULT_DB_ALIAS).execute_sql(CURSOR) as cursor: @@ -125,6 +126,22 @@ class LastExecutedQueryTest(TestCase): sql % params, ) + @skipUnlessDBFeature("supports_paramstyle_pyformat") + def test_last_executed_query_dict_overlap_keys(self): + square_opts = Square._meta + sql = "INSERT INTO %s (%s, %s) VALUES (%%(root)s, %%(root2)s)" % ( + connection.introspection.identifier_converter(square_opts.db_table), + connection.ops.quote_name(square_opts.get_field("root").column), + connection.ops.quote_name(square_opts.get_field("square").column), + ) + with connection.cursor() as cursor: + params = {"root": 2, "root2": 4} + cursor.execute(sql, params) + self.assertEqual( + cursor.db.ops.last_executed_query(cursor, sql, params), + sql % params, + ) + class ParameterHandlingTest(TestCase): def test_bad_parameter_count(self):