Re: BUG #15170: PQtransactionStatus returns ACTIVE after Empty Commit

From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: Rick Gabriel <klaxian(at)gmail(dot)com>
Cc: pgsql-bugs(at)lists(dot)postgresql(dot)org
Subject: Re: BUG #15170: PQtransactionStatus returns ACTIVE after Empty Commit
Date: 2018-04-25 13:45:10
Message-ID: 2588.1524663910@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

Rick Gabriel <klaxian(at)gmail(dot)com> writes:
> First, I forgot to mention that I am sending async queries (PQsendQuery).
> libpq documentation states that PQgetResult() must be called repeatedly
> until it returns a null pointer.

Right.

> Unfortunately, there is nothing about this
> requirement in the official docs for PHP's libpq wrapper extension.

I think you have grounds to call that a PHP documentation bug. Or at
least it should be made clearer that you also need to read the libpq docs.

> If I
> don't call PQgetResult() one more time than I really need, the transaction
> and connection statuses remain active/busy. Even though PG reports its
> status as "busy", subsequent queries succeed normally.

That's because if you start a new query, libpq will read-and-discard any
remaining server output from the last one. That's not really a good thing
to depend on though --- for example, you might miss an error message that
way.

> I suggest that the connection and transaction states should be updated when
> all queued async queries are completed, without the extra call to
> PQgetResult().
> What do you think?

I think we're not going to change that, because

(a) it's not a bug, it's operating as designed and documented;
(b) this behavior has been stable for more than a dozen years, and
changing it might well break clients expecting the current behavior;
(c) it's not very clear how libpq could do that at all.

I think what you're seeing is related to the fact that the server's
response to a query string involves one or more query results (each
containing some Data messages then a CommandComplete message), followed
by a ReadyForQuery message. PQgetResult will return a PGresult when it's
consumed a CommandComplete message, but you have to call it again to get
libpq to consume the RFQ message --- and it's that message that causes
the PQtransactionStatus result to change. Since RFQ bears the info about
whether the server is truly idle or just idle-in-transaction, libpq cannot
correctly update PQtransactionStatus without reading that message.

You could argue that libpq should "look ahead" after reading
CommandComplete to see if there's an RFQ already received, but I don't
think that could be made to work reliably. You'd either have unwanted
blocking in some cases, or false negatives, anytime the RFQ wasn't
contained in the same TCP packet as the last CC. I doubt people would
want to work with a spec that says "99% of the time PQtransactionStatus
will be updated by the last real PQgetResult call, but sometimes you
need one more call".

regards, tom lane

In response to

Browse pgsql-bugs by date

  From Date Subject
Next Message Rémi Aubel 2018-04-25 14:15:36 Re: BUG: Unable to bind a null value typed as a UUID in a PreparedStatement
Previous Message Kyotaro HORIGUCHI 2018-04-25 08:31:39 Re: set/reset issues in create function and set_config