PostgreSQL Source Code  git master
plancache.h File Reference
#include "access/tupdesc.h"
#include "lib/ilist.h"
#include "nodes/params.h"
#include "tcop/cmdtag.h"
#include "utils/queryenvironment.h"
#include "utils/resowner.h"
Include dependency graph for plancache.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  CachedPlanSource
 
struct  CachedPlan
 
struct  CachedExpression
 

Macros

#define CACHEDPLANSOURCE_MAGIC   195726186
 
#define CACHEDPLAN_MAGIC   953717834
 
#define CACHEDEXPR_MAGIC   838275847
 

Typedefs

typedef struct CachedPlanSource CachedPlanSource
 
typedef struct CachedPlan CachedPlan
 
typedef struct CachedExpression CachedExpression
 

Enumerations

enum  PlanCacheMode { PLAN_CACHE_MODE_AUTO , PLAN_CACHE_MODE_FORCE_GENERIC_PLAN , PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN }
 

Functions

void InitPlanCache (void)
 
void ResetPlanCache (void)
 
void ReleaseAllPlanCacheRefsInOwner (ResourceOwner owner)
 
CachedPlanSourceCreateCachedPlan (struct RawStmt *raw_parse_tree, const char *query_string, CommandTag commandTag)
 
CachedPlanSourceCreateOneShotCachedPlan (struct RawStmt *raw_parse_tree, const char *query_string, CommandTag commandTag)
 
void CompleteCachedPlan (CachedPlanSource *plansource, List *querytree_list, MemoryContext querytree_context, Oid *param_types, int num_params, ParserSetupHook parserSetup, void *parserSetupArg, int cursor_options, bool fixed_result)
 
void SaveCachedPlan (CachedPlanSource *plansource)
 
void DropCachedPlan (CachedPlanSource *plansource)
 
void CachedPlanSetParentContext (CachedPlanSource *plansource, MemoryContext newcontext)
 
CachedPlanSourceCopyCachedPlan (CachedPlanSource *plansource)
 
bool CachedPlanIsValid (CachedPlanSource *plansource)
 
ListCachedPlanGetTargetList (CachedPlanSource *plansource, 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)
 
CachedExpressionGetCachedExpression (Node *expr)
 
void FreeCachedExpression (CachedExpression *cexpr)
 

Variables

PGDLLIMPORT int plan_cache_mode
 

Macro Definition Documentation

◆ CACHEDEXPR_MAGIC

#define CACHEDEXPR_MAGIC   838275847

Definition at line 42 of file plancache.h.

◆ CACHEDPLAN_MAGIC

#define CACHEDPLAN_MAGIC   953717834

Definition at line 41 of file plancache.h.

◆ CACHEDPLANSOURCE_MAGIC

#define CACHEDPLANSOURCE_MAGIC   195726186

Definition at line 40 of file plancache.h.

Typedef Documentation

◆ CachedExpression

◆ CachedPlan

typedef struct CachedPlan CachedPlan

◆ CachedPlanSource

Enumeration Type Documentation

◆ PlanCacheMode

Enumerator
PLAN_CACHE_MODE_AUTO 
PLAN_CACHE_MODE_FORCE_GENERIC_PLAN 
PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN 

Definition at line 30 of file plancache.h.

31 {
PlanCacheMode
Definition: plancache.h:31
@ PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN
Definition: plancache.h:34
@ PLAN_CACHE_MODE_FORCE_GENERIC_PLAN
Definition: plancache.h:33
@ PLAN_CACHE_MODE_AUTO
Definition: plancache.h:32

Function Documentation

◆ CachedPlanAllowsSimpleValidityCheck()

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

Definition at line 1338 of file plancache.c.

1340 {
1341  ListCell *lc;
1342 
1343  /*
1344  * Sanity-check that the caller gave us a validated generic plan. Notice
1345  * that we *don't* assert plansource->is_valid as you might expect; that's
1346  * because it's possible that that's already false when GetCachedPlan
1347  * returns, e.g. because ResetPlanCache happened partway through. We
1348  * should accept the plan as long as plan->is_valid is true, and expect to
1349  * replan after the next CachedPlanIsSimplyValid call.
1350  */
1351  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1352  Assert(plan->magic == CACHEDPLAN_MAGIC);
1353  Assert(plan->is_valid);
1354  Assert(plan == plansource->gplan);
1355  Assert(plansource->search_path != NULL);
1357 
1358  /* We don't support oneshot plans here. */
1359  if (plansource->is_oneshot)
1360  return false;
1361  Assert(!plan->is_oneshot);
1362 
1363  /*
1364  * If the plan is dependent on RLS considerations, or it's transient,
1365  * reject. These things probably can't ever happen for table-free
1366  * queries, but for safety's sake let's check.
1367  */
1368  if (plansource->dependsOnRLS)
1369  return false;
1370  if (plan->dependsOnRole)
1371  return false;
1372  if (TransactionIdIsValid(plan->saved_xmin))
1373  return false;
1374 
1375  /*
1376  * Reject if AcquirePlannerLocks would have anything to do. This is
1377  * simplistic, but there's no need to inquire any more carefully; indeed,
1378  * for current callers it shouldn't even be possible to hit any of these
1379  * checks.
1380  */
1381  foreach(lc, plansource->query_list)
1382  {
1383  Query *query = lfirst_node(Query, lc);
1384 
1385  if (query->commandType == CMD_UTILITY)
1386  return false;
1387  if (query->rtable || query->cteList || query->hasSubLinks)
1388  return false;
1389  }
1390 
1391  /*
1392  * Reject if AcquireExecutorLocks would have anything to do. This is
1393  * probably unnecessary given the previous check, but let's be safe.
1394  */
1395  foreach(lc, plan->stmt_list)
1396  {
1397  PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1398  ListCell *lc2;
1399 
1400  if (plannedstmt->commandType == CMD_UTILITY)
1401  return false;
1402 
1403  /*
1404  * We have to grovel through the rtable because it's likely to contain
1405  * an RTE_RESULT relation, rather than being totally empty.
1406  */
1407  foreach(lc2, plannedstmt->rtable)
1408  {
1409  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1410 
1411  if (rte->rtekind == RTE_RELATION)
1412  return false;
1413  }
1414  }
1415 
1416  /*
1417  * Okay, it's simple. Note that what we've primarily established here is
1418  * that no locks need be taken before checking the plan's is_valid flag.
1419  */
1420 
1421  /* Bump refcount if requested. */
1422  if (owner)
1423  {
1424  ResourceOwnerEnlarge(owner);
1425  plan->refcount++;
1427  }
1428 
1429  return true;
1430 }
Assert(fmt[strlen(fmt) - 1] !='\n')
bool SearchPathMatchesCurrentEnvironment(SearchPathMatcher *path)
Definition: namespace.c:3878
@ CMD_UTILITY
Definition: nodes.h:281
@ RTE_RELATION
Definition: parsenodes.h:1006
#define lfirst(lc)
Definition: pg_list.h:172
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define plan(x)
Definition: pg_regress.c:162
static void ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
Definition: plancache.c:136
#define CACHEDPLAN_MAGIC
Definition: plancache.h:41
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:40
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition: resowner.c:448
struct CachedPlan * gplan
Definition: plancache.h:121
struct SearchPathMatcher * search_path
Definition: plancache.h:114
List * query_list
Definition: plancache.h:111
CmdType commandType
Definition: plannodes.h:52
List * rtable
Definition: plannodes.h:72
List * cteList
Definition: parsenodes.h:165
List * rtable
Definition: parsenodes.h:167
CmdType commandType
Definition: parsenodes.h:120
RTEKind rtekind
Definition: parsenodes.h:1025
#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 1642 of file plancache.c.

1644 {
1645  Query *pstmt;
1646 
1647  /* Assert caller is doing things in a sane order */
1648  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1649  Assert(plansource->is_complete);
1650 
1651  /*
1652  * No work needed if statement doesn't return tuples (we assume this
1653  * feature cannot be changed by an invalidation)
1654  */
1655  if (plansource->resultDesc == NULL)
1656  return NIL;
1657 
1658  /* Make sure the querytree list is valid and we have parse-time locks */
1659  RevalidateCachedQuery(plansource, queryEnv);
1660 
1661  /* Get the primary statement and find out what it returns */
1662  pstmt = QueryListGetPrimaryStmt(plansource->query_list);
1663 
1664  return FetchStatementTargetList((Node *) pstmt);
1665 }
#define NIL
Definition: pg_list.h:68
static List * RevalidateCachedQuery(CachedPlanSource *plansource, QueryEnvironment *queryEnv)
Definition: plancache.c:584
static Query * QueryListGetPrimaryStmt(List *stmts)
Definition: plancache.c:1755
List * FetchStatementTargetList(Node *stmt)
Definition: pquery.c:348
TupleDesc resultDesc
Definition: plancache.h:108
Definition: nodes.h:129

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

1455 {
1456  /*
1457  * Careful here: since the caller doesn't necessarily hold a refcount on
1458  * the plan to start with, it's possible that "plan" is a dangling
1459  * pointer. Don't dereference it until we've verified that it still
1460  * matches the plansource's gplan (which is either valid or NULL).
1461  */
1462  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1463 
1464  /*
1465  * Has cache invalidation fired on this plan? We can check this right
1466  * away since there are no locks that we'd need to acquire first. Note
1467  * that here we *do* check plansource->is_valid, so as to force plan
1468  * rebuild if that's become false.
1469  */
1470  if (!plansource->is_valid ||
1471  plan == NULL || plan != plansource->gplan ||
1472  !plan->is_valid)
1473  return false;
1474 
1475  Assert(plan->magic == CACHEDPLAN_MAGIC);
1476 
1477  /* Is the search_path still the same as when we made it? */
1478  Assert(plansource->search_path != NULL);
1480  return false;
1481 
1482  /* It's still good. Bump refcount if requested. */
1483  if (owner)
1484  {
1485  ResourceOwnerEnlarge(owner);
1486  plan->refcount++;
1488  }
1489 
1490  return true;
1491 }

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

1630 {
1631  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1632  return plansource->is_valid;
1633 }

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

1502 {
1503  /* Assert caller is doing things in a sane order */
1504  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1505  Assert(plansource->is_complete);
1506 
1507  /* These seem worth real tests, though */
1508  if (plansource->is_saved)
1509  elog(ERROR, "cannot move a saved cached plan to another context");
1510  if (plansource->is_oneshot)
1511  elog(ERROR, "cannot move a one-shot cached plan to another context");
1512 
1513  /* OK, let the caller keep the plan where he wishes */
1514  MemoryContextSetParent(plansource->context, newcontext);
1515 
1516  /*
1517  * The query_context needs no special handling, since it's a child of
1518  * plansource->context. But if there's a generic plan, it should be
1519  * maintained as a sibling of plansource->context.
1520  */
1521  if (plansource->gplan)
1522  {
1523  Assert(plansource->gplan->magic == CACHEDPLAN_MAGIC);
1524  MemoryContextSetParent(plansource->gplan->context, newcontext);
1525  }
1526 }
#define ERROR
Definition: elog.h:39
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:546
MemoryContext context
Definition: plancache.h:109
MemoryContext context
Definition: plancache.h:160

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().

◆ CompleteCachedPlan()

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

Definition at line 367 of file plancache.c.

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

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

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

◆ CopyCachedPlan()

CachedPlanSource* CopyCachedPlan ( CachedPlanSource plansource)

Definition at line 1538 of file plancache.c.

1539 {
1540  CachedPlanSource *newsource;
1541  MemoryContext source_context;
1542  MemoryContext querytree_context;
1543  MemoryContext oldcxt;
1544 
1545  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1546  Assert(plansource->is_complete);
1547 
1548  /*
1549  * One-shot plans can't be copied, because we haven't taken care that
1550  * parsing/planning didn't scribble on the raw parse tree or querytrees.
1551  */
1552  if (plansource->is_oneshot)
1553  elog(ERROR, "cannot copy a one-shot cached plan");
1554 
1556  "CachedPlanSource",
1558 
1559  oldcxt = MemoryContextSwitchTo(source_context);
1560 
1561  newsource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
1562  newsource->magic = CACHEDPLANSOURCE_MAGIC;
1563  newsource->raw_parse_tree = copyObject(plansource->raw_parse_tree);
1564  newsource->query_string = pstrdup(plansource->query_string);
1565  MemoryContextSetIdentifier(source_context, newsource->query_string);
1566  newsource->commandTag = plansource->commandTag;
1567  if (plansource->num_params > 0)
1568  {
1569  newsource->param_types = (Oid *)
1570  palloc(plansource->num_params * sizeof(Oid));
1571  memcpy(newsource->param_types, plansource->param_types,
1572  plansource->num_params * sizeof(Oid));
1573  }
1574  else
1575  newsource->param_types = NULL;
1576  newsource->num_params = plansource->num_params;
1577  newsource->parserSetup = plansource->parserSetup;
1578  newsource->parserSetupArg = plansource->parserSetupArg;
1579  newsource->cursor_options = plansource->cursor_options;
1580  newsource->fixed_result = plansource->fixed_result;
1581  if (plansource->resultDesc)
1582  newsource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
1583  else
1584  newsource->resultDesc = NULL;
1585  newsource->context = source_context;
1586 
1587  querytree_context = AllocSetContextCreate(source_context,
1588  "CachedPlanQuery",
1590  MemoryContextSwitchTo(querytree_context);
1591  newsource->query_list = copyObject(plansource->query_list);
1592  newsource->relationOids = copyObject(plansource->relationOids);
1593  newsource->invalItems = copyObject(plansource->invalItems);
1594  if (plansource->search_path)
1595  newsource->search_path = CopySearchPathMatcher(plansource->search_path);
1596  newsource->query_context = querytree_context;
1597  newsource->rewriteRoleId = plansource->rewriteRoleId;
1598  newsource->rewriteRowSecurity = plansource->rewriteRowSecurity;
1599  newsource->dependsOnRLS = plansource->dependsOnRLS;
1600 
1601  newsource->gplan = NULL;
1602 
1603  newsource->is_oneshot = false;
1604  newsource->is_complete = true;
1605  newsource->is_saved = false;
1606  newsource->is_valid = plansource->is_valid;
1607  newsource->generation = plansource->generation;
1608 
1609  /* We may as well copy any acquired cost knowledge */
1610  newsource->generic_cost = plansource->generic_cost;
1611  newsource->total_custom_cost = plansource->total_custom_cost;
1612  newsource->num_generic_plans = plansource->num_generic_plans;
1613  newsource->num_custom_plans = plansource->num_custom_plans;
1614 
1615  MemoryContextSwitchTo(oldcxt);
1616 
1617  return newsource;
1618 }
char * pstrdup(const char *in)
Definition: mcxt.c:1644
void * palloc0(Size size)
Definition: mcxt.c:1257
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:521
SearchPathMatcher * CopySearchPathMatcher(SearchPathMatcher *path)
Definition: namespace.c:3856
CommandTag commandTag
Definition: plancache.h:101
double total_custom_cost
Definition: plancache.h:132
const char * query_string
Definition: plancache.h:100
struct RawStmt * raw_parse_tree
Definition: plancache.h:99
int64 num_custom_plans
Definition: plancache.h:133
int64 num_generic_plans
Definition: plancache.h:134
double generic_cost
Definition: plancache.h:131
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:133

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

Referenced by _SPI_save_plan().

◆ CreateCachedPlan()

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

Definition at line 193 of file plancache.c.

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

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

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

◆ CreateOneShotCachedPlan()

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

Definition at line 277 of file plancache.c.

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

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

Referenced by _SPI_prepare_oneshot_plan().

◆ DropCachedPlan()

void DropCachedPlan ( CachedPlanSource plansource)

Definition at line 527 of file plancache.c.

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

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

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

◆ FreeCachedExpression()

void FreeCachedExpression ( CachedExpression cexpr)

Definition at line 1736 of file plancache.c.

1737 {
1738  /* Sanity check */
1739  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
1740  /* Unlink from global list */
1741  dlist_delete(&cexpr->node);
1742  /* Free all storage associated with CachedExpression */
1743  MemoryContextDelete(cexpr->context);
1744 }
#define CACHEDEXPR_MAGIC
Definition: plancache.h:42
MemoryContext context
Definition: plancache.h:183
dlist_node node
Definition: plancache.h:184

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

1680 {
1681  CachedExpression *cexpr;
1682  List *relationOids;
1683  List *invalItems;
1684  MemoryContext cexpr_context;
1685  MemoryContext oldcxt;
1686 
1687  /*
1688  * Pass the expression through the planner, and collect dependencies.
1689  * Everything built here is leaked in the caller's context; that's
1690  * intentional to minimize the size of the permanent data structure.
1691  */
1692  expr = (Node *) expression_planner_with_deps((Expr *) expr,
1693  &relationOids,
1694  &invalItems);
1695 
1696  /*
1697  * Make a private memory context, and copy what we need into that. To
1698  * avoid leaking a long-lived context if we fail while copying data, we
1699  * initially make the context under the caller's context.
1700  */
1702  "CachedExpression",
1704 
1705  oldcxt = MemoryContextSwitchTo(cexpr_context);
1706 
1707  cexpr = (CachedExpression *) palloc(sizeof(CachedExpression));
1708  cexpr->magic = CACHEDEXPR_MAGIC;
1709  cexpr->expr = copyObject(expr);
1710  cexpr->is_valid = true;
1711  cexpr->relationOids = copyObject(relationOids);
1712  cexpr->invalItems = copyObject(invalItems);
1713  cexpr->context = cexpr_context;
1714 
1715  MemoryContextSwitchTo(oldcxt);
1716 
1717  /*
1718  * Reparent the expr's memory context under CacheMemoryContext so that it
1719  * will live indefinitely.
1720  */
1722 
1723  /*
1724  * Add the entry to the global list of cached expressions.
1725  */
1727 
1728  return cexpr;
1729 }
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:364
MemoryContext CacheMemoryContext
Definition: mcxt.c:144
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:160
static dlist_head cached_expression_list
Definition: plancache.c:101
Expr * expression_planner_with_deps(Expr *expr, List **relationOids, List **invalItems)
Definition: planner.c:6510
List * relationOids
Definition: plancache.h:181
List * invalItems
Definition: plancache.h:182
Definition: pg_list.h:54

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

1172 {
1173  CachedPlan *plan = NULL;
1174  List *qlist;
1175  bool customplan;
1176 
1177  /* Assert caller is doing things in a sane order */
1178  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1179  Assert(plansource->is_complete);
1180  /* This seems worth a real test, though */
1181  if (owner && !plansource->is_saved)
1182  elog(ERROR, "cannot apply ResourceOwner to non-saved cached plan");
1183 
1184  /* Make sure the querytree list is valid and we have parse-time locks */
1185  qlist = RevalidateCachedQuery(plansource, queryEnv);
1186 
1187  /* Decide whether to use a custom plan */
1188  customplan = choose_custom_plan(plansource, boundParams);
1189 
1190  if (!customplan)
1191  {
1192  if (CheckCachedPlan(plansource))
1193  {
1194  /* We want a generic plan, and we already have a valid one */
1195  plan = plansource->gplan;
1196  Assert(plan->magic == CACHEDPLAN_MAGIC);
1197  }
1198  else
1199  {
1200  /* Build a new generic plan */
1201  plan = BuildCachedPlan(plansource, qlist, NULL, queryEnv);
1202  /* Just make real sure plansource->gplan is clear */
1203  ReleaseGenericPlan(plansource);
1204  /* Link the new generic plan into the plansource */
1205  plansource->gplan = plan;
1206  plan->refcount++;
1207  /* Immediately reparent into appropriate context */
1208  if (plansource->is_saved)
1209  {
1210  /* saved plans all live under CacheMemoryContext */
1212  plan->is_saved = true;
1213  }
1214  else
1215  {
1216  /* otherwise, it should be a sibling of the plansource */
1217  MemoryContextSetParent(plan->context,
1218  MemoryContextGetParent(plansource->context));
1219  }
1220  /* Update generic_cost whenever we make a new generic plan */
1221  plansource->generic_cost = cached_plan_cost(plan, false);
1222 
1223  /*
1224  * If, based on the now-known value of generic_cost, we'd not have
1225  * chosen to use a generic plan, then forget it and make a custom
1226  * plan. This is a bit of a wart but is necessary to avoid a
1227  * glitch in behavior when the custom plans are consistently big
1228  * winners; at some point we'll experiment with a generic plan and
1229  * find it's a loser, but we don't want to actually execute that
1230  * plan.
1231  */
1232  customplan = choose_custom_plan(plansource, boundParams);
1233 
1234  /*
1235  * If we choose to plan again, we need to re-copy the query_list,
1236  * since the planner probably scribbled on it. We can force
1237  * BuildCachedPlan to do that by passing NIL.
1238  */
1239  qlist = NIL;
1240  }
1241  }
1242 
1243  if (customplan)
1244  {
1245  /* Build a custom plan */
1246  plan = BuildCachedPlan(plansource, qlist, boundParams, queryEnv);
1247  /* Accumulate total costs of custom plans */
1248  plansource->total_custom_cost += cached_plan_cost(plan, true);
1249 
1250  plansource->num_custom_plans++;
1251  }
1252  else
1253  {
1254  plansource->num_generic_plans++;
1255  }
1256 
1257  Assert(plan != NULL);
1258 
1259  /* Flag the plan as in use by caller */
1260  if (owner)
1261  ResourceOwnerEnlarge(owner);
1262  plan->refcount++;
1263  if (owner)
1265 
1266  /*
1267  * Saved plans should be under CacheMemoryContext so they will not go away
1268  * until their reference count goes to zero. In the generic-plan cases we
1269  * already took care of that, but for a custom plan, do it as soon as we
1270  * have created a reference-counted link.
1271  */
1272  if (customplan && plansource->is_saved)
1273  {
1275  plan->is_saved = true;
1276  }
1277 
1278  return plan;
1279 }
MemoryContext MemoryContextGetParent(MemoryContext context)
Definition: mcxt.c:640
static bool choose_custom_plan(CachedPlanSource *plansource, ParamListInfo boundParams)
Definition: plancache.c:1048
static CachedPlan * BuildCachedPlan(CachedPlanSource *plansource, List *qlist, ParamListInfo boundParams, QueryEnvironment *queryEnv)
Definition: plancache.c:908
static bool CheckCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:824
static double cached_plan_cost(CachedPlan *plan, bool include_planner)
Definition: plancache.c:1105

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

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

◆ InitPlanCache()

void InitPlanCache ( void  )

Definition at line 156 of file plancache.c.

157 {
166 }
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition: inval.c:1560
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1518
static void PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:2180
static void PlanCacheObjectCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:2071
static void PlanCacheRelCallback(Datum arg, Oid relid)
Definition: plancache.c:1987
uintptr_t Datum
Definition: postgres.h:64
@ FOREIGNSERVEROID
Definition: syscache.h:64
@ TYPEOID
Definition: syscache.h:114
@ OPEROID
Definition: syscache.h:72
@ PROCOID
Definition: syscache.h:79
@ FOREIGNDATAWRAPPEROID
Definition: syscache.h:62
@ AMOPOPID
Definition: syscache.h:37
@ NAMESPACEOID
Definition: syscache.h:70

References AMOPOPID, CacheRegisterRelcacheCallback(), CacheRegisterSyscacheCallback(), FOREIGNDATAWRAPPEROID, FOREIGNSERVEROID, NAMESPACEOID, OPEROID, PlanCacheObjectCallback(), PlanCacheRelCallback(), PlanCacheSysCallback(), PROCOID, and TYPEOID.

Referenced by InitPostgres().

◆ ReleaseAllPlanCacheRefsInOwner()

void ReleaseAllPlanCacheRefsInOwner ( ResourceOwner  owner)

Definition at line 2236 of file plancache.c.

2237 {
2239 }
static const ResourceOwnerDesc planref_resowner_desc
Definition: plancache.c:125
void ResourceOwnerReleaseAllOfKind(ResourceOwner owner, const ResourceOwnerDesc *kind)
Definition: resowner.c:802

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

1294 {
1295  Assert(plan->magic == CACHEDPLAN_MAGIC);
1296  if (owner)
1297  {
1298  Assert(plan->is_saved);
1300  }
1301  Assert(plan->refcount > 0);
1302  plan->refcount--;
1303  if (plan->refcount == 0)
1304  {
1305  /* Mark it no longer valid */
1306  plan->magic = 0;
1307 
1308  /* One-shot plans do not own their context, so we can't free them */
1309  if (!plan->is_oneshot)
1310  MemoryContextDelete(plan->context);
1311  }
1312 }
static void ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
Definition: plancache.c:141

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

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

◆ ResetPlanCache()

void ResetPlanCache ( void  )

Definition at line 2189 of file plancache.c.

2190 {
2191  dlist_iter iter;
2192 
2194  {
2196  node, iter.cur);
2197 
2198  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2199 
2200  /* No work if it's already invalidated */
2201  if (!plansource->is_valid)
2202  continue;
2203 
2204  /*
2205  * We *must not* mark transaction control statements as invalid,
2206  * particularly not ROLLBACK, because they may need to be executed in
2207  * aborted transactions when we can't revalidate them (cf bug #5269).
2208  * In general there's no point in invalidating statements for which a
2209  * new parse analysis/rewrite/plan cycle would certainly give the same
2210  * results.
2211  */
2212  if (!StmtPlanRequiresRevalidation(plansource))
2213  continue;
2214 
2215  plansource->is_valid = false;
2216  if (plansource->gplan)
2217  plansource->gplan->is_valid = false;
2218  }
2219 
2220  /* Likewise invalidate cached expressions */
2222  {
2224  node, iter.cur);
2225 
2226  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2227 
2228  cexpr->is_valid = false;
2229  }
2230 }
#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:96
bool is_valid
Definition: plancache.h:153
dlist_node * cur
Definition: ilist.h:179

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().

◆ SaveCachedPlan()

void SaveCachedPlan ( CachedPlanSource plansource)

Definition at line 483 of file plancache.c.

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

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

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

Variable Documentation

◆ plan_cache_mode

PGDLLIMPORT int plan_cache_mode
extern

Definition at line 148 of file plancache.c.

Referenced by choose_custom_plan().