From 3518d51697f1f2e0a516cd82dfc6e05f9f686dab Mon Sep 17 00:00:00 2001
From: Josh Smeaton <josh.smeaton@gmail.com>
Date: Tue, 10 Feb 2015 10:54:51 +1100
Subject: [PATCH] [1.8.x] Fixed #24200 -- Made introspection bypass statement
 cache

Backport of 1fbe8a2de3 from master
---
 django/db/backends/oracle/features.py      | 1 -
 django/db/backends/oracle/introspection.py | 7 ++++++-
 django/db/backends/oracle/schema.py        | 3 ---
 docs/releases/1.8.txt                      | 4 ++++
 4 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/django/db/backends/oracle/features.py b/django/db/backends/oracle/features.py
index 93c0beaf1e..80744d6e1c 100644
--- a/django/db/backends/oracle/features.py
+++ b/django/db/backends/oracle/features.py
@@ -34,7 +34,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     supports_combined_alters = False
     nulls_order_largest = True
     requires_literal_defaults = True
-    connection_persists_old_columns = True
     closed_cursor_error_class = InterfaceError
     bare_select_suffix = " FROM DUAL"
     uppercases_column_names = True
diff --git a/django/db/backends/oracle/introspection.py b/django/db/backends/oracle/introspection.py
index 3596368b6b..c058418ec3 100644
--- a/django/db/backends/oracle/introspection.py
+++ b/django/db/backends/oracle/introspection.py
@@ -33,6 +33,8 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
     except AttributeError:
         pass
 
+    cache_bust_counter = 1
+
     def get_field_type(self, data_type, description):
         # If it's a NUMBER with scale == 0, consider it an IntegerField
         if data_type == cx_Oracle.NUMBER:
@@ -59,7 +61,10 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
 
     def get_table_description(self, cursor, table_name):
         "Returns a description of the table, with the DB-API cursor.description interface."
-        cursor.execute("SELECT * FROM %s WHERE ROWNUM < 2" % self.connection.ops.quote_name(table_name))
+        self.cache_bust_counter += 1
+        cursor.execute("SELECT * FROM {} WHERE ROWNUM < 2 AND {} > 0".format(
+            self.connection.ops.quote_name(table_name),
+            self.cache_bust_counter))
         description = []
         for desc in cursor.description:
             name = force_text(desc[0])  # cx_Oracle always returns a 'str' on both Python 2 and 3
diff --git a/django/db/backends/oracle/schema.py b/django/db/backends/oracle/schema.py
index fa710dc443..e4b02fcc7b 100644
--- a/django/db/backends/oracle/schema.py
+++ b/django/db/backends/oracle/schema.py
@@ -87,9 +87,6 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
         self.remove_field(model, old_field)
         # Rename the new field
         self.alter_field(model, new_temp_field, new_field)
-        # Close the connection to force cx_Oracle to get column types right
-        # on a new cursor
-        self.connection.close()
 
     def normalize_name(self, name):
         """
diff --git a/docs/releases/1.8.txt b/docs/releases/1.8.txt
index ac1dd36374..e24426d4c1 100644
--- a/docs/releases/1.8.txt
+++ b/docs/releases/1.8.txt
@@ -286,6 +286,10 @@ Database backends
 * The MySQL backend no longer creates explicit indexes for foreign keys when
   using the InnoDB storage engine, as MySQL already creates them automatically.
 
+* The Oracle backend no longer defines the ``connection_persists_old_columns``
+  feature as ``True``. Instead, Oracle will now include a cache busting clause
+  when getting the description of a table.
+
 Email
 ^^^^^