From 0b75b2cce0eaf3ee5e5f84660cbe7952b6acf153 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Wed, 12 Jun 2019 23:43:08 +0100 Subject: [PATCH] Always cast SQL parameters to tuples As reported in #50. --- HISTORY.rst | 2 ++ django_mysql/models/aggregates.py | 2 +- django_mysql/models/expressions.py | 24 ++++++------------------ django_mysql/models/fields/dynamic.py | 2 +- django_mysql/models/fields/json.py | 2 +- django_mysql/models/fields/lists.py | 2 +- django_mysql/models/lookups.py | 24 ++++++++++++------------ 7 files changed, 24 insertions(+), 34 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index a47bf005..7405d455 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -10,6 +10,8 @@ Pending * Update Python support to 3.5-3.7, as 3.4 has reached its end of life. +* Always cast SQL params to tuples in ORM code. + 3.1.0 (2019-05-17) ------------------ diff --git a/django_mysql/models/aggregates.py b/django_mysql/models/aggregates.py index ab0c8069..ba12b7d0 100644 --- a/django_mysql/models/aggregates.py +++ b/django_mysql/models/aggregates.py @@ -64,4 +64,4 @@ def as_sql(self, compiler, connection, function=None, template=None): sql.append(")") - return "".join(sql), params + return "".join(sql), tuple(params) diff --git a/django_mysql/models/expressions.py b/django_mysql/models/expressions.py index 15e7b682..8ec46b39 100644 --- a/django_mysql/models/expressions.py +++ b/django_mysql/models/expressions.py @@ -64,10 +64,7 @@ def as_sql(self, compiler, connection): value, value_params = compiler.compile(self.rhs) sql = self.sql_expression % (field, value) - - params = [] - params.extend(value_params) - params.extend(field_params) + params = tuple(value_params) + tuple(field_params) return sql, params @@ -96,10 +93,7 @@ def as_sql(self, compiler, connection): value, value_params = compiler.compile(self.rhs) sql = self.sql_expression % (value, field) - - params = [] - params.extend(field_params) - params.extend(value_params) + params = tuple(field_params) + tuple(value_params) return sql, params @@ -136,7 +130,7 @@ def as_sql(self, compiler, connection): field, field_params = compiler.compile(self.lhs) sql = self.sql_expression % (field) - return sql, field_params + return sql, tuple(field_params) class PopLeftListF(BaseExpression): @@ -163,7 +157,7 @@ def as_sql(self, compiler, connection): field, field_params = compiler.compile(self.lhs) sql = self.sql_expression % (field) - return sql, field_params + return sql, tuple(field_params) class SetF(object): @@ -206,10 +200,7 @@ def as_sql(self, compiler, connection): value, value_params = compiler.compile(self.rhs) sql = self.sql_expression % (value, field) - - params = [] - params.extend(value_params) - params.extend(field_params) + params = tuple(value_params) + tuple(field_params) return sql, params @@ -257,9 +248,6 @@ def as_sql(self, compiler, connection): value, value_params = compiler.compile(self.rhs) sql = self.sql_expression % (value, field) - - params = [] - params.extend(value_params) - params.extend(field_params) + params = tuple(value_params) + tuple(field_params) return sql, params diff --git a/django_mysql/models/fields/dynamic.py b/django_mysql/models/fields/dynamic.py index 2acfdb0a..30dd38c9 100644 --- a/django_mysql/models/fields/dynamic.py +++ b/django_mysql/models/fields/dynamic.py @@ -299,7 +299,7 @@ def as_sql(self, compiler, connection): lhs, params = compiler.compile(self.lhs) return ( "COLUMN_GET({}, %s AS {})".format(lhs, self.data_type), - params + [self.key_name], + tuple(params) + (self.key_name,), ) diff --git a/django_mysql/models/fields/json.py b/django_mysql/models/fields/json.py index db8ec5f2..350fa468 100644 --- a/django_mysql/models/fields/json.py +++ b/django_mysql/models/fields/json.py @@ -207,7 +207,7 @@ def as_sql(self, compiler, connection): json_path = self.compile_json_path(key_transforms) - return 'JSON_EXTRACT({}, %s)'.format(lhs), params + [json_path] + return 'JSON_EXTRACT({}, %s)'.format(lhs), tuple(params) + (json_path,) def compile_json_path(self, key_transforms): path = ['$'] diff --git a/django_mysql/models/fields/lists.py b/django_mysql/models/fields/lists.py index 79f1741a..5d30e248 100644 --- a/django_mysql/models/fields/lists.py +++ b/django_mysql/models/fields/lists.py @@ -228,7 +228,7 @@ def __init__(self, index, *args, **kwargs): def as_sql(self, qn, connection): lhs, lhs_params = self.process_lhs(qn, connection) rhs, rhs_params = self.process_rhs(qn, connection) - params = lhs_params + rhs_params + params = tuple(lhs_params) + tuple(rhs_params) # Put rhs on the left since that's the order FIND_IN_SET uses return '(FIND_IN_SET(%s, %s) = %s)' % (rhs, lhs, self.index), params diff --git a/django_mysql/models/lookups.py b/django_mysql/models/lookups.py index 43589f25..d6a2a0e0 100644 --- a/django_mysql/models/lookups.py +++ b/django_mysql/models/lookups.py @@ -20,7 +20,7 @@ class SoundsLike(Lookup): def as_sql(self, qn, connection): lhs, lhs_params = self.process_lhs(qn, connection) rhs, rhs_params = self.process_rhs(qn, connection) - params = lhs_params + rhs_params + params = tuple(lhs_params) + tuple(rhs_params) return '%s SOUNDS LIKE %s' % (lhs, rhs), params @@ -73,7 +73,7 @@ class JSONContainedBy(Lookup): def as_sql(self, qn, connection): lhs, lhs_params = self.process_lhs(qn, connection) rhs, rhs_params = self.process_rhs(qn, connection) - params = rhs_params + lhs_params + params = tuple(rhs_params) + tuple(lhs_params) return 'JSON_CONTAINS({}, {})'.format(rhs, lhs), params @@ -83,7 +83,7 @@ class JSONContains(JSONLookupMixin, Lookup): def as_sql(self, qn, connection): lhs, lhs_params = self.process_lhs(qn, connection) rhs, rhs_params = self.process_rhs(qn, connection) - params = lhs_params + rhs_params + params = tuple(lhs_params) + tuple(rhs_params) return 'JSON_CONTAINS({}, {})'.format(lhs, rhs), params @@ -101,7 +101,7 @@ def as_sql(self, qn, connection): lhs, lhs_params = self.process_lhs(qn, connection) key_name = self.rhs path = '$.{}'.format(json.dumps(key_name)) - params = lhs_params + [path] + params = tuple(lhs_params) + (path,) return "JSON_CONTAINS_PATH({}, 'one', %s)".format(lhs), params @@ -120,11 +120,11 @@ class JSONHasKeys(JSONSequencesMixin, Lookup): def as_sql(self, qn, connection): lhs, lhs_params = self.process_lhs(qn, connection) - paths = [ + paths = tuple( '$.{}'.format(json.dumps(key_name)) for key_name in self.rhs - ] - params = lhs_params + paths + ) + params = tuple(lhs_params) + paths sql = ['JSON_CONTAINS_PATH(', lhs, ", 'all', "] sql.append(', '.join('%s' for _ in paths)) @@ -137,11 +137,11 @@ class JSONHasAnyKeys(JSONSequencesMixin, Lookup): def as_sql(self, qn, connection): lhs, lhs_params = self.process_lhs(qn, connection) - paths = [ + paths = tuple( '$.{}'.format(json.dumps(key_name)) for key_name in self.rhs - ] - params = lhs_params + paths + ) + params = tuple(lhs_params) + paths sql = ['JSON_CONTAINS_PATH(', lhs, ", 'one', "] sql.append(', '.join('%s' for _ in paths)) @@ -169,7 +169,7 @@ def get_prep_lookup(self): def as_sql(self, qn, connection): lhs, lhs_params = self.process_lhs(qn, connection) rhs, rhs_params = self.process_rhs(qn, connection) - params = lhs_params + rhs_params + params = tuple(lhs_params) + tuple(rhs_params) # Put rhs on the left since that's the order FIND_IN_SET uses return 'FIND_IN_SET(%s, %s)' % (rhs, lhs), params @@ -187,5 +187,5 @@ class DynColHasKey(Lookup): def as_sql(self, qn, connection): lhs, lhs_params = self.process_lhs(qn, connection) rhs, rhs_params = self.process_rhs(qn, connection) - params = lhs_params + rhs_params + params = tuple(lhs_params) + tuple(rhs_params) return 'COLUMN_EXISTS(%s, %s)' % (lhs, rhs), params