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