PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
plancache.h File Reference
#include "access/tupdesc.h"
#include "lib/ilist.h"
#include "nodes/params.h"
#include "nodes/parsenodes.h"
#include "nodes/plannodes.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 void(* PostRewriteHook) (List *querytree_list, void *arg)
 
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)
 
CachedPlanSourceCreateCachedPlanForQuery (struct Query *analyzed_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 SetPostRewriteHook (CachedPlanSource *plansource, PostRewriteHook postRewrite, void *postRewriteArg)
 
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)
 
PlannedStmtUpdateCachedPlan (CachedPlanSource *plansource, int query_index, 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)
 
static bool CachedPlanRequiresLocking (CachedPlan *cplan)
 
static bool CachedPlanValid (CachedPlan *cplan)
 

Variables

PGDLLIMPORT int plan_cache_mode
 

Macro Definition Documentation

◆ CACHEDEXPR_MAGIC

#define CACHEDEXPR_MAGIC   838275847

Definition at line 48 of file plancache.h.

◆ CACHEDPLAN_MAGIC

#define CACHEDPLAN_MAGIC   953717834

Definition at line 47 of file plancache.h.

◆ CACHEDPLANSOURCE_MAGIC

#define CACHEDPLANSOURCE_MAGIC   195726186

Definition at line 46 of file plancache.h.

Typedef Documentation

◆ CachedExpression

◆ CachedPlan

typedef struct CachedPlan CachedPlan

◆ CachedPlanSource

◆ PostRewriteHook

typedef void(* PostRewriteHook) (List *querytree_list, void *arg)

Definition at line 44 of file plancache.h.

Enumeration Type Documentation

◆ PlanCacheMode

Enumerator
PLAN_CACHE_MODE_AUTO 
PLAN_CACHE_MODE_FORCE_GENERIC_PLAN 
PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN 

Definition at line 33 of file plancache.h.

34{
PlanCacheMode
Definition: plancache.h:34
@ PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN
Definition: plancache.h:37
@ PLAN_CACHE_MODE_FORCE_GENERIC_PLAN
Definition: plancache.h:36
@ PLAN_CACHE_MODE_AUTO
Definition: plancache.h:35

Function Documentation

◆ CachedPlanAllowsSimpleValidityCheck()

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

Definition at line 1592 of file plancache.c.

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

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

Referenced by exec_eval_simple_expr(), and exec_simple_check_plan().

◆ CachedPlanGetTargetList()

List * CachedPlanGetTargetList ( CachedPlanSource plansource,
QueryEnvironment queryEnv 
)

Definition at line 1899 of file plancache.c.

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

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

Referenced by exec_describe_statement_message(), and FetchPreparedStatementTargetList().

◆ CachedPlanIsSimplyValid()

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

Definition at line 1707 of file plancache.c.

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

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

Referenced by exec_eval_simple_expr().

◆ CachedPlanIsValid()

bool CachedPlanIsValid ( CachedPlanSource plansource)

Definition at line 1886 of file plancache.c.

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

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

Referenced by SPI_plan_is_valid().

◆ CachedPlanRequiresLocking()

static bool CachedPlanRequiresLocking ( CachedPlan cplan)
inlinestatic

Definition at line 276 of file plancache.h.

277{
278 return !cplan->is_oneshot && cplan->is_reused;
279}
bool is_oneshot
Definition: plancache.h:166
bool is_reused
Definition: plancache.h:168

References CachedPlan::is_oneshot, and CachedPlan::is_reused.

Referenced by ExecShouldLockRelations().

◆ CachedPlanSetParentContext()

void CachedPlanSetParentContext ( CachedPlanSource plansource,
MemoryContext  newcontext 
)

Definition at line 1754 of file plancache.c.

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

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

Referenced by _SPI_make_plan_non_temp().

◆ CachedPlanValid()

static bool CachedPlanValid ( CachedPlan cplan)
inlinestatic

Definition at line 289 of file plancache.h.

290{
291 return cplan->is_valid;
292}
bool is_valid
Definition: plancache.h:169

References CachedPlan::is_valid.

Referenced by ExecPlanStillValid().

◆ CompleteCachedPlan()

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

Definition at line 392 of file plancache.c.

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

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

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

◆ CopyCachedPlan()

CachedPlanSource * CopyCachedPlan ( CachedPlanSource plansource)

Definition at line 1792 of file plancache.c.

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

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

Referenced by _SPI_save_plan().

◆ CreateCachedPlan()

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

Definition at line 184 of file plancache.c.

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

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

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

◆ CreateCachedPlanForQuery()

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

Definition at line 264 of file plancache.c.

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

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

Referenced by prepare_next_query().

◆ CreateOneShotCachedPlan()

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

Definition at line 299 of file plancache.c.

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

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

Referenced by _SPI_prepare_oneshot_plan().

◆ DropCachedPlan()

void DropCachedPlan ( CachedPlanSource plansource)

Definition at line 575 of file plancache.c.

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

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

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

◆ FreeCachedExpression()

void FreeCachedExpression ( CachedExpression cexpr)

Definition at line 1993 of file plancache.c.

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

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

Referenced by get_cast_hashentry().

◆ GetCachedExpression()

CachedExpression * GetCachedExpression ( Node expr)

Definition at line 1936 of file plancache.c.

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

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

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

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

◆ InitPlanCache()

void InitPlanCache ( void  )

Definition at line 147 of file plancache.c.

148{
156 CacheRegisterSyscacheCallback(FOREIGNDATAWRAPPEROID, PlanCacheSysCallback, (Datum) 0);
157}
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition: inval.c:1854
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1812
static void PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:2438
static void PlanCacheObjectCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:2329
static void PlanCacheRelCallback(Datum arg, Oid relid)
Definition: plancache.c:2245
uintptr_t Datum
Definition: postgres.h:69

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

Referenced by InitPostgres().

◆ ReleaseAllPlanCacheRefsInOwner()

void ReleaseAllPlanCacheRefsInOwner ( ResourceOwner  owner)

Definition at line 2494 of file plancache.c.

2495{
2497}
static const ResourceOwnerDesc planref_resowner_desc
Definition: plancache.c:116
void ResourceOwnerReleaseAllOfKind(ResourceOwner owner, const ResourceOwnerDesc *kind)
Definition: resowner.c:818

References planref_resowner_desc, and ResourceOwnerReleaseAllOfKind().

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

◆ ReleaseCachedPlan()

void ReleaseCachedPlan ( CachedPlan plan,
ResourceOwner  owner 
)

Definition at line 1547 of file plancache.c.

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

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

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

◆ ResetPlanCache()

void ResetPlanCache ( void  )

Definition at line 2447 of file plancache.c.

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

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

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

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

◆ SetPostRewriteHook()

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

Definition at line 506 of file plancache.c.

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

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

Referenced by prepare_next_query().

◆ UpdateCachedPlan()

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

Definition at line 1205 of file plancache.c.

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

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

Referenced by ExecutorStartCachedPlan().

Variable Documentation

◆ plan_cache_mode

PGDLLIMPORT int plan_cache_mode
extern

Definition at line 139 of file plancache.c.

Referenced by choose_custom_plan().