mirror of
https://github.com/django/django.git
synced 2025-02-23 16:24:46 +00:00
Fixed #27632 -- Unified query parameters by their values on Oracle.
This commit is contained in:
parent
f6671c5d78
commit
6dbe56ed78
@ -450,7 +450,7 @@ class FormatStylePlaceholderCursor(object):
|
|||||||
else:
|
else:
|
||||||
return [p.force_bytes for p in params]
|
return [p.force_bytes for p in params]
|
||||||
|
|
||||||
def _fix_for_params(self, query, params):
|
def _fix_for_params(self, query, params, unify_by_values=False):
|
||||||
# cx_Oracle wants no trailing ';' for SQL statements. For PL/SQL, it
|
# cx_Oracle wants no trailing ';' for SQL statements. For PL/SQL, it
|
||||||
# it does want a trailing ';' but not a trailing '/'. However, these
|
# it does want a trailing ';' but not a trailing '/'. However, these
|
||||||
# characters must be included in the original query in case the query
|
# characters must be included in the original query in case the query
|
||||||
@ -464,6 +464,18 @@ class FormatStylePlaceholderCursor(object):
|
|||||||
# Handle params as dict
|
# Handle params as dict
|
||||||
args = {k: ":%s" % k for k in params.keys()}
|
args = {k: ":%s" % k for k in params.keys()}
|
||||||
query = convert_unicode(query % args, self.charset)
|
query = convert_unicode(query % args, self.charset)
|
||||||
|
elif unify_by_values:
|
||||||
|
# Handle params as a dict with unified query parameters by their
|
||||||
|
# values. It can be used only in single query execute() because
|
||||||
|
# executemany() shares the formatted query with each of the params
|
||||||
|
# list. e.g. for input params = [0.75, 2, 0.75, 'sth', 0.75]
|
||||||
|
# params_dict = {0.75: ':arg0', 2: ':arg1', 'sth': ':arg2'}
|
||||||
|
# args = [':arg0', ':arg1', ':arg0', ':arg2', ':arg0']
|
||||||
|
# params = {':arg0': 0.75, ':arg1': 2, ':arg2': 'sth'}
|
||||||
|
params_dict = {param: ':arg%d' % i for i, param in enumerate(set(params))}
|
||||||
|
args = [params_dict[param] for param in params]
|
||||||
|
params = dict(zip(params_dict.values(), params_dict.keys()))
|
||||||
|
query = convert_unicode(query % tuple(args), self.charset)
|
||||||
else:
|
else:
|
||||||
# Handle params as sequence
|
# Handle params as sequence
|
||||||
args = [(':arg%d' % i) for i in range(len(params))]
|
args = [(':arg%d' % i) for i in range(len(params))]
|
||||||
@ -471,7 +483,7 @@ class FormatStylePlaceholderCursor(object):
|
|||||||
return query, self._format_params(params)
|
return query, self._format_params(params)
|
||||||
|
|
||||||
def execute(self, query, params=None):
|
def execute(self, query, params=None):
|
||||||
query, params = self._fix_for_params(query, params)
|
query, params = self._fix_for_params(query, params, unify_by_values=True)
|
||||||
self._guess_input_sizes([params])
|
self._guess_input_sizes([params])
|
||||||
try:
|
try:
|
||||||
return self.cursor.execute(query, self._param_generator(params))
|
return self.cursor.execute(query, self._param_generator(params))
|
||||||
|
@ -107,6 +107,19 @@ class AggregationTests(TestCase):
|
|||||||
for attr, value in six.iteritems(kwargs):
|
for attr, value in six.iteritems(kwargs):
|
||||||
self.assertEqual(getattr(obj, attr), value)
|
self.assertEqual(getattr(obj, attr), value)
|
||||||
|
|
||||||
|
def test_annotation_with_value(self):
|
||||||
|
values = Book.objects.filter(
|
||||||
|
name='Practical Django Projects',
|
||||||
|
).annotate(
|
||||||
|
discount_price=F('price') * 2,
|
||||||
|
).values(
|
||||||
|
'discount_price',
|
||||||
|
).annotate(sum_discount=Sum('discount_price'))
|
||||||
|
self.assertSequenceEqual(
|
||||||
|
values,
|
||||||
|
[{'discount_price': Decimal('59.38'), 'sum_discount': Decimal('59.38')}]
|
||||||
|
)
|
||||||
|
|
||||||
def test_aggregates_in_where_clause(self):
|
def test_aggregates_in_where_clause(self):
|
||||||
"""
|
"""
|
||||||
Regression test for #12822: DatabaseError: aggregates not allowed in
|
Regression test for #12822: DatabaseError: aggregates not allowed in
|
||||||
|
Loading…
x
Reference in New Issue
Block a user