PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 "rewrite/rewriteHandler.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.

Functions

static void ReleaseGenericPlan (CachedPlanSource *plansource)
 
static bool StmtPlanRequiresRevalidation (CachedPlanSource *plansource)
 
static bool BuildingPlanRequiresSnapshot (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)
 
CachedPlanSourceCreateCachedPlanForQuery (Query *analyzed_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 SetPostRewriteHook (CachedPlanSource *plansource, PostRewriteHook postRewrite, void *postRewriteArg)
 
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
 

Function Documentation

◆ AcquireExecutorLocks()

static void AcquireExecutorLocks ( List stmt_list,
bool  acquire 
)
static

Definition at line 2031 of file plancache.c.

2032{
2033 ListCell *lc1;
2034
2035 foreach(lc1, stmt_list)
2036 {
2037 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
2038 int rtindex;
2039
2040 if (plannedstmt->commandType == CMD_UTILITY)
2041 {
2042 /*
2043 * Ignore utility statements, except those (such as EXPLAIN) that
2044 * contain a parsed-but-not-planned query. Note: it's okay to use
2045 * ScanQueryForLocks, even though the query hasn't been through
2046 * rule rewriting, because rewriting doesn't change the query
2047 * representation.
2048 */
2049 Query *query = UtilityContainsQuery(plannedstmt->utilityStmt);
2050
2051 if (query)
2052 ScanQueryForLocks(query, acquire);
2053 continue;
2054 }
2055
2056 rtindex = -1;
2057 while ((rtindex = bms_next_member(plannedstmt->unprunableRelids,
2058 rtindex)) >= 0)
2059 {
2061 plannedstmt->rtable,
2062 rtindex - 1);
2063
2064 Assert(rte->rtekind == RTE_RELATION ||
2065 (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)));
2066
2067 /*
2068 * Acquire the appropriate type of lock on each relation OID. Note
2069 * that we don't actually try to open the rel, and hence will not
2070 * fail if it's been dropped entirely --- we'll just transiently
2071 * acquire a non-conflicting lock.
2072 */
2073 if (acquire)
2074 LockRelationOid(rte->relid, rte->rellockmode);
2075 else
2076 UnlockRelationOid(rte->relid, rte->rellockmode);
2077 }
2078 }
2079}
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:276
@ 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:2115
Bitmapset * unprunableRelids
Definition: plannodes.h:97
CmdType commandType
Definition: plannodes.h:53
Node * utilityStmt
Definition: plannodes.h:139
List * rtable
Definition: plannodes.h:91
RTEKind rtekind
Definition: parsenodes.h:1061
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:2179

References Assert(), bms_next_member(), CMD_UTILITY, PlannedStmt::commandType, lfirst_node, list_nth_node, LockRelationOid(), OidIsValid, 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 2090 of file plancache.c.

2091{
2092 ListCell *lc;
2093
2094 foreach(lc, stmt_list)
2095 {
2096 Query *query = lfirst_node(Query, lc);
2097
2098 if (query->commandType == CMD_UTILITY)
2099 {
2100 /* Ignore utility statements, unless they contain a Query */
2101 query = UtilityContainsQuery(query->utilityStmt);
2102 if (query)
2103 ScanQueryForLocks(query, acquire);
2104 continue;
2105 }
2106
2107 ScanQueryForLocks(query, acquire);
2108 }
2109}
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 1032 of file plancache.c.

1034{
1036 List *plist;
1037 bool snapshot_set;
1038 bool is_transient;
1039 MemoryContext plan_context;
1040 MemoryContext stmt_context = NULL;
1042 ListCell *lc;
1043
1044 /*
1045 * Normally the querytree should be valid already, but if it's not,
1046 * rebuild it.
1047 *
1048 * NOTE: GetCachedPlan should have called RevalidateCachedQuery first, so
1049 * we ought to be holding sufficient locks to prevent any invalidation.
1050 * However, if we're building a custom plan after having built and
1051 * rejected a generic plan, it's possible to reach here with is_valid
1052 * false due to an invalidation while making the generic plan. In theory
1053 * the invalidation must be a false positive, perhaps a consequence of an
1054 * sinval reset event or the debug_discard_caches code. But for safety,
1055 * let's treat it as real and redo the RevalidateCachedQuery call.
1056 */
1057 if (!plansource->is_valid)
1058 qlist = RevalidateCachedQuery(plansource, queryEnv, true);
1059
1060 /*
1061 * If we don't already have a copy of the querytree list that can be
1062 * scribbled on by the planner, make one. For a one-shot plan, we assume
1063 * it's okay to scribble on the original query_list.
1064 */
1065 if (qlist == NIL)
1066 {
1067 if (!plansource->is_oneshot)
1068 qlist = copyObject(plansource->query_list);
1069 else
1070 qlist = plansource->query_list;
1071 }
1072
1073 /*
1074 * If a snapshot is already set (the normal case), we can just use that
1075 * for planning. But if it isn't, and we need one, install one.
1076 */
1077 snapshot_set = false;
1078 if (!ActiveSnapshotSet() &&
1079 BuildingPlanRequiresSnapshot(plansource))
1080 {
1082 snapshot_set = true;
1083 }
1084
1085 /*
1086 * Generate the plan.
1087 */
1088 plist = pg_plan_queries(qlist, plansource->query_string,
1089 plansource->cursor_options, boundParams);
1090
1091 /* Release snapshot if we got one */
1092 if (snapshot_set)
1094
1095 /*
1096 * Normally, we create a dedicated memory context for the CachedPlan and
1097 * its subsidiary data. Although it's usually not very large, the context
1098 * is designed to allow growth if necessary.
1099 *
1100 * The PlannedStmts are stored in a separate child context (stmt_context)
1101 * of the CachedPlan's memory context. This separation allows
1102 * UpdateCachedPlan() to free and replace the PlannedStmts without
1103 * affecting the CachedPlan structure or its stmt_list List.
1104 *
1105 * For one-shot plans, we instead use the caller's memory context, as the
1106 * CachedPlan will not persist. stmt_context will be set to NULL in this
1107 * case, because UpdateCachedPlan() should never get called on a one-shot
1108 * plan.
1109 */
1110 if (!plansource->is_oneshot)
1111 {
1113 "CachedPlan",
1115 MemoryContextCopyAndSetIdentifier(plan_context, plansource->query_string);
1116
1118 "CachedPlan PlannedStmts",
1120 MemoryContextCopyAndSetIdentifier(stmt_context, plansource->query_string);
1121 MemoryContextSetParent(stmt_context, plan_context);
1122
1123 MemoryContextSwitchTo(stmt_context);
1124 plist = copyObject(plist);
1125
1126 MemoryContextSwitchTo(plan_context);
1127 plist = list_copy(plist);
1128 }
1129 else
1130 plan_context = CurrentMemoryContext;
1131
1132 /*
1133 * Create and fill the CachedPlan struct within the new context.
1134 */
1135 plan = (CachedPlan *) palloc(sizeof(CachedPlan));
1136 plan->magic = CACHEDPLAN_MAGIC;
1137 plan->stmt_list = plist;
1138
1139 /*
1140 * CachedPlan is dependent on role either if RLS affected the rewrite
1141 * phase or if a role dependency was injected during planning. And it's
1142 * transient if any plan is marked so.
1143 */
1144 plan->planRoleId = GetUserId();
1145 plan->dependsOnRole = plansource->dependsOnRLS;
1146 is_transient = false;
1147 foreach(lc, plist)
1148 {
1149 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1150
1151 if (plannedstmt->commandType == CMD_UTILITY)
1152 continue; /* Ignore utility statements */
1153
1154 if (plannedstmt->transientPlan)
1155 is_transient = true;
1156 if (plannedstmt->dependsOnRole)
1157 plan->dependsOnRole = true;
1158 }
1159 if (is_transient)
1160 {
1162 plan->saved_xmin = TransactionXmin;
1163 }
1164 else
1165 plan->saved_xmin = InvalidTransactionId;
1166 plan->refcount = 0;
1167 plan->context = plan_context;
1168 plan->stmt_context = stmt_context;
1169 plan->is_oneshot = plansource->is_oneshot;
1170 plan->is_saved = false;
1171 plan->is_reused = false;
1172 plan->is_valid = true;
1173
1174 /* assign generation number to new plan */
1175 plan->generation = ++(plansource->generation);
1176
1177 MemoryContextSwitchTo(oldcxt);
1178
1179 return plan;
1180}
List * list_copy(const List *oldlist)
Definition: list.c:1573
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:668
void * palloc(Size size)
Definition: mcxt.c:1939
MemoryContext CurrentMemoryContext
Definition: mcxt.c:159
#define AllocSetContextCreate
Definition: memutils.h:149
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:197
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:121
Oid GetUserId(void)
Definition: miscinit.c:520
#define copyObject(obj)
Definition: nodes.h:230
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#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:674
static bool BuildingPlanRequiresSnapshot(CachedPlanSource *plansource)
Definition: plancache.c:643
#define CACHEDPLAN_MAGIC
Definition: plancache.h:47
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:112
List * query_list
Definition: plancache.h:125
Definition: pg_list.h:54
bool transientPlan
Definition: plannodes.h:71
bool dependsOnRole
Definition: plannodes.h:74
#define InvalidTransactionId
Definition: transam.h:31
#define TransactionIdIsNormal(xid)
Definition: transam.h:42

References ActiveSnapshotSet(), ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, Assert(), BuildingPlanRequiresSnapshot(), 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, RevalidateCachedQuery(), TransactionIdIsNormal, TransactionXmin, and PlannedStmt::transientPlan.

Referenced by GetCachedPlan().

◆ BuildingPlanRequiresSnapshot()

static bool BuildingPlanRequiresSnapshot ( CachedPlanSource plansource)
static

Definition at line 643 of file plancache.c.

644{
645 if (plansource->raw_parse_tree != NULL)
646 return analyze_requires_snapshot(plansource->raw_parse_tree);
647 else if (plansource->analyzed_parse_tree != NULL)
649 /* empty query never needs a snapshot */
650 return false;
651}
bool analyze_requires_snapshot(RawStmt *parseTree)
Definition: analyze.c:576
bool query_requires_rewrite_plan(Query *query)
Definition: analyze.c:605
struct Query * analyzed_parse_tree
Definition: plancache.h:111
struct RawStmt * raw_parse_tree
Definition: plancache.h:110

References analyze_requires_snapshot(), CachedPlanSource::analyzed_parse_tree, query_requires_rewrite_plan(), and CachedPlanSource::raw_parse_tree.

Referenced by BuildCachedPlan().

◆ cached_plan_cost()

static double cached_plan_cost ( CachedPlan plan,
bool  include_planner 
)
static

Definition at line 1352 of file plancache.c.

1353{
1354 double result = 0;
1355 ListCell *lc;
1356
1357 foreach(lc, plan->stmt_list)
1358 {
1359 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1360
1361 if (plannedstmt->commandType == CMD_UTILITY)
1362 continue; /* Ignore utility statements */
1363
1364 result += plannedstmt->planTree->total_cost;
1365
1366 if (include_planner)
1367 {
1368 /*
1369 * Currently we use a very crude estimate of planning effort based
1370 * on the number of relations in the finished plan's rangetable.
1371 * Join planning effort actually scales much worse than linearly
1372 * in the number of relations --- but only until the join collapse
1373 * limits kick in. Also, while inheritance child relations surely
1374 * add to planning effort, they don't make the join situation
1375 * worse. So the actual shape of the planning cost curve versus
1376 * number of relations isn't all that obvious. It will take
1377 * considerable work to arrive at a less crude estimate, and for
1378 * now it's not clear that's worth doing.
1379 *
1380 * The other big difficulty here is that we don't have any very
1381 * good model of how planning cost compares to execution costs.
1382 * The current multiplier of 1000 * cpu_operator_cost is probably
1383 * on the low side, but we'll try this for awhile before making a
1384 * more aggressive correction.
1385 *
1386 * If we ever do write a more complicated estimator, it should
1387 * probably live in src/backend/optimizer/ not here.
1388 */
1389 int nrelations = list_length(plannedstmt->rtable);
1390
1391 result += 1000.0 * cpu_operator_cost * (nrelations + 1);
1392 }
1393 }
1394
1395 return result;
1396}
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:179
struct Plan * planTree
Definition: plannodes.h:83

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 1592 of file plancache.c.

1594{
1595 ListCell *lc;
1596
1597 /*
1598 * Sanity-check that the caller gave us a validated generic plan. Notice
1599 * that we *don't* assert plansource->is_valid as you might expect; that's
1600 * because it's possible that that's already false when GetCachedPlan
1601 * returns, e.g. because ResetPlanCache happened partway through. We
1602 * should accept the plan as long as plan->is_valid is true, and expect to
1603 * replan after the next CachedPlanIsSimplyValid call.
1604 */
1605 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1606 Assert(plan->magic == CACHEDPLAN_MAGIC);
1607 Assert(plan->is_valid);
1608 Assert(plan == plansource->gplan);
1609 Assert(plansource->search_path != NULL);
1611
1612 /* We don't support oneshot plans here. */
1613 if (plansource->is_oneshot)
1614 return false;
1615 Assert(!plan->is_oneshot);
1616
1617 /*
1618 * If the plan is dependent on RLS considerations, or it's transient,
1619 * reject. These things probably can't ever happen for table-free
1620 * queries, but for safety's sake let's check.
1621 */
1622 if (plansource->dependsOnRLS)
1623 return false;
1624 if (plan->dependsOnRole)
1625 return false;
1626 if (TransactionIdIsValid(plan->saved_xmin))
1627 return false;
1628
1629 /*
1630 * Reject if AcquirePlannerLocks would have anything to do. This is
1631 * simplistic, but there's no need to inquire any more carefully; indeed,
1632 * for current callers it shouldn't even be possible to hit any of these
1633 * checks.
1634 */
1635 foreach(lc, plansource->query_list)
1636 {
1637 Query *query = lfirst_node(Query, lc);
1638
1639 if (query->commandType == CMD_UTILITY)
1640 return false;
1641 if (query->rtable || query->cteList || query->hasSubLinks)
1642 return false;
1643 }
1644
1645 /*
1646 * Reject if AcquireExecutorLocks would have anything to do. This is
1647 * probably unnecessary given the previous check, but let's be safe.
1648 */
1649 foreach(lc, plan->stmt_list)
1650 {
1651 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1652 ListCell *lc2;
1653
1654 if (plannedstmt->commandType == CMD_UTILITY)
1655 return false;
1656
1657 /*
1658 * We have to grovel through the rtable because it's likely to contain
1659 * an RTE_RESULT relation, rather than being totally empty.
1660 */
1661 foreach(lc2, plannedstmt->rtable)
1662 {
1663 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1664
1665 if (rte->rtekind == RTE_RELATION)
1666 return false;
1667 }
1668 }
1669
1670 /*
1671 * Okay, it's simple. Note that what we've primarily established here is
1672 * that no locks need be taken before checking the plan's is_valid flag.
1673 */
1674
1675 /* Bump refcount if requested. */
1676 if (owner)
1677 {
1678 ResourceOwnerEnlarge(owner);
1679 plan->refcount++;
1681 }
1682
1683 return true;
1684}
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:127
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:46
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition: resowner.c:452
struct CachedPlan * gplan
Definition: plancache.h:135
struct SearchPathMatcher * search_path
Definition: plancache.h:128
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 1899 of file plancache.c.

1901{
1902 Query *pstmt;
1903
1904 /* Assert caller is doing things in a sane order */
1905 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1906 Assert(plansource->is_complete);
1907
1908 /*
1909 * No work needed if statement doesn't return tuples (we assume this
1910 * feature cannot be changed by an invalidation)
1911 */
1912 if (plansource->resultDesc == NULL)
1913 return NIL;
1914
1915 /* Make sure the querytree list is valid and we have parse-time locks */
1916 RevalidateCachedQuery(plansource, queryEnv, true);
1917
1918 /* Get the primary statement and find out what it returns */
1919 pstmt = QueryListGetPrimaryStmt(plansource->query_list);
1920
1921 return FetchStatementTargetList((Node *) pstmt);
1922}
static Query * QueryListGetPrimaryStmt(List *stmts)
Definition: plancache.c:2012
List * FetchStatementTargetList(Node *stmt)
Definition: pquery.c:370
TupleDesc resultDesc
Definition: plancache.h:122
Definition: nodes.h:135

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 1707 of file plancache.c.

1709{
1710 /*
1711 * Careful here: since the caller doesn't necessarily hold a refcount on
1712 * the plan to start with, it's possible that "plan" is a dangling
1713 * pointer. Don't dereference it until we've verified that it still
1714 * matches the plansource's gplan (which is either valid or NULL).
1715 */
1716 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1717
1718 /*
1719 * Has cache invalidation fired on this plan? We can check this right
1720 * away since there are no locks that we'd need to acquire first. Note
1721 * that here we *do* check plansource->is_valid, so as to force plan
1722 * rebuild if that's become false.
1723 */
1724 if (!plansource->is_valid ||
1725 plan == NULL || plan != plansource->gplan ||
1726 !plan->is_valid)
1727 return false;
1728
1729 Assert(plan->magic == CACHEDPLAN_MAGIC);
1730
1731 /* Is the search_path still the same as when we made it? */
1732 Assert(plansource->search_path != NULL);
1734 return false;
1735
1736 /* It's still good. Bump refcount if requested. */
1737 if (owner)
1738 {
1739 ResourceOwnerEnlarge(owner);
1740 plan->refcount++;
1742 }
1743
1744 return true;
1745}

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 1886 of file plancache.c.

1887{
1888 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1889 return plansource->is_valid;
1890}

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 1754 of file plancache.c.

1756{
1757 /* Assert caller is doing things in a sane order */
1758 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1759 Assert(plansource->is_complete);
1760
1761 /* These seem worth real tests, though */
1762 if (plansource->is_saved)
1763 elog(ERROR, "cannot move a saved cached plan to another context");
1764 if (plansource->is_oneshot)
1765 elog(ERROR, "cannot move a one-shot cached plan to another context");
1766
1767 /* OK, let the caller keep the plan where he wishes */
1768 MemoryContextSetParent(plansource->context, newcontext);
1769
1770 /*
1771 * The query_context needs no special handling, since it's a child of
1772 * plansource->context. But if there's a generic plan, it should be
1773 * maintained as a sibling of plansource->context.
1774 */
1775 if (plansource->gplan)
1776 {
1777 Assert(plansource->gplan->magic == CACHEDPLAN_MAGIC);
1778 MemoryContextSetParent(plansource->gplan->context, newcontext);
1779 }
1780}
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
MemoryContext context
Definition: plancache.h:123
MemoryContext context
Definition: plancache.h:176

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 946 of file plancache.c.

947{
948 CachedPlan *plan = plansource->gplan;
949
950 /* Assert that caller checked the querytree */
951 Assert(plansource->is_valid);
952
953 /* If there's no generic plan, just say "false" */
954 if (!plan)
955 return false;
956
957 Assert(plan->magic == CACHEDPLAN_MAGIC);
958 /* Generic plans are never one-shot */
959 Assert(!plan->is_oneshot);
960
961 /*
962 * If plan isn't valid for current role, we can't use it.
963 */
964 if (plan->is_valid && plan->dependsOnRole &&
965 plan->planRoleId != GetUserId())
966 plan->is_valid = false;
967
968 /*
969 * If it appears valid, acquire locks and recheck; this is much the same
970 * logic as in RevalidateCachedQuery, but for a plan.
971 */
972 if (plan->is_valid)
973 {
974 /*
975 * Plan must have positive refcount because it is referenced by
976 * plansource; so no need to fear it disappears under us here.
977 */
978 Assert(plan->refcount > 0);
979
980 AcquireExecutorLocks(plan->stmt_list, true);
981
982 /*
983 * If plan was transient, check to see if TransactionXmin has
984 * advanced, and if so invalidate it.
985 */
986 if (plan->is_valid &&
987 TransactionIdIsValid(plan->saved_xmin) &&
989 plan->is_valid = false;
990
991 /*
992 * By now, if any invalidation has happened, the inval callback
993 * functions will have marked the plan invalid.
994 */
995 if (plan->is_valid)
996 {
997 /* Successfully revalidated and locked the query. */
998 return true;
999 }
1000
1001 /* Oops, the race case happened. Release useless locks. */
1002 AcquireExecutorLocks(plan->stmt_list, false);
1003 }
1004
1005 /*
1006 * Plan has been invalidated, so unlink it from the parent and release it.
1007 */
1008 ReleaseGenericPlan(plansource);
1009
1010 return false;
1011}
static void ReleaseGenericPlan(CachedPlanSource *plansource)
Definition: plancache.c:604
static void AcquireExecutorLocks(List *stmt_list, bool acquire)
Definition: plancache.c:2031
#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 1295 of file plancache.c.

1296{
1297 double avg_custom_cost;
1298
1299 /* One-shot plans will always be considered custom */
1300 if (plansource->is_oneshot)
1301 return true;
1302
1303 /* Otherwise, never any point in a custom plan if there's no parameters */
1304 if (boundParams == NULL)
1305 return false;
1306 /* ... nor when planning would be a no-op */
1307 if (!StmtPlanRequiresRevalidation(plansource))
1308 return false;
1309
1310 /* Let settings force the decision */
1312 return false;
1314 return true;
1315
1316 /* See if caller wants to force the decision */
1317 if (plansource->cursor_options & CURSOR_OPT_GENERIC_PLAN)
1318 return false;
1319 if (plansource->cursor_options & CURSOR_OPT_CUSTOM_PLAN)
1320 return true;
1321
1322 /* Generate custom plans until we have done at least 5 (arbitrary) */
1323 if (plansource->num_custom_plans < 5)
1324 return true;
1325
1326 avg_custom_cost = plansource->total_custom_cost / plansource->num_custom_plans;
1327
1328 /*
1329 * Prefer generic plan if it's less expensive than the average custom
1330 * plan. (Because we include a charge for cost of planning in the
1331 * custom-plan costs, this means the generic plan only has to be less
1332 * expensive than the execution cost plus replan cost of the custom
1333 * plans.)
1334 *
1335 * Note that if generic_cost is -1 (indicating we've not yet determined
1336 * the generic plan cost), we'll always prefer generic at this point.
1337 */
1338 if (plansource->generic_cost < avg_custom_cost)
1339 return false;
1340
1341 return true;
1342}
#define CURSOR_OPT_GENERIC_PLAN
Definition: parsenodes.h:3383
#define CURSOR_OPT_CUSTOM_PLAN
Definition: parsenodes.h:3384
int plan_cache_mode
Definition: plancache.c:139
static bool StmtPlanRequiresRevalidation(CachedPlanSource *plansource)
Definition: plancache.c:626
@ PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN
Definition: plancache.h:37
@ PLAN_CACHE_MODE_FORCE_GENERIC_PLAN
Definition: plancache.h:36
double total_custom_cost
Definition: plancache.h:146
int64 num_custom_plans
Definition: plancache.h:147
double generic_cost
Definition: plancache.h:145

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 392 of file plancache.c.

401{
402 MemoryContext source_context = plansource->context;
404
405 /* Assert caller is doing things in a sane order */
406 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
407 Assert(!plansource->is_complete);
408
409 /*
410 * If caller supplied a querytree_context, reparent it underneath the
411 * CachedPlanSource's context; otherwise, create a suitable context and
412 * copy the querytree_list into it. But no data copying should be done
413 * for one-shot plans; for those, assume the passed querytree_list is
414 * sufficiently long-lived.
415 */
416 if (plansource->is_oneshot)
417 {
418 querytree_context = CurrentMemoryContext;
419 }
420 else if (querytree_context != NULL)
421 {
422 MemoryContextSetParent(querytree_context, source_context);
423 MemoryContextSwitchTo(querytree_context);
424 }
425 else
426 {
427 /* Again, it's a good bet the querytree_context can be small */
428 querytree_context = AllocSetContextCreate(source_context,
429 "CachedPlanQuery",
431 MemoryContextSwitchTo(querytree_context);
432 querytree_list = copyObject(querytree_list);
433 }
434
435 plansource->query_context = querytree_context;
436 plansource->query_list = querytree_list;
437
438 if (!plansource->is_oneshot && StmtPlanRequiresRevalidation(plansource))
439 {
440 /*
441 * Use the planner machinery to extract dependencies. Data is saved
442 * in query_context. (We assume that not a lot of extra cruft is
443 * created by this call.) We can skip this for one-shot plans, and
444 * plans not needing revalidation have no such dependencies anyway.
445 */
446 extract_query_dependencies((Node *) querytree_list,
447 &plansource->relationOids,
448 &plansource->invalItems,
449 &plansource->dependsOnRLS);
450
451 /* Update RLS info as well. */
452 plansource->rewriteRoleId = GetUserId();
453 plansource->rewriteRowSecurity = row_security;
454
455 /*
456 * Also save the current search_path in the query_context. (This
457 * should not generate much extra cruft either, since almost certainly
458 * the path is already valid.) Again, we don't really need this for
459 * one-shot plans; and we *must* skip this for transaction control
460 * commands, because this could result in catalog accesses.
461 */
462 plansource->search_path = GetSearchPathMatcher(querytree_context);
463 }
464
465 /*
466 * Save the final parameter types (or other parameter specification data)
467 * into the source_context, as well as our other parameters. Also save
468 * the result tuple descriptor.
469 */
470 MemoryContextSwitchTo(source_context);
471
472 if (num_params > 0)
473 {
474 plansource->param_types = (Oid *) palloc(num_params * sizeof(Oid));
475 memcpy(plansource->param_types, param_types, num_params * sizeof(Oid));
476 }
477 else
478 plansource->param_types = NULL;
479 plansource->num_params = num_params;
480 plansource->parserSetup = parserSetup;
481 plansource->parserSetupArg = parserSetupArg;
482 plansource->cursor_options = cursor_options;
483 plansource->fixed_result = fixed_result;
484 plansource->resultDesc = PlanCacheComputeResultDesc(querytree_list);
485
486 MemoryContextSwitchTo(oldcxt);
487
488 plansource->is_complete = true;
489 plansource->is_valid = true;
490}
bool row_security
Definition: guc_tables.c:527
SearchPathMatcher * GetSearchPathMatcher(MemoryContext context)
Definition: namespace.c:3852
static TupleDesc PlanCacheComputeResultDesc(List *stmt_list)
Definition: plancache.c:2209
unsigned int Oid
Definition: postgres_ext.h:30
void extract_query_dependencies(Node *query, List **relationOids, List **invalItems, bool *hasRowSecurity)
Definition: setrefs.c:3633
MemoryContext query_context
Definition: plancache.h:130
List * invalItems
Definition: plancache.h:127
ParserSetupHook parserSetup
Definition: plancache.h:116
bool rewriteRowSecurity
Definition: plancache.h:132
List * relationOids
Definition: plancache.h:126
void * parserSetupArg
Definition: plancache.h:117

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(), prepare_next_query(), and PrepareQuery().

◆ CopyCachedPlan()

CachedPlanSource * CopyCachedPlan ( CachedPlanSource plansource)

Definition at line 1792 of file plancache.c.

1793{
1794 CachedPlanSource *newsource;
1795 MemoryContext source_context;
1796 MemoryContext querytree_context;
1797 MemoryContext oldcxt;
1798
1799 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1800 Assert(plansource->is_complete);
1801
1802 /*
1803 * One-shot plans can't be copied, because we haven't taken care that
1804 * parsing/planning didn't scribble on the raw parse tree or querytrees.
1805 */
1806 if (plansource->is_oneshot)
1807 elog(ERROR, "cannot copy a one-shot cached plan");
1808
1810 "CachedPlanSource",
1812
1813 oldcxt = MemoryContextSwitchTo(source_context);
1814
1815 newsource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
1816 newsource->magic = CACHEDPLANSOURCE_MAGIC;
1817 newsource->raw_parse_tree = copyObject(plansource->raw_parse_tree);
1818 newsource->analyzed_parse_tree = copyObject(plansource->analyzed_parse_tree);
1819 newsource->query_string = pstrdup(plansource->query_string);
1820 MemoryContextSetIdentifier(source_context, newsource->query_string);
1821 newsource->commandTag = plansource->commandTag;
1822 if (plansource->num_params > 0)
1823 {
1824 newsource->param_types = (Oid *)
1825 palloc(plansource->num_params * sizeof(Oid));
1826 memcpy(newsource->param_types, plansource->param_types,
1827 plansource->num_params * sizeof(Oid));
1828 }
1829 else
1830 newsource->param_types = NULL;
1831 newsource->num_params = plansource->num_params;
1832 newsource->parserSetup = plansource->parserSetup;
1833 newsource->parserSetupArg = plansource->parserSetupArg;
1834 newsource->postRewrite = plansource->postRewrite;
1835 newsource->postRewriteArg = plansource->postRewriteArg;
1836 newsource->cursor_options = plansource->cursor_options;
1837 newsource->fixed_result = plansource->fixed_result;
1838 if (plansource->resultDesc)
1839 newsource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
1840 else
1841 newsource->resultDesc = NULL;
1842 newsource->context = source_context;
1843
1844 querytree_context = AllocSetContextCreate(source_context,
1845 "CachedPlanQuery",
1847 MemoryContextSwitchTo(querytree_context);
1848 newsource->query_list = copyObject(plansource->query_list);
1849 newsource->relationOids = copyObject(plansource->relationOids);
1850 newsource->invalItems = copyObject(plansource->invalItems);
1851 if (plansource->search_path)
1852 newsource->search_path = CopySearchPathMatcher(plansource->search_path);
1853 newsource->query_context = querytree_context;
1854 newsource->rewriteRoleId = plansource->rewriteRoleId;
1855 newsource->rewriteRowSecurity = plansource->rewriteRowSecurity;
1856 newsource->dependsOnRLS = plansource->dependsOnRLS;
1857
1858 newsource->gplan = NULL;
1859
1860 newsource->is_oneshot = false;
1861 newsource->is_complete = true;
1862 newsource->is_saved = false;
1863 newsource->is_valid = plansource->is_valid;
1864 newsource->generation = plansource->generation;
1865
1866 /* We may as well copy any acquired cost knowledge */
1867 newsource->generic_cost = plansource->generic_cost;
1868 newsource->total_custom_cost = plansource->total_custom_cost;
1869 newsource->num_generic_plans = plansource->num_generic_plans;
1870 newsource->num_custom_plans = plansource->num_custom_plans;
1871
1872 MemoryContextSwitchTo(oldcxt);
1873
1874 return newsource;
1875}
char * pstrdup(const char *in)
Definition: mcxt.c:2321
void * palloc0(Size size)
Definition: mcxt.c:1969
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:643
SearchPathMatcher * CopySearchPathMatcher(SearchPathMatcher *path)
Definition: namespace.c:3889
PostRewriteHook postRewrite
Definition: plancache.h:118
CommandTag commandTag
Definition: plancache.h:113
int64 num_generic_plans
Definition: plancache.h:148
void * postRewriteArg
Definition: plancache.h:119
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:245

References ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, CachedPlanSource::analyzed_parse_tree, 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, CachedPlanSource::postRewrite, CachedPlanSource::postRewriteArg, 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 184 of file plancache.c.

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

References ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, CachedPlanSource::analyzed_parse_tree, 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, CachedPlanSource::postRewrite, CachedPlanSource::postRewriteArg, 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(), CreateCachedPlanForQuery(), exec_parse_message(), prepare_next_query(), and PrepareQuery().

◆ CreateCachedPlanForQuery()

CachedPlanSource * CreateCachedPlanForQuery ( Query analyzed_parse_tree,
const char *  query_string,
CommandTag  commandTag 
)

Definition at line 264 of file plancache.c.

267{
268 CachedPlanSource *plansource;
269 MemoryContext oldcxt;
270
271 /* Rather than duplicating CreateCachedPlan, just do this: */
272 plansource = CreateCachedPlan(NULL, query_string, commandTag);
273 oldcxt = MemoryContextSwitchTo(plansource->context);
274 plansource->analyzed_parse_tree = copyObject(analyzed_parse_tree);
275 MemoryContextSwitchTo(oldcxt);
276
277 return plansource;
278}
CachedPlanSource * CreateCachedPlan(RawStmt *raw_parse_tree, const char *query_string, CommandTag commandTag)
Definition: plancache.c:184

References CachedPlanSource::analyzed_parse_tree, CachedPlanSource::context, copyObject, CreateCachedPlan(), and MemoryContextSwitchTo().

Referenced by prepare_next_query().

◆ CreateOneShotCachedPlan()

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

Definition at line 299 of file plancache.c.

302{
303 CachedPlanSource *plansource;
304
305 Assert(query_string != NULL); /* required as of 8.4 */
306
307 /*
308 * Create and fill the CachedPlanSource struct within the caller's memory
309 * context. Most fields are just left empty for the moment.
310 */
311 plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
312 plansource->magic = CACHEDPLANSOURCE_MAGIC;
313 plansource->raw_parse_tree = raw_parse_tree;
314 plansource->analyzed_parse_tree = NULL;
315 plansource->query_string = query_string;
316 plansource->commandTag = commandTag;
317 plansource->param_types = NULL;
318 plansource->num_params = 0;
319 plansource->parserSetup = NULL;
320 plansource->parserSetupArg = NULL;
321 plansource->postRewrite = NULL;
322 plansource->postRewriteArg = NULL;
323 plansource->cursor_options = 0;
324 plansource->fixed_result = false;
325 plansource->resultDesc = NULL;
326 plansource->context = CurrentMemoryContext;
327 plansource->query_list = NIL;
328 plansource->relationOids = NIL;
329 plansource->invalItems = NIL;
330 plansource->search_path = NULL;
331 plansource->query_context = NULL;
332 plansource->rewriteRoleId = InvalidOid;
333 plansource->rewriteRowSecurity = false;
334 plansource->dependsOnRLS = false;
335 plansource->gplan = NULL;
336 plansource->is_oneshot = true;
337 plansource->is_complete = false;
338 plansource->is_saved = false;
339 plansource->is_valid = false;
340 plansource->generation = 0;
341 plansource->generic_cost = -1;
342 plansource->total_custom_cost = 0;
343 plansource->num_generic_plans = 0;
344 plansource->num_custom_plans = 0;
345
346 return plansource;
347}

References CachedPlanSource::analyzed_parse_tree, 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::postRewrite, CachedPlanSource::postRewriteArg, 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 575 of file plancache.c.

576{
577 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
578
579 /* If it's been saved, remove it from the list */
580 if (plansource->is_saved)
581 {
582 dlist_delete(&plansource->node);
583 plansource->is_saved = false;
584 }
585
586 /* Decrement generic CachedPlan's refcount and drop if no longer needed */
587 ReleaseGenericPlan(plansource);
588
589 /* Mark it no longer valid */
590 plansource->magic = 0;
591
592 /*
593 * Remove the CachedPlanSource and all subsidiary data (including the
594 * query_context if any). But if it's a one-shot we can't free anything.
595 */
596 if (!plansource->is_oneshot)
597 MemoryContextDelete(plansource->context);
598}
static void dlist_delete(dlist_node *node)
Definition: ilist.h:405
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:485
dlist_node node
Definition: plancache.h:143

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(), SPI_freeplan(), and sql_delete_callback().

◆ FreeCachedExpression()

void FreeCachedExpression ( CachedExpression cexpr)

Definition at line 1993 of file plancache.c.

1994{
1995 /* Sanity check */
1996 Assert(cexpr->magic == CACHEDEXPR_MAGIC);
1997 /* Unlink from global list */
1998 dlist_delete(&cexpr->node);
1999 /* Free all storage associated with CachedExpression */
2001}
#define CACHEDEXPR_MAGIC
Definition: plancache.h:48
MemoryContext context
Definition: plancache.h:203
dlist_node node
Definition: plancache.h:204

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 1936 of file plancache.c.

1937{
1938 CachedExpression *cexpr;
1939 List *relationOids;
1940 List *invalItems;
1941 MemoryContext cexpr_context;
1942 MemoryContext oldcxt;
1943
1944 /*
1945 * Pass the expression through the planner, and collect dependencies.
1946 * Everything built here is leaked in the caller's context; that's
1947 * intentional to minimize the size of the permanent data structure.
1948 */
1949 expr = (Node *) expression_planner_with_deps((Expr *) expr,
1950 &relationOids,
1951 &invalItems);
1952
1953 /*
1954 * Make a private memory context, and copy what we need into that. To
1955 * avoid leaking a long-lived context if we fail while copying data, we
1956 * initially make the context under the caller's context.
1957 */
1959 "CachedExpression",
1961
1962 oldcxt = MemoryContextSwitchTo(cexpr_context);
1963
1964 cexpr = (CachedExpression *) palloc(sizeof(CachedExpression));
1965 cexpr->magic = CACHEDEXPR_MAGIC;
1966 cexpr->expr = copyObject(expr);
1967 cexpr->is_valid = true;
1968 cexpr->relationOids = copyObject(relationOids);
1969 cexpr->invalItems = copyObject(invalItems);
1970 cexpr->context = cexpr_context;
1971
1972 MemoryContextSwitchTo(oldcxt);
1973
1974 /*
1975 * Reparent the expr's memory context under CacheMemoryContext so that it
1976 * will live indefinitely.
1977 */
1979
1980 /*
1981 * Add the entry to the global list of cached expressions.
1982 */
1984
1985 return cexpr;
1986}
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:364
MemoryContext CacheMemoryContext
Definition: mcxt.c:168
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:190
static dlist_head cached_expression_list
Definition: plancache.c:89
Expr * expression_planner_with_deps(Expr *expr, List **relationOids, List **invalItems)
Definition: planner.c:6672
List * relationOids
Definition: plancache.h:201
List * invalItems
Definition: plancache.h:202

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 1422 of file plancache.c.

1424{
1425 CachedPlan *plan = NULL;
1426 List *qlist;
1427 bool customplan;
1428
1429 /* Assert caller is doing things in a sane order */
1430 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1431 Assert(plansource->is_complete);
1432 /* This seems worth a real test, though */
1433 if (owner && !plansource->is_saved)
1434 elog(ERROR, "cannot apply ResourceOwner to non-saved cached plan");
1435
1436 /* Make sure the querytree list is valid and we have parse-time locks */
1437 qlist = RevalidateCachedQuery(plansource, queryEnv, true);
1438
1439 /* Decide whether to use a custom plan */
1440 customplan = choose_custom_plan(plansource, boundParams);
1441
1442 if (!customplan)
1443 {
1444 if (CheckCachedPlan(plansource))
1445 {
1446 /* We want a generic plan, and we already have a valid one */
1447 plan = plansource->gplan;
1448 Assert(plan->magic == CACHEDPLAN_MAGIC);
1449 /* Reusing the existing plan, so not all locks may be acquired. */
1450 plan->is_reused = true;
1451 }
1452 else
1453 {
1454 /* Build a new generic plan */
1455 plan = BuildCachedPlan(plansource, qlist, NULL, queryEnv);
1456 /* Just make real sure plansource->gplan is clear */
1457 ReleaseGenericPlan(plansource);
1458 /* Link the new generic plan into the plansource */
1459 plansource->gplan = plan;
1460 plan->refcount++;
1461 /* Immediately reparent into appropriate context */
1462 if (plansource->is_saved)
1463 {
1464 /* saved plans all live under CacheMemoryContext */
1466 plan->is_saved = true;
1467 }
1468 else
1469 {
1470 /* otherwise, it should be a sibling of the plansource */
1472 MemoryContextGetParent(plansource->context));
1473 }
1474 /* Update generic_cost whenever we make a new generic plan */
1475 plansource->generic_cost = cached_plan_cost(plan, false);
1476
1477 /*
1478 * If, based on the now-known value of generic_cost, we'd not have
1479 * chosen to use a generic plan, then forget it and make a custom
1480 * plan. This is a bit of a wart but is necessary to avoid a
1481 * glitch in behavior when the custom plans are consistently big
1482 * winners; at some point we'll experiment with a generic plan and
1483 * find it's a loser, but we don't want to actually execute that
1484 * plan.
1485 */
1486 customplan = choose_custom_plan(plansource, boundParams);
1487
1488 /*
1489 * If we choose to plan again, we need to re-copy the query_list,
1490 * since the planner probably scribbled on it. We can force
1491 * BuildCachedPlan to do that by passing NIL.
1492 */
1493 qlist = NIL;
1494 }
1495 }
1496
1497 if (customplan)
1498 {
1499 /* Build a custom plan */
1500 plan = BuildCachedPlan(plansource, qlist, boundParams, queryEnv);
1501 /* Accumulate total costs of custom plans */
1502 plansource->total_custom_cost += cached_plan_cost(plan, true);
1503
1504 plansource->num_custom_plans++;
1505 }
1506 else
1507 {
1508 plansource->num_generic_plans++;
1509 }
1510
1511 Assert(plan != NULL);
1512
1513 /* Flag the plan as in use by caller */
1514 if (owner)
1515 ResourceOwnerEnlarge(owner);
1516 plan->refcount++;
1517 if (owner)
1519
1520 /*
1521 * Saved plans should be under CacheMemoryContext so they will not go away
1522 * until their reference count goes to zero. In the generic-plan cases we
1523 * already took care of that, but for a custom plan, do it as soon as we
1524 * have created a reference-counted link.
1525 */
1526 if (customplan && plansource->is_saved)
1527 {
1529 plan->is_saved = true;
1530 }
1531
1532 return plan;
1533}
MemoryContext MemoryContextGetParent(MemoryContext context)
Definition: mcxt.c:762
static bool choose_custom_plan(CachedPlanSource *plansource, ParamListInfo boundParams)
Definition: plancache.c:1295
static CachedPlan * BuildCachedPlan(CachedPlanSource *plansource, List *qlist, ParamListInfo boundParams, QueryEnvironment *queryEnv)
Definition: plancache.c:1032
static bool CheckCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:946
static double cached_plan_cost(CachedPlan *plan, bool include_planner)
Definition: plancache.c:1352

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(), init_execution_state(), SPI_cursor_open_internal(), and SPI_plan_get_cached_plan().

◆ InitPlanCache()

void InitPlanCache ( void  )

Definition at line 147 of file plancache.c.

148{
156 CacheRegisterSyscacheCallback(FOREIGNDATAWRAPPEROID, PlanCacheSysCallback, (Datum) 0);
157}
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition: inval.c:1854
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1812
static void PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:2438
static void PlanCacheObjectCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:2329
static void PlanCacheRelCallback(Datum arg, Oid relid)
Definition: plancache.c:2245
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 2209 of file plancache.c.

2210{
2211 Query *query;
2212
2213 switch (ChoosePortalStrategy(stmt_list))
2214 {
2215 case PORTAL_ONE_SELECT:
2217 query = linitial_node(Query, stmt_list);
2218 return ExecCleanTypeFromTL(query->targetList);
2219
2221 query = QueryListGetPrimaryStmt(stmt_list);
2222 Assert(query->returningList);
2223 return ExecCleanTypeFromTL(query->returningList);
2224
2225 case PORTAL_UTIL_SELECT:
2226 query = linitial_node(Query, stmt_list);
2227 Assert(query->utilityStmt);
2228 return UtilityTupleDescriptor(query->utilityStmt);
2229
2230 case PORTAL_MULTI_QUERY:
2231 /* will not return tuples */
2232 break;
2233 }
2234 return NULL;
2235}
TupleDesc ExecCleanTypeFromTL(List *targetList)
Definition: execTuples.c:2139
#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 2329 of file plancache.c.

2330{
2331 dlist_iter iter;
2332
2334 {
2336 node, iter.cur);
2337 ListCell *lc;
2338
2339 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2340
2341 /* No work if it's already invalidated */
2342 if (!plansource->is_valid)
2343 continue;
2344
2345 /* Never invalidate if parse/plan would be a no-op anyway */
2346 if (!StmtPlanRequiresRevalidation(plansource))
2347 continue;
2348
2349 /*
2350 * Check the dependency list for the rewritten querytree.
2351 */
2352 foreach(lc, plansource->invalItems)
2353 {
2354 PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2355
2356 if (item->cacheId != cacheid)
2357 continue;
2358 if (hashvalue == 0 ||
2359 item->hashValue == hashvalue)
2360 {
2361 /* Invalidate the querytree and generic plan */
2362 plansource->is_valid = false;
2363 if (plansource->gplan)
2364 plansource->gplan->is_valid = false;
2365 break;
2366 }
2367 }
2368
2369 /*
2370 * The generic plan, if any, could have more dependencies than the
2371 * querytree does, so we have to check it too.
2372 */
2373 if (plansource->gplan && plansource->gplan->is_valid)
2374 {
2375 foreach(lc, plansource->gplan->stmt_list)
2376 {
2377 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2378 ListCell *lc3;
2379
2380 if (plannedstmt->commandType == CMD_UTILITY)
2381 continue; /* Ignore utility statements */
2382 foreach(lc3, plannedstmt->invalItems)
2383 {
2384 PlanInvalItem *item = (PlanInvalItem *) lfirst(lc3);
2385
2386 if (item->cacheId != cacheid)
2387 continue;
2388 if (hashvalue == 0 ||
2389 item->hashValue == hashvalue)
2390 {
2391 /* Invalidate the generic plan only */
2392 plansource->gplan->is_valid = false;
2393 break; /* out of invalItems scan */
2394 }
2395 }
2396 if (!plansource->gplan->is_valid)
2397 break; /* out of stmt_list scan */
2398 }
2399 }
2400 }
2401
2402 /* Likewise check cached expressions */
2404 {
2406 node, iter.cur);
2407 ListCell *lc;
2408
2409 Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2410
2411 /* No work if it's already invalidated */
2412 if (!cexpr->is_valid)
2413 continue;
2414
2415 foreach(lc, cexpr->invalItems)
2416 {
2417 PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2418
2419 if (item->cacheId != cacheid)
2420 continue;
2421 if (hashvalue == 0 ||
2422 item->hashValue == hashvalue)
2423 {
2424 cexpr->is_valid = false;
2425 break;
2426 }
2427 }
2428 }
2429}
#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:84
bool is_valid
Definition: plancache.h:169
List * stmt_list
Definition: plancache.h:165
uint32 hashValue
Definition: plannodes.h:1754
List * invalItems
Definition: plannodes.h:133
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 2245 of file plancache.c.

2246{
2247 dlist_iter iter;
2248
2250 {
2252 node, iter.cur);
2253
2254 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2255
2256 /* No work if it's already invalidated */
2257 if (!plansource->is_valid)
2258 continue;
2259
2260 /* Never invalidate if parse/plan would be a no-op anyway */
2261 if (!StmtPlanRequiresRevalidation(plansource))
2262 continue;
2263
2264 /*
2265 * Check the dependency list for the rewritten querytree.
2266 */
2267 if ((relid == InvalidOid) ? plansource->relationOids != NIL :
2268 list_member_oid(plansource->relationOids, relid))
2269 {
2270 /* Invalidate the querytree and generic plan */
2271 plansource->is_valid = false;
2272 if (plansource->gplan)
2273 plansource->gplan->is_valid = false;
2274 }
2275
2276 /*
2277 * The generic plan, if any, could have more dependencies than the
2278 * querytree does, so we have to check it too.
2279 */
2280 if (plansource->gplan && plansource->gplan->is_valid)
2281 {
2282 ListCell *lc;
2283
2284 foreach(lc, plansource->gplan->stmt_list)
2285 {
2286 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2287
2288 if (plannedstmt->commandType == CMD_UTILITY)
2289 continue; /* Ignore utility statements */
2290 if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
2291 list_member_oid(plannedstmt->relationOids, relid))
2292 {
2293 /* Invalidate the generic plan only */
2294 plansource->gplan->is_valid = false;
2295 break; /* out of stmt_list scan */
2296 }
2297 }
2298 }
2299 }
2300
2301 /* Likewise check cached expressions */
2303 {
2305 node, iter.cur);
2306
2307 Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2308
2309 /* No work if it's already invalidated */
2310 if (!cexpr->is_valid)
2311 continue;
2312
2313 if ((relid == InvalidOid) ? cexpr->relationOids != NIL :
2314 list_member_oid(cexpr->relationOids, relid))
2315 {
2316 cexpr->is_valid = false;
2317 }
2318 }
2319}
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:722
List * relationOids
Definition: plannodes.h:130

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 2438 of file plancache.c.

2439{
2441}
void ResetPlanCache(void)
Definition: plancache.c:2447

References ResetPlanCache().

Referenced by InitPlanCache().

◆ QueryListGetPrimaryStmt()

static Query * QueryListGetPrimaryStmt ( List stmts)
static

Definition at line 2012 of file plancache.c.

2013{
2014 ListCell *lc;
2015
2016 foreach(lc, stmts)
2017 {
2018 Query *stmt = lfirst_node(Query, lc);
2019
2020 if (stmt->canSetTag)
2021 return stmt;
2022 }
2023 return NULL;
2024}
#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 2494 of file plancache.c.

2495{
2497}
static const ResourceOwnerDesc planref_resowner_desc
Definition: plancache.c:116
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 1547 of file plancache.c.

1548{
1549 Assert(plan->magic == CACHEDPLAN_MAGIC);
1550 if (owner)
1551 {
1552 Assert(plan->is_saved);
1554 }
1555 Assert(plan->refcount > 0);
1556 plan->refcount--;
1557 if (plan->refcount == 0)
1558 {
1559 /* Mark it no longer valid */
1560 plan->magic = 0;
1561
1562 /* One-shot plans do not own their context, so we can't free them */
1563 if (!plan->is_oneshot)
1564 MemoryContextDelete(plan->context);
1565 }
1566}
static void ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
Definition: plancache.c:132

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

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

◆ ReleaseGenericPlan()

static void ReleaseGenericPlan ( CachedPlanSource plansource)
static

Definition at line 604 of file plancache.c.

605{
606 /* Be paranoid about the possibility that ReleaseCachedPlan fails */
607 if (plansource->gplan)
608 {
609 CachedPlan *plan = plansource->gplan;
610
611 Assert(plan->magic == CACHEDPLAN_MAGIC);
612 plansource->gplan = NULL;
613 ReleaseCachedPlan(plan, NULL);
614 }
615}
void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1547

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

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

◆ ResetPlanCache()

void ResetPlanCache ( void  )

Definition at line 2447 of file plancache.c.

2448{
2449 dlist_iter iter;
2450
2452 {
2454 node, iter.cur);
2455
2456 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2457
2458 /* No work if it's already invalidated */
2459 if (!plansource->is_valid)
2460 continue;
2461
2462 /*
2463 * We *must not* mark transaction control statements as invalid,
2464 * particularly not ROLLBACK, because they may need to be executed in
2465 * aborted transactions when we can't revalidate them (cf bug #5269).
2466 * In general there's no point in invalidating statements for which a
2467 * new parse analysis/rewrite/plan cycle would certainly give the same
2468 * results.
2469 */
2470 if (!StmtPlanRequiresRevalidation(plansource))
2471 continue;
2472
2473 plansource->is_valid = false;
2474 if (plansource->gplan)
2475 plansource->gplan->is_valid = false;
2476 }
2477
2478 /* Likewise invalidate cached expressions */
2480 {
2482 node, iter.cur);
2483
2484 Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2485
2486 cexpr->is_valid = false;
2487 }
2488}

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 132 of file plancache.c.

133{
135}
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 127 of file plancache.c.

128{
130}
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 2502 of file plancache.c.

2503{
2505}
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 674 of file plancache.c.

677{
678 bool snapshot_set;
679 List *tlist; /* transient query-tree list */
680 List *qlist; /* permanent query-tree list */
681 TupleDesc resultDesc;
682 MemoryContext querytree_context;
683 MemoryContext oldcxt;
684
685 /*
686 * For one-shot plans, we do not support revalidation checking; it's
687 * assumed the query is parsed, planned, and executed in one transaction,
688 * so that no lock re-acquisition is necessary. Also, if the statement
689 * type can't require revalidation, we needn't do anything (and we mustn't
690 * risk catalog accesses when handling, eg, transaction control commands).
691 */
692 if (plansource->is_oneshot || !StmtPlanRequiresRevalidation(plansource))
693 {
694 Assert(plansource->is_valid);
695 return NIL;
696 }
697
698 /*
699 * If the query is currently valid, we should have a saved search_path ---
700 * check to see if that matches the current environment. If not, we want
701 * to force replan. (We could almost ignore this consideration when
702 * working from an analyzed parse tree; but there are scenarios where
703 * planning can have search_path-dependent results, for example if it
704 * inlines an old-style SQL function.)
705 */
706 if (plansource->is_valid)
707 {
708 Assert(plansource->search_path != NULL);
710 {
711 /* Invalidate the querytree and generic plan */
712 plansource->is_valid = false;
713 if (plansource->gplan)
714 plansource->gplan->is_valid = false;
715 }
716 }
717
718 /*
719 * If the query rewrite phase had a possible RLS dependency, we must redo
720 * it if either the role or the row_security setting has changed.
721 */
722 if (plansource->is_valid && plansource->dependsOnRLS &&
723 (plansource->rewriteRoleId != GetUserId() ||
724 plansource->rewriteRowSecurity != row_security))
725 plansource->is_valid = false;
726
727 /*
728 * If the query is currently valid, acquire locks on the referenced
729 * objects; then check again. We need to do it this way to cover the race
730 * condition that an invalidation message arrives before we get the locks.
731 */
732 if (plansource->is_valid)
733 {
734 AcquirePlannerLocks(plansource->query_list, true);
735
736 /*
737 * By now, if any invalidation has happened, the inval callback
738 * functions will have marked the query invalid.
739 */
740 if (plansource->is_valid)
741 {
742 /* Successfully revalidated and locked the query. */
743 return NIL;
744 }
745
746 /* Oops, the race case happened. Release useless locks. */
747 AcquirePlannerLocks(plansource->query_list, false);
748 }
749
750 /*
751 * Discard the no-longer-useful rewritten query tree. (Note: we don't
752 * want to do this any earlier, else we'd not have been able to release
753 * locks correctly in the race condition case.)
754 */
755 plansource->is_valid = false;
756 plansource->query_list = NIL;
757 plansource->relationOids = NIL;
758 plansource->invalItems = NIL;
759 plansource->search_path = NULL;
760
761 /*
762 * Free the query_context. We don't really expect MemoryContextDelete to
763 * fail, but just in case, make sure the CachedPlanSource is left in a
764 * reasonably sane state. (The generic plan won't get unlinked yet, but
765 * that's acceptable.)
766 */
767 if (plansource->query_context)
768 {
769 MemoryContext qcxt = plansource->query_context;
770
771 plansource->query_context = NULL;
773 }
774
775 /* Drop the generic plan reference, if any, and if requested */
776 if (release_generic)
777 ReleaseGenericPlan(plansource);
778
779 /*
780 * Now re-do parse analysis and rewrite. This not incidentally acquires
781 * the locks we need to do planning safely.
782 */
783 Assert(plansource->is_complete);
784
785 /*
786 * If a snapshot is already set (the normal case), we can just use that
787 * for parsing/planning. But if it isn't, install one. Note: no point in
788 * checking whether parse analysis requires a snapshot; utility commands
789 * don't have invalidatable plans, so we'd not get here for such a
790 * command.
791 */
792 snapshot_set = false;
793 if (!ActiveSnapshotSet())
794 {
796 snapshot_set = true;
797 }
798
799 /*
800 * Run parse analysis (if needed) and rule rewriting.
801 */
802 if (plansource->raw_parse_tree != NULL)
803 {
804 /* Source is raw parse tree */
805 RawStmt *rawtree;
806
807 /*
808 * The parser tends to scribble on its input, so we must copy the raw
809 * parse tree to prevent corruption of the cache.
810 */
811 rawtree = copyObject(plansource->raw_parse_tree);
812 if (plansource->parserSetup != NULL)
813 tlist = pg_analyze_and_rewrite_withcb(rawtree,
814 plansource->query_string,
815 plansource->parserSetup,
816 plansource->parserSetupArg,
817 queryEnv);
818 else
820 plansource->query_string,
821 plansource->param_types,
822 plansource->num_params,
823 queryEnv);
824 }
825 else if (plansource->analyzed_parse_tree != NULL)
826 {
827 /* Source is pre-analyzed query, so we only need to rewrite */
828 Query *analyzed_tree;
829
830 /* The rewriter scribbles on its input, too, so copy */
831 analyzed_tree = copyObject(plansource->analyzed_parse_tree);
832 /* Acquire locks needed before rewriting ... */
833 AcquireRewriteLocks(analyzed_tree, true, false);
834 /* ... and do it */
835 tlist = pg_rewrite_query(analyzed_tree);
836 }
837 else
838 {
839 /* Empty query, nothing to do */
840 tlist = NIL;
841 }
842
843 /* Apply post-rewrite callback if there is one */
844 if (plansource->postRewrite != NULL)
845 plansource->postRewrite(tlist, plansource->postRewriteArg);
846
847 /* Release snapshot if we got one */
848 if (snapshot_set)
850
851 /*
852 * Check or update the result tupdesc.
853 *
854 * We assume the parameter types didn't change from the first time, so no
855 * need to update that.
856 */
857 resultDesc = PlanCacheComputeResultDesc(tlist);
858 if (resultDesc == NULL && plansource->resultDesc == NULL)
859 {
860 /* OK, doesn't return tuples */
861 }
862 else if (resultDesc == NULL || plansource->resultDesc == NULL ||
863 !equalRowTypes(resultDesc, plansource->resultDesc))
864 {
865 /* can we give a better error message? */
866 if (plansource->fixed_result)
868 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
869 errmsg("cached plan must not change result type")));
870 oldcxt = MemoryContextSwitchTo(plansource->context);
871 if (resultDesc)
872 resultDesc = CreateTupleDescCopy(resultDesc);
873 if (plansource->resultDesc)
874 FreeTupleDesc(plansource->resultDesc);
875 plansource->resultDesc = resultDesc;
876 MemoryContextSwitchTo(oldcxt);
877 }
878
879 /*
880 * Allocate new query_context and copy the completed querytree into it.
881 * It's transient until we complete the copying and dependency extraction.
882 */
884 "CachedPlanQuery",
886 oldcxt = MemoryContextSwitchTo(querytree_context);
887
888 qlist = copyObject(tlist);
889
890 /*
891 * Use the planner machinery to extract dependencies. Data is saved in
892 * query_context. (We assume that not a lot of extra cruft is created by
893 * this call.)
894 */
896 &plansource->relationOids,
897 &plansource->invalItems,
898 &plansource->dependsOnRLS);
899
900 /* Update RLS info as well. */
901 plansource->rewriteRoleId = GetUserId();
902 plansource->rewriteRowSecurity = row_security;
903
904 /*
905 * Also save the current search_path in the query_context. (This should
906 * not generate much extra cruft either, since almost certainly the path
907 * is already valid.)
908 */
909 plansource->search_path = GetSearchPathMatcher(querytree_context);
910
911 MemoryContextSwitchTo(oldcxt);
912
913 /* Now reparent the finished query_context and save the links */
914 MemoryContextSetParent(querytree_context, plansource->context);
915
916 plansource->query_context = querytree_context;
917 plansource->query_list = qlist;
918
919 /*
920 * Note: we do not reset generic_cost or total_custom_cost, although we
921 * could choose to do so. If the DDL or statistics change that prompted
922 * the invalidation meant a significant change in the cost estimates, it
923 * would be better to reset those variables and start fresh; but often it
924 * doesn't, and we're better retaining our hard-won knowledge about the
925 * relative costs.
926 */
927
928 plansource->is_valid = true;
929
930 /* Return transient copy of querytrees for possible use in planning */
931 return tlist;
932}
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ereport(elevel,...)
Definition: elog.h:149
static void AcquirePlannerLocks(List *stmt_list, bool acquire)
Definition: plancache.c:2090
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
List * pg_rewrite_query(Query *query)
Definition: postgres.c:798
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:495
bool equalRowTypes(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:770

References AcquirePlannerLocks(), AcquireRewriteLocks(), ActiveSnapshotSet(), ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, CachedPlanSource::analyzed_parse_tree, 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(), pg_rewrite_query(), PlanCacheComputeResultDesc(), PopActiveSnapshot(), CachedPlanSource::postRewrite, CachedPlanSource::postRewriteArg, 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 531 of file plancache.c.

532{
533 /* Assert caller is doing things in a sane order */
534 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
535 Assert(plansource->is_complete);
536 Assert(!plansource->is_saved);
537
538 /* This seems worth a real test, though */
539 if (plansource->is_oneshot)
540 elog(ERROR, "cannot save one-shot cached plan");
541
542 /*
543 * In typical use, this function would be called before generating any
544 * plans from the CachedPlanSource. If there is a generic plan, moving it
545 * into CacheMemoryContext would be pretty risky since it's unclear
546 * whether the caller has taken suitable care with making references
547 * long-lived. Best thing to do seems to be to discard the plan.
548 */
549 ReleaseGenericPlan(plansource);
550
551 /*
552 * Reparent the source memory context under CacheMemoryContext so that it
553 * will live indefinitely. The query_context follows along since it's
554 * already a child of the other one.
555 */
557
558 /*
559 * Add the entry to the global list of cached plans.
560 */
561 dlist_push_tail(&saved_plan_list, &plansource->node);
562
563 plansource->is_saved = true;
564}

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(), prepare_next_query(), SPI_keepplan(), and StorePreparedStatement().

◆ ScanQueryForLocks()

static void ScanQueryForLocks ( Query parsetree,
bool  acquire 
)
static

Definition at line 2115 of file plancache.c.

2116{
2117 ListCell *lc;
2118
2119 /* Shouldn't get called on utility commands */
2120 Assert(parsetree->commandType != CMD_UTILITY);
2121
2122 /*
2123 * First, process RTEs of the current query level.
2124 */
2125 foreach(lc, parsetree->rtable)
2126 {
2127 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2128
2129 switch (rte->rtekind)
2130 {
2131 case RTE_RELATION:
2132 /* Acquire or release the appropriate type of lock */
2133 if (acquire)
2134 LockRelationOid(rte->relid, rte->rellockmode);
2135 else
2136 UnlockRelationOid(rte->relid, rte->rellockmode);
2137 break;
2138
2139 case RTE_SUBQUERY:
2140 /* If this was a view, must lock/unlock the view */
2141 if (OidIsValid(rte->relid))
2142 {
2143 if (acquire)
2144 LockRelationOid(rte->relid, rte->rellockmode);
2145 else
2146 UnlockRelationOid(rte->relid, rte->rellockmode);
2147 }
2148 /* Recurse into subquery-in-FROM */
2149 ScanQueryForLocks(rte->subquery, acquire);
2150 break;
2151
2152 default:
2153 /* ignore other types of RTEs */
2154 break;
2155 }
2156 }
2157
2158 /* Recurse into subquery-in-WITH */
2159 foreach(lc, parsetree->cteList)
2160 {
2162
2163 ScanQueryForLocks(castNode(Query, cte->ctequery), acquire);
2164 }
2165
2166 /*
2167 * Recurse into sublink subqueries, too. But we already did the ones in
2168 * the rtable and cteList.
2169 */
2170 if (parsetree->hasSubLinks)
2171 {
2172 query_tree_walker(parsetree, ScanQueryWalker, &acquire,
2174 }
2175}
#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:182
static bool ScanQueryWalker(Node *node, bool *acquire)
Definition: plancache.c:2181
Query * subquery
Definition: parsenodes.h:1118

References Assert(), castNode, CMD_UTILITY, Query::commandType, Query::cteList, CommonTableExpr::ctequery, lfirst, lfirst_node, LockRelationOid(), OidIsValid, QTW_IGNORE_RC_SUBQUERIES, query_tree_walker, 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 2181 of file plancache.c.

2182{
2183 if (node == NULL)
2184 return false;
2185 if (IsA(node, SubLink))
2186 {
2187 SubLink *sub = (SubLink *) node;
2188
2189 /* Do what we came for */
2190 ScanQueryForLocks(castNode(Query, sub->subselect), *acquire);
2191 /* Fall through to process lefthand args of SubLink */
2192 }
2193
2194 /*
2195 * Do NOT recurse into Query nodes, because ScanQueryForLocks already
2196 * processed subselects of subselects for us.
2197 */
2198 return expression_tree_walker(node, ScanQueryWalker, acquire);
2199}
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:153
#define IsA(nodeptr, _type_)
Definition: nodes.h:164

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

Referenced by ScanQueryForLocks(), and ScanQueryWalker().

◆ SetPostRewriteHook()

void SetPostRewriteHook ( CachedPlanSource plansource,
PostRewriteHook  postRewrite,
void *  postRewriteArg 
)

Definition at line 506 of file plancache.c.

509{
510 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
511 plansource->postRewrite = postRewrite;
512 plansource->postRewriteArg = postRewriteArg;
513}

References Assert(), CACHEDPLANSOURCE_MAGIC, CachedPlanSource::magic, CachedPlanSource::postRewrite, and CachedPlanSource::postRewriteArg.

Referenced by prepare_next_query().

◆ StmtPlanRequiresRevalidation()

static bool StmtPlanRequiresRevalidation ( CachedPlanSource plansource)
static

Definition at line 626 of file plancache.c.

627{
628 if (plansource->raw_parse_tree != NULL)
630 else if (plansource->analyzed_parse_tree != NULL)
632 /* empty query never needs revalidation */
633 return false;
634}
bool stmt_requires_parse_analysis(RawStmt *parseTree)
Definition: analyze.c:532

References CachedPlanSource::analyzed_parse_tree, query_requires_rewrite_plan(), CachedPlanSource::raw_parse_tree, and stmt_requires_parse_analysis().

Referenced by choose_custom_plan(), CompleteCachedPlan(), PlanCacheObjectCallback(), PlanCacheRelCallback(), ResetPlanCache(), and RevalidateCachedQuery().

◆ UpdateCachedPlan()

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

Definition at line 1205 of file plancache.c.

1207{
1208 List *query_list = plansource->query_list,
1209 *plan_list;
1210 ListCell *l1,
1211 *l2;
1212 CachedPlan *plan = plansource->gplan;
1213 MemoryContext oldcxt;
1214
1216
1217 /* Sanity checks (XXX can be Asserts?) */
1218 if (plan == NULL)
1219 elog(ERROR, "UpdateCachedPlan() called in the wrong context: plansource->gplan is NULL");
1220 else if (plan->is_valid)
1221 elog(ERROR, "UpdateCachedPlan() called in the wrong context: plansource->gplan->is_valid is true");
1222 else if (plan->is_oneshot)
1223 elog(ERROR, "UpdateCachedPlan() called in the wrong context: plansource->gplan->is_oneshot is true");
1224
1225 /*
1226 * The plansource might have become invalid since GetCachedPlan() returned
1227 * the CachedPlan. See the comment in BuildCachedPlan() for details on why
1228 * this might happen. Although invalidation is likely a false positive as
1229 * stated there, we make the plan valid to ensure the query list used for
1230 * planning is up to date.
1231 *
1232 * The risk of catching an invalidation is higher here than when
1233 * BuildCachedPlan() is called from GetCachedPlan(), because this function
1234 * is normally called long after GetCachedPlan() returns the CachedPlan,
1235 * so much more processing could have occurred including things that mark
1236 * the CachedPlanSource invalid.
1237 *
1238 * Note: Do not release plansource->gplan, because the upstream callers
1239 * (such as the callers of ExecutorStartCachedPlan()) would still be
1240 * referencing it.
1241 */
1242 if (!plansource->is_valid)
1243 query_list = RevalidateCachedQuery(plansource, queryEnv, false);
1244 Assert(query_list != NIL);
1245
1246 /*
1247 * Build a new generic plan for all the queries after making a copy to be
1248 * scribbled on by the planner.
1249 */
1250 query_list = copyObject(query_list);
1251
1252 /*
1253 * Planning work is done in the caller's memory context. The resulting
1254 * PlannedStmt is then copied into plan->stmt_context after throwing away
1255 * the old ones.
1256 */
1257 plan_list = pg_plan_queries(query_list, plansource->query_string,
1258 plansource->cursor_options, NULL);
1259 Assert(list_length(plan_list) == list_length(plan->stmt_list));
1260
1261 MemoryContextReset(plan->stmt_context);
1262 oldcxt = MemoryContextSwitchTo(plan->stmt_context);
1263 forboth(l1, plan_list, l2, plan->stmt_list)
1264 {
1265 PlannedStmt *plannedstmt = lfirst(l1);
1266
1267 lfirst(l2) = copyObject(plannedstmt);
1268 }
1269 MemoryContextSwitchTo(oldcxt);
1270
1271 /*
1272 * XXX Should this also (re)set the properties of the CachedPlan that are
1273 * set in BuildCachedPlan() after creating the fresh plans such as
1274 * planRoleId, dependsOnRole, and save_xmin?
1275 */
1276
1277 /*
1278 * We've updated all the plans that might have been invalidated, so mark
1279 * the CachedPlan as valid.
1280 */
1281 plan->is_valid = true;
1282
1283 /* Also update generic_cost because we just created a new generic plan. */
1284 plansource->generic_cost = cached_plan_cost(plan, false);
1285
1286 return list_nth_node(PlannedStmt, plan->stmt_list, query_index);
1287}
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:414
#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 139 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:2502
#define RELEASE_PRIO_PLANCACHE_REFS
Definition: resowner.h:73
@ RESOURCE_RELEASE_AFTER_LOCKS
Definition: resowner.h:56

Definition at line 116 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