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

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

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

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

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

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

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

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

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

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

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

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

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

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

1735 {
1736  /* Sanity check */
1737  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
1738  /* Unlink from global list */
1739  dlist_delete(&cexpr->node);
1740  /* Free all storage associated with CachedExpression */
1741  MemoryContextDelete(cexpr->context);
1742 }
#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 1677 of file plancache.c.

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

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

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

156 {
164  CacheRegisterSyscacheCallback(FOREIGNDATAWRAPPEROID, PlanCacheSysCallback, (Datum) 0);
165 }
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition: inval.c:1558
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1516
static void PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:2178
static void PlanCacheObjectCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:2069
static void PlanCacheRelCallback(Datum arg, Oid relid)
Definition: plancache.c:1985
uintptr_t Datum
Definition: postgres.h:64

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

Referenced by InitPostgres().

◆ ReleaseAllPlanCacheRefsInOwner()

void ReleaseAllPlanCacheRefsInOwner ( ResourceOwner  owner)

Definition at line 2234 of file plancache.c.

2235 {
2237 }
static const ResourceOwnerDesc planref_resowner_desc
Definition: plancache.c:124
void ResourceOwnerReleaseAllOfKind(ResourceOwner owner, const ResourceOwnerDesc *kind)
Definition: resowner.c:801

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

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

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

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

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

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

Referenced by choose_custom_plan().