mirror of
https://github.com/django/django.git
synced 2025-03-12 18:30:48 +00:00
Refs #33817 -- Removed support for cx_Oracle per deprecation timeline.
This commit is contained in:
parent
0a0f9b4acc
commit
b4bc393b23
@ -1,6 +1,7 @@
|
|||||||
|
import oracledb
|
||||||
|
|
||||||
from django.contrib.gis.db.backends.base.adapter import WKTAdapter
|
from django.contrib.gis.db.backends.base.adapter import WKTAdapter
|
||||||
from django.contrib.gis.geos import GeometryCollection, Polygon
|
from django.contrib.gis.geos import GeometryCollection, Polygon
|
||||||
from django.db.backends.oracle.oracledb_any import oracledb
|
|
||||||
|
|
||||||
|
|
||||||
class OracleSpatialAdapter(WKTAdapter):
|
class OracleSpatialAdapter(WKTAdapter):
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
import oracledb
|
||||||
|
|
||||||
from django.db.backends.oracle.introspection import DatabaseIntrospection
|
from django.db.backends.oracle.introspection import DatabaseIntrospection
|
||||||
from django.db.backends.oracle.oracledb_any import oracledb
|
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ from django.conf import settings
|
|||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.db import IntegrityError
|
from django.db import IntegrityError
|
||||||
from django.db.backends.base.base import BaseDatabaseWrapper
|
from django.db.backends.base.base import BaseDatabaseWrapper
|
||||||
from django.db.backends.oracle.oracledb_any import is_oracledb
|
|
||||||
from django.db.backends.utils import debug_transaction
|
from django.db.backends.utils import debug_transaction
|
||||||
from django.utils.asyncio import async_unsafe
|
from django.utils.asyncio import async_unsafe
|
||||||
from django.utils.encoding import force_bytes, force_str
|
from django.utils.encoding import force_bytes, force_str
|
||||||
@ -22,7 +21,7 @@ from django.utils.functional import cached_property
|
|||||||
from django.utils.version import get_version_tuple
|
from django.utils.version import get_version_tuple
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from django.db.backends.oracle.oracledb_any import oracledb as Database
|
import oracledb as Database
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
raise ImproperlyConfigured(f"Error loading oracledb module: {e}")
|
raise ImproperlyConfigured(f"Error loading oracledb module: {e}")
|
||||||
|
|
||||||
@ -286,11 +285,6 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
|||||||
return self.oracle_version
|
return self.oracle_version
|
||||||
|
|
||||||
def get_connection_params(self):
|
def get_connection_params(self):
|
||||||
# Pooling feature is only supported for oracledb.
|
|
||||||
if self.is_pool and not is_oracledb:
|
|
||||||
raise ImproperlyConfigured(
|
|
||||||
"Pooling isn't supported by cx_Oracle. Use python-oracledb instead."
|
|
||||||
)
|
|
||||||
conn_params = self.settings_dict["OPTIONS"].copy()
|
conn_params = self.settings_dict["OPTIONS"].copy()
|
||||||
if "use_returning_into" in conn_params:
|
if "use_returning_into" in conn_params:
|
||||||
del conn_params["use_returning_into"]
|
del conn_params["use_returning_into"]
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
from django.db import DatabaseError, InterfaceError
|
from django.db import DatabaseError, InterfaceError
|
||||||
from django.db.backends.base.features import BaseDatabaseFeatures
|
from django.db.backends.base.features import BaseDatabaseFeatures
|
||||||
from django.db.backends.oracle.oracledb_any import is_oracledb
|
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
|
||||||
|
|
||||||
@ -158,16 +157,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if is_oracledb and self.connection.oracledb_version >= (2, 1, 2):
|
|
||||||
skips.update(
|
|
||||||
{
|
|
||||||
"python-oracledb 2.1.2+ no longer hides 'ORA-1403: no data found' "
|
|
||||||
"exceptions raised in database triggers.": {
|
|
||||||
"backends.oracle.tests.TransactionalTests."
|
|
||||||
"test_hidden_no_data_found_exception"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
return skips
|
return skips
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
|
import oracledb
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.backends.base.introspection import BaseDatabaseIntrospection
|
from django.db.backends.base.introspection import BaseDatabaseIntrospection
|
||||||
from django.db.backends.base.introspection import FieldInfo as BaseFieldInfo
|
from django.db.backends.base.introspection import FieldInfo as BaseFieldInfo
|
||||||
from django.db.backends.base.introspection import TableInfo as BaseTableInfo
|
from django.db.backends.base.introspection import TableInfo as BaseTableInfo
|
||||||
from django.db.backends.oracle.oracledb_any import oracledb
|
|
||||||
|
|
||||||
FieldInfo = namedtuple(
|
FieldInfo = namedtuple(
|
||||||
"FieldInfo", BaseFieldInfo._fields + ("is_autofield", "is_json", "comment")
|
"FieldInfo", BaseFieldInfo._fields + ("is_autofield", "is_json", "comment")
|
||||||
|
@ -3,7 +3,7 @@ import uuid
|
|||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import DatabaseError, NotSupportedError
|
from django.db import NotSupportedError
|
||||||
from django.db.backends.base.operations import BaseDatabaseOperations
|
from django.db.backends.base.operations import BaseDatabaseOperations
|
||||||
from django.db.backends.utils import split_tzname_delta, strip_quotes, truncate_name
|
from django.db.backends.utils import split_tzname_delta, strip_quotes, truncate_name
|
||||||
from django.db.models import AutoField, Exists, ExpressionWrapper, Lookup
|
from django.db.models import AutoField, Exists, ExpressionWrapper, Lookup
|
||||||
@ -295,15 +295,6 @@ END;
|
|||||||
columns = []
|
columns = []
|
||||||
for param in returning_params:
|
for param in returning_params:
|
||||||
value = param.get_value()
|
value = param.get_value()
|
||||||
# Can be removed when cx_Oracle is no longer supported and
|
|
||||||
# python-oracle 2.1.2 becomes the minimum supported version.
|
|
||||||
if value == []:
|
|
||||||
raise DatabaseError(
|
|
||||||
"The database did not return a new row id. Probably "
|
|
||||||
'"ORA-1403: no data found" was raised internally but was '
|
|
||||||
"hidden by the Oracle OCI library (see "
|
|
||||||
"https://code.djangoproject.com/ticket/28859)."
|
|
||||||
)
|
|
||||||
columns.append(value[0])
|
columns.append(value[0])
|
||||||
return tuple(columns)
|
return tuple(columns)
|
||||||
|
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
import warnings
|
|
||||||
|
|
||||||
from django.utils.deprecation import RemovedInDjango60Warning
|
|
||||||
|
|
||||||
try:
|
|
||||||
import oracledb
|
|
||||||
|
|
||||||
is_oracledb = True
|
|
||||||
except ImportError as e:
|
|
||||||
try:
|
|
||||||
import cx_Oracle as oracledb # NOQA
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"cx_Oracle is deprecated. Use oracledb instead.",
|
|
||||||
RemovedInDjango60Warning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
is_oracledb = False
|
|
||||||
except ImportError:
|
|
||||||
raise e from None
|
|
@ -990,10 +990,6 @@ Oracle notes
|
|||||||
Django supports `Oracle Database Server`_ versions 19c and higher. Version
|
Django supports `Oracle Database Server`_ versions 19c and higher. Version
|
||||||
2.3.0 or higher of the `oracledb`_ Python driver is required.
|
2.3.0 or higher of the `oracledb`_ Python driver is required.
|
||||||
|
|
||||||
.. deprecated:: 5.0
|
|
||||||
|
|
||||||
Support for ``cx_Oracle`` is deprecated.
|
|
||||||
|
|
||||||
.. _`Oracle Database Server`: https://www.oracle.com/
|
.. _`Oracle Database Server`: https://www.oracle.com/
|
||||||
.. _`oracledb`: https://oracle.github.io/python-oracledb/
|
.. _`oracledb`: https://oracle.github.io/python-oracledb/
|
||||||
|
|
||||||
|
@ -281,6 +281,8 @@ to remove usage of these features.
|
|||||||
|
|
||||||
* The ``ForeignObject.get_reverse_joining_columns()`` method is be removed.
|
* The ``ForeignObject.get_reverse_joining_columns()`` method is be removed.
|
||||||
|
|
||||||
|
* Support for ``cx_Oracle`` is removed.
|
||||||
|
|
||||||
See :ref:`deprecated-features-5.1` for details on these changes, including how
|
See :ref:`deprecated-features-5.1` for details on these changes, including how
|
||||||
to remove usage of these features.
|
to remove usage of these features.
|
||||||
|
|
||||||
|
@ -3,16 +3,11 @@ import unittest
|
|||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.db import DatabaseError, NotSupportedError, ProgrammingError, connection
|
from django.db import NotSupportedError, ProgrammingError, connection
|
||||||
from django.db.models import BooleanField
|
from django.db.models import BooleanField
|
||||||
from django.test import TestCase, TransactionTestCase
|
from django.test import TestCase, TransactionTestCase
|
||||||
|
|
||||||
from ..models import Square, VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
|
from ..models import VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
|
||||||
|
|
||||||
try:
|
|
||||||
from django.db.backends.oracle.oracledb_any import is_oracledb
|
|
||||||
except ImportError:
|
|
||||||
is_oracledb = False
|
|
||||||
|
|
||||||
|
|
||||||
def no_pool_connection(alias=None):
|
def no_pool_connection(alias=None):
|
||||||
@ -85,7 +80,6 @@ class Tests(TestCase):
|
|||||||
connection.check_database_version_supported()
|
connection.check_database_version_supported()
|
||||||
self.assertTrue(mocked_get_database_version.called)
|
self.assertTrue(mocked_get_database_version.called)
|
||||||
|
|
||||||
@unittest.skipUnless(is_oracledb, "Pool specific tests")
|
|
||||||
def test_pool_set_to_true(self):
|
def test_pool_set_to_true(self):
|
||||||
new_connection = no_pool_connection(alias="default_pool")
|
new_connection = no_pool_connection(alias="default_pool")
|
||||||
new_connection.settings_dict["OPTIONS"]["pool"] = True
|
new_connection.settings_dict["OPTIONS"]["pool"] = True
|
||||||
@ -94,7 +88,6 @@ class Tests(TestCase):
|
|||||||
finally:
|
finally:
|
||||||
new_connection.close_pool()
|
new_connection.close_pool()
|
||||||
|
|
||||||
@unittest.skipUnless(is_oracledb, "Pool specific tests")
|
|
||||||
def test_pool_reuse(self):
|
def test_pool_reuse(self):
|
||||||
new_connection = no_pool_connection(alias="default_pool")
|
new_connection = no_pool_connection(alias="default_pool")
|
||||||
new_connection.settings_dict["OPTIONS"]["pool"] = {
|
new_connection.settings_dict["OPTIONS"]["pool"] = {
|
||||||
@ -128,7 +121,6 @@ class Tests(TestCase):
|
|||||||
conn.close()
|
conn.close()
|
||||||
new_connection.close_pool()
|
new_connection.close_pool()
|
||||||
|
|
||||||
@unittest.skipUnless(is_oracledb, "Pool specific tests")
|
|
||||||
def test_cannot_open_new_connection_in_atomic_block(self):
|
def test_cannot_open_new_connection_in_atomic_block(self):
|
||||||
new_connection = no_pool_connection(alias="default_pool")
|
new_connection = no_pool_connection(alias="default_pool")
|
||||||
new_connection.settings_dict["OPTIONS"]["pool"] = True
|
new_connection.settings_dict["OPTIONS"]["pool"] = True
|
||||||
@ -138,7 +130,6 @@ class Tests(TestCase):
|
|||||||
with self.assertRaisesMessage(ProgrammingError, msg):
|
with self.assertRaisesMessage(ProgrammingError, msg):
|
||||||
new_connection.ensure_connection()
|
new_connection.ensure_connection()
|
||||||
|
|
||||||
@unittest.skipUnless(is_oracledb, "Pool specific tests")
|
|
||||||
def test_pooling_not_support_persistent_connections(self):
|
def test_pooling_not_support_persistent_connections(self):
|
||||||
new_connection = no_pool_connection(alias="default_pool")
|
new_connection = no_pool_connection(alias="default_pool")
|
||||||
new_connection.settings_dict["OPTIONS"]["pool"] = True
|
new_connection.settings_dict["OPTIONS"]["pool"] = True
|
||||||
@ -147,48 +138,11 @@ class Tests(TestCase):
|
|||||||
with self.assertRaisesMessage(ImproperlyConfigured, msg):
|
with self.assertRaisesMessage(ImproperlyConfigured, msg):
|
||||||
new_connection.pool
|
new_connection.pool
|
||||||
|
|
||||||
@unittest.skipIf(is_oracledb, "cx_oracle specific tests")
|
|
||||||
def test_cx_Oracle_not_support_pooling(self):
|
|
||||||
new_connection = no_pool_connection()
|
|
||||||
new_connection.settings_dict["OPTIONS"]["pool"] = True
|
|
||||||
msg = "Pooling isn't supported by cx_Oracle. Use python-oracledb instead."
|
|
||||||
with self.assertRaisesMessage(ImproperlyConfigured, msg):
|
|
||||||
new_connection.connect()
|
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(connection.vendor == "oracle", "Oracle tests")
|
@unittest.skipUnless(connection.vendor == "oracle", "Oracle tests")
|
||||||
class TransactionalTests(TransactionTestCase):
|
class TransactionalTests(TransactionTestCase):
|
||||||
available_apps = ["backends"]
|
available_apps = ["backends"]
|
||||||
|
|
||||||
def test_hidden_no_data_found_exception(self):
|
|
||||||
# "ORA-1403: no data found" exception is hidden by Oracle OCI library
|
|
||||||
# when an INSERT statement is used with a RETURNING clause (see #28859).
|
|
||||||
with connection.cursor() as cursor:
|
|
||||||
# Create trigger that raises "ORA-1403: no data found".
|
|
||||||
cursor.execute(
|
|
||||||
"""
|
|
||||||
CREATE OR REPLACE TRIGGER "TRG_NO_DATA_FOUND"
|
|
||||||
AFTER INSERT ON "BACKENDS_SQUARE"
|
|
||||||
FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
RAISE NO_DATA_FOUND;
|
|
||||||
END;
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
with self.assertRaisesMessage(
|
|
||||||
DatabaseError,
|
|
||||||
(
|
|
||||||
'The database did not return a new row id. Probably "ORA-1403: no '
|
|
||||||
'data found" was raised internally but was hidden by the Oracle '
|
|
||||||
"OCI library (see https://code.djangoproject.com/ticket/28859)."
|
|
||||||
),
|
|
||||||
):
|
|
||||||
Square.objects.create(root=2, square=4)
|
|
||||||
finally:
|
|
||||||
with connection.cursor() as cursor:
|
|
||||||
cursor.execute('DROP TRIGGER "TRG_NO_DATA_FOUND"')
|
|
||||||
|
|
||||||
def test_password_with_at_sign(self):
|
def test_password_with_at_sign(self):
|
||||||
from django.db.backends.oracle.base import Database
|
from django.db.backends.oracle.base import Database
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user