1
0
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:
Sarah Boyce 2024-12-12 17:56:14 +01:00
parent 0a0f9b4acc
commit b4bc393b23
10 changed files with 12 additions and 103 deletions

View File

@ -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):

View File

@ -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

View File

@ -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"]

View File

@ -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

View File

@ -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")

View File

@ -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)

View File

@ -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

View File

@ -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/

View File

@ -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.

View File

@ -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