PostgreSQL Source Code git master
plancache.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/transam.h"
#include "catalog/namespace.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "parser/analyze.h"
#include "storage/lmgr.h"
#include "tcop/pquery.h"
#include "tcop/utility.h"
#include "utils/inval.h"
#include "utils/memutils.h"
#include "utils/resowner.h"
#include "utils/rls.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
Include dependency graph for plancache.c:

Go to the source code of this file.

Macros

#define StmtPlanRequiresRevalidation(plansource)
 

Functions

static void ReleaseGenericPlan (CachedPlanSource *plansource)
 
static ListRevalidateCachedQuery (CachedPlanSource *plansource, QueryEnvironment *queryEnv, bool release_generic)
 
static bool CheckCachedPlan (CachedPlanSource *plansource)
 
static CachedPlanBuildCachedPlan (CachedPlanSource *plansource, List *qlist, ParamListInfo boundParams, QueryEnvironment *queryEnv)
 
static bool choose_custom_plan (CachedPlanSource *plansource, ParamListInfo boundParams)
 
static double cached_plan_cost (CachedPlan *plan, bool include_planner)
 
static QueryQueryListGetPrimaryStmt (List *stmts)
 
static void AcquireExecutorLocks (List *stmt_list, bool acquire)
 
static void AcquirePlannerLocks (List *stmt_list, bool acquire)
 
static void ScanQueryForLocks (Query *parsetree, bool acquire)
 
static bool ScanQueryWalker (Node *node, bool *acquire)
 
static TupleDesc PlanCacheComputeResultDesc (List *stmt_list)
 
static void PlanCacheRelCallback (Datum arg, Oid relid)
 
static void PlanCacheObjectCallback (Datum arg, int cacheid, uint32 hashvalue)
 
static void PlanCacheSysCallback (Datum arg, int cacheid, uint32 hashvalue)
 
static void ResOwnerReleaseCachedPlan (Datum res)
 
static void ResourceOwnerRememberPlanCacheRef (ResourceOwner owner, CachedPlan *plan)
 
static void ResourceOwnerForgetPlanCacheRef (ResourceOwner owner, CachedPlan *plan)
 
void InitPlanCache (void)
 
CachedPlanSourceCreateCachedPlan (RawStmt *raw_parse_tree, const char *query_string, CommandTag commandTag)
 
CachedPlanSourceCreateOneShotCachedPlan (RawStmt *raw_parse_tree, const char *query_string, CommandTag commandTag)
 
void CompleteCachedPlan (CachedPlanSource *plansource, List *querytree_list, MemoryContext querytree_context, Oid *param_types, int num_params, ParserSetupHook parserSetup, void *parserSetupArg, int cursor_options, bool fixed_result)
 
void SaveCachedPlan (CachedPlanSource *plansource)
 
void DropCachedPlan (CachedPlanSource *plansource)
 
PlannedStmtUpdateCachedPlan (CachedPlanSource *plansource, int query_index, QueryEnvironment *queryEnv)
 
CachedPlanGetCachedPlan (CachedPlanSource *plansource, ParamListInfo boundParams, ResourceOwner owner, QueryEnvironment *queryEnv)
 
void ReleaseCachedPlan (CachedPlan *plan, ResourceOwner owner)
 
bool CachedPlanAllowsSimpleValidityCheck (CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
 
bool CachedPlanIsSimplyValid (CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
 
void CachedPlanSetParentContext (CachedPlanSource *plansource, MemoryContext newcontext)
 
CachedPlanSourceCopyCachedPlan (CachedPlanSource *plansource)
 
bool CachedPlanIsValid (CachedPlanSource *plansource)
 
ListCachedPlanGetTargetList (CachedPlanSource *plansource, QueryEnvironment *queryEnv)
 
CachedExpressionGetCachedExpression (Node *expr)
 
void FreeCachedExpression (CachedExpression *cexpr)
 
void ResetPlanCache (void)
 
void ReleaseAllPlanCacheRefsInOwner (ResourceOwner owner)
 

Variables

static dlist_head saved_plan_list = DLIST_STATIC_INIT(saved_plan_list)
 
static dlist_head cached_expression_list = DLIST_STATIC_INIT(cached_expression_list)
 
static const ResourceOwnerDesc planref_resowner_desc
 
int plan_cache_mode = PLAN_CACHE_MODE_AUTO
 

Macro Definition Documentation

◆ StmtPlanRequiresRevalidation

#define StmtPlanRequiresRevalidation (   plansource)
Value:
((plansource)->raw_parse_tree != NULL && \
stmt_requires_parse_analysis((plansource)->raw_parse_tree))
bool stmt_requires_parse_analysis(RawStmt *parseTree)
Definition: analyze.c:532

Definition at line 85 of file plancache.c.

Function Documentation

◆ AcquireExecutorLocks()

static void AcquireExecutorLocks ( List stmt_list,
bool  acquire 
)
static

Definition at line 1916 of file plancache.c.

1917{
1918 ListCell *lc1;
1919
1920 foreach(lc1, stmt_list)
1921 {
1922 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
1923 int rtindex;
1924
1925 if (plannedstmt->commandType == CMD_UTILITY)
1926 {
1927 /*
1928 * Ignore utility statements, except those (such as EXPLAIN) that
1929 * contain a parsed-but-not-planned query. Note: it's okay to use
1930 * ScanQueryForLocks, even though the query hasn't been through
1931 * rule rewriting, because rewriting doesn't change the query
1932 * representation.
1933 */
1934 Query *query = UtilityContainsQuery(plannedstmt->utilityStmt);
1935
1936 if (query)
1937 ScanQueryForLocks(query, acquire);
1938 continue;
1939 }
1940
1941 rtindex = -1;
1942 while ((rtindex = bms_next_member(plannedstmt->unprunableRelids,
1943 rtindex)) >= 0)
1944 {
1946 plannedstmt->rtable,
1947 rtindex - 1);
1948
1949 Assert(rte->rtekind == RTE_RELATION ||
1950 (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)));
1951
1952 /*
1953 * Acquire the appropriate type of lock on each relation OID. Note
1954 * that we don't actually try to open the rel, and hence will not
1955 * fail if it's been dropped entirely --- we'll just transiently
1956 * acquire a non-conflicting lock.
1957 */
1958 if (acquire)
1959 LockRelationOid(rte->relid, rte->rellockmode);
1960 else
1961 UnlockRelationOid(rte->relid, rte->rellockmode);
1962 }
1963 }
1964}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
#define OidIsValid(objectId)
Definition: c.h:746
Assert(PointerIsAligned(start, uint64))
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:229
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:107
@ CMD_UTILITY
Definition: nodes.h:272
@ RTE_SUBQUERY
Definition: parsenodes.h:1027
@ RTE_RELATION
Definition: parsenodes.h:1026
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define list_nth_node(type, list, n)
Definition: pg_list.h:327
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition: plancache.c:2000
Bitmapset * unprunableRelids
Definition: plannodes.h:94
CmdType commandType
Definition: plannodes.h:53
Node * utilityStmt
Definition: plannodes.h:136
List * rtable
Definition: plannodes.h:88
RTEKind rtekind
Definition: parsenodes.h:1056
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:2179

References Assert(), bms_next_member(), CMD_UTILITY, PlannedStmt::commandType, lfirst_node, list_nth_node, LockRelationOid(), OidIsValid, RangeTblEntry::relid, PlannedStmt::rtable, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, ScanQueryForLocks(), UnlockRelationOid(), PlannedStmt::unprunableRelids, UtilityContainsQuery(), and PlannedStmt::utilityStmt.

Referenced by CheckCachedPlan().

◆ AcquirePlannerLocks()

static void AcquirePlannerLocks ( List stmt_list,
bool  acquire 
)
static

Definition at line 1975 of file plancache.c.

1976{
1977 ListCell *lc;
1978
1979 foreach(lc, stmt_list)
1980 {
1981 Query *query = lfirst_node(Query, lc);
1982
1983 if (query->commandType == CMD_UTILITY)
1984 {
1985 /* Ignore utility statements, unless they contain a Query */
1986 query = UtilityContainsQuery(query->utilityStmt);
1987 if (query)
1988 ScanQueryForLocks(query, acquire);
1989 continue;
1990 }
1991
1992 ScanQueryForLocks(query, acquire);
1993 }
1994}
CmdType commandType
Definition: parsenodes.h:121
Node * utilityStmt
Definition: parsenodes.h:136

References CMD_UTILITY, Query::commandType, lfirst_node, ScanQueryForLocks(), UtilityContainsQuery(), and Query::utilityStmt.

Referenced by RevalidateCachedQuery().

◆ BuildCachedPlan()

static CachedPlan * BuildCachedPlan ( CachedPlanSource plansource,
List qlist,
ParamListInfo  boundParams,
QueryEnvironment queryEnv 
)
static

Definition at line 919 of file plancache.c.

921{
923 List *plist;
924 bool snapshot_set;
925 bool is_transient;
926 MemoryContext plan_context;
927 MemoryContext stmt_context = NULL;
929 ListCell *lc;
930
931 /*
932 * Normally the querytree should be valid already, but if it's not,
933 * rebuild it.
934 *
935 * NOTE: GetCachedPlan should have called RevalidateCachedQuery first, so
936 * we ought to be holding sufficient locks to prevent any invalidation.
937 * However, if we're building a custom plan after having built and
938 * rejected a generic plan, it's possible to reach here with is_valid
939 * false due to an invalidation while making the generic plan. In theory
940 * the invalidation must be a false positive, perhaps a consequence of an
941 * sinval reset event or the debug_discard_caches code. But for safety,
942 * let's treat it as real and redo the RevalidateCachedQuery call.
943 */
944 if (!plansource->is_valid)
945 qlist = RevalidateCachedQuery(plansource, queryEnv, true);
946
947 /*
948 * If we don't already have a copy of the querytree list that can be
949 * scribbled on by the planner, make one. For a one-shot plan, we assume
950 * it's okay to scribble on the original query_list.
951 */
952 if (qlist == NIL)
953 {
954 if (!plansource->is_oneshot)
955 qlist = copyObject(plansource->query_list);
956 else
957 qlist = plansource->query_list;
958 }
959
960 /*
961 * If a snapshot is already set (the normal case), we can just use that
962 * for planning. But if it isn't, and we need one, install one.
963 */
964 snapshot_set = false;
965 if (!ActiveSnapshotSet() &&
966 plansource->raw_parse_tree &&
968 {
970 snapshot_set = true;
971 }
972
973 /*
974 * Generate the plan.
975 */
976 plist = pg_plan_queries(qlist, plansource->query_string,
977 plansource->cursor_options, boundParams);
978
979 /* Release snapshot if we got one */
980 if (snapshot_set)
982
983 /*
984 * Normally, we create a dedicated memory context for the CachedPlan and
985 * its subsidiary data. Although it's usually not very large, the context
986 * is designed to allow growth if necessary.
987 *
988 * The PlannedStmts are stored in a separate child context (stmt_context)
989 * of the CachedPlan's memory context. This separation allows
990 * UpdateCachedPlan() to free and replace the PlannedStmts without
991 * affecting the CachedPlan structure or its stmt_list List.
992 *
993 * For one-shot plans, we instead use the caller's memory context, as the
994 * CachedPlan will not persist. stmt_context will be set to NULL in this
995 * case, because UpdateCachedPlan() should never get called on a one-shot
996 * plan.
997 */
998 if (!plansource->is_oneshot)
999 {
1001 "CachedPlan",
1003 MemoryContextCopyAndSetIdentifier(plan_context, plansource->query_string);
1004
1006 "CachedPlan PlannedStmts",
1008 MemoryContextCopyAndSetIdentifier(stmt_context, plansource->query_string);
1009 MemoryContextSetParent(stmt_context, plan_context);
1010
1011 MemoryContextSwitchTo(stmt_context);
1012 plist = copyObject(plist);
1013
1014 MemoryContextSwitchTo(plan_context);
1015 plist = list_copy(plist);
1016 }
1017 else
1018 plan_context = CurrentMemoryContext;
1019
1020 /*
1021 * Create and fill the CachedPlan struct within the new context.
1022 */
1023 plan = (CachedPlan *) palloc(sizeof(CachedPlan));
1024 plan->magic = CACHEDPLAN_MAGIC;
1025 plan->stmt_list = plist;
1026
1027 /*
1028 * CachedPlan is dependent on role either if RLS affected the rewrite
1029 * phase or if a role dependency was injected during planning. And it's
1030 * transient if any plan is marked so.
1031 */
1032 plan->planRoleId = GetUserId();
1033 plan->dependsOnRole = plansource->dependsOnRLS;
1034 is_transient = false;
1035 foreach(lc, plist)
1036 {
1037 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1038
1039 if (plannedstmt->commandType == CMD_UTILITY)
1040 continue; /* Ignore utility statements */
1041
1042 if (plannedstmt->transientPlan)
1043 is_transient = true;
1044 if (plannedstmt->dependsOnRole)
1045 plan->dependsOnRole = true;
1046 }
1047 if (is_transient)
1048 {
1050 plan->saved_xmin = TransactionXmin;
1051 }
1052 else
1053 plan->saved_xmin = InvalidTransactionId;
1054 plan->refcount = 0;
1055 plan->context = plan_context;
1056 plan->stmt_context = stmt_context;
1057 plan->is_oneshot = plansource->is_oneshot;
1058 plan->is_saved = false;
1059 plan->is_reused = false;
1060 plan->is_valid = true;
1061
1062 /* assign generation number to new plan */
1063 plan->generation = ++(plansource->generation);
1064
1065 MemoryContextSwitchTo(oldcxt);
1066
1067 return plan;
1068}
List * list_copy(const List *oldlist)
Definition: list.c:1573
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:637
void * palloc(Size size)
Definition: mcxt.c:1317
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:177
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:101
Oid GetUserId(void)
Definition: miscinit.c:520
#define copyObject(obj)
Definition: nodes.h:226
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
bool analyze_requires_snapshot(RawStmt *parseTree)
Definition: analyze.c:576
#define NIL
Definition: pg_list.h:68
#define plan(x)
Definition: pg_regress.c:161
static List * RevalidateCachedQuery(CachedPlanSource *plansource, QueryEnvironment *queryEnv, bool release_generic)
Definition: plancache.c:590
#define CACHEDPLAN_MAGIC
Definition: plancache.h:43
List * pg_plan_queries(List *querytrees, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:970
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:271
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:669
TransactionId TransactionXmin
Definition: snapmgr.c:158
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:799
void PopActiveSnapshot(void)
Definition: snapmgr.c:762
const char * query_string
Definition: plancache.h:97
struct RawStmt * raw_parse_tree
Definition: plancache.h:96
List * query_list
Definition: plancache.h:108
Definition: pg_list.h:54
bool transientPlan
Definition: plannodes.h:68
bool dependsOnRole
Definition: plannodes.h:71
#define InvalidTransactionId
Definition: transam.h:31
#define TransactionIdIsNormal(xid)
Definition: transam.h:42

References ActiveSnapshotSet(), ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, analyze_requires_snapshot(), Assert(), CACHEDPLAN_MAGIC, CMD_UTILITY, PlannedStmt::commandType, copyObject, CurrentMemoryContext, CachedPlanSource::cursor_options, CachedPlanSource::dependsOnRLS, PlannedStmt::dependsOnRole, CachedPlanSource::generation, GetTransactionSnapshot(), GetUserId(), InvalidTransactionId, CachedPlanSource::is_oneshot, CachedPlanSource::is_valid, lfirst_node, list_copy(), MemoryContextCopyAndSetIdentifier, MemoryContextSetParent(), MemoryContextSwitchTo(), NIL, palloc(), pg_plan_queries(), plan, PopActiveSnapshot(), PushActiveSnapshot(), CachedPlanSource::query_list, CachedPlanSource::query_string, CachedPlanSource::raw_parse_tree, RevalidateCachedQuery(), TransactionIdIsNormal, TransactionXmin, and PlannedStmt::transientPlan.

Referenced by GetCachedPlan().

◆ cached_plan_cost()

static double cached_plan_cost ( CachedPlan plan,
bool  include_planner 
)
static

Definition at line 1240 of file plancache.c.

1241{
1242 double result = 0;
1243 ListCell *lc;
1244
1245 foreach(lc, plan->stmt_list)
1246 {
1247 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1248
1249 if (plannedstmt->commandType == CMD_UTILITY)
1250 continue; /* Ignore utility statements */
1251
1252 result += plannedstmt->planTree->total_cost;
1253
1254 if (include_planner)
1255 {
1256 /*
1257 * Currently we use a very crude estimate of planning effort based
1258 * on the number of relations in the finished plan's rangetable.
1259 * Join planning effort actually scales much worse than linearly
1260 * in the number of relations --- but only until the join collapse
1261 * limits kick in. Also, while inheritance child relations surely
1262 * add to planning effort, they don't make the join situation
1263 * worse. So the actual shape of the planning cost curve versus
1264 * number of relations isn't all that obvious. It will take
1265 * considerable work to arrive at a less crude estimate, and for
1266 * now it's not clear that's worth doing.
1267 *
1268 * The other big difficulty here is that we don't have any very
1269 * good model of how planning cost compares to execution costs.
1270 * The current multiplier of 1000 * cpu_operator_cost is probably
1271 * on the low side, but we'll try this for awhile before making a
1272 * more aggressive correction.
1273 *
1274 * If we ever do write a more complicated estimator, it should
1275 * probably live in src/backend/optimizer/ not here.
1276 */
1277 int nrelations = list_length(plannedstmt->rtable);
1278
1279 result += 1000.0 * cpu_operator_cost * (nrelations + 1);
1280 }
1281 }
1282
1283 return result;
1284}
double cpu_operator_cost
Definition: costsize.c:134
static int list_length(const List *l)
Definition: pg_list.h:152
Cost total_cost
Definition: plannodes.h:176
struct Plan * planTree
Definition: plannodes.h:80

References CMD_UTILITY, PlannedStmt::commandType, cpu_operator_cost, lfirst_node, list_length(), plan, PlannedStmt::planTree, PlannedStmt::rtable, and Plan::total_cost.

Referenced by GetCachedPlan(), and UpdateCachedPlan().

◆ CachedPlanAllowsSimpleValidityCheck()

bool CachedPlanAllowsSimpleValidityCheck ( CachedPlanSource plansource,
CachedPlan plan,
ResourceOwner  owner 
)

Definition at line 1480 of file plancache.c.

1482{
1483 ListCell *lc;
1484
1485 /*
1486 * Sanity-check that the caller gave us a validated generic plan. Notice
1487 * that we *don't* assert plansource->is_valid as you might expect; that's
1488 * because it's possible that that's already false when GetCachedPlan
1489 * returns, e.g. because ResetPlanCache happened partway through. We
1490 * should accept the plan as long as plan->is_valid is true, and expect to
1491 * replan after the next CachedPlanIsSimplyValid call.
1492 */
1493 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1494 Assert(plan->magic == CACHEDPLAN_MAGIC);
1495 Assert(plan->is_valid);
1496 Assert(plan == plansource->gplan);
1497 Assert(plansource->search_path != NULL);
1499
1500 /* We don't support oneshot plans here. */
1501 if (plansource->is_oneshot)
1502 return false;
1503 Assert(!plan->is_oneshot);
1504
1505 /*
1506 * If the plan is dependent on RLS considerations, or it's transient,
1507 * reject. These things probably can't ever happen for table-free
1508 * queries, but for safety's sake let's check.
1509 */
1510 if (plansource->dependsOnRLS)
1511 return false;
1512 if (plan->dependsOnRole)
1513 return false;
1514 if (TransactionIdIsValid(plan->saved_xmin))
1515 return false;
1516
1517 /*
1518 * Reject if AcquirePlannerLocks would have anything to do. This is
1519 * simplistic, but there's no need to inquire any more carefully; indeed,
1520 * for current callers it shouldn't even be possible to hit any of these
1521 * checks.
1522 */
1523 foreach(lc, plansource->query_list)
1524 {
1525 Query *query = lfirst_node(Query, lc);
1526
1527 if (query->commandType == CMD_UTILITY)
1528 return false;
1529 if (query->rtable || query->cteList || query->hasSubLinks)
1530 return false;
1531 }
1532
1533 /*
1534 * Reject if AcquireExecutorLocks would have anything to do. This is
1535 * probably unnecessary given the previous check, but let's be safe.
1536 */
1537 foreach(lc, plan->stmt_list)
1538 {
1539 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1540 ListCell *lc2;
1541
1542 if (plannedstmt->commandType == CMD_UTILITY)
1543 return false;
1544
1545 /*
1546 * We have to grovel through the rtable because it's likely to contain
1547 * an RTE_RESULT relation, rather than being totally empty.
1548 */
1549 foreach(lc2, plannedstmt->rtable)
1550 {
1551 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1552
1553 if (rte->rtekind == RTE_RELATION)
1554 return false;
1555 }
1556 }
1557
1558 /*
1559 * Okay, it's simple. Note that what we've primarily established here is
1560 * that no locks need be taken before checking the plan's is_valid flag.
1561 */
1562
1563 /* Bump refcount if requested. */
1564 if (owner)
1565 {
1566 ResourceOwnerEnlarge(owner);
1567 plan->refcount++;
1569 }
1570
1571 return true;
1572}
bool SearchPathMatchesCurrentEnvironment(SearchPathMatcher *path)
Definition: namespace.c:3911
#define lfirst(lc)
Definition: pg_list.h:172
static void ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
Definition: plancache.c:136
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:42
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition: resowner.c:452
struct CachedPlan * gplan
Definition: plancache.h:118
struct SearchPathMatcher * search_path
Definition: plancache.h:111
List * cteList
Definition: parsenodes.h:168
List * rtable
Definition: parsenodes.h:170
#define TransactionIdIsValid(xid)
Definition: transam.h:41

References Assert(), CACHEDPLAN_MAGIC, CACHEDPLANSOURCE_MAGIC, CMD_UTILITY, Query::commandType, PlannedStmt::commandType, Query::cteList, CachedPlanSource::dependsOnRLS, CachedPlanSource::gplan, CachedPlanSource::is_oneshot, lfirst, lfirst_node, CachedPlanSource::magic, plan, CachedPlanSource::query_list, ResourceOwnerEnlarge(), ResourceOwnerRememberPlanCacheRef(), Query::rtable, PlannedStmt::rtable, RTE_RELATION, RangeTblEntry::rtekind, CachedPlanSource::search_path, SearchPathMatchesCurrentEnvironment(), and TransactionIdIsValid.

Referenced by exec_eval_simple_expr(), and exec_simple_check_plan().

◆ CachedPlanGetTargetList()

List * CachedPlanGetTargetList ( CachedPlanSource plansource,
QueryEnvironment queryEnv 
)

Definition at line 1784 of file plancache.c.

1786{
1787 Query *pstmt;
1788
1789 /* Assert caller is doing things in a sane order */
1790 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1791 Assert(plansource->is_complete);
1792
1793 /*
1794 * No work needed if statement doesn't return tuples (we assume this
1795 * feature cannot be changed by an invalidation)
1796 */
1797 if (plansource->resultDesc == NULL)
1798 return NIL;
1799
1800 /* Make sure the querytree list is valid and we have parse-time locks */
1801 RevalidateCachedQuery(plansource, queryEnv, true);
1802
1803 /* Get the primary statement and find out what it returns */
1804 pstmt = QueryListGetPrimaryStmt(plansource->query_list);
1805
1806 return FetchStatementTargetList((Node *) pstmt);
1807}
static Query * QueryListGetPrimaryStmt(List *stmts)
Definition: plancache.c:1897
List * FetchStatementTargetList(Node *stmt)
Definition: pquery.c:370
TupleDesc resultDesc
Definition: plancache.h:105
Definition: nodes.h:131

References Assert(), CACHEDPLANSOURCE_MAGIC, FetchStatementTargetList(), CachedPlanSource::is_complete, CachedPlanSource::magic, NIL, CachedPlanSource::query_list, QueryListGetPrimaryStmt(), CachedPlanSource::resultDesc, and RevalidateCachedQuery().

Referenced by exec_describe_statement_message(), and FetchPreparedStatementTargetList().

◆ CachedPlanIsSimplyValid()

bool CachedPlanIsSimplyValid ( CachedPlanSource plansource,
CachedPlan plan,
ResourceOwner  owner 
)

Definition at line 1595 of file plancache.c.

1597{
1598 /*
1599 * Careful here: since the caller doesn't necessarily hold a refcount on
1600 * the plan to start with, it's possible that "plan" is a dangling
1601 * pointer. Don't dereference it until we've verified that it still
1602 * matches the plansource's gplan (which is either valid or NULL).
1603 */
1604 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1605
1606 /*
1607 * Has cache invalidation fired on this plan? We can check this right
1608 * away since there are no locks that we'd need to acquire first. Note
1609 * that here we *do* check plansource->is_valid, so as to force plan
1610 * rebuild if that's become false.
1611 */
1612 if (!plansource->is_valid ||
1613 plan == NULL || plan != plansource->gplan ||
1614 !plan->is_valid)
1615 return false;
1616
1617 Assert(plan->magic == CACHEDPLAN_MAGIC);
1618
1619 /* Is the search_path still the same as when we made it? */
1620 Assert(plansource->search_path != NULL);
1622 return false;
1623
1624 /* It's still good. Bump refcount if requested. */
1625 if (owner)
1626 {
1627 ResourceOwnerEnlarge(owner);
1628 plan->refcount++;
1630 }
1631
1632 return true;
1633}

References Assert(), CACHEDPLAN_MAGIC, CACHEDPLANSOURCE_MAGIC, CachedPlanSource::gplan, CachedPlanSource::is_valid, CachedPlanSource::magic, plan, ResourceOwnerEnlarge(), ResourceOwnerRememberPlanCacheRef(), CachedPlanSource::search_path, and SearchPathMatchesCurrentEnvironment().

Referenced by exec_eval_simple_expr().

◆ CachedPlanIsValid()

bool CachedPlanIsValid ( CachedPlanSource plansource)

Definition at line 1771 of file plancache.c.

1772{
1773 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1774 return plansource->is_valid;
1775}

References Assert(), CACHEDPLANSOURCE_MAGIC, CachedPlanSource::is_valid, and CachedPlanSource::magic.

Referenced by SPI_plan_is_valid().

◆ CachedPlanSetParentContext()

void CachedPlanSetParentContext ( CachedPlanSource plansource,
MemoryContext  newcontext 
)

Definition at line 1642 of file plancache.c.

1644{
1645 /* Assert caller is doing things in a sane order */
1646 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1647 Assert(plansource->is_complete);
1648
1649 /* These seem worth real tests, though */
1650 if (plansource->is_saved)
1651 elog(ERROR, "cannot move a saved cached plan to another context");
1652 if (plansource->is_oneshot)
1653 elog(ERROR, "cannot move a one-shot cached plan to another context");
1654
1655 /* OK, let the caller keep the plan where he wishes */
1656 MemoryContextSetParent(plansource->context, newcontext);
1657
1658 /*
1659 * The query_context needs no special handling, since it's a child of
1660 * plansource->context. But if there's a generic plan, it should be
1661 * maintained as a sibling of plansource->context.
1662 */
1663 if (plansource->gplan)
1664 {
1665 Assert(plansource->gplan->magic == CACHEDPLAN_MAGIC);
1666 MemoryContextSetParent(plansource->gplan->context, newcontext);
1667 }
1668}
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
MemoryContext context
Definition: plancache.h:106
MemoryContext context
Definition: plancache.h:159

References Assert(), CACHEDPLAN_MAGIC, CACHEDPLANSOURCE_MAGIC, CachedPlanSource::context, CachedPlan::context, elog, ERROR, CachedPlanSource::gplan, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_saved, CachedPlanSource::magic, CachedPlan::magic, and MemoryContextSetParent().

Referenced by _SPI_make_plan_non_temp().

◆ CheckCachedPlan()

static bool CheckCachedPlan ( CachedPlanSource plansource)
static

Definition at line 833 of file plancache.c.

834{
835 CachedPlan *plan = plansource->gplan;
836
837 /* Assert that caller checked the querytree */
838 Assert(plansource->is_valid);
839
840 /* If there's no generic plan, just say "false" */
841 if (!plan)
842 return false;
843
844 Assert(plan->magic == CACHEDPLAN_MAGIC);
845 /* Generic plans are never one-shot */
846 Assert(!plan->is_oneshot);
847
848 /*
849 * If plan isn't valid for current role, we can't use it.
850 */
851 if (plan->is_valid && plan->dependsOnRole &&
852 plan->planRoleId != GetUserId())
853 plan->is_valid = false;
854
855 /*
856 * If it appears valid, acquire locks and recheck; this is much the same
857 * logic as in RevalidateCachedQuery, but for a plan.
858 */
859 if (plan->is_valid)
860 {
861 /*
862 * Plan must have positive refcount because it is referenced by
863 * plansource; so no need to fear it disappears under us here.
864 */
865 Assert(plan->refcount > 0);
866
867 AcquireExecutorLocks(plan->stmt_list, true);
868
869 /*
870 * If plan was transient, check to see if TransactionXmin has
871 * advanced, and if so invalidate it.
872 */
873 if (plan->is_valid &&
874 TransactionIdIsValid(plan->saved_xmin) &&
876 plan->is_valid = false;
877
878 /*
879 * By now, if any invalidation has happened, the inval callback
880 * functions will have marked the plan invalid.
881 */
882 if (plan->is_valid)
883 {
884 /* Successfully revalidated and locked the query. */
885 return true;
886 }
887
888 /* Oops, the race case happened. Release useless locks. */
889 AcquireExecutorLocks(plan->stmt_list, false);
890 }
891
892 /*
893 * Plan has been invalidated, so unlink it from the parent and release it.
894 */
895 ReleaseGenericPlan(plansource);
896
897 return false;
898}
static void ReleaseGenericPlan(CachedPlanSource *plansource)
Definition: plancache.c:556
static void AcquireExecutorLocks(List *stmt_list, bool acquire)
Definition: plancache.c:1916
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43

References AcquireExecutorLocks(), Assert(), CACHEDPLAN_MAGIC, GetUserId(), CachedPlanSource::gplan, CachedPlanSource::is_valid, plan, ReleaseGenericPlan(), TransactionIdEquals, TransactionIdIsValid, and TransactionXmin.

Referenced by GetCachedPlan().

◆ choose_custom_plan()

static bool choose_custom_plan ( CachedPlanSource plansource,
ParamListInfo  boundParams 
)
static

Definition at line 1183 of file plancache.c.

1184{
1185 double avg_custom_cost;
1186
1187 /* One-shot plans will always be considered custom */
1188 if (plansource->is_oneshot)
1189 return true;
1190
1191 /* Otherwise, never any point in a custom plan if there's no parameters */
1192 if (boundParams == NULL)
1193 return false;
1194 /* ... nor when planning would be a no-op */
1195 if (!StmtPlanRequiresRevalidation(plansource))
1196 return false;
1197
1198 /* Let settings force the decision */
1200 return false;
1202 return true;
1203
1204 /* See if caller wants to force the decision */
1205 if (plansource->cursor_options & CURSOR_OPT_GENERIC_PLAN)
1206 return false;
1207 if (plansource->cursor_options & CURSOR_OPT_CUSTOM_PLAN)
1208 return true;
1209
1210 /* Generate custom plans until we have done at least 5 (arbitrary) */
1211 if (plansource->num_custom_plans < 5)
1212 return true;
1213
1214 avg_custom_cost = plansource->total_custom_cost / plansource->num_custom_plans;
1215
1216 /*
1217 * Prefer generic plan if it's less expensive than the average custom
1218 * plan. (Because we include a charge for cost of planning in the
1219 * custom-plan costs, this means the generic plan only has to be less
1220 * expensive than the execution cost plus replan cost of the custom
1221 * plans.)
1222 *
1223 * Note that if generic_cost is -1 (indicating we've not yet determined
1224 * the generic plan cost), we'll always prefer generic at this point.
1225 */
1226 if (plansource->generic_cost < avg_custom_cost)
1227 return false;
1228
1229 return true;
1230}
#define CURSOR_OPT_GENERIC_PLAN
Definition: parsenodes.h:3376
#define CURSOR_OPT_CUSTOM_PLAN
Definition: parsenodes.h:3377
int plan_cache_mode
Definition: plancache.c:148
#define StmtPlanRequiresRevalidation(plansource)
Definition: plancache.c:85
@ PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN
Definition: plancache.h:36
@ PLAN_CACHE_MODE_FORCE_GENERIC_PLAN
Definition: plancache.h:35
double total_custom_cost
Definition: plancache.h:129
int64 num_custom_plans
Definition: plancache.h:130
double generic_cost
Definition: plancache.h:128

References CURSOR_OPT_CUSTOM_PLAN, CURSOR_OPT_GENERIC_PLAN, CachedPlanSource::cursor_options, CachedPlanSource::generic_cost, CachedPlanSource::is_oneshot, CachedPlanSource::num_custom_plans, plan_cache_mode, PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN, PLAN_CACHE_MODE_FORCE_GENERIC_PLAN, StmtPlanRequiresRevalidation, and CachedPlanSource::total_custom_cost.

Referenced by GetCachedPlan().

◆ CompleteCachedPlan()

void CompleteCachedPlan ( CachedPlanSource plansource,
List querytree_list,
MemoryContext  querytree_context,
Oid param_types,
int  num_params,
ParserSetupHook  parserSetup,
void *  parserSetupArg,
int  cursor_options,
bool  fixed_result 
)

Definition at line 367 of file plancache.c.

376{
377 MemoryContext source_context = plansource->context;
379
380 /* Assert caller is doing things in a sane order */
381 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
382 Assert(!plansource->is_complete);
383
384 /*
385 * If caller supplied a querytree_context, reparent it underneath the
386 * CachedPlanSource's context; otherwise, create a suitable context and
387 * copy the querytree_list into it. But no data copying should be done
388 * for one-shot plans; for those, assume the passed querytree_list is
389 * sufficiently long-lived.
390 */
391 if (plansource->is_oneshot)
392 {
393 querytree_context = CurrentMemoryContext;
394 }
395 else if (querytree_context != NULL)
396 {
397 MemoryContextSetParent(querytree_context, source_context);
398 MemoryContextSwitchTo(querytree_context);
399 }
400 else
401 {
402 /* Again, it's a good bet the querytree_context can be small */
403 querytree_context = AllocSetContextCreate(source_context,
404 "CachedPlanQuery",
406 MemoryContextSwitchTo(querytree_context);
407 querytree_list = copyObject(querytree_list);
408 }
409
410 plansource->query_context = querytree_context;
411 plansource->query_list = querytree_list;
412
413 if (!plansource->is_oneshot && StmtPlanRequiresRevalidation(plansource))
414 {
415 /*
416 * Use the planner machinery to extract dependencies. Data is saved
417 * in query_context. (We assume that not a lot of extra cruft is
418 * created by this call.) We can skip this for one-shot plans, and
419 * plans not needing revalidation have no such dependencies anyway.
420 */
421 extract_query_dependencies((Node *) querytree_list,
422 &plansource->relationOids,
423 &plansource->invalItems,
424 &plansource->dependsOnRLS);
425
426 /* Update RLS info as well. */
427 plansource->rewriteRoleId = GetUserId();
428 plansource->rewriteRowSecurity = row_security;
429
430 /*
431 * Also save the current search_path in the query_context. (This
432 * should not generate much extra cruft either, since almost certainly
433 * the path is already valid.) Again, we don't really need this for
434 * one-shot plans; and we *must* skip this for transaction control
435 * commands, because this could result in catalog accesses.
436 */
437 plansource->search_path = GetSearchPathMatcher(querytree_context);
438 }
439
440 /*
441 * Save the final parameter types (or other parameter specification data)
442 * into the source_context, as well as our other parameters. Also save
443 * the result tuple descriptor.
444 */
445 MemoryContextSwitchTo(source_context);
446
447 if (num_params > 0)
448 {
449 plansource->param_types = (Oid *) palloc(num_params * sizeof(Oid));
450 memcpy(plansource->param_types, param_types, num_params * sizeof(Oid));
451 }
452 else
453 plansource->param_types = NULL;
454 plansource->num_params = num_params;
455 plansource->parserSetup = parserSetup;
456 plansource->parserSetupArg = parserSetupArg;
457 plansource->cursor_options = cursor_options;
458 plansource->fixed_result = fixed_result;
459 plansource->resultDesc = PlanCacheComputeResultDesc(querytree_list);
460
461 MemoryContextSwitchTo(oldcxt);
462
463 plansource->is_complete = true;
464 plansource->is_valid = true;
465}
bool row_security
Definition: guc_tables.c:515
SearchPathMatcher * GetSearchPathMatcher(MemoryContext context)
Definition: namespace.c:3852
static TupleDesc PlanCacheComputeResultDesc(List *stmt_list)
Definition: plancache.c:2094
unsigned int Oid
Definition: postgres_ext.h:32
void extract_query_dependencies(Node *query, List **relationOids, List **invalItems, bool *hasRowSecurity)
Definition: setrefs.c:3633
Oid * param_types
Definition: plancache.h:99
MemoryContext query_context
Definition: plancache.h:113
List * invalItems
Definition: plancache.h:110
ParserSetupHook parserSetup
Definition: plancache.h:101
bool rewriteRowSecurity
Definition: plancache.h:115
List * relationOids
Definition: plancache.h:109
void * parserSetupArg
Definition: plancache.h:102

References ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, Assert(), CACHEDPLANSOURCE_MAGIC, CachedPlanSource::context, copyObject, CurrentMemoryContext, CachedPlanSource::cursor_options, CachedPlanSource::dependsOnRLS, extract_query_dependencies(), CachedPlanSource::fixed_result, GetSearchPathMatcher(), GetUserId(), CachedPlanSource::invalItems, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_valid, CachedPlanSource::magic, MemoryContextSetParent(), MemoryContextSwitchTo(), CachedPlanSource::num_params, palloc(), CachedPlanSource::param_types, CachedPlanSource::parserSetup, CachedPlanSource::parserSetupArg, PlanCacheComputeResultDesc(), CachedPlanSource::query_context, CachedPlanSource::query_list, CachedPlanSource::relationOids, CachedPlanSource::resultDesc, CachedPlanSource::rewriteRoleId, CachedPlanSource::rewriteRowSecurity, row_security, CachedPlanSource::search_path, and StmtPlanRequiresRevalidation.

Referenced by _SPI_execute_plan(), _SPI_prepare_plan(), exec_parse_message(), and PrepareQuery().

◆ CopyCachedPlan()

CachedPlanSource * CopyCachedPlan ( CachedPlanSource plansource)

Definition at line 1680 of file plancache.c.

1681{
1682 CachedPlanSource *newsource;
1683 MemoryContext source_context;
1684 MemoryContext querytree_context;
1685 MemoryContext oldcxt;
1686
1687 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1688 Assert(plansource->is_complete);
1689
1690 /*
1691 * One-shot plans can't be copied, because we haven't taken care that
1692 * parsing/planning didn't scribble on the raw parse tree or querytrees.
1693 */
1694 if (plansource->is_oneshot)
1695 elog(ERROR, "cannot copy a one-shot cached plan");
1696
1698 "CachedPlanSource",
1700
1701 oldcxt = MemoryContextSwitchTo(source_context);
1702
1703 newsource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
1704 newsource->magic = CACHEDPLANSOURCE_MAGIC;
1705 newsource->raw_parse_tree = copyObject(plansource->raw_parse_tree);
1706 newsource->query_string = pstrdup(plansource->query_string);
1707 MemoryContextSetIdentifier(source_context, newsource->query_string);
1708 newsource->commandTag = plansource->commandTag;
1709 if (plansource->num_params > 0)
1710 {
1711 newsource->param_types = (Oid *)
1712 palloc(plansource->num_params * sizeof(Oid));
1713 memcpy(newsource->param_types, plansource->param_types,
1714 plansource->num_params * sizeof(Oid));
1715 }
1716 else
1717 newsource->param_types = NULL;
1718 newsource->num_params = plansource->num_params;
1719 newsource->parserSetup = plansource->parserSetup;
1720 newsource->parserSetupArg = plansource->parserSetupArg;
1721 newsource->cursor_options = plansource->cursor_options;
1722 newsource->fixed_result = plansource->fixed_result;
1723 if (plansource->resultDesc)
1724 newsource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
1725 else
1726 newsource->resultDesc = NULL;
1727 newsource->context = source_context;
1728
1729 querytree_context = AllocSetContextCreate(source_context,
1730 "CachedPlanQuery",
1732 MemoryContextSwitchTo(querytree_context);
1733 newsource->query_list = copyObject(plansource->query_list);
1734 newsource->relationOids = copyObject(plansource->relationOids);
1735 newsource->invalItems = copyObject(plansource->invalItems);
1736 if (plansource->search_path)
1737 newsource->search_path = CopySearchPathMatcher(plansource->search_path);
1738 newsource->query_context = querytree_context;
1739 newsource->rewriteRoleId = plansource->rewriteRoleId;
1740 newsource->rewriteRowSecurity = plansource->rewriteRowSecurity;
1741 newsource->dependsOnRLS = plansource->dependsOnRLS;
1742
1743 newsource->gplan = NULL;
1744
1745 newsource->is_oneshot = false;
1746 newsource->is_complete = true;
1747 newsource->is_saved = false;
1748 newsource->is_valid = plansource->is_valid;
1749 newsource->generation = plansource->generation;
1750
1751 /* We may as well copy any acquired cost knowledge */
1752 newsource->generic_cost = plansource->generic_cost;
1753 newsource->total_custom_cost = plansource->total_custom_cost;
1754 newsource->num_generic_plans = plansource->num_generic_plans;
1755 newsource->num_custom_plans = plansource->num_custom_plans;
1756
1757 MemoryContextSwitchTo(oldcxt);
1758
1759 return newsource;
1760}
char * pstrdup(const char *in)
Definition: mcxt.c:1699
void * palloc0(Size size)
Definition: mcxt.c:1347
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:612
SearchPathMatcher * CopySearchPathMatcher(SearchPathMatcher *path)
Definition: namespace.c:3889
CommandTag commandTag
Definition: plancache.h:98
int64 num_generic_plans
Definition: plancache.h:131
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:234

References ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, Assert(), CACHEDPLANSOURCE_MAGIC, CachedPlanSource::commandTag, CachedPlanSource::context, copyObject, CopySearchPathMatcher(), CreateTupleDescCopy(), CurrentMemoryContext, CachedPlanSource::cursor_options, CachedPlanSource::dependsOnRLS, elog, ERROR, CachedPlanSource::fixed_result, CachedPlanSource::generation, CachedPlanSource::generic_cost, CachedPlanSource::gplan, CachedPlanSource::invalItems, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_saved, CachedPlanSource::is_valid, CachedPlanSource::magic, MemoryContextSetIdentifier(), MemoryContextSwitchTo(), CachedPlanSource::num_custom_plans, CachedPlanSource::num_generic_plans, CachedPlanSource::num_params, palloc(), palloc0(), CachedPlanSource::param_types, CachedPlanSource::parserSetup, CachedPlanSource::parserSetupArg, pstrdup(), CachedPlanSource::query_context, CachedPlanSource::query_list, CachedPlanSource::query_string, CachedPlanSource::raw_parse_tree, CachedPlanSource::relationOids, CachedPlanSource::resultDesc, CachedPlanSource::rewriteRoleId, CachedPlanSource::rewriteRowSecurity, CachedPlanSource::search_path, and CachedPlanSource::total_custom_cost.

Referenced by _SPI_save_plan().

◆ CreateCachedPlan()

CachedPlanSource * CreateCachedPlan ( RawStmt raw_parse_tree,
const char *  query_string,
CommandTag  commandTag 
)

Definition at line 193 of file plancache.c.

196{
197 CachedPlanSource *plansource;
198 MemoryContext source_context;
199 MemoryContext oldcxt;
200
201 Assert(query_string != NULL); /* required as of 8.4 */
202
203 /*
204 * Make a dedicated memory context for the CachedPlanSource and its
205 * permanent subsidiary data. It's probably not going to be large, but
206 * just in case, allow it to grow large. Initially it's a child of the
207 * caller's context (which we assume to be transient), so that it will be
208 * cleaned up on error.
209 */
211 "CachedPlanSource",
213
214 /*
215 * Create and fill the CachedPlanSource struct within the new context.
216 * Most fields are just left empty for the moment.
217 */
218 oldcxt = MemoryContextSwitchTo(source_context);
219
220 plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
221 plansource->magic = CACHEDPLANSOURCE_MAGIC;
222 plansource->raw_parse_tree = copyObject(raw_parse_tree);
223 plansource->query_string = pstrdup(query_string);
224 MemoryContextSetIdentifier(source_context, plansource->query_string);
225 plansource->commandTag = commandTag;
226 plansource->param_types = NULL;
227 plansource->num_params = 0;
228 plansource->parserSetup = NULL;
229 plansource->parserSetupArg = NULL;
230 plansource->cursor_options = 0;
231 plansource->fixed_result = false;
232 plansource->resultDesc = NULL;
233 plansource->context = source_context;
234 plansource->query_list = NIL;
235 plansource->relationOids = NIL;
236 plansource->invalItems = NIL;
237 plansource->search_path = NULL;
238 plansource->query_context = NULL;
239 plansource->rewriteRoleId = InvalidOid;
240 plansource->rewriteRowSecurity = false;
241 plansource->dependsOnRLS = false;
242 plansource->gplan = NULL;
243 plansource->is_oneshot = false;
244 plansource->is_complete = false;
245 plansource->is_saved = false;
246 plansource->is_valid = false;
247 plansource->generation = 0;
248 plansource->generic_cost = -1;
249 plansource->total_custom_cost = 0;
250 plansource->num_generic_plans = 0;
251 plansource->num_custom_plans = 0;
252
253 MemoryContextSwitchTo(oldcxt);
254
255 return plansource;
256}
#define InvalidOid
Definition: postgres_ext.h:37

References ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, Assert(), CACHEDPLANSOURCE_MAGIC, CachedPlanSource::commandTag, CachedPlanSource::context, copyObject, CurrentMemoryContext, CachedPlanSource::cursor_options, CachedPlanSource::dependsOnRLS, CachedPlanSource::fixed_result, CachedPlanSource::generation, CachedPlanSource::generic_cost, CachedPlanSource::gplan, InvalidOid, CachedPlanSource::invalItems, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_saved, CachedPlanSource::is_valid, CachedPlanSource::magic, MemoryContextSetIdentifier(), MemoryContextSwitchTo(), NIL, CachedPlanSource::num_custom_plans, CachedPlanSource::num_generic_plans, CachedPlanSource::num_params, palloc0(), CachedPlanSource::param_types, CachedPlanSource::parserSetup, CachedPlanSource::parserSetupArg, pstrdup(), CachedPlanSource::query_context, CachedPlanSource::query_list, CachedPlanSource::query_string, CachedPlanSource::raw_parse_tree, CachedPlanSource::relationOids, CachedPlanSource::resultDesc, CachedPlanSource::rewriteRoleId, CachedPlanSource::rewriteRowSecurity, CachedPlanSource::search_path, and CachedPlanSource::total_custom_cost.

Referenced by _SPI_prepare_plan(), exec_parse_message(), and PrepareQuery().

◆ CreateOneShotCachedPlan()

CachedPlanSource * CreateOneShotCachedPlan ( RawStmt raw_parse_tree,
const char *  query_string,
CommandTag  commandTag 
)

Definition at line 277 of file plancache.c.

280{
281 CachedPlanSource *plansource;
282
283 Assert(query_string != NULL); /* required as of 8.4 */
284
285 /*
286 * Create and fill the CachedPlanSource struct within the caller's memory
287 * context. Most fields are just left empty for the moment.
288 */
289 plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
290 plansource->magic = CACHEDPLANSOURCE_MAGIC;
291 plansource->raw_parse_tree = raw_parse_tree;
292 plansource->query_string = query_string;
293 plansource->commandTag = commandTag;
294 plansource->param_types = NULL;
295 plansource->num_params = 0;
296 plansource->parserSetup = NULL;
297 plansource->parserSetupArg = NULL;
298 plansource->cursor_options = 0;
299 plansource->fixed_result = false;
300 plansource->resultDesc = NULL;
301 plansource->context = CurrentMemoryContext;
302 plansource->query_list = NIL;
303 plansource->relationOids = NIL;
304 plansource->invalItems = NIL;
305 plansource->search_path = NULL;
306 plansource->query_context = NULL;
307 plansource->rewriteRoleId = InvalidOid;
308 plansource->rewriteRowSecurity = false;
309 plansource->dependsOnRLS = false;
310 plansource->gplan = NULL;
311 plansource->is_oneshot = true;
312 plansource->is_complete = false;
313 plansource->is_saved = false;
314 plansource->is_valid = false;
315 plansource->generation = 0;
316 plansource->generic_cost = -1;
317 plansource->total_custom_cost = 0;
318 plansource->num_generic_plans = 0;
319 plansource->num_custom_plans = 0;
320
321 return plansource;
322}

References Assert(), CACHEDPLANSOURCE_MAGIC, CachedPlanSource::commandTag, CachedPlanSource::context, CurrentMemoryContext, CachedPlanSource::cursor_options, CachedPlanSource::dependsOnRLS, CachedPlanSource::fixed_result, CachedPlanSource::generation, CachedPlanSource::generic_cost, CachedPlanSource::gplan, InvalidOid, CachedPlanSource::invalItems, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_saved, CachedPlanSource::is_valid, CachedPlanSource::magic, NIL, CachedPlanSource::num_custom_plans, CachedPlanSource::num_generic_plans, CachedPlanSource::num_params, palloc0(), CachedPlanSource::param_types, CachedPlanSource::parserSetup, CachedPlanSource::parserSetupArg, CachedPlanSource::query_context, CachedPlanSource::query_list, CachedPlanSource::query_string, CachedPlanSource::raw_parse_tree, CachedPlanSource::relationOids, CachedPlanSource::resultDesc, CachedPlanSource::rewriteRoleId, CachedPlanSource::rewriteRowSecurity, CachedPlanSource::search_path, and CachedPlanSource::total_custom_cost.

Referenced by _SPI_prepare_oneshot_plan().

◆ DropCachedPlan()

void DropCachedPlan ( CachedPlanSource plansource)

Definition at line 527 of file plancache.c.

528{
529 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
530
531 /* If it's been saved, remove it from the list */
532 if (plansource->is_saved)
533 {
534 dlist_delete(&plansource->node);
535 plansource->is_saved = false;
536 }
537
538 /* Decrement generic CachedPlan's refcount and drop if no longer needed */
539 ReleaseGenericPlan(plansource);
540
541 /* Mark it no longer valid */
542 plansource->magic = 0;
543
544 /*
545 * Remove the CachedPlanSource and all subsidiary data (including the
546 * query_context if any). But if it's a one-shot we can't free anything.
547 */
548 if (!plansource->is_oneshot)
549 MemoryContextDelete(plansource->context);
550}
static void dlist_delete(dlist_node *node)
Definition: ilist.h:405
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
dlist_node node
Definition: plancache.h:126

References Assert(), CACHEDPLANSOURCE_MAGIC, CachedPlanSource::context, dlist_delete(), CachedPlanSource::is_oneshot, CachedPlanSource::is_saved, CachedPlanSource::magic, MemoryContextDelete(), CachedPlanSource::node, and ReleaseGenericPlan().

Referenced by drop_unnamed_stmt(), DropAllPreparedStatements(), DropPreparedStatement(), and SPI_freeplan().

◆ FreeCachedExpression()

void FreeCachedExpression ( CachedExpression cexpr)

Definition at line 1878 of file plancache.c.

1879{
1880 /* Sanity check */
1881 Assert(cexpr->magic == CACHEDEXPR_MAGIC);
1882 /* Unlink from global list */
1883 dlist_delete(&cexpr->node);
1884 /* Free all storage associated with CachedExpression */
1886}
#define CACHEDEXPR_MAGIC
Definition: plancache.h:44
MemoryContext context
Definition: plancache.h:186
dlist_node node
Definition: plancache.h:187

References Assert(), CACHEDEXPR_MAGIC, CachedExpression::context, dlist_delete(), CachedExpression::magic, MemoryContextDelete(), and CachedExpression::node.

Referenced by get_cast_hashentry().

◆ GetCachedExpression()

CachedExpression * GetCachedExpression ( Node expr)

Definition at line 1821 of file plancache.c.

1822{
1823 CachedExpression *cexpr;
1824 List *relationOids;
1825 List *invalItems;
1826 MemoryContext cexpr_context;
1827 MemoryContext oldcxt;
1828
1829 /*
1830 * Pass the expression through the planner, and collect dependencies.
1831 * Everything built here is leaked in the caller's context; that's
1832 * intentional to minimize the size of the permanent data structure.
1833 */
1834 expr = (Node *) expression_planner_with_deps((Expr *) expr,
1835 &relationOids,
1836 &invalItems);
1837
1838 /*
1839 * Make a private memory context, and copy what we need into that. To
1840 * avoid leaking a long-lived context if we fail while copying data, we
1841 * initially make the context under the caller's context.
1842 */
1844 "CachedExpression",
1846
1847 oldcxt = MemoryContextSwitchTo(cexpr_context);
1848
1849 cexpr = (CachedExpression *) palloc(sizeof(CachedExpression));
1850 cexpr->magic = CACHEDEXPR_MAGIC;
1851 cexpr->expr = copyObject(expr);
1852 cexpr->is_valid = true;
1853 cexpr->relationOids = copyObject(relationOids);
1854 cexpr->invalItems = copyObject(invalItems);
1855 cexpr->context = cexpr_context;
1856
1857 MemoryContextSwitchTo(oldcxt);
1858
1859 /*
1860 * Reparent the expr's memory context under CacheMemoryContext so that it
1861 * will live indefinitely.
1862 */
1864
1865 /*
1866 * Add the entry to the global list of cached expressions.
1867 */
1869
1870 return cexpr;
1871}
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:364
MemoryContext CacheMemoryContext
Definition: mcxt.c:152
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:170
static dlist_head cached_expression_list
Definition: plancache.c:100
Expr * expression_planner_with_deps(Expr *expr, List **relationOids, List **invalItems)
Definition: planner.c:6668
List * relationOids
Definition: plancache.h:184
List * invalItems
Definition: plancache.h:185

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, cached_expression_list, CACHEDEXPR_MAGIC, CacheMemoryContext, CachedExpression::context, copyObject, CurrentMemoryContext, dlist_push_tail(), CachedExpression::expr, expression_planner_with_deps(), CachedExpression::invalItems, CachedExpression::is_valid, CachedExpression::magic, MemoryContextSetParent(), MemoryContextSwitchTo(), CachedExpression::node, palloc(), and CachedExpression::relationOids.

Referenced by get_cast_hashentry().

◆ GetCachedPlan()

CachedPlan * GetCachedPlan ( CachedPlanSource plansource,
ParamListInfo  boundParams,
ResourceOwner  owner,
QueryEnvironment queryEnv 
)

Definition at line 1310 of file plancache.c.

1312{
1313 CachedPlan *plan = NULL;
1314 List *qlist;
1315 bool customplan;
1316
1317 /* Assert caller is doing things in a sane order */
1318 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1319 Assert(plansource->is_complete);
1320 /* This seems worth a real test, though */
1321 if (owner && !plansource->is_saved)
1322 elog(ERROR, "cannot apply ResourceOwner to non-saved cached plan");
1323
1324 /* Make sure the querytree list is valid and we have parse-time locks */
1325 qlist = RevalidateCachedQuery(plansource, queryEnv, true);
1326
1327 /* Decide whether to use a custom plan */
1328 customplan = choose_custom_plan(plansource, boundParams);
1329
1330 if (!customplan)
1331 {
1332 if (CheckCachedPlan(plansource))
1333 {
1334 /* We want a generic plan, and we already have a valid one */
1335 plan = plansource->gplan;
1336 Assert(plan->magic == CACHEDPLAN_MAGIC);
1337 /* Reusing the existing plan, so not all locks may be acquired. */
1338 plan->is_reused = true;
1339 }
1340 else
1341 {
1342 /* Build a new generic plan */
1343 plan = BuildCachedPlan(plansource, qlist, NULL, queryEnv);
1344 /* Just make real sure plansource->gplan is clear */
1345 ReleaseGenericPlan(plansource);
1346 /* Link the new generic plan into the plansource */
1347 plansource->gplan = plan;
1348 plan->refcount++;
1349 /* Immediately reparent into appropriate context */
1350 if (plansource->is_saved)
1351 {
1352 /* saved plans all live under CacheMemoryContext */
1354 plan->is_saved = true;
1355 }
1356 else
1357 {
1358 /* otherwise, it should be a sibling of the plansource */
1360 MemoryContextGetParent(plansource->context));
1361 }
1362 /* Update generic_cost whenever we make a new generic plan */
1363 plansource->generic_cost = cached_plan_cost(plan, false);
1364
1365 /*
1366 * If, based on the now-known value of generic_cost, we'd not have
1367 * chosen to use a generic plan, then forget it and make a custom
1368 * plan. This is a bit of a wart but is necessary to avoid a
1369 * glitch in behavior when the custom plans are consistently big
1370 * winners; at some point we'll experiment with a generic plan and
1371 * find it's a loser, but we don't want to actually execute that
1372 * plan.
1373 */
1374 customplan = choose_custom_plan(plansource, boundParams);
1375
1376 /*
1377 * If we choose to plan again, we need to re-copy the query_list,
1378 * since the planner probably scribbled on it. We can force
1379 * BuildCachedPlan to do that by passing NIL.
1380 */
1381 qlist = NIL;
1382 }
1383 }
1384
1385 if (customplan)
1386 {
1387 /* Build a custom plan */
1388 plan = BuildCachedPlan(plansource, qlist, boundParams, queryEnv);
1389 /* Accumulate total costs of custom plans */
1390 plansource->total_custom_cost += cached_plan_cost(plan, true);
1391
1392 plansource->num_custom_plans++;
1393 }
1394 else
1395 {
1396 plansource->num_generic_plans++;
1397 }
1398
1399 Assert(plan != NULL);
1400
1401 /* Flag the plan as in use by caller */
1402 if (owner)
1403 ResourceOwnerEnlarge(owner);
1404 plan->refcount++;
1405 if (owner)
1407
1408 /*
1409 * Saved plans should be under CacheMemoryContext so they will not go away
1410 * until their reference count goes to zero. In the generic-plan cases we
1411 * already took care of that, but for a custom plan, do it as soon as we
1412 * have created a reference-counted link.
1413 */
1414 if (customplan && plansource->is_saved)
1415 {
1417 plan->is_saved = true;
1418 }
1419
1420 return plan;
1421}
MemoryContext MemoryContextGetParent(MemoryContext context)
Definition: mcxt.c:731
static bool choose_custom_plan(CachedPlanSource *plansource, ParamListInfo boundParams)
Definition: plancache.c:1183
static CachedPlan * BuildCachedPlan(CachedPlanSource *plansource, List *qlist, ParamListInfo boundParams, QueryEnvironment *queryEnv)
Definition: plancache.c:919
static bool CheckCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:833
static double cached_plan_cost(CachedPlan *plan, bool include_planner)
Definition: plancache.c:1240

References Assert(), BuildCachedPlan(), cached_plan_cost(), CACHEDPLAN_MAGIC, CACHEDPLANSOURCE_MAGIC, CacheMemoryContext, CheckCachedPlan(), choose_custom_plan(), CachedPlanSource::context, elog, ERROR, CachedPlanSource::generic_cost, CachedPlanSource::gplan, CachedPlanSource::is_complete, CachedPlanSource::is_saved, CachedPlanSource::magic, MemoryContextGetParent(), MemoryContextSetParent(), NIL, CachedPlanSource::num_custom_plans, CachedPlanSource::num_generic_plans, plan, ReleaseGenericPlan(), ResourceOwnerEnlarge(), ResourceOwnerRememberPlanCacheRef(), RevalidateCachedQuery(), and CachedPlanSource::total_custom_cost.

Referenced by _SPI_execute_plan(), exec_bind_message(), ExecuteQuery(), ExplainExecuteQuery(), SPI_cursor_open_internal(), and SPI_plan_get_cached_plan().

◆ InitPlanCache()

void InitPlanCache ( void  )

Definition at line 156 of file plancache.c.

157{
165 CacheRegisterSyscacheCallback(FOREIGNDATAWRAPPEROID, PlanCacheSysCallback, (Datum) 0);
166}
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition: inval.c:1844
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1802
static void PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:2323
static void PlanCacheObjectCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:2214
static void PlanCacheRelCallback(Datum arg, Oid relid)
Definition: plancache.c:2130
uintptr_t Datum
Definition: postgres.h:69

References CacheRegisterRelcacheCallback(), CacheRegisterSyscacheCallback(), PlanCacheObjectCallback(), PlanCacheRelCallback(), and PlanCacheSysCallback().

Referenced by InitPostgres().

◆ PlanCacheComputeResultDesc()

static TupleDesc PlanCacheComputeResultDesc ( List stmt_list)
static

Definition at line 2094 of file plancache.c.

2095{
2096 Query *query;
2097
2098 switch (ChoosePortalStrategy(stmt_list))
2099 {
2100 case PORTAL_ONE_SELECT:
2102 query = linitial_node(Query, stmt_list);
2103 return ExecCleanTypeFromTL(query->targetList);
2104
2106 query = QueryListGetPrimaryStmt(stmt_list);
2107 Assert(query->returningList);
2108 return ExecCleanTypeFromTL(query->returningList);
2109
2110 case PORTAL_UTIL_SELECT:
2111 query = linitial_node(Query, stmt_list);
2112 Assert(query->utilityStmt);
2113 return UtilityTupleDescriptor(query->utilityStmt);
2114
2115 case PORTAL_MULTI_QUERY:
2116 /* will not return tuples */
2117 break;
2118 }
2119 return NULL;
2120}
TupleDesc ExecCleanTypeFromTL(List *targetList)
Definition: execTuples.c:2137
#define linitial_node(type, l)
Definition: pg_list.h:181
@ PORTAL_ONE_RETURNING
Definition: portal.h:92
@ PORTAL_MULTI_QUERY
Definition: portal.h:95
@ PORTAL_ONE_SELECT
Definition: portal.h:91
@ PORTAL_ONE_MOD_WITH
Definition: portal.h:93
@ PORTAL_UTIL_SELECT
Definition: portal.h:94
PortalStrategy ChoosePortalStrategy(List *stmts)
Definition: pquery.c:231
List * returningList
Definition: parsenodes.h:209
List * targetList
Definition: parsenodes.h:193
TupleDesc UtilityTupleDescriptor(Node *parsetree)
Definition: utility.c:2084

References Assert(), ChoosePortalStrategy(), ExecCleanTypeFromTL(), linitial_node, PORTAL_MULTI_QUERY, PORTAL_ONE_MOD_WITH, PORTAL_ONE_RETURNING, PORTAL_ONE_SELECT, PORTAL_UTIL_SELECT, QueryListGetPrimaryStmt(), Query::returningList, Query::targetList, Query::utilityStmt, and UtilityTupleDescriptor().

Referenced by CompleteCachedPlan(), and RevalidateCachedQuery().

◆ PlanCacheObjectCallback()

static void PlanCacheObjectCallback ( Datum  arg,
int  cacheid,
uint32  hashvalue 
)
static

Definition at line 2214 of file plancache.c.

2215{
2216 dlist_iter iter;
2217
2219 {
2221 node, iter.cur);
2222 ListCell *lc;
2223
2224 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2225
2226 /* No work if it's already invalidated */
2227 if (!plansource->is_valid)
2228 continue;
2229
2230 /* Never invalidate if parse/plan would be a no-op anyway */
2231 if (!StmtPlanRequiresRevalidation(plansource))
2232 continue;
2233
2234 /*
2235 * Check the dependency list for the rewritten querytree.
2236 */
2237 foreach(lc, plansource->invalItems)
2238 {
2239 PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2240
2241 if (item->cacheId != cacheid)
2242 continue;
2243 if (hashvalue == 0 ||
2244 item->hashValue == hashvalue)
2245 {
2246 /* Invalidate the querytree and generic plan */
2247 plansource->is_valid = false;
2248 if (plansource->gplan)
2249 plansource->gplan->is_valid = false;
2250 break;
2251 }
2252 }
2253
2254 /*
2255 * The generic plan, if any, could have more dependencies than the
2256 * querytree does, so we have to check it too.
2257 */
2258 if (plansource->gplan && plansource->gplan->is_valid)
2259 {
2260 foreach(lc, plansource->gplan->stmt_list)
2261 {
2262 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2263 ListCell *lc3;
2264
2265 if (plannedstmt->commandType == CMD_UTILITY)
2266 continue; /* Ignore utility statements */
2267 foreach(lc3, plannedstmt->invalItems)
2268 {
2269 PlanInvalItem *item = (PlanInvalItem *) lfirst(lc3);
2270
2271 if (item->cacheId != cacheid)
2272 continue;
2273 if (hashvalue == 0 ||
2274 item->hashValue == hashvalue)
2275 {
2276 /* Invalidate the generic plan only */
2277 plansource->gplan->is_valid = false;
2278 break; /* out of invalItems scan */
2279 }
2280 }
2281 if (!plansource->gplan->is_valid)
2282 break; /* out of stmt_list scan */
2283 }
2284 }
2285 }
2286
2287 /* Likewise check cached expressions */
2289 {
2291 node, iter.cur);
2292 ListCell *lc;
2293
2294 Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2295
2296 /* No work if it's already invalidated */
2297 if (!cexpr->is_valid)
2298 continue;
2299
2300 foreach(lc, cexpr->invalItems)
2301 {
2302 PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2303
2304 if (item->cacheId != cacheid)
2305 continue;
2306 if (hashvalue == 0 ||
2307 item->hashValue == hashvalue)
2308 {
2309 cexpr->is_valid = false;
2310 break;
2311 }
2312 }
2313 }
2314}
#define dlist_foreach(iter, lhead)
Definition: ilist.h:623
#define dlist_container(type, membername, ptr)
Definition: ilist.h:593
static dlist_head saved_plan_list
Definition: plancache.c:95
bool is_valid
Definition: plancache.h:152
List * stmt_list
Definition: plancache.h:148
uint32 hashValue
Definition: plannodes.h:1751
List * invalItems
Definition: plannodes.h:130
dlist_node * cur
Definition: ilist.h:179

References Assert(), cached_expression_list, CACHEDEXPR_MAGIC, CACHEDPLANSOURCE_MAGIC, PlanInvalItem::cacheId, CMD_UTILITY, PlannedStmt::commandType, dlist_iter::cur, dlist_container, dlist_foreach, CachedPlanSource::gplan, PlanInvalItem::hashValue, PlannedStmt::invalItems, CachedPlanSource::invalItems, CachedExpression::invalItems, CachedPlanSource::is_valid, CachedPlan::is_valid, CachedExpression::is_valid, lfirst, lfirst_node, CachedPlanSource::magic, CachedExpression::magic, saved_plan_list, CachedPlan::stmt_list, and StmtPlanRequiresRevalidation.

Referenced by InitPlanCache().

◆ PlanCacheRelCallback()

static void PlanCacheRelCallback ( Datum  arg,
Oid  relid 
)
static

Definition at line 2130 of file plancache.c.

2131{
2132 dlist_iter iter;
2133
2135 {
2137 node, iter.cur);
2138
2139 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2140
2141 /* No work if it's already invalidated */
2142 if (!plansource->is_valid)
2143 continue;
2144
2145 /* Never invalidate if parse/plan would be a no-op anyway */
2146 if (!StmtPlanRequiresRevalidation(plansource))
2147 continue;
2148
2149 /*
2150 * Check the dependency list for the rewritten querytree.
2151 */
2152 if ((relid == InvalidOid) ? plansource->relationOids != NIL :
2153 list_member_oid(plansource->relationOids, relid))
2154 {
2155 /* Invalidate the querytree and generic plan */
2156 plansource->is_valid = false;
2157 if (plansource->gplan)
2158 plansource->gplan->is_valid = false;
2159 }
2160
2161 /*
2162 * The generic plan, if any, could have more dependencies than the
2163 * querytree does, so we have to check it too.
2164 */
2165 if (plansource->gplan && plansource->gplan->is_valid)
2166 {
2167 ListCell *lc;
2168
2169 foreach(lc, plansource->gplan->stmt_list)
2170 {
2171 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2172
2173 if (plannedstmt->commandType == CMD_UTILITY)
2174 continue; /* Ignore utility statements */
2175 if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
2176 list_member_oid(plannedstmt->relationOids, relid))
2177 {
2178 /* Invalidate the generic plan only */
2179 plansource->gplan->is_valid = false;
2180 break; /* out of stmt_list scan */
2181 }
2182 }
2183 }
2184 }
2185
2186 /* Likewise check cached expressions */
2188 {
2190 node, iter.cur);
2191
2192 Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2193
2194 /* No work if it's already invalidated */
2195 if (!cexpr->is_valid)
2196 continue;
2197
2198 if ((relid == InvalidOid) ? cexpr->relationOids != NIL :
2199 list_member_oid(cexpr->relationOids, relid))
2200 {
2201 cexpr->is_valid = false;
2202 }
2203 }
2204}
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:722
List * relationOids
Definition: plannodes.h:127

References Assert(), cached_expression_list, CACHEDEXPR_MAGIC, CACHEDPLANSOURCE_MAGIC, CMD_UTILITY, PlannedStmt::commandType, dlist_iter::cur, dlist_container, dlist_foreach, CachedPlanSource::gplan, InvalidOid, CachedPlanSource::is_valid, CachedPlan::is_valid, CachedExpression::is_valid, lfirst_node, list_member_oid(), CachedPlanSource::magic, CachedExpression::magic, NIL, PlannedStmt::relationOids, CachedPlanSource::relationOids, CachedExpression::relationOids, saved_plan_list, CachedPlan::stmt_list, and StmtPlanRequiresRevalidation.

Referenced by InitPlanCache().

◆ PlanCacheSysCallback()

static void PlanCacheSysCallback ( Datum  arg,
int  cacheid,
uint32  hashvalue 
)
static

Definition at line 2323 of file plancache.c.

2324{
2326}
void ResetPlanCache(void)
Definition: plancache.c:2332

References ResetPlanCache().

Referenced by InitPlanCache().

◆ QueryListGetPrimaryStmt()

static Query * QueryListGetPrimaryStmt ( List stmts)
static

Definition at line 1897 of file plancache.c.

1898{
1899 ListCell *lc;
1900
1901 foreach(lc, stmts)
1902 {
1903 Query *stmt = lfirst_node(Query, lc);
1904
1905 if (stmt->canSetTag)
1906 return stmt;
1907 }
1908 return NULL;
1909}
#define stmt
Definition: indent_codes.h:59

References lfirst_node, and stmt.

Referenced by CachedPlanGetTargetList(), and PlanCacheComputeResultDesc().

◆ ReleaseAllPlanCacheRefsInOwner()

void ReleaseAllPlanCacheRefsInOwner ( ResourceOwner  owner)

Definition at line 2379 of file plancache.c.

2380{
2382}
static const ResourceOwnerDesc planref_resowner_desc
Definition: plancache.c:125
void ResourceOwnerReleaseAllOfKind(ResourceOwner owner, const ResourceOwnerDesc *kind)
Definition: resowner.c:818

References planref_resowner_desc, and ResourceOwnerReleaseAllOfKind().

Referenced by plpgsql_call_handler(), plpgsql_inline_handler(), and plpgsql_xact_cb().

◆ ReleaseCachedPlan()

void ReleaseCachedPlan ( CachedPlan plan,
ResourceOwner  owner 
)

Definition at line 1435 of file plancache.c.

1436{
1437 Assert(plan->magic == CACHEDPLAN_MAGIC);
1438 if (owner)
1439 {
1440 Assert(plan->is_saved);
1442 }
1443 Assert(plan->refcount > 0);
1444 plan->refcount--;
1445 if (plan->refcount == 0)
1446 {
1447 /* Mark it no longer valid */
1448 plan->magic = 0;
1449
1450 /* One-shot plans do not own their context, so we can't free them */
1451 if (!plan->is_oneshot)
1452 MemoryContextDelete(plan->context);
1453 }
1454}
static void ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
Definition: plancache.c:141

References Assert(), CACHEDPLAN_MAGIC, MemoryContextDelete(), plan, and ResourceOwnerForgetPlanCacheRef().

Referenced by _SPI_execute_plan(), exec_eval_simple_expr(), exec_simple_check_plan(), ExplainExecuteQuery(), make_callstmt_target(), PortalReleaseCachedPlan(), ReleaseGenericPlan(), ResOwnerReleaseCachedPlan(), and SPI_cursor_open_internal().

◆ ReleaseGenericPlan()

static void ReleaseGenericPlan ( CachedPlanSource plansource)
static

Definition at line 556 of file plancache.c.

557{
558 /* Be paranoid about the possibility that ReleaseCachedPlan fails */
559 if (plansource->gplan)
560 {
561 CachedPlan *plan = plansource->gplan;
562
563 Assert(plan->magic == CACHEDPLAN_MAGIC);
564 plansource->gplan = NULL;
565 ReleaseCachedPlan(plan, NULL);
566 }
567}
void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1435

References Assert(), CACHEDPLAN_MAGIC, CachedPlanSource::gplan, plan, and ReleaseCachedPlan().

Referenced by CheckCachedPlan(), DropCachedPlan(), GetCachedPlan(), RevalidateCachedQuery(), and SaveCachedPlan().

◆ ResetPlanCache()

void ResetPlanCache ( void  )

Definition at line 2332 of file plancache.c.

2333{
2334 dlist_iter iter;
2335
2337 {
2339 node, iter.cur);
2340
2341 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2342
2343 /* No work if it's already invalidated */
2344 if (!plansource->is_valid)
2345 continue;
2346
2347 /*
2348 * We *must not* mark transaction control statements as invalid,
2349 * particularly not ROLLBACK, because they may need to be executed in
2350 * aborted transactions when we can't revalidate them (cf bug #5269).
2351 * In general there's no point in invalidating statements for which a
2352 * new parse analysis/rewrite/plan cycle would certainly give the same
2353 * results.
2354 */
2355 if (!StmtPlanRequiresRevalidation(plansource))
2356 continue;
2357
2358 plansource->is_valid = false;
2359 if (plansource->gplan)
2360 plansource->gplan->is_valid = false;
2361 }
2362
2363 /* Likewise invalidate cached expressions */
2365 {
2367 node, iter.cur);
2368
2369 Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2370
2371 cexpr->is_valid = false;
2372 }
2373}

References Assert(), cached_expression_list, CACHEDEXPR_MAGIC, CACHEDPLANSOURCE_MAGIC, dlist_iter::cur, dlist_container, dlist_foreach, CachedPlanSource::gplan, CachedPlanSource::is_valid, CachedPlan::is_valid, CachedExpression::is_valid, CachedPlanSource::magic, CachedExpression::magic, saved_plan_list, and StmtPlanRequiresRevalidation.

Referenced by assign_session_replication_role(), DiscardAll(), DiscardCommand(), and PlanCacheSysCallback().

◆ ResourceOwnerForgetPlanCacheRef()

static void ResourceOwnerForgetPlanCacheRef ( ResourceOwner  owner,
CachedPlan plan 
)
inlinestatic

Definition at line 141 of file plancache.c.

142{
144}
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
void ResourceOwnerForget(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:564

References plan, planref_resowner_desc, PointerGetDatum(), and ResourceOwnerForget().

Referenced by ReleaseCachedPlan().

◆ ResourceOwnerRememberPlanCacheRef()

static void ResourceOwnerRememberPlanCacheRef ( ResourceOwner  owner,
CachedPlan plan 
)
inlinestatic

Definition at line 136 of file plancache.c.

137{
139}
void ResourceOwnerRemember(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:524

References plan, planref_resowner_desc, PointerGetDatum(), and ResourceOwnerRemember().

Referenced by CachedPlanAllowsSimpleValidityCheck(), CachedPlanIsSimplyValid(), and GetCachedPlan().

◆ ResOwnerReleaseCachedPlan()

static void ResOwnerReleaseCachedPlan ( Datum  res)
static

Definition at line 2387 of file plancache.c.

2388{
2390}
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317

References DatumGetPointer(), and ReleaseCachedPlan().

◆ RevalidateCachedQuery()

static List * RevalidateCachedQuery ( CachedPlanSource plansource,
QueryEnvironment queryEnv,
bool  release_generic 
)
static

Definition at line 590 of file plancache.c.

593{
594 bool snapshot_set;
595 RawStmt *rawtree;
596 List *tlist; /* transient query-tree list */
597 List *qlist; /* permanent query-tree list */
598 TupleDesc resultDesc;
599 MemoryContext querytree_context;
600 MemoryContext oldcxt;
601
602 /*
603 * For one-shot plans, we do not support revalidation checking; it's
604 * assumed the query is parsed, planned, and executed in one transaction,
605 * so that no lock re-acquisition is necessary. Also, if the statement
606 * type can't require revalidation, we needn't do anything (and we mustn't
607 * risk catalog accesses when handling, eg, transaction control commands).
608 */
609 if (plansource->is_oneshot || !StmtPlanRequiresRevalidation(plansource))
610 {
611 Assert(plansource->is_valid);
612 return NIL;
613 }
614
615 /*
616 * If the query is currently valid, we should have a saved search_path ---
617 * check to see if that matches the current environment. If not, we want
618 * to force replan.
619 */
620 if (plansource->is_valid)
621 {
622 Assert(plansource->search_path != NULL);
624 {
625 /* Invalidate the querytree and generic plan */
626 plansource->is_valid = false;
627 if (plansource->gplan)
628 plansource->gplan->is_valid = false;
629 }
630 }
631
632 /*
633 * If the query rewrite phase had a possible RLS dependency, we must redo
634 * it if either the role or the row_security setting has changed.
635 */
636 if (plansource->is_valid && plansource->dependsOnRLS &&
637 (plansource->rewriteRoleId != GetUserId() ||
638 plansource->rewriteRowSecurity != row_security))
639 plansource->is_valid = false;
640
641 /*
642 * If the query is currently valid, acquire locks on the referenced
643 * objects; then check again. We need to do it this way to cover the race
644 * condition that an invalidation message arrives before we get the locks.
645 */
646 if (plansource->is_valid)
647 {
648 AcquirePlannerLocks(plansource->query_list, true);
649
650 /*
651 * By now, if any invalidation has happened, the inval callback
652 * functions will have marked the query invalid.
653 */
654 if (plansource->is_valid)
655 {
656 /* Successfully revalidated and locked the query. */
657 return NIL;
658 }
659
660 /* Oops, the race case happened. Release useless locks. */
661 AcquirePlannerLocks(plansource->query_list, false);
662 }
663
664 /*
665 * Discard the no-longer-useful query tree. (Note: we don't want to do
666 * this any earlier, else we'd not have been able to release locks
667 * correctly in the race condition case.)
668 */
669 plansource->is_valid = false;
670 plansource->query_list = NIL;
671 plansource->relationOids = NIL;
672 plansource->invalItems = NIL;
673 plansource->search_path = NULL;
674
675 /*
676 * Free the query_context. We don't really expect MemoryContextDelete to
677 * fail, but just in case, make sure the CachedPlanSource is left in a
678 * reasonably sane state. (The generic plan won't get unlinked yet, but
679 * that's acceptable.)
680 */
681 if (plansource->query_context)
682 {
683 MemoryContext qcxt = plansource->query_context;
684
685 plansource->query_context = NULL;
687 }
688
689 /* Drop the generic plan reference, if any, and if requested */
690 if (release_generic)
691 ReleaseGenericPlan(plansource);
692
693 /*
694 * Now re-do parse analysis and rewrite. This not incidentally acquires
695 * the locks we need to do planning safely.
696 */
697 Assert(plansource->is_complete);
698
699 /*
700 * If a snapshot is already set (the normal case), we can just use that
701 * for parsing/planning. But if it isn't, install one. Note: no point in
702 * checking whether parse analysis requires a snapshot; utility commands
703 * don't have invalidatable plans, so we'd not get here for such a
704 * command.
705 */
706 snapshot_set = false;
707 if (!ActiveSnapshotSet())
708 {
710 snapshot_set = true;
711 }
712
713 /*
714 * Run parse analysis and rule rewriting. The parser tends to scribble on
715 * its input, so we must copy the raw parse tree to prevent corruption of
716 * the cache.
717 */
718 rawtree = copyObject(plansource->raw_parse_tree);
719 if (rawtree == NULL)
720 tlist = NIL;
721 else if (plansource->parserSetup != NULL)
722 tlist = pg_analyze_and_rewrite_withcb(rawtree,
723 plansource->query_string,
724 plansource->parserSetup,
725 plansource->parserSetupArg,
726 queryEnv);
727 else
729 plansource->query_string,
730 plansource->param_types,
731 plansource->num_params,
732 queryEnv);
733
734 /* Release snapshot if we got one */
735 if (snapshot_set)
737
738 /*
739 * Check or update the result tupdesc.
740 *
741 * We assume the parameter types didn't change from the first time, so no
742 * need to update that.
743 */
744 resultDesc = PlanCacheComputeResultDesc(tlist);
745 if (resultDesc == NULL && plansource->resultDesc == NULL)
746 {
747 /* OK, doesn't return tuples */
748 }
749 else if (resultDesc == NULL || plansource->resultDesc == NULL ||
750 !equalRowTypes(resultDesc, plansource->resultDesc))
751 {
752 /* can we give a better error message? */
753 if (plansource->fixed_result)
755 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
756 errmsg("cached plan must not change result type")));
757 oldcxt = MemoryContextSwitchTo(plansource->context);
758 if (resultDesc)
759 resultDesc = CreateTupleDescCopy(resultDesc);
760 if (plansource->resultDesc)
761 FreeTupleDesc(plansource->resultDesc);
762 plansource->resultDesc = resultDesc;
763 MemoryContextSwitchTo(oldcxt);
764 }
765
766 /*
767 * Allocate new query_context and copy the completed querytree into it.
768 * It's transient until we complete the copying and dependency extraction.
769 */
771 "CachedPlanQuery",
773 oldcxt = MemoryContextSwitchTo(querytree_context);
774
775 qlist = copyObject(tlist);
776
777 /*
778 * Use the planner machinery to extract dependencies. Data is saved in
779 * query_context. (We assume that not a lot of extra cruft is created by
780 * this call.)
781 */
783 &plansource->relationOids,
784 &plansource->invalItems,
785 &plansource->dependsOnRLS);
786
787 /* Update RLS info as well. */
788 plansource->rewriteRoleId = GetUserId();
789 plansource->rewriteRowSecurity = row_security;
790
791 /*
792 * Also save the current search_path in the query_context. (This should
793 * not generate much extra cruft either, since almost certainly the path
794 * is already valid.)
795 */
796 plansource->search_path = GetSearchPathMatcher(querytree_context);
797
798 MemoryContextSwitchTo(oldcxt);
799
800 /* Now reparent the finished query_context and save the links */
801 MemoryContextSetParent(querytree_context, plansource->context);
802
803 plansource->query_context = querytree_context;
804 plansource->query_list = qlist;
805
806 /*
807 * Note: we do not reset generic_cost or total_custom_cost, although we
808 * could choose to do so. If the DDL or statistics change that prompted
809 * the invalidation meant a significant change in the cost estimates, it
810 * would be better to reset those variables and start fresh; but often it
811 * doesn't, and we're better retaining our hard-won knowledge about the
812 * relative costs.
813 */
814
815 plansource->is_valid = true;
816
817 /* Return transient copy of querytrees for possible use in planning */
818 return tlist;
819}
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ereport(elevel,...)
Definition: elog.h:149
static void AcquirePlannerLocks(List *stmt_list, bool acquire)
Definition: plancache.c:1975
List * pg_analyze_and_rewrite_withcb(RawStmt *parsetree, const char *query_string, ParserSetupHook parserSetup, void *parserSetupArg, QueryEnvironment *queryEnv)
Definition: postgres.c:758
List * pg_analyze_and_rewrite_fixedparams(RawStmt *parsetree, const char *query_string, const Oid *paramTypes, int numParams, QueryEnvironment *queryEnv)
Definition: postgres.c:665
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:479
bool equalRowTypes(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:736

References AcquirePlannerLocks(), ActiveSnapshotSet(), ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, Assert(), CachedPlanSource::context, copyObject, CreateTupleDescCopy(), CurrentMemoryContext, CachedPlanSource::dependsOnRLS, equalRowTypes(), ereport, errcode(), errmsg(), ERROR, extract_query_dependencies(), CachedPlanSource::fixed_result, FreeTupleDesc(), GetSearchPathMatcher(), GetTransactionSnapshot(), GetUserId(), CachedPlanSource::gplan, CachedPlanSource::invalItems, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_valid, CachedPlan::is_valid, MemoryContextDelete(), MemoryContextSetParent(), MemoryContextSwitchTo(), NIL, CachedPlanSource::num_params, CachedPlanSource::param_types, CachedPlanSource::parserSetup, CachedPlanSource::parserSetupArg, pg_analyze_and_rewrite_fixedparams(), pg_analyze_and_rewrite_withcb(), PlanCacheComputeResultDesc(), PopActiveSnapshot(), PushActiveSnapshot(), CachedPlanSource::query_context, CachedPlanSource::query_list, CachedPlanSource::query_string, CachedPlanSource::raw_parse_tree, CachedPlanSource::relationOids, ReleaseGenericPlan(), CachedPlanSource::resultDesc, CachedPlanSource::rewriteRoleId, CachedPlanSource::rewriteRowSecurity, row_security, CachedPlanSource::search_path, SearchPathMatchesCurrentEnvironment(), and StmtPlanRequiresRevalidation.

Referenced by BuildCachedPlan(), CachedPlanGetTargetList(), GetCachedPlan(), and UpdateCachedPlan().

◆ SaveCachedPlan()

void SaveCachedPlan ( CachedPlanSource plansource)

Definition at line 483 of file plancache.c.

484{
485 /* Assert caller is doing things in a sane order */
486 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
487 Assert(plansource->is_complete);
488 Assert(!plansource->is_saved);
489
490 /* This seems worth a real test, though */
491 if (plansource->is_oneshot)
492 elog(ERROR, "cannot save one-shot cached plan");
493
494 /*
495 * In typical use, this function would be called before generating any
496 * plans from the CachedPlanSource. If there is a generic plan, moving it
497 * into CacheMemoryContext would be pretty risky since it's unclear
498 * whether the caller has taken suitable care with making references
499 * long-lived. Best thing to do seems to be to discard the plan.
500 */
501 ReleaseGenericPlan(plansource);
502
503 /*
504 * Reparent the source memory context under CacheMemoryContext so that it
505 * will live indefinitely. The query_context follows along since it's
506 * already a child of the other one.
507 */
509
510 /*
511 * Add the entry to the global list of cached plans.
512 */
513 dlist_push_tail(&saved_plan_list, &plansource->node);
514
515 plansource->is_saved = true;
516}

References Assert(), CACHEDPLANSOURCE_MAGIC, CacheMemoryContext, CachedPlanSource::context, dlist_push_tail(), elog, ERROR, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_saved, CachedPlanSource::magic, MemoryContextSetParent(), CachedPlanSource::node, ReleaseGenericPlan(), and saved_plan_list.

Referenced by _SPI_save_plan(), exec_parse_message(), SPI_keepplan(), and StorePreparedStatement().

◆ ScanQueryForLocks()

static void ScanQueryForLocks ( Query parsetree,
bool  acquire 
)
static

Definition at line 2000 of file plancache.c.

2001{
2002 ListCell *lc;
2003
2004 /* Shouldn't get called on utility commands */
2005 Assert(parsetree->commandType != CMD_UTILITY);
2006
2007 /*
2008 * First, process RTEs of the current query level.
2009 */
2010 foreach(lc, parsetree->rtable)
2011 {
2012 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2013
2014 switch (rte->rtekind)
2015 {
2016 case RTE_RELATION:
2017 /* Acquire or release the appropriate type of lock */
2018 if (acquire)
2019 LockRelationOid(rte->relid, rte->rellockmode);
2020 else
2021 UnlockRelationOid(rte->relid, rte->rellockmode);
2022 break;
2023
2024 case RTE_SUBQUERY:
2025 /* If this was a view, must lock/unlock the view */
2026 if (OidIsValid(rte->relid))
2027 {
2028 if (acquire)
2029 LockRelationOid(rte->relid, rte->rellockmode);
2030 else
2031 UnlockRelationOid(rte->relid, rte->rellockmode);
2032 }
2033 /* Recurse into subquery-in-FROM */
2034 ScanQueryForLocks(rte->subquery, acquire);
2035 break;
2036
2037 default:
2038 /* ignore other types of RTEs */
2039 break;
2040 }
2041 }
2042
2043 /* Recurse into subquery-in-WITH */
2044 foreach(lc, parsetree->cteList)
2045 {
2047
2048 ScanQueryForLocks(castNode(Query, cte->ctequery), acquire);
2049 }
2050
2051 /*
2052 * Recurse into sublink subqueries, too. But we already did the ones in
2053 * the rtable and cteList.
2054 */
2055 if (parsetree->hasSubLinks)
2056 {
2057 query_tree_walker(parsetree, ScanQueryWalker, &acquire,
2059 }
2060}
#define query_tree_walker(q, w, c, f)
Definition: nodeFuncs.h:158
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:24
#define castNode(_type_, nodeptr)
Definition: nodes.h:178
static bool ScanQueryWalker(Node *node, bool *acquire)
Definition: plancache.c:2066
Query * subquery
Definition: parsenodes.h:1113

References Assert(), castNode, CMD_UTILITY, Query::commandType, Query::cteList, CommonTableExpr::ctequery, lfirst, lfirst_node, LockRelationOid(), OidIsValid, QTW_IGNORE_RC_SUBQUERIES, query_tree_walker, RangeTblEntry::relid, Query::rtable, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, ScanQueryForLocks(), ScanQueryWalker(), RangeTblEntry::subquery, and UnlockRelationOid().

Referenced by AcquireExecutorLocks(), AcquirePlannerLocks(), ScanQueryForLocks(), and ScanQueryWalker().

◆ ScanQueryWalker()

static bool ScanQueryWalker ( Node node,
bool *  acquire 
)
static

Definition at line 2066 of file plancache.c.

2067{
2068 if (node == NULL)
2069 return false;
2070 if (IsA(node, SubLink))
2071 {
2072 SubLink *sub = (SubLink *) node;
2073
2074 /* Do what we came for */
2075 ScanQueryForLocks(castNode(Query, sub->subselect), *acquire);
2076 /* Fall through to process lefthand args of SubLink */
2077 }
2078
2079 /*
2080 * Do NOT recurse into Query nodes, because ScanQueryForLocks already
2081 * processed subselects of subselects for us.
2082 */
2083 return expression_tree_walker(node, ScanQueryWalker, acquire);
2084}
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:153
#define IsA(nodeptr, _type_)
Definition: nodes.h:160

References castNode, expression_tree_walker, IsA, ScanQueryForLocks(), ScanQueryWalker(), and SubLink::subselect.

Referenced by ScanQueryForLocks(), and ScanQueryWalker().

◆ UpdateCachedPlan()

PlannedStmt * UpdateCachedPlan ( CachedPlanSource plansource,
int  query_index,
QueryEnvironment queryEnv 
)

Definition at line 1093 of file plancache.c.

1095{
1096 List *query_list = plansource->query_list,
1097 *plan_list;
1098 ListCell *l1,
1099 *l2;
1100 CachedPlan *plan = plansource->gplan;
1101 MemoryContext oldcxt;
1102
1104
1105 /* Sanity checks (XXX can be Asserts?) */
1106 if (plan == NULL)
1107 elog(ERROR, "UpdateCachedPlan() called in the wrong context: plansource->gplan is NULL");
1108 else if (plan->is_valid)
1109 elog(ERROR, "UpdateCachedPlan() called in the wrong context: plansource->gplan->is_valid is true");
1110 else if (plan->is_oneshot)
1111 elog(ERROR, "UpdateCachedPlan() called in the wrong context: plansource->gplan->is_oneshot is true");
1112
1113 /*
1114 * The plansource might have become invalid since GetCachedPlan() returned
1115 * the CachedPlan. See the comment in BuildCachedPlan() for details on why
1116 * this might happen. Although invalidation is likely a false positive as
1117 * stated there, we make the plan valid to ensure the query list used for
1118 * planning is up to date.
1119 *
1120 * The risk of catching an invalidation is higher here than when
1121 * BuildCachedPlan() is called from GetCachedPlan(), because this function
1122 * is normally called long after GetCachedPlan() returns the CachedPlan,
1123 * so much more processing could have occurred including things that mark
1124 * the CachedPlanSource invalid.
1125 *
1126 * Note: Do not release plansource->gplan, because the upstream callers
1127 * (such as the callers of ExecutorStartCachedPlan()) would still be
1128 * referencing it.
1129 */
1130 if (!plansource->is_valid)
1131 query_list = RevalidateCachedQuery(plansource, queryEnv, false);
1132 Assert(query_list != NIL);
1133
1134 /*
1135 * Build a new generic plan for all the queries after making a copy to be
1136 * scribbled on by the planner.
1137 */
1138 query_list = copyObject(query_list);
1139
1140 /*
1141 * Planning work is done in the caller's memory context. The resulting
1142 * PlannedStmt is then copied into plan->stmt_context after throwing away
1143 * the old ones.
1144 */
1145 plan_list = pg_plan_queries(query_list, plansource->query_string,
1146 plansource->cursor_options, NULL);
1147 Assert(list_length(plan_list) == list_length(plan->stmt_list));
1148
1149 MemoryContextReset(plan->stmt_context);
1150 oldcxt = MemoryContextSwitchTo(plan->stmt_context);
1151 forboth(l1, plan_list, l2, plan->stmt_list)
1152 {
1153 PlannedStmt *plannedstmt = lfirst(l1);
1154
1155 lfirst(l2) = copyObject(plannedstmt);
1156 }
1157 MemoryContextSwitchTo(oldcxt);
1158
1159 /*
1160 * XXX Should this also (re)set the properties of the CachedPlan that are
1161 * set in BuildCachedPlan() after creating the fresh plans such as
1162 * planRoleId, dependsOnRole, and save_xmin?
1163 */
1164
1165 /*
1166 * We've updated all the plans that might have been invalidated, so mark
1167 * the CachedPlan as valid.
1168 */
1169 plan->is_valid = true;
1170
1171 /* Also update generic_cost because we just created a new generic plan. */
1172 plansource->generic_cost = cached_plan_cost(plan, false);
1173
1174 return list_nth_node(PlannedStmt, plan->stmt_list, query_index);
1175}
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518

References ActiveSnapshotSet(), Assert(), cached_plan_cost(), copyObject, CachedPlanSource::cursor_options, elog, ERROR, forboth, CachedPlanSource::generic_cost, CachedPlanSource::gplan, CachedPlanSource::is_valid, lfirst, list_length(), list_nth_node, MemoryContextReset(), MemoryContextSwitchTo(), NIL, pg_plan_queries(), plan, CachedPlanSource::query_list, CachedPlanSource::query_string, and RevalidateCachedQuery().

Referenced by ExecutorStartCachedPlan().

Variable Documentation

◆ cached_expression_list

dlist_head cached_expression_list = DLIST_STATIC_INIT(cached_expression_list)
static

◆ plan_cache_mode

int plan_cache_mode = PLAN_CACHE_MODE_AUTO

Definition at line 148 of file plancache.c.

Referenced by choose_custom_plan().

◆ planref_resowner_desc

const ResourceOwnerDesc planref_resowner_desc
static
Initial value:
=
{
.name = "plancache reference",
.release_phase = RESOURCE_RELEASE_AFTER_LOCKS,
.release_priority = RELEASE_PRIO_PLANCACHE_REFS,
.ReleaseResource = ResOwnerReleaseCachedPlan,
.DebugPrint = NULL
}
static void ResOwnerReleaseCachedPlan(Datum res)
Definition: plancache.c:2387
#define RELEASE_PRIO_PLANCACHE_REFS
Definition: resowner.h:73
@ RESOURCE_RELEASE_AFTER_LOCKS
Definition: resowner.h:56

Definition at line 125 of file plancache.c.

Referenced by ReleaseAllPlanCacheRefsInOwner(), ResourceOwnerForgetPlanCacheRef(), and ResourceOwnerRememberPlanCacheRef().

◆ saved_plan_list

dlist_head saved_plan_list = DLIST_STATIC_INIT(saved_plan_list)
static