summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2021-02-02 21:34:36 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-02-02 21:35:35 +0100
commit7d658893450eb999f828c53a8e4efa03dff65cf3 (patch)
treed018c9551774574d0b9568ef0411aaf09ff808d9
parenteab0b8b8045b2a63109f40f755c9f0a220e660fd (diff)
downloaddjango-7d658893450eb999f828c53a8e4efa03dff65cf3.tar.gz
[3.2.x] Fixed #32403 -- Fixed re-raising DatabaseErrors when using only 'postgres' database.
Thanks Kazantcev Andrey for the report. Regression in f48f671223a20b161ca819cf7d6298e43b8ba5fe. Backport of f131841c601b9d4884adcdb284b4213c2ad89231 from master
-rw-r--r--django/db/backends/postgresql/base.py3
-rw-r--r--docs/releases/3.1.7.txt4
-rw-r--r--tests/backends/postgresql/tests.py50
3 files changed, 55 insertions, 2 deletions
diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py
index c752b5dba4..a8efb0e080 100644
--- a/django/db/backends/postgresql/base.py
+++ b/django/db/backends/postgresql/base.py
@@ -320,6 +320,9 @@ class DatabaseWrapper(BaseDatabaseWrapper):
yield cursor
finally:
conn.close()
+ break
+ else:
+ raise
@cached_property
def pg_version(self):
diff --git a/docs/releases/3.1.7.txt b/docs/releases/3.1.7.txt
index f6be18b0e8..1ef16b76c7 100644
--- a/docs/releases/3.1.7.txt
+++ b/docs/releases/3.1.7.txt
@@ -9,4 +9,6 @@ Django 3.1.7 fixes several bugs in 3.1.6.
Bugfixes
========
-* ...
+* Fixed a regression in Django 3.1 that caused ``RuntimeError`` instead of
+ connection errors when using only the ``'postgres'`` database
+ (:ticket:`32403`).
diff --git a/tests/backends/postgresql/tests.py b/tests/backends/postgresql/tests.py
index 8d0a801ea2..c37b83bb90 100644
--- a/tests/backends/postgresql/tests.py
+++ b/tests/backends/postgresql/tests.py
@@ -1,9 +1,10 @@
+import copy
import unittest
from io import StringIO
from unittest import mock
from django.core.exceptions import ImproperlyConfigured
-from django.db import DatabaseError, connection, connections
+from django.db import DEFAULT_DB_ALIAS, DatabaseError, connection, connections
from django.db.backends.base.base import BaseDatabaseWrapper
from django.test import TestCase, override_settings
@@ -54,6 +55,53 @@ class Tests(TestCase):
self.assertIsNone(cursor.db.connection)
self.assertIsNotNone(cursor.db.settings_dict['NAME'])
self.assertEqual(cursor.db.settings_dict['NAME'], connections['other'].settings_dict['NAME'])
+ # Cursor is yielded only for the first PostgreSQL database.
+ with self.assertWarnsMessage(RuntimeWarning, msg):
+ with mock.patch(
+ 'django.db.backends.base.base.BaseDatabaseWrapper.connect',
+ side_effect=mocked_connect,
+ autospec=True,
+ ):
+ with connection._nodb_cursor() as cursor:
+ self.assertIs(cursor.closed, False)
+ self.assertIsNotNone(cursor.db.connection)
+
+ def test_nodb_cursor_raises_postgres_authentication_failure(self):
+ """
+ _nodb_cursor() re-raises authentication failure to the 'postgres' db
+ when other connection to the PostgreSQL database isn't available.
+ """
+ def mocked_connect(self):
+ raise DatabaseError()
+
+ def mocked_all(self):
+ test_connection = copy.copy(connections[DEFAULT_DB_ALIAS])
+ test_connection.settings_dict = copy.deepcopy(connection.settings_dict)
+ test_connection.settings_dict['NAME'] = 'postgres'
+ return [test_connection]
+
+ msg = (
+ "Normally Django will use a connection to the 'postgres' database "
+ "to avoid running initialization queries against the production "
+ "database when it's not needed (for example, when running tests). "
+ "Django was unable to create a connection to the 'postgres' "
+ "database and will use the first PostgreSQL database instead."
+ )
+ with self.assertWarnsMessage(RuntimeWarning, msg):
+ mocker_connections_all = mock.patch(
+ 'django.utils.connection.BaseConnectionHandler.all',
+ side_effect=mocked_all,
+ autospec=True,
+ )
+ mocker_connect = mock.patch(
+ 'django.db.backends.base.base.BaseDatabaseWrapper.connect',
+ side_effect=mocked_connect,
+ autospec=True,
+ )
+ with mocker_connections_all, mocker_connect:
+ with self.assertRaises(DatabaseError):
+ with connection._nodb_cursor():
+ pass
def test_database_name_too_long(self):
from django.db.backends.postgresql.base import DatabaseWrapper