mirror of https://github.com/django/django.git
Fixed #33340 -- Fixed unquoted column names in queries used by DatabaseCache.
This commit is contained in:
parent
eba9a9b7f7
commit
17df72114e
1
AUTHORS
1
AUTHORS
|
@ -97,6 +97,7 @@ answer newbie questions, and generally made Django that much better:
|
|||
arien <regexbot@gmail.com>
|
||||
Armin Ronacher
|
||||
Aron Podrigal <aronp@guaranteedplus.com>
|
||||
Arsalan Ghassemi <arsalan.ghassemi@gmail.com>
|
||||
Artem Gnilov <boobsd@gmail.com>
|
||||
Arthur <avandorp@gmail.com>
|
||||
Arthur Jovart <arthur@jovart.com>
|
||||
|
|
|
@ -228,10 +228,11 @@ class DatabaseCache(BaseDatabaseCache):
|
|||
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
'SELECT %s FROM %s WHERE %s = %%s and expires > %%s' % (
|
||||
'SELECT %s FROM %s WHERE %s = %%s and %s > %%s' % (
|
||||
quote_name('cache_key'),
|
||||
quote_name(self._table),
|
||||
quote_name('cache_key'),
|
||||
quote_name('expires'),
|
||||
),
|
||||
[key, connection.ops.adapt_datetimefield_value(now)]
|
||||
)
|
||||
|
@ -243,8 +244,10 @@ class DatabaseCache(BaseDatabaseCache):
|
|||
else:
|
||||
connection = connections[db]
|
||||
table = connection.ops.quote_name(self._table)
|
||||
cursor.execute("DELETE FROM %s WHERE expires < %%s" % table,
|
||||
[connection.ops.adapt_datetimefield_value(now)])
|
||||
cursor.execute('DELETE FROM %s WHERE %s < %%s' % (
|
||||
table,
|
||||
connection.ops.quote_name('expires'),
|
||||
), [connection.ops.adapt_datetimefield_value(now)])
|
||||
deleted_count = cursor.rowcount
|
||||
remaining_num = num - deleted_count
|
||||
if remaining_num > self._max_entries:
|
||||
|
@ -255,7 +258,10 @@ class DatabaseCache(BaseDatabaseCache):
|
|||
last_cache_key = cursor.fetchone()
|
||||
if last_cache_key:
|
||||
cursor.execute(
|
||||
'DELETE FROM %s WHERE cache_key < %%s' % table,
|
||||
'DELETE FROM %s WHERE %s < %%s' % (
|
||||
table,
|
||||
connection.ops.quote_name('cache_key'),
|
||||
),
|
||||
[last_cache_key[0]],
|
||||
)
|
||||
|
||||
|
|
|
@ -88,7 +88,8 @@ class BaseDatabaseOperations:
|
|||
This is used by the 'db' cache backend to determine where to start
|
||||
culling.
|
||||
"""
|
||||
return "SELECT cache_key FROM %s ORDER BY cache_key LIMIT 1 OFFSET %%s"
|
||||
cache_key = self.quote_name('cache_key')
|
||||
return f'SELECT {cache_key} FROM %s ORDER BY {cache_key} LIMIT 1 OFFSET %%s'
|
||||
|
||||
def unification_cast_sql(self, output_field):
|
||||
"""
|
||||
|
|
|
@ -72,7 +72,12 @@ END;
|
|||
}
|
||||
|
||||
def cache_key_culling_sql(self):
|
||||
return 'SELECT cache_key FROM %s ORDER BY cache_key OFFSET %%s ROWS FETCH FIRST 1 ROWS ONLY'
|
||||
cache_key = self.quote_name('cache_key')
|
||||
return (
|
||||
f'SELECT {cache_key} '
|
||||
f'FROM %s '
|
||||
f'ORDER BY {cache_key} OFFSET %%s ROWS FETCH FIRST 1 ROWS ONLY'
|
||||
)
|
||||
|
||||
def date_extract_sql(self, lookup_type, field_name):
|
||||
if lookup_type == 'week_day':
|
||||
|
|
|
@ -1113,7 +1113,7 @@ class DBCacheTests(BaseCacheTests, TransactionTestCase):
|
|||
with self.assertNumQueries(1):
|
||||
cache.delete_many(['a', 'b', 'c'])
|
||||
|
||||
def test_cull_count_queries(self):
|
||||
def test_cull_queries(self):
|
||||
old_max_entries = cache._max_entries
|
||||
# Force _cull to delete on first cached record.
|
||||
cache._max_entries = -1
|
||||
|
@ -1124,6 +1124,13 @@ class DBCacheTests(BaseCacheTests, TransactionTestCase):
|
|||
cache._max_entries = old_max_entries
|
||||
num_count_queries = sum('COUNT' in query['sql'] for query in captured_queries)
|
||||
self.assertEqual(num_count_queries, 1)
|
||||
# Column names are quoted.
|
||||
for query in captured_queries:
|
||||
sql = query['sql']
|
||||
if 'expires' in sql:
|
||||
self.assertIn(connection.ops.quote_name('expires'), sql)
|
||||
if 'cache_key' in sql:
|
||||
self.assertIn(connection.ops.quote_name('cache_key'), sql)
|
||||
|
||||
def test_delete_cursor_rowcount(self):
|
||||
"""
|
||||
|
@ -1180,6 +1187,15 @@ class DBCacheTests(BaseCacheTests, TransactionTestCase):
|
|||
)
|
||||
self.assertEqual(out.getvalue(), "Cache table 'test cache table' created.\n")
|
||||
|
||||
def test_has_key_query_columns_quoted(self):
|
||||
with CaptureQueriesContext(connection) as captured_queries:
|
||||
cache.has_key('key')
|
||||
self.assertEqual(len(captured_queries), 1)
|
||||
sql = captured_queries[0]['sql']
|
||||
# Column names are quoted.
|
||||
self.assertIn(connection.ops.quote_name('expires'), sql)
|
||||
self.assertIn(connection.ops.quote_name('cache_key'), sql)
|
||||
|
||||
|
||||
@override_settings(USE_TZ=True)
|
||||
class DBCacheWithTimeZoneTests(DBCacheTests):
|
||||
|
|
Loading…
Reference in New Issue