Re: Chapter 43.8. "Transaction Management" fails to state twocritical restrictions

Поиск
Список
Период
Сортировка
От Bryn Llewellyn
Тема Re: Chapter 43.8. "Transaction Management" fails to state twocritical restrictions
Дата
Msg-id 07A18A12-FEA3-40AD-A72B-B52BCEAC195E@yugabyte.com
обсуждение исходный текст
Ответ на Re: Chapter 43.8. "Transaction Management" fails to state twocritical restrictions  (Bruce Momjian <bruce@momjian.us>)
Список pgsql-docs
Hello, Bruce.  (We met at the OUGN conference last March on the Oslo-Kiel ferry.) Thanks for your reply.

1. About AUTOCOMMIT

It’s very hard to get a clear account of what AUTOCOMMIT really is. So consider the example from the docs section that I cited, and run these psql commands at its prompt:

DROP TABLE IF EXISTS test1;
CREATE TABLE test1(a int);

CREATE OR REPLACE PROCEDURE transaction_test1()
LANGUAGE plpgsql
AS $$
BEGIN
    FOR i IN 0..9 LOOP
        INSERT INTO test1 (a) VALUES (i);
        IF i % 2 = 0 THEN
            COMMIT;
        ELSE
            ROLLBACK;
        END IF;
    END LOOP;
END
$$;

Now invoke it like this:

\set AUTOCOMMIT on
CALL transaction_test1();

And see what it produced like this:

SELECT a FROM test1 ORDER BY a; 

The result is what I expect (even values of “a” from 0 through 8). Now re-test like this

\set AUTOCOMMIT on
DELETE FROM test1;

\set AUTOCOMMIT off
CALL transaction_test1();

It causes this error:

ERROR:  invalid transaction termination
CONTEXT:  PL/pgSQL function transaction_test1() line 6 at COMMIT

And (of course), following the ROLLBACK that you must do before any new SQL works, table test1 is left empty. You get the identical outcome (as I’d expect) if you execute this:

START TRANSACTION;

between setting AUTOCOMMIT to off and calling the proc.

I work at YugaByte (www.yugabyte.com) and I filed this issue on 1-Aug-2019:

https://github.com/yugabyte/yugabyte-db/issues/1957

You can see from what I wrote how confused I was. (My earlier life was at Oracle Corp where the corresponding notions are simple and intuitive.) Then I sent the URL to the pgsql-general list asking for comments. I got all sorts of replies—mainly trying to tell me that my aim (ultimately to write a PL/pgSQL proc to encapsulate the retry loop that you need when you execute a txn at the serializable level) was silly. (The point there is that a serialization error sometimes occurs first on attempting to commit the txn.) There were some exchanges on Twitter. And eventually Peter Eisentraut tweeted to say that the AUTOCOMMIT requirement was probably an implementation restriction.

2. About committing in a block statement’s executable section when the block statement has an exception section

Simply modify the proc from the docs thus:

CREATE OR REPLACE PROCEDURE transaction_test1()
LANGUAGE plpgsql
AS $$
BEGIN
    FOR i IN 0..9 LOOP
        IF i = 9 THEN
          RAISE EXCEPTION 'My bad' USING errcode = '99999';
        END IF;

        INSERT INTO test1 (a) VALUES (i);
        IF i % 2 = 0 THEN
            COMMIT;
        ELSE
            ROLLBACK;
        END IF;
    END LOOP;
EXCEPTION
  WHEN OTHERS THEN
    RAISE INFO 'sqlerrm:  %', sqlerrm;
    RAISE INFO 'sqlstate: %', sqlstate;
END
$$;

With proper semantics, it ought to commit the even values of “a” from 0 through 8, then report “My bad” using RAISE INFO, and then end silently.

And invoke it (as we now know we must) like this:

\set AUTOCOMMIT on
CALL transaction_test1();

It actually reports this:

INFO:  sqlerrm:  cannot commit while a subtransaction is active
INFO:  sqlstate: 2D000

In other words, executing “commit” in the circumstances that I complained about causes the error that my OTHERS handler reports.

This undocumented behavior means that stored procedures in PostgreSQL simply cannot, in general, be used for their intended purpose. I just filed this issue (on 29-Sep-2019):

https://github.com/yugabyte/yugabyte-db/issues/2464

I indent as write to the pgsql-hackers list, tell them this URL, and ask for comments.

Obviously, I’ll be delighted to be shown that my pessimistic analysis is faulty. My aim is simply to implement my use cases.

3. Back to AUTOCOMMIT in general

It seems to me that the notion is a conflation of what could have been a pure client-side mode with a server-side mode. Apparently, different client-side drivers do different things when AUTOCOMMIT is off (like silently issuing a BEGIN or START TRANSACTION on your behalf before submitting your intended SQL statement). But something must also be going on server side—else the execution of a stored proc could not know whether the client code did its own BEGIN or if this was done implicitly. I’ve been told that the server distinguishes between a so-called explicit txn and and implicit txn. I’d be happy if someone would explain this clearly to me.

On 30-Sep-2019, at 07:24, Bruce Momjian <bruce@momjian.us> wrote:

On Mon, Sep 30, 2019 at 04:11:47AM +0000, PG Doc comments form wrote:
The following documentation comment has been logged on the website:

Page: https://www.postgresql.org/docs/11/plpgsql-transactions.html
Description:

This chapter fails to state:

(1) If a PL/pgSQL procedure issues "commit" then it must be called with
AUTOCOMMIT set to On. This is counter-intuitive. You'd expect the
opposite.

You mean psql autocommit mode?

(2) If a PL/pgSQL procedure has a block statement with an exception section
(this might be the procedure's defining block, or an inner block) then that
block's executabe section must not issue "commit". Doing so causes a
run-time error.

Uh, that's a good point since you are in a subtransaction at that point.
What error do you get?

--
 Bruce Momjian  <bruce@momjian.us>        http://momjian.us
 EnterpriseDB                             http://enterprisedb.com

+ As you are, so once was I.  As I am, so you will be. +
+                      Ancient Roman grave inscription +

В списке pgsql-docs по дате отправления:

Предыдущее
От: Bruce Momjian
Дата:
Сообщение: Re: Most-common value docs in PG 12
Следующее
От: Stephen Frost
Дата:
Сообщение: Re: I'm surprised to see the word master here