diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c index a81a45700cc..fd7a9c14ba7 100644 --- a/src/backend/tcop/pquery.c +++ b/src/backend/tcop/pquery.c @@ -1863,13 +1863,24 @@ PortalLockCachedPlan(Portal portal, bool do_prep, else if (AcquireExecutorLocks(portal->cplan)) return false; - /* Replan. Locks will be taken freshly. */ - ReleaseCachedPlan(portal->cplan, portal->resowner); + /* + * Replan. Locks will be taken freshly. + * + * The portal's reference to its cached plan is acquired with a NULL + * owner, both by ExecuteQuery() and by exec_bind_message(), and + * PortalReleaseCachedPlan() releases it the same way. Keep the + * replacement reference on that same footing: handing portal->resowner + * here would release a reference that resource owner never owned, and + * register the new one where nothing will release it. The locks taken + * below do belong to portal->resowner, which is why ExecutorPrepAndLock() + * above still gets it. + */ + ReleaseCachedPlan(portal->cplan, NULL); portal->cplan = NULL; portal->stmts = NIL; portal->cplan = GetCachedPlan(portal->plansource, portal->portalParams, - portal->resowner, + NULL, portal->queryEnv); portal->stmts = portal->cplan->stmt_list; portal->strategy = ChoosePortalStrategy(portal->stmts);