From 5cde9a7018021fc3c005e4ebcfa63967bcf56285 Mon Sep 17 00:00:00 2001
From: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Sun, 8 Jun 2014 22:42:12 +0200
Subject: [PATCH] [1.7.x] Fixed #20420 -- Normalized query counts on Oracle.

This is achieved by inserting a fake entry in connection.queries when
not releasing a savepoint (since Oracle doesn't support that operation.)

Also removed the can_release_savepoints feature that was recently added,
but is superseded by this solution.

Backport of 40bfd856 from master.
---
 django/db/backends/__init__.py    |  7 +++++--
 django/db/backends/oracle/base.py | 10 +++++++---
 tests/admin_views/tests.py        | 13 ++-----------
 3 files changed, 14 insertions(+), 16 deletions(-)

diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
index 529920a5a1..a566340b7b 100644
--- a/django/db/backends/__init__.py
+++ b/django/db/backends/__init__.py
@@ -82,6 +82,10 @@ class BaseDatabaseWrapper(object):
     def __hash__(self):
         return hash(self.alias)
 
+    @property
+    def queries_logged(self):
+        return self.use_debug_cursor or settings.DEBUG
+
     ##### Backend-specific methods for creating connections and cursors #####
 
     def get_connection_params(self):
@@ -157,7 +161,7 @@ class BaseDatabaseWrapper(object):
         Creates a cursor, opening a connection if necessary.
         """
         self.validate_thread_sharing()
-        if self.use_debug_cursor or settings.DEBUG:
+        if self.queries_logged:
             cursor = self.make_debug_cursor(self._cursor())
         else:
             cursor = utils.CursorWrapper(self._cursor(), self)
@@ -579,7 +583,6 @@ class BaseDatabaseFeatures(object):
     can_return_id_from_insert = False
     has_bulk_insert = False
     uses_savepoints = False
-    can_release_savepoints = True
     can_combine_inserts_with_and_without_auto_increment_pk = False
 
     # If True, don't use integer foreign keys referring to, e.g., positive
diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py
index f7790415db..b0b9a5f5a1 100644
--- a/django/db/backends/oracle/base.py
+++ b/django/db/backends/oracle/base.py
@@ -96,7 +96,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     needs_datetime_string_cast = False
     interprets_empty_strings_as_nulls = True
     uses_savepoints = True
-    can_release_savepoints = False
     has_select_for_update = True
     has_select_for_update_nowait = True
     can_return_id_from_insert = True
@@ -691,9 +690,14 @@ class DatabaseWrapper(BaseDatabaseWrapper):
         "Returns a new instance of this backend's SchemaEditor"
         return DatabaseSchemaEditor(self, *args, **kwargs)
 
-    # Oracle doesn't support savepoint commits.  Ignore them.
+    # Oracle doesn't support releasing savepoints. But we fake them when query
+    # logging is enabled to keep query counts consistent with other backends.
     def _savepoint_commit(self, sid):
-        pass
+        if self.queries_logged:
+            self.queries_log.append({
+                'sql': '-- RELEASE SAVEPOINT %s (faked)' % self.ops.quote_name(sid),
+                'time': '0.000',
+            })
 
     def _set_autocommit(self, autocommit):
         with self.wrap_database_errors:
diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py
index 21f1eb818c..957c7cd033 100644
--- a/tests/admin_views/tests.py
+++ b/tests/admin_views/tests.py
@@ -3962,11 +3962,7 @@ class UserAdminTest(TestCase):
         # Don't depend on a warm cache, see #17377.
         ContentType.objects.clear_cache()
 
-        expected_queries = 10
-        if not connection.features.can_release_savepoints:
-            expected_queries -= 1
-
-        with self.assertNumQueries(expected_queries):
+        with self.assertNumQueries(10):
             response = self.client.get('/test_admin/admin/auth/user/%s/' % u.pk)
             self.assertEqual(response.status_code, 200)
 
@@ -4003,12 +3999,7 @@ class GroupAdminTest(TestCase):
 
     def test_group_permission_performance(self):
         g = Group.objects.create(name="test_group")
-
-        expected_queries = 8
-        if not connection.features.can_release_savepoints:
-            expected_queries -= 1
-
-        with self.assertNumQueries(expected_queries):
+        with self.assertNumQueries(8):
             response = self.client.get('/test_admin/admin/auth/group/%s/' % g.pk)
             self.assertEqual(response.status_code, 200)