Fixed #27649 -- Bumped required cx_Oracle to 5.2.
Removed obsolete workarounds from1aa4889808
anddcf3be7a62
.
This commit is contained in:
parent
5eff8a7783
commit
fae56427e1
|
@ -62,7 +62,7 @@ from .features import DatabaseFeatures # NOQA isort:skip
|
||||||
from .introspection import DatabaseIntrospection # NOQA isort:skip
|
from .introspection import DatabaseIntrospection # NOQA isort:skip
|
||||||
from .operations import DatabaseOperations # NOQA isort:skip
|
from .operations import DatabaseOperations # NOQA isort:skip
|
||||||
from .schema import DatabaseSchemaEditor # NOQA isort:skip
|
from .schema import DatabaseSchemaEditor # NOQA isort:skip
|
||||||
from .utils import Oracle_datetime, convert_unicode # NOQA isort:skip
|
from .utils import Oracle_datetime # NOQA isort:skip
|
||||||
|
|
||||||
|
|
||||||
class _UninitializedOperatorsDescriptor(object):
|
class _UninitializedOperatorsDescriptor(object):
|
||||||
|
@ -208,8 +208,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
return conn_params
|
return conn_params
|
||||||
|
|
||||||
def get_new_connection(self, conn_params):
|
def get_new_connection(self, conn_params):
|
||||||
conn_string = convert_unicode(self._connect_string())
|
return Database.connect(self._connect_string(), **conn_params)
|
||||||
return Database.connect(conn_string, **conn_params)
|
|
||||||
|
|
||||||
def init_connection_state(self):
|
def init_connection_state(self):
|
||||||
cursor = self.create_cursor()
|
cursor = self.create_cursor()
|
||||||
|
@ -246,13 +245,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
self.operators = self._standard_operators
|
self.operators = self._standard_operators
|
||||||
self.pattern_ops = self._standard_pattern_ops
|
self.pattern_ops = self._standard_pattern_ops
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
self.connection.stmtcachesize = 20
|
||||||
try:
|
|
||||||
self.connection.stmtcachesize = 20
|
|
||||||
except AttributeError:
|
|
||||||
# Django docs specify cx_Oracle version 4.3.1 or higher, but
|
|
||||||
# stmtcachesize is available only in 4.3.2 and up.
|
|
||||||
pass
|
|
||||||
# Ensure all changes are preserved even when AUTOCOMMIT is False.
|
# Ensure all changes are preserved even when AUTOCOMMIT is False.
|
||||||
if not self.get_autocommit():
|
if not self.get_autocommit():
|
||||||
self.commit()
|
self.commit()
|
||||||
|
@ -265,7 +258,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
try:
|
try:
|
||||||
return self.connection.commit()
|
return self.connection.commit()
|
||||||
except Database.DatabaseError as e:
|
except Database.DatabaseError as e:
|
||||||
# cx_Oracle 5.0.4 raises a cx_Oracle.DatabaseError exception
|
# cx_Oracle raises a cx_Oracle.DatabaseError exception
|
||||||
# with the following attributes and values:
|
# with the following attributes and values:
|
||||||
# code = 2091
|
# code = 2091
|
||||||
# message = 'ORA-02091: transaction rolled back
|
# message = 'ORA-02091: transaction rolled back
|
||||||
|
@ -363,7 +356,7 @@ class OracleParam(object):
|
||||||
else:
|
else:
|
||||||
# To transmit to the database, we need Unicode if supported
|
# To transmit to the database, we need Unicode if supported
|
||||||
# To get size right, we must consider bytes.
|
# To get size right, we must consider bytes.
|
||||||
self.force_bytes = convert_unicode(param, cursor.charset, strings_only)
|
self.force_bytes = force_text(param, cursor.charset, strings_only)
|
||||||
if isinstance(self.force_bytes, six.string_types):
|
if isinstance(self.force_bytes, six.string_types):
|
||||||
# We could optimize by only converting up to 4000 bytes here
|
# We could optimize by only converting up to 4000 bytes here
|
||||||
string_size = len(force_bytes(param, cursor.charset, strings_only))
|
string_size = len(force_bytes(param, cursor.charset, strings_only))
|
||||||
|
@ -459,11 +452,11 @@ class FormatStylePlaceholderCursor(object):
|
||||||
query = query[:-1]
|
query = query[:-1]
|
||||||
if params is None:
|
if params is None:
|
||||||
params = []
|
params = []
|
||||||
query = convert_unicode(query, self.charset)
|
query = query
|
||||||
elif hasattr(params, 'keys'):
|
elif hasattr(params, 'keys'):
|
||||||
# Handle params as dict
|
# Handle params as dict
|
||||||
args = {k: ":%s" % k for k in params.keys()}
|
args = {k: ":%s" % k for k in params.keys()}
|
||||||
query = convert_unicode(query % args, self.charset)
|
query = query % args
|
||||||
elif unify_by_values and len(params) > 0:
|
elif unify_by_values and len(params) > 0:
|
||||||
# Handle params as a dict with unified query parameters by their
|
# Handle params as a dict with unified query parameters by their
|
||||||
# values. It can be used only in single query execute() because
|
# values. It can be used only in single query execute() because
|
||||||
|
@ -480,23 +473,17 @@ class FormatStylePlaceholderCursor(object):
|
||||||
params_dict = {param: ':arg%d' % i for i, param in enumerate(set(params))}
|
params_dict = {param: ':arg%d' % i for i, param in enumerate(set(params))}
|
||||||
args = [params_dict[param] for param in params]
|
args = [params_dict[param] for param in params]
|
||||||
params = dict(zip(params_dict.values(), list(zip(*params_dict.keys()))[0]))
|
params = dict(zip(params_dict.values(), list(zip(*params_dict.keys()))[0]))
|
||||||
query = convert_unicode(query % tuple(args), self.charset)
|
query = query % tuple(args)
|
||||||
else:
|
else:
|
||||||
# Handle params as sequence
|
# Handle params as sequence
|
||||||
args = [(':arg%d' % i) for i in range(len(params))]
|
args = [(':arg%d' % i) for i in range(len(params))]
|
||||||
query = convert_unicode(query % tuple(args), self.charset)
|
query = query % tuple(args)
|
||||||
return query, self._format_params(params)
|
return force_text(query, self.charset), self._format_params(params)
|
||||||
|
|
||||||
def execute(self, query, params=None):
|
def execute(self, query, params=None):
|
||||||
query, params = self._fix_for_params(query, params, unify_by_values=True)
|
query, params = self._fix_for_params(query, params, unify_by_values=True)
|
||||||
self._guess_input_sizes([params])
|
self._guess_input_sizes([params])
|
||||||
try:
|
return self.cursor.execute(query, self._param_generator(params))
|
||||||
return self.cursor.execute(query, self._param_generator(params))
|
|
||||||
except Database.DatabaseError as e:
|
|
||||||
# cx_Oracle <= 4.4.0 wrongly raises a DatabaseError for ORA-01400.
|
|
||||||
if hasattr(e.args[0], 'code') and e.args[0].code == 1400 and not isinstance(e, Database.IntegrityError):
|
|
||||||
six.reraise(utils.IntegrityError, utils.IntegrityError(*tuple(e.args)), sys.exc_info()[2])
|
|
||||||
raise
|
|
||||||
|
|
||||||
def executemany(self, query, params=None):
|
def executemany(self, query, params=None):
|
||||||
if not params:
|
if not params:
|
||||||
|
@ -509,13 +496,7 @@ class FormatStylePlaceholderCursor(object):
|
||||||
# more than once, we can't make it lazy by using a generator
|
# more than once, we can't make it lazy by using a generator
|
||||||
formatted = [firstparams] + [self._format_params(p) for p in params_iter]
|
formatted = [firstparams] + [self._format_params(p) for p in params_iter]
|
||||||
self._guess_input_sizes(formatted)
|
self._guess_input_sizes(formatted)
|
||||||
try:
|
return self.cursor.executemany(query, [self._param_generator(p) for p in formatted])
|
||||||
return self.cursor.executemany(query, [self._param_generator(p) for p in formatted])
|
|
||||||
except Database.DatabaseError as e:
|
|
||||||
# cx_Oracle <= 4.4.0 wrongly raises a DatabaseError for ORA-01400.
|
|
||||||
if hasattr(e.args[0], 'code') and e.args[0].code == 1400 and not isinstance(e, Database.IntegrityError):
|
|
||||||
six.reraise(utils.IntegrityError, utils.IntegrityError(*tuple(e.args)), sys.exc_info()[2])
|
|
||||||
raise
|
|
||||||
|
|
||||||
def fetchone(self):
|
def fetchone(self):
|
||||||
row = self.cursor.fetchone()
|
row = self.cursor.fetchone()
|
||||||
|
|
|
@ -11,7 +11,7 @@ from django.utils import six, timezone
|
||||||
from django.utils.encoding import force_bytes, force_text
|
from django.utils.encoding import force_bytes, force_text
|
||||||
|
|
||||||
from .base import Database
|
from .base import Database
|
||||||
from .utils import InsertIdVar, Oracle_datetime, convert_unicode
|
from .utils import InsertIdVar, Oracle_datetime
|
||||||
|
|
||||||
|
|
||||||
class DatabaseOperations(BaseDatabaseOperations):
|
class DatabaseOperations(BaseDatabaseOperations):
|
||||||
|
@ -310,10 +310,10 @@ WHEN (new.%(col_name)s IS NULL)
|
||||||
return "RETURNING %s INTO %%s", (InsertIdVar(),)
|
return "RETURNING %s INTO %%s", (InsertIdVar(),)
|
||||||
|
|
||||||
def savepoint_create_sql(self, sid):
|
def savepoint_create_sql(self, sid):
|
||||||
return convert_unicode("SAVEPOINT " + self.quote_name(sid))
|
return "SAVEPOINT " + self.quote_name(sid)
|
||||||
|
|
||||||
def savepoint_rollback_sql(self, sid):
|
def savepoint_rollback_sql(self, sid):
|
||||||
return convert_unicode("ROLLBACK TO SAVEPOINT " + self.quote_name(sid))
|
return "ROLLBACK TO SAVEPOINT " + self.quote_name(sid)
|
||||||
|
|
||||||
def sql_flush(self, style, tables, sequences, allow_cascade=False):
|
def sql_flush(self, style, tables, sequences, allow_cascade=False):
|
||||||
# Return a list of 'TRUNCATE x;', 'TRUNCATE y;',
|
# Return a list of 'TRUNCATE x;', 'TRUNCATE y;',
|
||||||
|
|
|
@ -1,18 +1,7 @@
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from django.utils.encoding import force_bytes, force_text
|
|
||||||
|
|
||||||
from .base import Database
|
from .base import Database
|
||||||
|
|
||||||
# Check whether cx_Oracle was compiled with the WITH_UNICODE option if cx_Oracle is pre-5.1. This will
|
|
||||||
# also be True for cx_Oracle 5.1 and in Python 3.0. See #19606
|
|
||||||
if int(Database.version.split('.', 1)[0]) >= 5 and \
|
|
||||||
(int(Database.version.split('.', 2)[1]) >= 1 or
|
|
||||||
not hasattr(Database, 'UNICODE')):
|
|
||||||
convert_unicode = force_text
|
|
||||||
else:
|
|
||||||
convert_unicode = force_bytes
|
|
||||||
|
|
||||||
|
|
||||||
class InsertIdVar(object):
|
class InsertIdVar(object):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -731,17 +731,7 @@ Oracle notes
|
||||||
============
|
============
|
||||||
|
|
||||||
Django supports `Oracle Database Server`_ versions 11.2 and higher. Version
|
Django supports `Oracle Database Server`_ versions 11.2 and higher. Version
|
||||||
4.3.1 or higher of the `cx_Oracle`_ Python driver is required, although we
|
5.2 or higher of the `cx_Oracle`_ Python driver is required.
|
||||||
recommend version 5.1.3 or later as these versions support Python 3.
|
|
||||||
|
|
||||||
Note that due to a Unicode-corruption bug in ``cx_Oracle`` 5.0, that
|
|
||||||
version of the driver should **not** be used with Django;
|
|
||||||
``cx_Oracle`` 5.0.1 resolved this issue, so if you'd like to use a
|
|
||||||
more recent ``cx_Oracle``, use version 5.0.1.
|
|
||||||
|
|
||||||
``cx_Oracle`` 5.0.1 or greater can optionally be compiled with the
|
|
||||||
``WITH_UNICODE`` environment variable. This is recommended but not
|
|
||||||
required.
|
|
||||||
|
|
||||||
.. _`Oracle Database Server`: http://www.oracle.com/
|
.. _`Oracle Database Server`: http://www.oracle.com/
|
||||||
.. _`cx_Oracle`: http://cx-oracle.sourceforge.net/
|
.. _`cx_Oracle`: http://cx-oracle.sourceforge.net/
|
||||||
|
|
|
@ -698,6 +698,8 @@ Miscellaneous
|
||||||
leaves ``request.POST`` immutable. If you're modifying that ``QueryDict``,
|
leaves ``request.POST`` immutable. If you're modifying that ``QueryDict``,
|
||||||
you must now first copy it, e.g. ``request.POST.copy()``.
|
you must now first copy it, e.g. ``request.POST.copy()``.
|
||||||
|
|
||||||
|
* Support for ``cx_Oracle`` < 5.2 is removed.
|
||||||
|
|
||||||
.. _deprecated-features-1.11:
|
.. _deprecated-features-1.11:
|
||||||
|
|
||||||
Features deprecated in 1.11
|
Features deprecated in 1.11
|
||||||
|
|
|
@ -86,11 +86,8 @@ class OracleTests(unittest.TestCase):
|
||||||
def test_dbms_session(self):
|
def test_dbms_session(self):
|
||||||
# If the backend is Oracle, test that we can call a standard
|
# If the backend is Oracle, test that we can call a standard
|
||||||
# stored procedure through our cursor wrapper.
|
# stored procedure through our cursor wrapper.
|
||||||
from django.db.backends.oracle.base import convert_unicode
|
|
||||||
|
|
||||||
with connection.cursor() as cursor:
|
with connection.cursor() as cursor:
|
||||||
cursor.callproc(convert_unicode('DBMS_SESSION.SET_IDENTIFIER'),
|
cursor.callproc('DBMS_SESSION.SET_IDENTIFIER', ['_django_testing!'])
|
||||||
[convert_unicode('_django_testing!')])
|
|
||||||
|
|
||||||
def test_cursor_var(self):
|
def test_cursor_var(self):
|
||||||
# If the backend is Oracle, test that we can pass cursor variables
|
# If the backend is Oracle, test that we can pass cursor variables
|
||||||
|
|
Loading…
Reference in New Issue