Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 9624321

Browse files
committed
Avoid crash when rolling back within a prepared statement.
If a portal is used to run a prepared CALL or DO statement that contains a ROLLBACK, PortalRunMulti fails because the portal's statement list gets cleared by the rollback. (Since the grammar doesn't allow CALL/DO in PREPARE, the only easy way to get to this is via extended query protocol, which treats all inputs as prepared statements.) It's difficult to avoid resetting the portal early because of resource-management issues, so work around this by teaching PortalRunMulti to be wary of portal->stmts having suddenly become NIL. The crash has only been seen to occur in v13 and HEAD (as a consequence of commit 1cff1b9 having added an extra touch of portal->stmts). But even before that, the code involved touching a List that the portal no longer has any claim on. In the test case at hand, the List will still exist because of another refcount on the cached plan; but I'm far from convinced that it's impossible for the cached plan to have been dropped by the time control gets back to PortalRunMulti. Hence, backpatch to v11 where nested transactions were added. Thomas Munro and Tom Lane, per bug #16811 from James Inform Discussion: https://postgr.es/m/16811-c1b599b2c6c2d622@postgresql.org
1 parent 2c8726c commit 9624321

File tree

1 file changed

+18
-7
lines changed

1 file changed

+18
-7
lines changed

src/backend/tcop/pquery.c

+18-7
Original file line numberDiff line numberDiff line change
@@ -1314,19 +1314,30 @@ PortalRunMulti(Portal portal,
13141314
}
13151315
}
13161316

1317-
/*
1318-
* Increment command counter between queries, but not after the last
1319-
* one.
1320-
*/
1321-
if (lnext(portal->stmts, stmtlist_item) != NULL)
1322-
CommandCounterIncrement();
1323-
13241317
/*
13251318
* Clear subsidiary contexts to recover temporary memory.
13261319
*/
13271320
Assert(portal->portalContext == CurrentMemoryContext);
13281321

13291322
MemoryContextDeleteChildren(portal->portalContext);
1323+
1324+
/*
1325+
* Avoid crashing if portal->stmts has been reset. This can only
1326+
* occur if a CALL or DO utility statement executed an internal
1327+
* COMMIT/ROLLBACK (cf PortalReleaseCachedPlan). The CALL or DO must
1328+
* have been the only statement in the portal, so there's nothing left
1329+
* for us to do; but we don't want to dereference a now-dangling list
1330+
* pointer.
1331+
*/
1332+
if (portal->stmts == NIL)
1333+
break;
1334+
1335+
/*
1336+
* Increment command counter between queries, but not after the last
1337+
* one.
1338+
*/
1339+
if (lnext(portal->stmts, stmtlist_item) != NULL)
1340+
CommandCounterIncrement();
13301341
}
13311342

13321343
/* Pop the snapshot if we pushed one. */

0 commit comments

Comments
 (0)