PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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)
 
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, SysCacheIdentifier cacheid, uint32 hashvalue)
 
static void PlanCacheSysCallback (Datum arg, SysCacheIdentifier 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)
 
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 1911 of file plancache.c.

1912{
1913 ListCell *lc1;
1914
1915 foreach(lc1, stmt_list)
1916 {
1917 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
1918 ListCell *lc2;
1919
1920 if (plannedstmt->commandType == CMD_UTILITY)
1921 {
1922 /*
1923 * Ignore utility statements, except those (such as EXPLAIN) that
1924 * contain a parsed-but-not-planned query. Note: it's okay to use
1925 * ScanQueryForLocks, even though the query hasn't been through
1926 * rule rewriting, because rewriting doesn't change the query
1927 * representation.
1928 */
1929 Query *query = UtilityContainsQuery(plannedstmt->utilityStmt);
1930
1931 if (query)
1932 ScanQueryForLocks(query, acquire);
1933 continue;
1934 }
1935
1936 foreach(lc2, plannedstmt->rtable)
1937 {
1939
1940 if (!(rte->rtekind == RTE_RELATION ||
1941 (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid))))
1942 continue;
1943
1944 /*
1945 * Acquire the appropriate type of lock on each relation OID. Note
1946 * that we don't actually try to open the rel, and hence will not
1947 * fail if it's been dropped entirely --- we'll just transiently
1948 * acquire a non-conflicting lock.
1949 */
1950 if (acquire)
1951 LockRelationOid(rte->relid, rte->rellockmode);
1952 else
1953 UnlockRelationOid(rte->relid, rte->rellockmode);
1954 }
1955 }
1956}
#define OidIsValid(objectId)
Definition c.h:800
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:280
@ RTE_SUBQUERY
@ RTE_RELATION
#define lfirst(lc)
Definition pg_list.h:172
#define lfirst_node(type, lc)
Definition pg_list.h:176
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition plancache.c:1992
static int fb(int x)
CmdType commandType
Definition plannodes.h:68
Node * utilityStmt
Definition plannodes.h:153
List * rtable
Definition plannodes.h:109
Query * UtilityContainsQuery(Node *parsetree)
Definition utility.c:2186

References CMD_UTILITY, PlannedStmt::commandType, fb(), lfirst, lfirst_node, LockRelationOid(), OidIsValid, PlannedStmt::rtable, RTE_RELATION, RTE_SUBQUERY, ScanQueryForLocks(), UnlockRelationOid(), UtilityContainsQuery(), and PlannedStmt::utilityStmt.

Referenced by CheckCachedPlan().

◆ AcquirePlannerLocks()

static void AcquirePlannerLocks ( List stmt_list,
bool  acquire 
)
static

Definition at line 1967 of file plancache.c.

1968{
1969 ListCell *lc;
1970
1971 foreach(lc, stmt_list)
1972 {
1973 Query *query = lfirst_node(Query, lc);
1974
1975 if (query->commandType == CMD_UTILITY)
1976 {
1977 /* Ignore utility statements, unless they contain a Query */
1978 query = UtilityContainsQuery(query->utilityStmt);
1979 if (query)
1980 ScanQueryForLocks(query, acquire);
1981 continue;
1982 }
1983
1984 ScanQueryForLocks(query, acquire);
1985 }
1986}
CmdType commandType
Definition parsenodes.h:121
Node * utilityStmt
Definition parsenodes.h:141

References CMD_UTILITY, Query::commandType, fb(), 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 1036 of file plancache.c.

1038{
1040 List *plist;
1041 bool snapshot_set;
1042 bool is_transient;
1045 ListCell *lc;
1046
1047 /*
1048 * Normally the querytree should be valid already, but if it's not,
1049 * rebuild it.
1050 *
1051 * NOTE: GetCachedPlan should have called RevalidateCachedQuery first, so
1052 * we ought to be holding sufficient locks to prevent any invalidation.
1053 * However, if we're building a custom plan after having built and
1054 * rejected a generic plan, it's possible to reach here with is_valid
1055 * false due to an invalidation while making the generic plan. In theory
1056 * the invalidation must be a false positive, perhaps a consequence of an
1057 * sinval reset event or the debug_discard_caches code. But for safety,
1058 * let's treat it as real and redo the RevalidateCachedQuery call.
1059 */
1060 if (!plansource->is_valid)
1061 qlist = RevalidateCachedQuery(plansource, queryEnv);
1062
1063 /*
1064 * If we don't already have a copy of the querytree list that can be
1065 * scribbled on by the planner, make one. For a one-shot plan, we assume
1066 * it's okay to scribble on the original query_list.
1067 */
1068 if (qlist == NIL)
1069 {
1070 if (!plansource->is_oneshot)
1071 qlist = copyObject(plansource->query_list);
1072 else
1073 qlist = plansource->query_list;
1074 }
1075
1076 /*
1077 * If a snapshot is already set (the normal case), we can just use that
1078 * for planning. But if it isn't, and we need one, install one.
1079 */
1080 snapshot_set = false;
1081 if (!ActiveSnapshotSet() &&
1082 BuildingPlanRequiresSnapshot(plansource))
1083 {
1085 snapshot_set = true;
1086 }
1087
1088 /*
1089 * Generate the plan.
1090 */
1091 plist = pg_plan_queries(qlist, plansource->query_string,
1092 plansource->cursor_options, boundParams);
1093
1094 /* Release snapshot if we got one */
1095 if (snapshot_set)
1097
1098 /*
1099 * Normally we make a dedicated memory context for the CachedPlan and its
1100 * subsidiary data. (It's probably not going to be large, but just in
1101 * case, allow it to grow large. It's transient for the moment.) But for
1102 * a one-shot plan, we just leave it in the caller's memory context.
1103 */
1104 if (!plansource->is_oneshot)
1105 {
1107 "CachedPlan",
1110
1111 /*
1112 * Copy plan into the new context.
1113 */
1115
1117 }
1118 else
1120
1121 /*
1122 * Create and fill the CachedPlan struct within the new context.
1123 */
1125 plan->magic = CACHEDPLAN_MAGIC;
1126 plan->stmt_list = plist;
1127
1128 /*
1129 * CachedPlan is dependent on role either if RLS affected the rewrite
1130 * phase or if a role dependency was injected during planning. And it's
1131 * transient if any plan is marked so.
1132 */
1133 plan->planRoleId = GetUserId();
1134 plan->dependsOnRole = plansource->dependsOnRLS;
1135 is_transient = false;
1136 foreach(lc, plist)
1137 {
1138 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1139
1140 if (plannedstmt->commandType == CMD_UTILITY)
1141 continue; /* Ignore utility statements */
1142
1143 if (plannedstmt->transientPlan)
1144 is_transient = true;
1145 if (plannedstmt->dependsOnRole)
1146 plan->dependsOnRole = true;
1147 }
1148 if (is_transient)
1149 {
1151 plan->saved_xmin = TransactionXmin;
1152 }
1153 else
1154 plan->saved_xmin = InvalidTransactionId;
1155 plan->refcount = 0;
1156 plan->context = plan_context;
1157 plan->is_oneshot = plansource->is_oneshot;
1158 plan->is_saved = false;
1159 plan->is_valid = true;
1160
1161 /* assign generation number to new plan */
1162 plan->generation = ++(plansource->generation);
1163
1165
1166 return plan;
1167}
#define Assert(condition)
Definition c.h:885
#define palloc_object(type)
Definition fe_memutils.h:74
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_START_SMALL_SIZES
Definition memutils.h:177
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition memutils.h:101
Oid GetUserId(void)
Definition miscinit.c:469
#define copyObject(obj)
Definition nodes.h:232
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)
Definition plancache.c:684
static bool BuildingPlanRequiresSnapshot(CachedPlanSource *plansource)
Definition plancache.c:659
#define CACHEDPLAN_MAGIC
Definition plancache.h:45
List * pg_plan_queries(List *querytrees, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition postgres.c:974
Snapshot GetTransactionSnapshot(void)
Definition snapmgr.c:272
void PushActiveSnapshot(Snapshot snapshot)
Definition snapmgr.c:682
TransactionId TransactionXmin
Definition snapmgr.c:159
bool ActiveSnapshotSet(void)
Definition snapmgr.c:812
void PopActiveSnapshot(void)
Definition snapmgr.c:775
const char * query_string
Definition plancache.h:110
Definition pg_list.h:54
bool transientPlan
Definition plannodes.h:89
bool dependsOnRole
Definition plannodes.h:92
#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, fb(), CachedPlanSource::generation, GetTransactionSnapshot(), GetUserId(), InvalidTransactionId, CachedPlanSource::is_oneshot, CachedPlanSource::is_valid, lfirst_node, MemoryContextCopyAndSetIdentifier, MemoryContextSwitchTo(), NIL, palloc_object, 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 659 of file plancache.c.

660{
661 if (plansource->raw_parse_tree != NULL)
662 return analyze_requires_snapshot(plansource->raw_parse_tree);
663 else if (plansource->analyzed_parse_tree != NULL)
665 /* empty query never needs a snapshot */
666 return false;
667}
bool analyze_requires_snapshot(RawStmt *parseTree)
Definition analyze.c:503
bool query_requires_rewrite_plan(Query *query)
Definition analyze.c:532
Query * analyzed_parse_tree
Definition plancache.h:109
RawStmt * raw_parse_tree
Definition plancache.h:108

References analyze_requires_snapshot(), CachedPlanSource::analyzed_parse_tree, fb(), 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 1232 of file plancache.c.

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

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

Referenced by GetCachedPlan().

◆ CachedPlanAllowsSimpleValidityCheck()

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

Definition at line 1473 of file plancache.c.

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

References Assert, CACHEDPLAN_MAGIC, CACHEDPLANSOURCE_MAGIC, CMD_UTILITY, Query::commandType, PlannedStmt::commandType, Query::cteList, CachedPlanSource::dependsOnRLS, fb(), CachedPlanSource::gplan, CachedPlanSource::is_oneshot, lfirst, lfirst_node, CachedPlanSource::magic, plan, CachedPlanSource::query_list, ResourceOwnerEnlarge(), ResourceOwnerRememberPlanCacheRef(), Query::rtable, PlannedStmt::rtable, RTE_RELATION, 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 1779 of file plancache.c.

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

References Assert, CACHEDPLANSOURCE_MAGIC, fb(), 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 1588 of file plancache.c.

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

References Assert, CACHEDPLAN_MAGIC, CACHEDPLANSOURCE_MAGIC, fb(), CachedPlanSource::gplan, CachedPlanSource::is_valid, CachedPlan::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 1766 of file plancache.c.

1767{
1768 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1769 return plansource->is_valid;
1770}

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

1637{
1638 /* Assert caller is doing things in a sane order */
1639 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1640 Assert(plansource->is_complete);
1641
1642 /* These seem worth real tests, though */
1643 if (plansource->is_saved)
1644 elog(ERROR, "cannot move a saved cached plan to another context");
1645 if (plansource->is_oneshot)
1646 elog(ERROR, "cannot move a one-shot cached plan to another context");
1647
1648 /* OK, let the caller keep the plan where he wishes */
1650
1651 /*
1652 * The query_context needs no special handling, since it's a child of
1653 * plansource->context. But if there's a generic plan, it should be
1654 * maintained as a sibling of plansource->context.
1655 */
1656 if (plansource->gplan)
1657 {
1658 Assert(plansource->gplan->magic == CACHEDPLAN_MAGIC);
1660 }
1661}
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition mcxt.c:686
MemoryContext context
Definition plancache.h:121
MemoryContext context
Definition plancache.h:172

References Assert, CACHEDPLAN_MAGIC, CACHEDPLANSOURCE_MAGIC, CachedPlanSource::context, CachedPlan::context, elog, ERROR, fb(), 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 952 of file plancache.c.

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

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

References CURSOR_OPT_CUSTOM_PLAN, CURSOR_OPT_GENERIC_PLAN, CachedPlanSource::cursor_options, fb(), 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 393 of file plancache.c.

402{
405
406 /* Assert caller is doing things in a sane order */
407 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
408 Assert(!plansource->is_complete);
409
410 /*
411 * If caller supplied a querytree_context, reparent it underneath the
412 * CachedPlanSource's context; otherwise, create a suitable context and
413 * copy the querytree_list into it. But no data copying should be done
414 * for one-shot plans; for those, assume the passed querytree_list is
415 * sufficiently long-lived.
416 */
417 if (plansource->is_oneshot)
418 {
420 }
421 else if (querytree_context != NULL)
422 {
425 }
426 else
427 {
428 /* Again, it's a good bet the querytree_context can be small */
430 "CachedPlanQuery",
434 }
435
436 plansource->query_context = querytree_context;
437 plansource->query_list = querytree_list;
438
439 if (!plansource->is_oneshot && StmtPlanRequiresRevalidation(plansource))
440 {
441 /*
442 * Use the planner machinery to extract dependencies. Data is saved
443 * in query_context. (We assume that not a lot of extra cruft is
444 * created by this call.) We can skip this for one-shot plans, and
445 * plans not needing revalidation have no such dependencies anyway.
446 */
448 &plansource->relationOids,
449 &plansource->invalItems,
450 &plansource->dependsOnRLS);
451
452 /* Update RLS info as well. */
453 plansource->rewriteRoleId = GetUserId();
454 plansource->rewriteRowSecurity = row_security;
455
456 /*
457 * Also save the current search_path in the query_context. (This
458 * should not generate much extra cruft either, since almost certainly
459 * the path is already valid.) Again, we don't really need this for
460 * one-shot plans; and we *must* skip this for transaction control
461 * commands, because this could result in catalog accesses.
462 */
464 }
465
466 /*
467 * Save the final parameter types (or other parameter specification data)
468 * into the source_context, as well as our other parameters.
469 */
471
472 if (num_params > 0)
473 {
474 plansource->param_types = palloc_array(Oid, num_params);
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
485 /*
486 * Also save the result tuple descriptor. PlanCacheComputeResultDesc may
487 * leak some cruft; normally we just accept that to save a copy step, but
488 * in USE_VALGRIND mode be tidy by running it in the caller's context.
489 */
490#ifdef USE_VALGRIND
493 if (plansource->resultDesc)
494 {
496 plansource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
498 }
499#else
502#endif
503
504 plansource->is_complete = true;
505 plansource->is_valid = true;
506}
#define palloc_array(type, count)
Definition fe_memutils.h:76
bool row_security
Definition guc_tables.c:538
SearchPathMatcher * GetSearchPathMatcher(MemoryContext context)
Definition namespace.c:3924
static TupleDesc PlanCacheComputeResultDesc(List *stmt_list)
Definition plancache.c:2086
unsigned int Oid
void extract_query_dependencies(Node *query, List **relationOids, List **invalItems, bool *hasRowSecurity)
Definition setrefs.c:3707
MemoryContext query_context
Definition plancache.h:128
ParserSetupHook parserSetup
Definition plancache.h:114
bool rewriteRowSecurity
Definition plancache.h:130
List * relationOids
Definition plancache.h:124
void * parserSetupArg
Definition plancache.h:115
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition tupdesc.c:235

References ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, Assert, CACHEDPLANSOURCE_MAGIC, CachedPlanSource::context, copyObject, CreateTupleDescCopy(), CurrentMemoryContext, CachedPlanSource::cursor_options, CachedPlanSource::dependsOnRLS, extract_query_dependencies(), fb(), CachedPlanSource::fixed_result, GetSearchPathMatcher(), GetUserId(), CachedPlanSource::invalItems, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_valid, CachedPlanSource::magic, MemoryContextSetParent(), MemoryContextSwitchTo(), CachedPlanSource::num_params, palloc_array, 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 1673 of file plancache.c.

1674{
1679
1680 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1681 Assert(plansource->is_complete);
1682
1683 /*
1684 * One-shot plans can't be copied, because we haven't taken care that
1685 * parsing/planning didn't scribble on the raw parse tree or querytrees.
1686 */
1687 if (plansource->is_oneshot)
1688 elog(ERROR, "cannot copy a one-shot cached plan");
1689
1691 "CachedPlanSource",
1693
1695
1698 newsource->raw_parse_tree = copyObject(plansource->raw_parse_tree);
1699 newsource->analyzed_parse_tree = copyObject(plansource->analyzed_parse_tree);
1700 newsource->query_string = pstrdup(plansource->query_string);
1702 newsource->commandTag = plansource->commandTag;
1703 if (plansource->num_params > 0)
1704 {
1705 newsource->param_types = palloc_array(Oid, plansource->num_params);
1706 memcpy(newsource->param_types, plansource->param_types,
1707 plansource->num_params * sizeof(Oid));
1708 }
1709 else
1710 newsource->param_types = NULL;
1711 newsource->num_params = plansource->num_params;
1712 newsource->parserSetup = plansource->parserSetup;
1713 newsource->parserSetupArg = plansource->parserSetupArg;
1714 newsource->postRewrite = plansource->postRewrite;
1715 newsource->postRewriteArg = plansource->postRewriteArg;
1716 newsource->cursor_options = plansource->cursor_options;
1717 newsource->fixed_result = plansource->fixed_result;
1718 if (plansource->resultDesc)
1719 newsource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
1720 else
1721 newsource->resultDesc = NULL;
1722 newsource->context = source_context;
1723
1725 "CachedPlanQuery",
1728 newsource->query_list = copyObject(plansource->query_list);
1729 newsource->relationOids = copyObject(plansource->relationOids);
1730 newsource->invalItems = copyObject(plansource->invalItems);
1731 if (plansource->search_path)
1732 newsource->search_path = CopySearchPathMatcher(plansource->search_path);
1733 newsource->query_context = querytree_context;
1734 newsource->rewriteRoleId = plansource->rewriteRoleId;
1735 newsource->rewriteRowSecurity = plansource->rewriteRowSecurity;
1736 newsource->dependsOnRLS = plansource->dependsOnRLS;
1737
1738 newsource->gplan = NULL;
1739
1740 newsource->is_oneshot = false;
1741 newsource->is_complete = true;
1742 newsource->is_saved = false;
1743 newsource->is_valid = plansource->is_valid;
1744 newsource->generation = plansource->generation;
1745
1746 /* We may as well copy any acquired cost knowledge */
1747 newsource->generic_cost = plansource->generic_cost;
1748 newsource->total_custom_cost = plansource->total_custom_cost;
1749 newsource->num_generic_plans = plansource->num_generic_plans;
1750 newsource->num_custom_plans = plansource->num_custom_plans;
1751
1753
1754 return newsource;
1755}
#define palloc0_object(type)
Definition fe_memutils.h:75
char * pstrdup(const char *in)
Definition mcxt.c:1781
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition mcxt.c:661
SearchPathMatcher * CopySearchPathMatcher(SearchPathMatcher *path)
Definition namespace.c:3961
PostRewriteHook postRewrite
Definition plancache.h:116
CommandTag commandTag
Definition plancache.h:111
int64 num_generic_plans
Definition plancache.h:146
void * postRewriteArg
Definition plancache.h:117

References ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, CachedPlanSource::analyzed_parse_tree, Assert, CACHEDPLANSOURCE_MAGIC, CachedPlanSource::commandTag, copyObject, CopySearchPathMatcher(), CreateTupleDescCopy(), CurrentMemoryContext, CachedPlanSource::cursor_options, CachedPlanSource::dependsOnRLS, elog, ERROR, fb(), CachedPlanSource::fixed_result, CachedPlanSource::generation, CachedPlanSource::generic_cost, CachedPlanSource::invalItems, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_valid, CachedPlanSource::magic, MemoryContextSetIdentifier(), MemoryContextSwitchTo(), CachedPlanSource::num_custom_plans, CachedPlanSource::num_generic_plans, CachedPlanSource::num_params, palloc0_object, palloc_array, CachedPlanSource::param_types, CachedPlanSource::parserSetup, CachedPlanSource::parserSetupArg, CachedPlanSource::postRewrite, CachedPlanSource::postRewriteArg, pstrdup(), 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 185 of file plancache.c.

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

References ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, CachedPlanSource::analyzed_parse_tree, Assert, CACHEDPLANSOURCE_MAGIC, CachedPlanSource::commandTag, CachedPlanSource::context, copyObject, CurrentMemoryContext, CachedPlanSource::cursor_options, CachedPlanSource::dependsOnRLS, fb(), 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_object, 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 265 of file plancache.c.

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

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

Referenced by prepare_next_query().

◆ CreateOneShotCachedPlan()

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

Definition at line 300 of file plancache.c.

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

References CachedPlanSource::analyzed_parse_tree, Assert, CACHEDPLANSOURCE_MAGIC, CachedPlanSource::commandTag, CachedPlanSource::context, CurrentMemoryContext, CachedPlanSource::cursor_options, CachedPlanSource::dependsOnRLS, fb(), 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_object, 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 591 of file plancache.c.

592{
593 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
594
595 /* If it's been saved, remove it from the list */
596 if (plansource->is_saved)
597 {
598 dlist_delete(&plansource->node);
599 plansource->is_saved = false;
600 }
601
602 /* Decrement generic CachedPlan's refcount and drop if no longer needed */
603 ReleaseGenericPlan(plansource);
604
605 /* Mark it no longer valid */
606 plansource->magic = 0;
607
608 /*
609 * Remove the CachedPlanSource and all subsidiary data (including the
610 * query_context if any). But if it's a one-shot we can't free anything.
611 */
612 if (!plansource->is_oneshot)
613 MemoryContextDelete(plansource->context);
614}
static void dlist_delete(dlist_node *node)
Definition ilist.h:405
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
dlist_node node
Definition plancache.h:141

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

1874{
1875 /* Sanity check */
1876 Assert(cexpr->magic == CACHEDEXPR_MAGIC);
1877 /* Unlink from global list */
1878 dlist_delete(&cexpr->node);
1879 /* Free all storage associated with CachedExpression */
1881}
#define CACHEDEXPR_MAGIC
Definition plancache.h:46
MemoryContext context
Definition plancache.h:195
dlist_node node
Definition plancache.h:196

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

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

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

Referenced by get_cast_hashentry().

◆ GetCachedPlan()

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

Definition at line 1297 of file plancache.c.

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

References Assert, BuildCachedPlan(), cached_plan_cost(), CACHEDPLAN_MAGIC, CACHEDPLANSOURCE_MAGIC, CacheMemoryContext, CheckCachedPlan(), choose_custom_plan(), CachedPlanSource::context, elog, ERROR, fb(), CachedPlanSource::generic_cost, CachedPlanSource::gplan, CachedPlanSource::is_complete, CachedPlanSource::is_saved, lfirst, CachedPlanSource::magic, MemoryContextGetParent(), MemoryContextSetParent(), NIL, CachedPlanSource::num_custom_plans, CachedPlanSource::num_generic_plans, plan, PLAN_STMT_CACHE_CUSTOM, PLAN_STMT_CACHE_GENERIC, PlannedStmt::planOrigin, CachedPlan::refcount, 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 148 of file plancache.c.

149{
158}
void CacheRegisterSyscacheCallback(SysCacheIdentifier cacheid, SyscacheCallbackFunction func, Datum arg)
Definition inval.c:1816
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition inval.c:1858
static void PlanCacheSysCallback(Datum arg, SysCacheIdentifier cacheid, uint32 hashvalue)
Definition plancache.c:2315
static void PlanCacheRelCallback(Datum arg, Oid relid)
Definition plancache.c:2122
static void PlanCacheObjectCallback(Datum arg, SysCacheIdentifier cacheid, uint32 hashvalue)
Definition plancache.c:2206
uint64_t Datum
Definition postgres.h:70

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

Referenced by InitPostgres().

◆ PlanCacheComputeResultDesc()

static TupleDesc PlanCacheComputeResultDesc ( List stmt_list)
static

Definition at line 2086 of file plancache.c.

2087{
2088 Query *query;
2089
2090 switch (ChoosePortalStrategy(stmt_list))
2091 {
2092 case PORTAL_ONE_SELECT:
2094 query = linitial_node(Query, stmt_list);
2095 return ExecCleanTypeFromTL(query->targetList);
2096
2098 query = QueryListGetPrimaryStmt(stmt_list);
2099 Assert(query->returningList);
2100 return ExecCleanTypeFromTL(query->returningList);
2101
2102 case PORTAL_UTIL_SELECT:
2103 query = linitial_node(Query, stmt_list);
2104 Assert(query->utilityStmt);
2105 return UtilityTupleDescriptor(query->utilityStmt);
2106
2107 case PORTAL_MULTI_QUERY:
2108 /* will not return tuples */
2109 break;
2110 }
2111 return NULL;
2112}
TupleDesc ExecCleanTypeFromTL(List *targetList)
#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:205
List * returningList
Definition parsenodes.h:214
List * targetList
Definition parsenodes.h:198
TupleDesc UtilityTupleDescriptor(Node *parsetree)
Definition utility.c:2088

References Assert, ChoosePortalStrategy(), ExecCleanTypeFromTL(), fb(), 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,
SysCacheIdentifier  cacheid,
uint32  hashvalue 
)
static

Definition at line 2206 of file plancache.c.

2207{
2208 dlist_iter iter;
2209
2211 {
2213 node, iter.cur);
2214 ListCell *lc;
2215
2216 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2217
2218 /* No work if it's already invalidated */
2219 if (!plansource->is_valid)
2220 continue;
2221
2222 /* Never invalidate if parse/plan would be a no-op anyway */
2223 if (!StmtPlanRequiresRevalidation(plansource))
2224 continue;
2225
2226 /*
2227 * Check the dependency list for the rewritten querytree.
2228 */
2229 foreach(lc, plansource->invalItems)
2230 {
2231 PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2232
2233 if (item->cacheId != cacheid)
2234 continue;
2235 if (hashvalue == 0 ||
2236 item->hashValue == hashvalue)
2237 {
2238 /* Invalidate the querytree and generic plan */
2239 plansource->is_valid = false;
2240 if (plansource->gplan)
2241 plansource->gplan->is_valid = false;
2242 break;
2243 }
2244 }
2245
2246 /*
2247 * The generic plan, if any, could have more dependencies than the
2248 * querytree does, so we have to check it too.
2249 */
2250 if (plansource->gplan && plansource->gplan->is_valid)
2251 {
2252 foreach(lc, plansource->gplan->stmt_list)
2253 {
2254 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2255 ListCell *lc3;
2256
2257 if (plannedstmt->commandType == CMD_UTILITY)
2258 continue; /* Ignore utility statements */
2259 foreach(lc3, plannedstmt->invalItems)
2260 {
2262
2263 if (item->cacheId != cacheid)
2264 continue;
2265 if (hashvalue == 0 ||
2266 item->hashValue == hashvalue)
2267 {
2268 /* Invalidate the generic plan only */
2269 plansource->gplan->is_valid = false;
2270 break; /* out of invalItems scan */
2271 }
2272 }
2273 if (!plansource->gplan->is_valid)
2274 break; /* out of stmt_list scan */
2275 }
2276 }
2277 }
2278
2279 /* Likewise check cached expressions */
2281 {
2283 node, iter.cur);
2284 ListCell *lc;
2285
2286 Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2287
2288 /* No work if it's already invalidated */
2289 if (!cexpr->is_valid)
2290 continue;
2291
2292 foreach(lc, cexpr->invalItems)
2293 {
2294 PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2295
2296 if (item->cacheId != cacheid)
2297 continue;
2298 if (hashvalue == 0 ||
2299 item->hashValue == hashvalue)
2300 {
2301 cexpr->is_valid = false;
2302 break;
2303 }
2304 }
2305 }
2306}
#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
List * stmt_list
Definition plancache.h:162
uint32 hashValue
Definition plannodes.h:1823
List * invalItems
Definition plannodes.h:147
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, fb(), 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 2122 of file plancache.c.

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

References Assert, cached_expression_list, CACHEDEXPR_MAGIC, CACHEDPLANSOURCE_MAGIC, CMD_UTILITY, PlannedStmt::commandType, dlist_iter::cur, dlist_container, dlist_foreach, fb(), 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,
SysCacheIdentifier  cacheid,
uint32  hashvalue 
)
static

Definition at line 2315 of file plancache.c.

2316{
2318}
void ResetPlanCache(void)
Definition plancache.c:2324

References ResetPlanCache().

Referenced by InitPlanCache().

◆ QueryListGetPrimaryStmt()

static Query * QueryListGetPrimaryStmt ( List stmts)
static

Definition at line 1892 of file plancache.c.

1893{
1894 ListCell *lc;
1895
1896 foreach(lc, stmts)
1897 {
1899
1900 if (stmt->canSetTag)
1901 return stmt;
1902 }
1903 return NULL;
1904}
#define stmt

References fb(), lfirst_node, and stmt.

Referenced by CachedPlanGetTargetList(), and PlanCacheComputeResultDesc().

◆ ReleaseAllPlanCacheRefsInOwner()

void ReleaseAllPlanCacheRefsInOwner ( ResourceOwner  owner)

Definition at line 2371 of file plancache.c.

2372{
2374}
static const ResourceOwnerDesc planref_resowner_desc
Definition plancache.c:117
void ResourceOwnerReleaseAllOfKind(ResourceOwner owner, const ResourceOwnerDesc *kind)
Definition resowner.c:815

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

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

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

621{
622 /* Be paranoid about the possibility that ReleaseCachedPlan fails */
623 if (plansource->gplan)
624 {
625 CachedPlan *plan = plansource->gplan;
626
627 Assert(plan->magic == CACHEDPLAN_MAGIC);
628 plansource->gplan = NULL;
630 }
631}
void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
Definition plancache.c:1428

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

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

◆ ResetPlanCache()

void ResetPlanCache ( void  )

Definition at line 2324 of file plancache.c.

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

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

134{
136}
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352
void ResourceOwnerForget(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition resowner.c:561

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

Referenced by ReleaseCachedPlan().

◆ ResourceOwnerRememberPlanCacheRef()

static void ResourceOwnerRememberPlanCacheRef ( ResourceOwner  owner,
CachedPlan plan 
)
inlinestatic

Definition at line 128 of file plancache.c.

129{
131}
void ResourceOwnerRemember(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition resowner.c:521

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

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

◆ ResOwnerReleaseCachedPlan()

static void ResOwnerReleaseCachedPlan ( Datum  res)
static

Definition at line 2379 of file plancache.c.

2380{
2382}
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:342

References DatumGetPointer(), fb(), and ReleaseCachedPlan().

◆ RevalidateCachedQuery()

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

Definition at line 684 of file plancache.c.

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

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(), fb(), 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(), and GetCachedPlan().

◆ SaveCachedPlan()

void SaveCachedPlan ( CachedPlanSource plansource)

Definition at line 547 of file plancache.c.

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

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

1993{
1994 ListCell *lc;
1995
1996 /* Shouldn't get called on utility commands */
1997 Assert(parsetree->commandType != CMD_UTILITY);
1998
1999 /*
2000 * First, process RTEs of the current query level.
2001 */
2002 foreach(lc, parsetree->rtable)
2003 {
2005
2006 switch (rte->rtekind)
2007 {
2008 case RTE_RELATION:
2009 /* Acquire or release the appropriate type of lock */
2010 if (acquire)
2011 LockRelationOid(rte->relid, rte->rellockmode);
2012 else
2013 UnlockRelationOid(rte->relid, rte->rellockmode);
2014 break;
2015
2016 case RTE_SUBQUERY:
2017 /* If this was a view, must lock/unlock the view */
2018 if (OidIsValid(rte->relid))
2019 {
2020 if (acquire)
2021 LockRelationOid(rte->relid, rte->rellockmode);
2022 else
2023 UnlockRelationOid(rte->relid, rte->rellockmode);
2024 }
2025 /* Recurse into subquery-in-FROM */
2026 ScanQueryForLocks(rte->subquery, acquire);
2027 break;
2028
2029 default:
2030 /* ignore other types of RTEs */
2031 break;
2032 }
2033 }
2034
2035 /* Recurse into subquery-in-WITH */
2036 foreach(lc, parsetree->cteList)
2037 {
2039
2041 }
2042
2043 /*
2044 * Recurse into sublink subqueries, too. But we already did the ones in
2045 * the rtable and cteList.
2046 */
2047 if (parsetree->hasSubLinks)
2048 {
2051 }
2052}
#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:2058

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

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

◆ ScanQueryWalker()

static bool ScanQueryWalker ( Node node,
bool acquire 
)
static

Definition at line 2058 of file plancache.c.

2059{
2060 if (node == NULL)
2061 return false;
2062 if (IsA(node, SubLink))
2063 {
2064 SubLink *sub = (SubLink *) node;
2065
2066 /* Do what we came for */
2068 /* Fall through to process lefthand args of SubLink */
2069 }
2070
2071 /*
2072 * Do NOT recurse into Query nodes, because ScanQueryForLocks already
2073 * processed subselects of subselects for us.
2074 */
2076}
#define expression_tree_walker(n, w, c)
Definition nodeFuncs.h:153
#define IsA(nodeptr, _type_)
Definition nodes.h:164

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

Referenced by ScanQueryForLocks(), and ScanQueryWalker().

◆ SetPostRewriteHook()

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

Definition at line 522 of file plancache.c.

525{
526 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
527 plansource->postRewrite = postRewrite;
528 plansource->postRewriteArg = postRewriteArg;
529}

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

643{
644 if (plansource->raw_parse_tree != NULL)
646 else if (plansource->analyzed_parse_tree != NULL)
648 /* empty query never needs revalidation */
649 return false;
650}
bool stmt_requires_parse_analysis(RawStmt *parseTree)
Definition analyze.c:459

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

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

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 140 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:2379
#define RELEASE_PRIO_PLANCACHE_REFS
Definition resowner.h:73
@ RESOURCE_RELEASE_AFTER_LOCKS
Definition resowner.h:56

Definition at line 117 of file plancache.c.

118{
119 .name = "plancache reference",
120 .release_phase = RESOURCE_RELEASE_AFTER_LOCKS,
121 .release_priority = RELEASE_PRIO_PLANCACHE_REFS,
122 .ReleaseResource = ResOwnerReleaseCachedPlan,
123 .DebugPrint = NULL /* the default message is fine */
124};

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

◆ saved_plan_list

dlist_head saved_plan_list = DLIST_STATIC_INIT(saved_plan_list)
static