diff --git a/NEWS b/NEWS index b48e932c..9e27a445 100644 --- a/NEWS +++ b/NEWS @@ -54,8 +54,6 @@ Other changes: - `~connection.isolation_level` doesn't read from the database but will return `~psycopg2.extensions.ISOLATION_LEVEL_DEFAULT` if no value was set on the connection. -- `~connection.set_isolation_level()` will throw an exception if executed - inside a transaction; previously it would have silently rolled it back. - Empty arrays no more converted into lists if they don't have a type attached (:ticket:`#506`) diff --git a/doc/src/connection.rst b/doc/src/connection.rst index c2a0c5ce..d554ce6d 100644 --- a/doc/src/connection.rst +++ b/doc/src/connection.rst @@ -480,8 +480,9 @@ The ``connection`` class .. note:: - From version 2.4.2, `set_session()` and `autocommit` offer - finer control on the transaction characteristics. + This is a legacy method mixing `~conn.isolation_level` and + `~conn.autocommit`. Using the respective properties is a better + option. Set the `transaction isolation level`_ for the current session. The level defines the different phenomena that can happen in the @@ -501,12 +502,6 @@ The ``connection`` class See also :ref:`transactions-control`. - .. versionchanged:: 2.7 - - the function must be called outside a transaction; previously it - would have executed an implicit :sql:`ROLLBACK`; it will now raise - an exception. - .. index:: pair: Client; Encoding diff --git a/psycopg/connection_type.c b/psycopg/connection_type.c index b09fdde7..df67c802 100644 --- a/psycopg/connection_type.c +++ b/psycopg/connection_type.c @@ -698,7 +698,9 @@ psyco_conn_set_isolation_level(connectionObject *self, PyObject *args) int level = 1; PyObject *pyval = NULL; - _set_session_checks(self, set_isolation_level); + EXC_IF_CONN_CLOSED(self); + EXC_IF_CONN_ASYNC(self, "isolation_level"); + EXC_IF_TPC_PREPARED(self, "isolation_level"); if (!PyArg_ParseTuple(args, "O", &pyval)) return NULL; @@ -717,6 +719,10 @@ psyco_conn_set_isolation_level(connectionObject *self, PyObject *args) } } + if (0 > conn_rollback(self)) { + return NULL; + } + if (level == 0) { if (0 > conn_set_session(self, 1, ISOLATION_LEVEL_DEFAULT, self->readonly, self->deferrable)) { diff --git a/tests/test_connection.py b/tests/test_connection.py index da0a588c..1d11ff16 100755 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -560,14 +560,34 @@ class IsolationLevelsTestCase(ConnectingTestCase): self.assertEqual(ext.TRANSACTION_STATUS_INTRANS, conn.get_transaction_status()) - # changed in psycopg 2.7 - self.assertRaises(psycopg2.ProgrammingError, - conn.set_isolation_level, - ext.ISOLATION_LEVEL_SERIALIZABLE) - self.assertEqual(ext.TRANSACTION_STATUS_INTRANS, + conn.set_isolation_level( + psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE) + self.assertEqual(psycopg2.extensions.TRANSACTION_STATUS_IDLE, conn.get_transaction_status()) + cur.execute("select count(*) from isolevel;") + self.assertEqual(0, cur.fetchone()[0]) + + cur.execute("insert into isolevel values (10);") + self.assertEqual(psycopg2.extensions.TRANSACTION_STATUS_INTRANS, + conn.get_transaction_status()) + conn.set_isolation_level( + psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT) + self.assertEqual(psycopg2.extensions.TRANSACTION_STATUS_IDLE, + conn.get_transaction_status()) + cur.execute("select count(*) from isolevel;") + self.assertEqual(0, cur.fetchone()[0]) + + cur.execute("insert into isolevel values (10);") + self.assertEqual(psycopg2.extensions.TRANSACTION_STATUS_IDLE, + conn.get_transaction_status()) + conn.set_isolation_level( + psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED) + self.assertEqual(psycopg2.extensions.TRANSACTION_STATUS_IDLE, + conn.get_transaction_status()) + cur.execute("select count(*) from isolevel;") + self.assertEqual(1, cur.fetchone()[0]) self.assertEqual(conn.isolation_level, - ext.ISOLATION_LEVEL_DEFAULT) + psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED) def test_isolation_level_autocommit(self): cnn1 = self.connect()