From 8f75984c263b89336cdf919c246a56ce49d07ddb Mon Sep 17 00:00:00 2001 From: Hajime Nakagami Date: Wed, 14 Mar 2018 11:46:41 +0900 Subject: [PATCH] Quoted field names in cache db backend SQL. On Firebird, 'value' is a reserved word and must be quoted. --- django/core/cache/backends/db.py | 75 ++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 18 deletions(-) diff --git a/django/core/cache/backends/db.py b/django/core/cache/backends/db.py index 041445aa563..cc922847098 100644 --- a/django/core/cache/backends/db.py +++ b/django/core/cache/backends/db.py @@ -51,11 +51,20 @@ class DatabaseCache(BaseDatabaseCache): self.validate_key(key) db = router.db_for_read(self.cache_model_class) connection = connections[db] - table = connection.ops.quote_name(self._table) + quote_name = connection.ops.quote_name + table = quote_name(self._table) with connection.cursor() as cursor: - cursor.execute("SELECT cache_key, value, expires FROM %s " - "WHERE cache_key = %%s" % table, [key]) + cursor.execute( + 'SELECT %s, %s, %s FROM %s WHERE %s = %%s' % ( + quote_name('cache_key'), + quote_name('value'), + quote_name('expires'), + table, + quote_name('cache_key'), + ), + [key] + ) row = cursor.fetchone() if row is None: return default @@ -73,8 +82,13 @@ class DatabaseCache(BaseDatabaseCache): db = router.db_for_write(self.cache_model_class) connection = connections[db] with connection.cursor() as cursor: - cursor.execute("DELETE FROM %s " - "WHERE cache_key = %%s" % table, [key]) + cursor.execute( + 'DELETE FROM %s WHERE %s = %%s' % ( + table, + quote_name('cache_key'), + ), + [key] + ) return default value = connection.ops.process_clob(row[1]) @@ -94,7 +108,8 @@ class DatabaseCache(BaseDatabaseCache): timeout = self.get_backend_timeout(timeout) db = router.db_for_write(self.cache_model_class) connection = connections[db] - table = connection.ops.quote_name(self._table) + quote_name = connection.ops.quote_name + table = quote_name(self._table) with connection.cursor() as cursor: cursor.execute("SELECT COUNT(*) FROM %s" % table) @@ -120,8 +135,15 @@ class DatabaseCache(BaseDatabaseCache): # so be careful about changes here - test suite will NOT pick # regressions. with transaction.atomic(using=db): - cursor.execute("SELECT cache_key, expires FROM %s " - "WHERE cache_key = %%s" % table, [key]) + cursor.execute( + 'SELECT %s, %s FROM %s WHERE %s = %%s' % ( + quote_name('cache_key'), + quote_name('expires'), + table, + quote_name('cache_key'), + ), + [key] + ) result = cursor.fetchone() if result: @@ -136,13 +158,25 @@ class DatabaseCache(BaseDatabaseCache): exp = connection.ops.adapt_datetimefield_value(exp) if result and (mode == 'set' or (mode == 'add' and current_expires < now)): - cursor.execute("UPDATE %s SET value = %%s, expires = %%s " - "WHERE cache_key = %%s" % table, - [b64encoded, exp, key]) + cursor.execute( + 'UPDATE %s SET %s = %%s, %s = %%s WHERE %s = %%s' % ( + table, + quote_name('value'), + quote_name('expires'), + quote_name('cache_key'), + ), + [b64encoded, exp, key] + ) else: - cursor.execute("INSERT INTO %s (cache_key, value, expires) " - "VALUES (%%s, %%s, %%s)" % table, - [key, b64encoded, exp]) + cursor.execute( + 'INSERT INTO %s (%s, %s, %s) VALUES (%%s, %%s, %%s)' % ( + table, + quote_name('cache_key'), + quote_name('value'), + quote_name('expires'), + ), + [key, b64encoded, exp] + ) except DatabaseError: # To be threadsafe, updates/inserts are allowed to fail silently return False @@ -166,7 +200,7 @@ class DatabaseCache(BaseDatabaseCache): db = router.db_for_read(self.cache_model_class) connection = connections[db] - table = connection.ops.quote_name(self._table) + quote_name = connection.ops.quote_name if settings.USE_TZ: now = datetime.utcnow() @@ -175,9 +209,14 @@ class DatabaseCache(BaseDatabaseCache): now = now.replace(microsecond=0) with connection.cursor() as cursor: - cursor.execute("SELECT cache_key FROM %s " - "WHERE cache_key = %%s and expires > %%s" % table, - [key, connection.ops.adapt_datetimefield_value(now)]) + cursor.execute( + 'SELECT %s FROM %s WHERE %s = %%s and expires > %%s' % ( + quote_name('cache_key'), + quote_name(self._table), + quote_name('cache_key'), + ), + [key, connection.ops.adapt_datetimefield_value(now)] + ) return cursor.fetchone() is not None def _cull(self, db, cursor, now):