Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitac63dca

Browse files
committed
Fix longstanding race condition in plancache.c.
When creating or manipulating a cached plan for a transaction controlcommand (particularly ROLLBACK), we must not perform any catalog accesses,since we might be in an aborted transaction. However, plancache.c busilysaved or examined the search_path for every cached plan. If we wereunlucky enough to do this at a moment where the path's expansion intoschema OIDs wasn't already cached, we'd do some catalog accesses; and withsome more bad luck such as an ill-timed signal arrival, that could lead tocrashes or Assert failures, as exhibited in bug #8095 from Nachiket Vaidya.Fortunately, there's no real need to consider the search path for suchcommands, so we can just skip the relevant steps when the subject statementis a TransactionStmt. This is somewhat related to bug #5269, though thefailure happens during initial cached-plan creation rather thanrevalidation.This bug has been there since the plan cache was invented, so back-patchto all supported branches.
1 parent61b9623 commitac63dca

File tree

1 file changed

+44
-14
lines changed

1 file changed

+44
-14
lines changed

‎src/backend/utils/cache/plancache.c

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@
6868
#include"utils/syscache.h"
6969

7070

71+
/*
72+
* We must skip "overhead" operations that involve database access when the
73+
* cached plan's subject statement is a transaction control command.
74+
*/
75+
#defineIsTransactionStmtPlan(plansource) \
76+
((plansource)->raw_parse_tree && \
77+
IsA((plansource)->raw_parse_tree, TransactionStmt))
78+
7179
/*
7280
* This is the head of the backend's list of "saved" CachedPlanSources (i.e.,
7381
* those that are in long-lived storage and are examined for sinval events).
@@ -352,23 +360,27 @@ CompleteCachedPlan(CachedPlanSource *plansource,
352360
plansource->query_context=querytree_context;
353361
plansource->query_list=querytree_list;
354362

355-
/*
356-
* Use the planner machinery to extract dependencies. Data is saved in
357-
* query_context. (We assume that not a lot of extra cruft is created by
358-
* this call.) We can skip this for one-shot plans.
359-
*/
360-
if (!plansource->is_oneshot)
363+
if (!plansource->is_oneshot&& !IsTransactionStmtPlan(plansource))
364+
{
365+
/*
366+
* Use the planner machinery to extract dependencies. Data is saved
367+
* in query_context. (We assume that not a lot of extra cruft is
368+
* created by this call.) We can skip this for one-shot plans, and
369+
* transaction control commands have no such dependencies anyway.
370+
*/
361371
extract_query_dependencies((Node*)querytree_list,
362372
&plansource->relationOids,
363373
&plansource->invalItems);
364374

365-
/*
366-
* Also save the current search_path in the query_context. (This should
367-
* not generate much extra cruft either, since almost certainly the path
368-
* is already valid.) Again, don't really need it for one-shot plans.
369-
*/
370-
if (!plansource->is_oneshot)
375+
/*
376+
* Also save the current search_path in the query_context. (This
377+
* should not generate much extra cruft either, since almost certainly
378+
* the path is already valid.) Again, we don't really need this for
379+
* one-shot plans; and we *must* skip this for transaction control
380+
* commands, because this could result in catalog accesses.
381+
*/
371382
plansource->search_path=GetOverrideSearchPath(querytree_context);
383+
}
372384

373385
/*
374386
* Save the final parameter types (or other parameter specification data)
@@ -542,9 +554,11 @@ RevalidateCachedQuery(CachedPlanSource *plansource)
542554
/*
543555
* For one-shot plans, we do not support revalidation checking; it's
544556
* assumed the query is parsed, planned, and executed in one transaction,
545-
* so that no lock re-acquisition is necessary.
557+
* so that no lock re-acquisition is necessary. Also, there is never
558+
* any need to revalidate plans for transaction control commands (and
559+
* we mustn't risk any catalog accesses when handling those).
546560
*/
547-
if (plansource->is_oneshot)
561+
if (plansource->is_oneshot||IsTransactionStmtPlan(plansource))
548562
{
549563
Assert(plansource->is_valid);
550564
returnNIL;
@@ -967,6 +981,9 @@ choose_custom_plan(CachedPlanSource *plansource, ParamListInfo boundParams)
967981
/* Otherwise, never any point in a custom plan if there's no parameters */
968982
if (boundParams==NULL)
969983
return false;
984+
/* ... nor for transaction control statements */
985+
if (IsTransactionStmtPlan(plansource))
986+
return false;
970987

971988
/* See if caller wants to force the decision */
972989
if (plansource->cursor_options&CURSOR_OPT_GENERIC_PLAN)
@@ -1622,6 +1639,10 @@ PlanCacheRelCallback(Datum arg, Oid relid)
16221639
if (!plansource->is_valid)
16231640
continue;
16241641

1642+
/* Never invalidate transaction control commands */
1643+
if (IsTransactionStmtPlan(plansource))
1644+
continue;
1645+
16251646
/*
16261647
* Check the dependency list for the rewritten querytree.
16271648
*/
@@ -1686,6 +1707,10 @@ PlanCacheFuncCallback(Datum arg, int cacheid, uint32 hashvalue)
16861707
if (!plansource->is_valid)
16871708
continue;
16881709

1710+
/* Never invalidate transaction control commands */
1711+
if (IsTransactionStmtPlan(plansource))
1712+
continue;
1713+
16891714
/*
16901715
* Check the dependency list for the rewritten querytree.
16911716
*/
@@ -1775,6 +1800,11 @@ ResetPlanCache(void)
17751800
* We *must not* mark transaction control statements as invalid,
17761801
* particularly not ROLLBACK, because they may need to be executed in
17771802
* aborted transactions when we can't revalidate them (cf bug #5269).
1803+
*/
1804+
if (IsTransactionStmtPlan(plansource))
1805+
continue;
1806+
1807+
/*
17781808
* In general there is no point in invalidating utility statements
17791809
* since they have no plans anyway. So invalidate it only if it
17801810
* contains at least one non-utility statement, or contains a utility

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp