Skip to content

Commit

Permalink
Revert "'with' starts a transaction even on autocommit connections"
Browse files Browse the repository at this point in the history
This reverts commit e5ad0ab.
  • Loading branch information
etripier committed Jan 13, 2025
1 parent 5509e01 commit 596f529
Show file tree
Hide file tree
Showing 6 changed files with 12 additions and 127 deletions.
2 changes: 0 additions & 2 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,6 @@ What's new in psycopg 2.9.1
What's new in psycopg 2.9
-------------------------

- ``with connection`` starts a transaction on autocommit transactions too
(:ticket:`#941`).
- Timezones with fractional minutes are supported on Python 3.7 and following
(:ticket:`#1272`).
- Escape table and column names in `~cursor.copy_from()` and
Expand Down
3 changes: 0 additions & 3 deletions doc/src/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -842,9 +842,6 @@ and each ``with`` block is effectively wrapped in a separate transaction::
finally:
conn.close()

.. versionchanged:: 2.9
``with connection`` starts a transaction also on autocommit connections.


.. index::
pair: Server side; Cursor
Expand Down
3 changes: 0 additions & 3 deletions psycopg/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,6 @@ struct connectionObject {

/* the pid this connection was created into */
pid_t procpid;

/* inside a with block */
int entered;
};

/* map isolation level values into a numeric const */
Expand Down
17 changes: 1 addition & 16 deletions psycopg/connection_type.c
Original file line number Diff line number Diff line change
Expand Up @@ -407,22 +407,10 @@ psyco_conn_tpc_recover(connectionObject *self, PyObject *dummy)
static PyObject *
psyco_conn_enter(connectionObject *self, PyObject *dummy)
{
PyObject *rv = NULL;

EXC_IF_CONN_CLOSED(self);

if (self->entered) {
PyErr_SetString(ProgrammingError,
"the connection cannot be re-entered recursively");
goto exit;
}

self->entered = 1;
Py_INCREF(self);
rv = (PyObject *)self;

exit:
return rv;
return (PyObject *)self;
}


Expand All @@ -440,9 +428,6 @@ psyco_conn_exit(connectionObject *self, PyObject *args)
goto exit;
}

/* even if there will be an error, consider ourselves out */
self->entered = 0;

if (type == Py_None) {
if (!(tmp = PyObject_CallMethod((PyObject *)self, "commit", NULL))) {
goto exit;
Expand Down
27 changes: 11 additions & 16 deletions psycopg/pqpath.c
Original file line number Diff line number Diff line change
Expand Up @@ -348,19 +348,14 @@ pq_begin_locked(connectionObject *conn, PyThreadState **tstate)
char buf[256]; /* buf size must be same as bufsize */
int result;

Dprintf("pq_begin_locked: pgconn = %p, %d, status = %d",
Dprintf("pq_begin_locked: pgconn = %p, autocommit = %d, status = %d",
conn->pgconn, conn->autocommit, conn->status);

if (conn->status != CONN_STATUS_READY) {
if (conn->autocommit || conn->status != CONN_STATUS_READY) {
Dprintf("pq_begin_locked: transaction in progress");
return 0;
}

if (conn->autocommit && !conn->entered) {
Dprintf("pq_begin_locked: autocommit and no with block");
return 0;
}

if (conn->isolevel == ISOLATION_LEVEL_DEFAULT
&& conn->readonly == STATE_DEFAULT
&& conn->deferrable == STATE_DEFAULT) {
Expand Down Expand Up @@ -399,10 +394,10 @@ pq_commit(connectionObject *conn)
Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&conn->lock);

Dprintf("pq_commit: pgconn = %p, status = %d",
conn->pgconn, conn->status);
Dprintf("pq_commit: pgconn = %p, autocommit = %d, status = %d",
conn->pgconn, conn->autocommit, conn->status);

if (conn->status != CONN_STATUS_BEGIN) {
if (conn->autocommit || conn->status != CONN_STATUS_BEGIN) {
Dprintf("pq_commit: no transaction to commit");
retvalue = 0;
}
Expand Down Expand Up @@ -434,10 +429,10 @@ pq_abort_locked(connectionObject *conn, PyThreadState **tstate)
{
int retvalue = -1;

Dprintf("pq_abort_locked: pgconn = %p, status = %d",
conn->pgconn, conn->status);
Dprintf("pq_abort_locked: pgconn = %p, autocommit = %d, status = %d",
conn->pgconn, conn->autocommit, conn->status);

if (conn->status != CONN_STATUS_BEGIN) {
if (conn->autocommit || conn->status != CONN_STATUS_BEGIN) {
Dprintf("pq_abort_locked: no transaction to abort");
return 0;
}
Expand Down Expand Up @@ -496,12 +491,12 @@ pq_reset_locked(connectionObject *conn, PyThreadState **tstate)
{
int retvalue = -1;

Dprintf("pq_reset_locked: pgconn = %p, status = %d",
conn->pgconn, conn->status);
Dprintf("pq_reset_locked: pgconn = %p, autocommit = %d, status = %d",
conn->pgconn, conn->autocommit, conn->status);

conn->mark += 1;

if (conn->status == CONN_STATUS_BEGIN) {
if (!conn->autocommit && conn->status == CONN_STATUS_BEGIN) {
retvalue = pq_execute_command_locked(conn, "ABORT", tstate);
if (retvalue != 0) return retvalue;
}
Expand Down
87 changes: 0 additions & 87 deletions tests/test_with.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,93 +155,6 @@ def rollback(self):
curs.execute("select * from test_with")
self.assertEqual(curs.fetchall(), [])

def test_cant_reenter(self):
raised_ok = False
with self.conn:
try:
with self.conn:
pass
except psycopg2.ProgrammingError:
raised_ok = True

self.assert_(raised_ok)

# Still good
with self.conn:
pass

def test_with_autocommit(self):
self.conn.autocommit = True
self.assertEqual(
self.conn.info.transaction_status, ext.TRANSACTION_STATUS_IDLE
)
with self.conn:
curs = self.conn.cursor()
curs.execute("insert into test_with values (1)")
self.assertEqual(
self.conn.info.transaction_status,
ext.TRANSACTION_STATUS_INTRANS,
)

self.assertEqual(
self.conn.info.transaction_status, ext.TRANSACTION_STATUS_IDLE
)
curs.execute("select count(*) from test_with")
self.assertEqual(curs.fetchone()[0], 1)
self.assertEqual(
self.conn.info.transaction_status, ext.TRANSACTION_STATUS_IDLE
)

def test_with_autocommit_pyerror(self):
self.conn.autocommit = True
raised_ok = False
try:
with self.conn:
curs = self.conn.cursor()
curs.execute("insert into test_with values (2)")
self.assertEqual(
self.conn.info.transaction_status,
ext.TRANSACTION_STATUS_INTRANS,
)
1 / 0
except ZeroDivisionError:
raised_ok = True

self.assert_(raised_ok)
self.assertEqual(
self.conn.info.transaction_status, ext.TRANSACTION_STATUS_IDLE
)
curs.execute("select count(*) from test_with")
self.assertEqual(curs.fetchone()[0], 0)
self.assertEqual(
self.conn.info.transaction_status, ext.TRANSACTION_STATUS_IDLE
)

def test_with_autocommit_pgerror(self):
self.conn.autocommit = True
raised_ok = False
try:
with self.conn:
curs = self.conn.cursor()
curs.execute("insert into test_with values (2)")
self.assertEqual(
self.conn.info.transaction_status,
ext.TRANSACTION_STATUS_INTRANS,
)
curs.execute("insert into test_with values ('x')")
except psycopg2.errors.InvalidTextRepresentation:
raised_ok = True

self.assert_(raised_ok)
self.assertEqual(
self.conn.info.transaction_status, ext.TRANSACTION_STATUS_IDLE
)
curs.execute("select count(*) from test_with")
self.assertEqual(curs.fetchone()[0], 0)
self.assertEqual(
self.conn.info.transaction_status, ext.TRANSACTION_STATUS_IDLE
)


class WithCursorTestCase(WithTestCase):
def test_with_ok(self):
Expand Down

0 comments on commit 596f529

Please sign in to comment.