diff options
| author | suraj <suraj.shaw@oracle.com> | 2024-09-10 20:56:16 +0530 |
|---|---|---|
| committer | Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> | 2024-12-17 11:26:32 +0100 |
| commit | 0d9872fc9a70ef6966930c68c68febea7eb60ede (patch) | |
| tree | eb61a0623f7c0bceb5eeb05c36839cfa98cb2d64 /django | |
| parent | 2249370c8611d97f8bdb6003fb7b4d8fd3646202 (diff) | |
Fixed #7732 -- Added support for connection pools on Oracle.
Diffstat (limited to 'django')
| -rw-r--r-- | django/db/backends/oracle/base.py | 52 | ||||
| -rw-r--r-- | django/db/backends/oracle/creation.py | 15 | ||||
| -rw-r--r-- | django/db/backends/oracle/features.py | 19 |
3 files changed, 80 insertions, 6 deletions
diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py index df78d9ba27..3b37c38f97 100644 --- a/django/db/backends/oracle/base.py +++ b/django/db/backends/oracle/base.py @@ -14,6 +14,7 @@ from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.db import IntegrityError 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.utils.asyncio import async_unsafe from django.utils.encoding import force_bytes, force_str @@ -235,6 +236,7 @@ class DatabaseWrapper(BaseDatabaseWrapper): introspection_class = DatabaseIntrospection ops_class = DatabaseOperations validation_class = DatabaseValidation + _connection_pools = {} def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -243,10 +245,52 @@ class DatabaseWrapper(BaseDatabaseWrapper): ) self.features.can_return_columns_from_insert = use_returning_into + @property + def is_pool(self): + return self.settings_dict["OPTIONS"].get("pool", False) + + @property + def pool(self): + if not self.is_pool: + return None + + if self.settings_dict.get("CONN_MAX_AGE", 0) != 0: + raise ImproperlyConfigured( + "Pooling doesn't support persistent connections." + ) + + pool_key = (self.alias, self.settings_dict["USER"]) + if pool_key not in self._connection_pools: + connect_kwargs = self.get_connection_params() + pool_options = connect_kwargs.pop("pool") + if pool_options is not True: + connect_kwargs.update(pool_options) + + pool = Database.create_pool( + user=self.settings_dict["USER"], + password=self.settings_dict["PASSWORD"], + dsn=dsn(self.settings_dict), + **connect_kwargs, + ) + self._connection_pools.setdefault(pool_key, pool) + + return self._connection_pools[pool_key] + + def close_pool(self): + if self.pool: + self.pool.close(force=True) + pool_key = (self.alias, self.settings_dict["USER"]) + del self._connection_pools[pool_key] + def get_database_version(self): return self.oracle_version 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() if "use_returning_into" in conn_params: del conn_params["use_returning_into"] @@ -254,6 +298,8 @@ class DatabaseWrapper(BaseDatabaseWrapper): @async_unsafe def get_new_connection(self, conn_params): + if self.pool: + return self.pool.acquire() return Database.connect( user=self.settings_dict["USER"], password=self.settings_dict["PASSWORD"], @@ -345,6 +391,12 @@ class DatabaseWrapper(BaseDatabaseWrapper): else: return True + def close_if_health_check_failed(self): + if self.pool: + # The pool only returns healthy connections. + return + return super().close_if_health_check_failed() + @cached_property def oracle_version(self): with self.temporary_connection(): diff --git a/django/db/backends/oracle/creation.py b/django/db/backends/oracle/creation.py index b0a5177728..682379930f 100644 --- a/django/db/backends/oracle/creation.py +++ b/django/db/backends/oracle/creation.py @@ -205,13 +205,15 @@ class DatabaseCreation(BaseDatabaseCreation): Destroy a test database, prompting the user for confirmation if the database already exists. Return the name of the test database created. """ - self.connection.settings_dict["USER"] = self.connection.settings_dict[ - "SAVED_USER" - ] - self.connection.settings_dict["PASSWORD"] = self.connection.settings_dict[ - "SAVED_PASSWORD" - ] + if not self.connection.is_pool: + self.connection.settings_dict["USER"] = self.connection.settings_dict[ + "SAVED_USER" + ] + self.connection.settings_dict["PASSWORD"] = self.connection.settings_dict[ + "SAVED_PASSWORD" + ] self.connection.close() + self.connection.close_pool() parameters = self._get_test_db_params() with self._maindb_connection.cursor() as cursor: if self._test_user_create(): @@ -223,6 +225,7 @@ class DatabaseCreation(BaseDatabaseCreation): self.log("Destroying test database tables...") self._execute_test_db_destruction(cursor, parameters, verbosity) self._maindb_connection.close() + self._maindb_connection.close_pool() def _execute_test_db_creation(self, cursor, parameters, verbosity, keepdb=False): if verbosity >= 2: diff --git a/django/db/backends/oracle/features.py b/django/db/backends/oracle/features.py index 72c6180f50..ad9ab8da55 100644 --- a/django/db/backends/oracle/features.py +++ b/django/db/backends/oracle/features.py @@ -139,6 +139,25 @@ class DatabaseFeatures(BaseDatabaseFeatures): }, } ) + if self.connection.is_pool: + skips.update( + { + "Pooling does not support persistent connections": { + "backends.base.test_base.ConnectionHealthChecksTests." + "test_health_checks_enabled", + "backends.base.test_base.ConnectionHealthChecksTests." + "test_health_checks_enabled_errors_occurred", + "backends.base.test_base.ConnectionHealthChecksTests." + "test_health_checks_disabled", + "backends.base.test_base.ConnectionHealthChecksTests." + "test_set_autocommit_health_checks_enabled", + "servers.tests.LiveServerTestCloseConnectionTest." + "test_closes_connections", + "backends.oracle.tests.TransactionalTests." + "test_password_with_at_sign", + }, + } + ) if is_oracledb and self.connection.oracledb_version >= (2, 1, 2): skips.update( { |
