1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-29 10:41:53 +03:00

Fix longstanding race condition in plancache.c.

When creating or manipulating a cached plan for a transaction control
command (particularly ROLLBACK), we must not perform any catalog accesses,
since we might be in an aborted transaction.  However, plancache.c busily
saved or examined the search_path for every cached plan.  If we were
unlucky enough to do this at a moment where the path's expansion into
schema OIDs wasn't already cached, we'd do some catalog accesses; and with
some more bad luck such as an ill-timed signal arrival, that could lead to
crashes or Assert failures, as exhibited in bug #8095 from Nachiket Vaidya.
Fortunately, there's no real need to consider the search path for such
commands, so we can just skip the relevant steps when the subject statement
is a TransactionStmt.  This is somewhat related to bug #5269, though the
failure happens during initial cached-plan creation rather than
revalidation.

This bug has been there since the plan cache was invented, so back-patch
to all supported branches.
This commit is contained in:
Tom Lane
2013-04-20 16:59:41 -04:00
parent 2534ac426d
commit eab46ee07f

View File

@ -59,6 +59,14 @@
#include "utils/syscache.h" #include "utils/syscache.h"
/*
* We must skip "overhead" operations that involve database access when the
* cached plan's subject statement is a transaction control command.
*/
#define IsTransactionStmtPlan(plansource) \
((plansource)->raw_parse_tree && \
IsA((plansource)->raw_parse_tree, TransactionStmt))
static List *cached_plans_list = NIL; static List *cached_plans_list = NIL;
static void StoreCachedPlan(CachedPlanSource *plansource, List *stmt_list, static void StoreCachedPlan(CachedPlanSource *plansource, List *stmt_list,
@ -135,8 +143,12 @@ CreateCachedPlan(Node *raw_parse_tree,
/* /*
* Fetch current search_path into new context, but do any recalculation * Fetch current search_path into new context, but do any recalculation
* work required in caller's context. * work required in caller's context. Skip this for a transaction control
* command, since we won't need it and can't risk catalog access.
*/ */
if (raw_parse_tree && IsA(raw_parse_tree, TransactionStmt))
search_path = NULL;
else
search_path = GetOverrideSearchPath(source_context); search_path = GetOverrideSearchPath(source_context);
/* /*
@ -225,8 +237,12 @@ FastCreateCachedPlan(Node *raw_parse_tree,
/* /*
* Fetch current search_path into given context, but do any recalculation * Fetch current search_path into given context, but do any recalculation
* work required in caller's context. * work required in caller's context. Skip this for a transaction control
* command, since we won't need it and can't risk catalog access.
*/ */
if (raw_parse_tree && IsA(raw_parse_tree, TransactionStmt))
search_path = NULL;
else
search_path = GetOverrideSearchPath(context); search_path = GetOverrideSearchPath(context);
/* /*
@ -474,6 +490,7 @@ RevalidateCachedPlan(CachedPlanSource *plansource, bool useResOwner)
* *
* (XXX is there anything else we really need to restore?) * (XXX is there anything else we really need to restore?)
*/ */
if (plansource->search_path)
PushOverrideSearchPath(plansource->search_path); PushOverrideSearchPath(plansource->search_path);
/* /*
@ -553,6 +570,7 @@ RevalidateCachedPlan(CachedPlanSource *plansource, bool useResOwner)
PopActiveSnapshot(); PopActiveSnapshot();
/* Now we can restore current search path */ /* Now we can restore current search path */
if (plansource->search_path)
PopOverrideSearchPath(); PopOverrideSearchPath();
/* /*