[bug fix] Savepoint-related statements terminates connection

Tsunakawa, Takayuki <tsunakawa.takay@jp.fujitsu.com>

From: "Tsunakawa, Takayuki" <tsunakawa.takay@jp.fujitsu.com>
To: "pgsql-hackers@postgresql.org" <pgsql-hackers@postgresql.org>
Date: 2017-03-31T07:10:44Z
Lists: pgsql-hackers

Attachments

Hello,

I found a trivial bug that terminates the connection.  The attached patch fixes this.


PROBLEM
========================================

Savepoint-related statements in a multi-command query terminates the connection unexpectedly, as follows.

$ psql -d postgres -c "SELECT 1; SAVEPOINT sp"
FATAL:  DefineSavepoint: unexpected state STARTED
server closed the connection unexpectedly
        This probably means the server terminated abnormally
        before or while processing the request.
connection to server was lost


CAUSE
========================================

1. In exec_simple_query(), isTopLevel is set to false.

	isTopLevel = (list_length(parsetree_list) == 1);

Then it is passed to PortalRun().

		(void) PortalRun(portal,
						 FETCH_ALL,
						 isTopLevel,
						 receiver,
						 receiver,
						 completionTag);

2. The isTopLevel flag is passed through ProcessUtility() to RequireTransactionChain().

							RequireTransactionChain(isTopLevel, "SAVEPOINT");


3. CheckTransactionChain() returns successfully here:

	/*
	 * inside a function call?
	 */
	if (!isTopLevel)
		return;


4. Finally, unexpectedly called DefineSavepoint() reports invalid transaction block state.

			/* These cases are invalid. */
		case TBLOCK_DEFAULT:
		case TBLOCK_STARTED:
...
			elog(FATAL, "DefineSavepoint: unexpected state %s",
				 BlockStateAsString(s->blockState));



SOLUTION
========================================

The manual page says "Savepoints can only be established when inside a transaction block."  So just check for it.

https://www.postgresql.org/docs/devel/static/sql-savepoint.html


RESULT AFTER FIX
========================================

$ psql -d postgres -c "SELECT 1; SAVEPOINT sp"
ERROR:  SAVEPOINT can only be used in transaction blocks


Regards
Takayuki Tsunakawa

Commits

  1. Improve documentation about behavior of multi-statement Query messages.

  2. Fix handling of savepoint commands within multi-statement Query strings.

  3. Arrange for PreventTransactionChain to reject commands submitted as part