-
-
Notifications
You must be signed in to change notification settings - Fork 504
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow to start transactions in autocommit mode #941
Comments
Hello Andres. I think there are a few things that can be done, yes. First a correction: it's a bit surprising but the connection context manager doesn't exit with close, but it terminates a transaction. I don't have code handy but I guess entering the CM with an autocommit transaction is a no-op. So I see two easy improvements:
In case of autocommit it would be better tracking the status using libpq Would you like to work on these changes in a MR? |
My current workaround (that relies on 3rd approach of @anarazel) to this issue is following: from contextlib import contextmanager
from typing import Iterator
from psycopg2.extensions import connection as PgConnection
@contextmanager
def transaction_in_autocommit_mode(connection: PgConnection) -> Iterator[None]:
connection.rollback()
connection.autocommit = False
try:
with connection:
yield
finally:
connection.autocommit = True Seems to be working as expected:
|
Based on @and-semakin's code I've created an elegant (IMHO) connection factory with autocommit and explicit transactions:
|
In the mean time, it could be cool to document the fact that, in |
This might be of interest: https://github.com/asqui/psycopg-nestedtransactions It's a Broadly similar to the |
We use There are certain Redshift commands that cannot run in a transaction. For example, |
I reproduce what @rachelcdavies is having as well on 2.9.1. I added Any solutions? I will need to rollback as well or stop using a with statement I guess Edit: Reverting to the old way with a
|
Yes, that's the way to do it: don't use a with block if you don't want a transaction to start. |
@dvarrazzo what if you want your connection to be cleaned up automatically? I guess I get changing the default behavior as that's more common, but |
@nicktimko using |
Remove context handler for connection. Complements psycopg/psycopg2#941.
Addresses aiidateam/aiida-core#5002: In v2.9, the context manager opens a transaction, but databases cannot be created within them. The fix is taken from: psycopg/psycopg2#941 (comment)
Psycopg 2.9 does uses transaction blocks withing context managers, which is not allowed for CREATE DATABASE psycopg/psycopg2#941
Psycopg 2.9 uses transaction blocks withing context managers, which is not allowed for CREATE DATABASE psycopg/psycopg2#941
Also just got bitten by this "feature" from psycopg2==2.9. I do not see any guidance in the documentation on how to turn off? For example, we are using: with psycopg2.connect(...) as cnx:
cnx.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
with cnx.cursor() as cursor:
# Create database.
try:
cursor.execute('CREATE DATABASE "name" WITH OWNER="owner";')
except psycopg2.errors.DuplicateDatabase as exc:
print(exc) Instead of |
@vsalvino Just don't use |
@dvarrazzo thanks for the quick reply... based on some further research I think we might take this as an opportunity to try out psycopg3, which seems to be able to disable the behavior in the connection. Linking here for others watching the thread: https://www.psycopg.org/psycopg3/docs/basic/transactions.html#autocommit-transactions |
@vsalvino Yes, unfortunately the psycopg2 connection context was not a happy design. Psycopg 3 might behave in a less surprising way. |
Bumps [psycopg2-binary](https://github.com/psycopg/psycopg2) from 2.9.1 to 2.9.2. <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/psycopg/psycopg2/blob/master/NEWS">psycopg2-binary's changelog</a>.</em></p> <blockquote> <h2>Current release</h2> <p>What's new in psycopg 2.9.2 ^^^^^^^^^^^^^^^^^^^^^^^^^^^</p> <ul> <li>Raise <code>ValueError</code> for dates >= Y10k (:ticket:<code>[#1307](https://github.com/psycopg/psycopg2/issues/1307)</code>).</li> <li><code>~psycopg2.errorcodes</code> map and <code>~psycopg2.errors</code> classes updated to PostgreSQL 14.</li> <li>Add preliminary support for Python 3.11 (:tickets:<code>[#1376](psycopg/psycopg2#1376), [#1386](https://github.com/psycopg/psycopg2/issues/1386)</code>).</li> <li>Wheel package compiled against OpenSSL 1.1.1l and PostgreSQL 14.1 (:ticket:<code>[#1388](https://github.com/psycopg/psycopg2/issues/1388)</code>).</li> </ul> <p>What's new in psycopg 2.9.1 ^^^^^^^^^^^^^^^^^^^^^^^^^^^</p> <p>Fix regression with named <code>sql.Placeholder</code> (:ticket:<code>[#1291](https://github.com/psycopg/psycopg2/issues/1291)</code>).</p> <h2>What's new in psycopg 2.9</h2> <ul> <li><code>with connection</code> starts a transaction on autocommit transactions too (:ticket:<code>[#941](https://github.com/psycopg/psycopg2/issues/941)</code>).</li> <li>Timezones with fractional minutes are supported on Python 3.7 and following (:ticket:<code>[#1272](https://github.com/psycopg/psycopg2/issues/1272)</code>).</li> <li>Escape table and column names in <code>~cursor.copy_from()</code> and <code>~cursor.copy_to()</code>.</li> <li>Connection exceptions with sqlstate <code>08XXX</code> reclassified as <code>~psycopg2.OperationalError</code> (a subclass of the previously used <code>~psycopg2.DatabaseError</code>) (:ticket:<code>[#1148](https://github.com/psycopg/psycopg2/issues/1148)</code>).</li> <li>Include library dirs required from libpq to work around MacOS build problems (:ticket:<code>[#1200](https://github.com/psycopg/psycopg2/issues/1200)</code>).</li> </ul> <p>Other changes:</p> <ul> <li>Dropped support for Python 2.7, 3.4, 3.5 (:tickets:<code>[#1198](psycopg/psycopg2#1198), [#1000](psycopg/psycopg2#1000), [#1197](https://github.com/psycopg/psycopg2/issues/1197)</code>).</li> <li>Dropped support for mx.DateTime.</li> <li>Use <code>datetime.timezone</code> objects by default in datetime objects instead of <code>~psycopg2.tz.FixedOffsetTimezone</code>.</li> <li>The <code>psycopg2.tz</code> module is deprecated and scheduled to be dropped in the next major release.</li> <li>Provide :pep:<code>599</code> wheels packages (manylinux2014 tag) for i686 and x86_64 platforms.</li> <li>Provide :pep:<code>600</code> wheels packages (manylinux_2_24 tag) for aarch64 and ppc64le platforms.</li> <li>Wheel package compiled against OpenSSL 1.1.1k and PostgreSQL 13.3.</li> <li>Build system for Linux/MacOS binary packages moved to GitHub Actions.</li> </ul> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/psycopg/psycopg2/commits">compare view</a></li> </ul> </details> <br /> [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=psycopg2-binary&package-manager=pip&previous-version=2.9.1&new-version=2.9.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details>
We ran into an exception caused by this changed
And the affected code is: with psycopg2.connect(...) as conn:
conn.set_session(autocommit=True)
with conn.cursor() as curs: Kind of confusing to see an exception about not being able to run inside a transaction, when the code clearly seems to be setting autocommits on. I think it would be useful to have a list of workarounds with code examples on this issue (and perhaps changelog), because this is clearly a breaking change from 2.8.x to 2.9. Workaround 1: pin |
Bumps [psycopg2-binary](https://github.com/psycopg/psycopg2) from 2.9.2 to 2.9.3. <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/psycopg/psycopg2/blob/master/NEWS">psycopg2-binary's changelog</a>.</em></p> <blockquote> <h2>Current release</h2> <p>What's new in psycopg 2.9.3 ^^^^^^^^^^^^^^^^^^^^^^^^^^^</p> <ul> <li>Alpine (musl) wheels now available (:ticket:<code>[#1148](https://github.com/psycopg/psycopg2/issues/1148)</code>).</li> </ul> <p>What's new in psycopg 2.9.2 ^^^^^^^^^^^^^^^^^^^^^^^^^^^</p> <ul> <li>Raise <code>ValueError</code> for dates >= Y10k (:ticket:<code>[#1307](https://github.com/psycopg/psycopg2/issues/1307)</code>).</li> <li><code>~psycopg2.errorcodes</code> map and <code>~psycopg2.errors</code> classes updated to PostgreSQL 14.</li> <li>Add preliminary support for Python 3.11 (:tickets:<code>[#1376](psycopg/psycopg2#1376), [#1386](https://github.com/psycopg/psycopg2/issues/1386)</code>).</li> <li>Wheel package compiled against OpenSSL 1.1.1l and PostgreSQL 14.1 (:ticket:<code>[#1388](https://github.com/psycopg/psycopg2/issues/1388)</code>).</li> </ul> <p>What's new in psycopg 2.9.1 ^^^^^^^^^^^^^^^^^^^^^^^^^^^</p> <p>Fix regression with named <code>sql.Placeholder</code> (:ticket:<code>[#1291](https://github.com/psycopg/psycopg2/issues/1291)</code>).</p> <h2>What's new in psycopg 2.9</h2> <ul> <li><code>with connection</code> starts a transaction on autocommit transactions too (:ticket:<code>[#941](https://github.com/psycopg/psycopg2/issues/941)</code>).</li> <li>Timezones with fractional minutes are supported on Python 3.7 and following (:ticket:<code>[#1272](https://github.com/psycopg/psycopg2/issues/1272)</code>).</li> <li>Escape table and column names in <code>~cursor.copy_from()</code> and <code>~cursor.copy_to()</code>.</li> <li>Connection exceptions with sqlstate <code>08XXX</code> reclassified as <code>~psycopg2.OperationalError</code> (a subclass of the previously used <code>~psycopg2.DatabaseError</code>) (:ticket:<code>[#1148](https://github.com/psycopg/psycopg2/issues/1148)</code>).</li> <li>Include library dirs required from libpq to work around MacOS build problems (:ticket:<code>[#1200](https://github.com/psycopg/psycopg2/issues/1200)</code>).</li> </ul> <p>Other changes:</p> <ul> <li>Dropped support for Python 2.7, 3.4, 3.5 (:tickets:<code>[#1198](psycopg/psycopg2#1198), [#1000](psycopg/psycopg2#1000), [#1197](https://github.com/psycopg/psycopg2/issues/1197)</code>).</li> <li>Dropped support for mx.DateTime.</li> <li>Use <code>datetime.timezone</code> objects by default in datetime objects instead of <code>~psycopg2.tz.FixedOffsetTimezone</code>.</li> <li>The <code>psycopg2.tz</code> module is deprecated and scheduled to be dropped in the next major release.</li> <li>Provide :pep:<code>599</code> wheels packages (manylinux2014 tag) for i686 and x86_64</li> </ul> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/psycopg/psycopg2/commits">compare view</a></li> </ul> </details> <br /> [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=psycopg2-binary&package-manager=pip&previous-version=2.9.2&new-version=2.9.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details>
CONCURRENT indexes are only valid if they are not created inside a transaction block. psycopg2 has started to automatically emit BEGIN / END transaction when using the "with " context manager, thus causing explicit transactions to happen for us here. See: psycopg/psycopg2#941 This means that we now need to stop using concurrently as we may or may not be inside a transaction block.
With psycopg2 we cannot use the "connect()" as a conext manager anymore without getting an transaction automatically opened. This means we need to replace it with our own wrapper function that does the same, but that also enables autocommit mode for the connection. This was forced by the upstream behaviour change documented: > > Yes, that's the way to do it: don't use a with block if you don't want > a transaction to start. psycopg/psycopg2#941 (comment)
v2.9 changed the autocommit handling of `with` blocks, so we can no longer create the connection using `with`. See [0] for details. [0]: psycopg/psycopg2#941
v2.9 changed the autocommit handling of `with` blocks, so we can no longer create the connection using `with`. See [0] for details. [0]: psycopg/psycopg2#941
psycopg2 has the following warning related to autocommit: > By default, any query execution, including a simple SELECT will start > a transaction: for long-running programs, if no further action is > taken, the session will remain “idle in transaction”, an undesirable > condition for several reasons (locks are held by the session, tables > bloat…). For long lived scripts, either ensure to terminate a > transaction as soon as possible or use an autocommit connection. In the 2.9 release notes, psycopg2 also made the following change: > `with connection` starts a transaction on autocommit transactions too Some of these connections are indeed long-lived, so we were retaining tons of WAL on the endpoints because we had a transaction pinned in the past. Link: https://www.psycopg.org/docs/news.html#what-s-new-in-psycopg-2-9 Link: psycopg/psycopg2#941 Signed-off-by: Tristan Partin <tristan@neon.tech>
Hi,
using autocommit mode can be quite useful for some long running applications, to make it less likely that transactions are accidentally left open, and to perform operations like
VACUUM
etc. psycopg provides for that by allowing to set autocommit to true.Unfortunately I think that's too large a hammer in a lot of cases. What I think is commonly desired is being able to granularly choose the desired behaviour, but psycopg doesn't allow that currently.
E.g. even when in autocommit mode, one might want to explicitly use a transaction. But that doesn't really work well right now. Approaches I considered:
con.begin()
- which doesn't exist.execute()
- but that breaks con.commit(), because:https://github.com/psycopg/psycopg2/blob/master/psycopg/pqpath.c#L396
even though the connection knows that it's in a transaction, it ignores that fact.
While I obviously just could commit using
.execute('COMMIT')
that seems too likely to break assumptions of other code.While I could work around that by resetting autocommit later, that requires exception handling etc.
What I think a sensible approach would be:
pq_commit()
actually commit, even if autocommit mode is on, if there's a transaction in progress - the transaction status is known at the client side.begin()
, to explicitly start a transaction (probably erroring out if there already is one in progress)con.begin()
.Regards
Andres
The text was updated successfully, but these errors were encountered: