Thanks Adrian. My aim with p1() was to show that its behavior, in each AUTOCOMMIT mode, aligns with my intuition. I’ve noticed the system-generated “begin” that you mention when I add this to my “/usr/local/var/postgres/postgresql.conf”: log_statement = 'all' log_directory = 'log' logging_collector = on and tail the most recent “/usr/local/var/postgres/log/postgresql-*.log” file. I assume that the “begin” is generated server-side—and not by the psql client-side program, other other such clients. However, the intuition that informs my understanding of the behavior of p1() lets me down for p2(). My staring assumption was that if I want to do txn control in a plpgsql proc, then I must grant it that ability by stopping doing txn control at the outer level. But experiments—and what I’ve been told—tell me that I must do the opposite. Here’s how I’ve tried to describe what I see for p2() with AUTOCOMMIT ON for myself: 1. my call p2() starts a txn. 2. However, during the execution of the proc, the usual autocommit behavior is programmatically turned off by explicit PostgreSQL code. 3. Other explicit PostgreSQL code makes “start transaction” inside a proc simply cause a runtime error under all circumstances. However, txns can be ended by “commit” or “rollback”. And new ones can be started—but only implicitly by executing a SQL statement that, as a top level SQL, would start a txn. 4. This is why “set transaction isolation level repeatable read” in my p2() is legal immediately after “rollback”—and produces the semantics I’d expect. At top level, and with autocommit turned on, it implicitly starts a txn—and you see the “begin” in the log file. 5. When the proc call ends, normal AUTOCOMMIT mode is turned on again, and a “commit” is issued automatically. This may, or may not, have something to do—as you can see by running p3() with AUTOCOMMIT ON. create or replace procedure p3() language plpgsql as $$ begin insert into t(n) values(17); rollback; insert into t(n) values(42); end; $$; After calling it, you see just one row with the value 42—and it’s already durable. This is why I want the folks who invented this behavior to describe the correct plplsql programmer’s mental model for me with the terminology that they designed. adrian.klaver@xxxxxxxxxxx wrote: HERE, on “AUTOCOMMIT”. “When on (the default), each SQL command is automatically committed upon successful completion. To postpone commit in this mode, you must enter a BEGIN or START TRANSACTION SQL command. When off or unset, SQL commands are not committed until you explicitly issue COMMIT or END. The autocommit-off mode works by issuing an implicit BEGIN for you, just before any command that is not already in a transaction block and is not itself a BEGIN or other transaction-control command, nor a command that cannot be executed inside a transaction block (such as VACUUM).” The way I understand it in your first case: \set AUTOCOMMIT off -- get clean start begin; delete from t; commit; call p1(); select n from t order by n; rollback; select n from t order by n; rollback; You have a implied BEGIN; before the begin; you wrap the delete in. Therefore you can do the rollback;. In the AUTOCOMMIT on there is only one transaction and it ends with the commit; after the delete. So when you attempt the rollback you get the error. REMEMBER in plpgsql Begin is not for transaction control, HERE (43.8. Transaction Management). Have not worked through the second case yet. -- Adrian Klaver adrian.klaver@xxxxxxxxxxx |