PostgreSQL Source Code  git master
plancache.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/transam.h"
#include "catalog/namespace.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "parser/analyze.h"
#include "parser/parsetree.h"
#include "storage/lmgr.h"
#include "tcop/pquery.h"
#include "tcop/utility.h"
#include "utils/inval.h"
#include "utils/memutils.h"
#include "utils/resowner_private.h"
#include "utils/rls.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
Include dependency graph for plancache.c:

Go to the source code of this file.

Macros

#define StmtPlanRequiresRevalidation(plansource)
 

Functions

static void ReleaseGenericPlan (CachedPlanSource *plansource)
 
static ListRevalidateCachedQuery (CachedPlanSource *plansource, QueryEnvironment *queryEnv)
 
static bool CheckCachedPlan (CachedPlanSource *plansource)
 
static CachedPlanBuildCachedPlan (CachedPlanSource *plansource, List *qlist, ParamListInfo boundParams, QueryEnvironment *queryEnv)
 
static bool choose_custom_plan (CachedPlanSource *plansource, ParamListInfo boundParams)
 
static double cached_plan_cost (CachedPlan *plan, bool include_planner)
 
static QueryQueryListGetPrimaryStmt (List *stmts)
 
static void AcquireExecutorLocks (List *stmt_list, bool acquire)
 
static void AcquirePlannerLocks (List *stmt_list, bool acquire)
 
static void ScanQueryForLocks (Query *parsetree, bool acquire)
 
static bool ScanQueryWalker (Node *node, bool *acquire)
 
static TupleDesc PlanCacheComputeResultDesc (List *stmt_list)
 
static void PlanCacheRelCallback (Datum arg, Oid relid)
 
static void PlanCacheObjectCallback (Datum arg, int cacheid, uint32 hashvalue)
 
static void PlanCacheSysCallback (Datum arg, int cacheid, uint32 hashvalue)
 
void InitPlanCache (void)
 
CachedPlanSourceCreateCachedPlan (RawStmt *raw_parse_tree, const char *query_string, CommandTag commandTag)
 
CachedPlanSourceCreateOneShotCachedPlan (RawStmt *raw_parse_tree, const char *query_string, CommandTag commandTag)
 
void CompleteCachedPlan (CachedPlanSource *plansource, List *querytree_list, MemoryContext querytree_context, Oid *param_types, int num_params, ParserSetupHook parserSetup, void *parserSetupArg, int cursor_options, bool fixed_result)
 
void SaveCachedPlan (CachedPlanSource *plansource)
 
void DropCachedPlan (CachedPlanSource *plansource)
 
CachedPlanGetCachedPlan (CachedPlanSource *plansource, ParamListInfo boundParams, ResourceOwner owner, QueryEnvironment *queryEnv)
 
void ReleaseCachedPlan (CachedPlan *plan, ResourceOwner owner)
 
bool CachedPlanAllowsSimpleValidityCheck (CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
 
bool CachedPlanIsSimplyValid (CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
 
void CachedPlanSetParentContext (CachedPlanSource *plansource, MemoryContext newcontext)
 
CachedPlanSourceCopyCachedPlan (CachedPlanSource *plansource)
 
bool CachedPlanIsValid (CachedPlanSource *plansource)
 
ListCachedPlanGetTargetList (CachedPlanSource *plansource, QueryEnvironment *queryEnv)
 
CachedExpressionGetCachedExpression (Node *expr)
 
void FreeCachedExpression (CachedExpression *cexpr)
 
void ResetPlanCache (void)
 

Variables

static dlist_head saved_plan_list = DLIST_STATIC_INIT(saved_plan_list)
 
static dlist_head cached_expression_list = DLIST_STATIC_INIT(cached_expression_list)
 
int plan_cache_mode = PLAN_CACHE_MODE_AUTO
 

Macro Definition Documentation

◆ StmtPlanRequiresRevalidation

#define StmtPlanRequiresRevalidation (   plansource)
Value:
((plansource)->raw_parse_tree != NULL && \
stmt_requires_parse_analysis((plansource)->raw_parse_tree))
bool stmt_requires_parse_analysis(RawStmt *parseTree)
Definition: analyze.c:444

Definition at line 86 of file plancache.c.

Function Documentation

◆ AcquireExecutorLocks()

static void AcquireExecutorLocks ( List stmt_list,
bool  acquire 
)
static

Definition at line 1749 of file plancache.c.

1750 {
1751  ListCell *lc1;
1752 
1753  foreach(lc1, stmt_list)
1754  {
1755  PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
1756  ListCell *lc2;
1757 
1758  if (plannedstmt->commandType == CMD_UTILITY)
1759  {
1760  /*
1761  * Ignore utility statements, except those (such as EXPLAIN) that
1762  * contain a parsed-but-not-planned query. Note: it's okay to use
1763  * ScanQueryForLocks, even though the query hasn't been through
1764  * rule rewriting, because rewriting doesn't change the query
1765  * representation.
1766  */
1767  Query *query = UtilityContainsQuery(plannedstmt->utilityStmt);
1768 
1769  if (query)
1770  ScanQueryForLocks(query, acquire);
1771  continue;
1772  }
1773 
1774  foreach(lc2, plannedstmt->rtable)
1775  {
1776  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1777 
1778  if (!(rte->rtekind == RTE_RELATION ||
1779  (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid))))
1780  continue;
1781 
1782  /*
1783  * Acquire the appropriate type of lock on each relation OID. Note
1784  * that we don't actually try to open the rel, and hence will not
1785  * fail if it's been dropped entirely --- we'll just transiently
1786  * acquire a non-conflicting lock.
1787  */
1788  if (acquire)
1789  LockRelationOid(rte->relid, rte->rellockmode);
1790  else
1791  UnlockRelationOid(rte->relid, rte->rellockmode);
1792  }
1793  }
1794 }
#define OidIsValid(objectId)
Definition: c.h:764
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:228
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:109
@ CMD_UTILITY
Definition: nodes.h:281
@ RTE_SUBQUERY
Definition: parsenodes.h:1014
@ RTE_RELATION
Definition: parsenodes.h:1013
#define lfirst(lc)
Definition: pg_list.h:172
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition: plancache.c:1830
CmdType commandType
Definition: plannodes.h:53
Node * utilityStmt
Definition: plannodes.h:96
List * rtable
Definition: plannodes.h:73
RTEKind rtekind
Definition: parsenodes.h:1032
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:2181

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

Referenced by CheckCachedPlan().

◆ AcquirePlannerLocks()

static void AcquirePlannerLocks ( List stmt_list,
bool  acquire 
)
static

Definition at line 1805 of file plancache.c.

1806 {
1807  ListCell *lc;
1808 
1809  foreach(lc, stmt_list)
1810  {
1811  Query *query = lfirst_node(Query, lc);
1812 
1813  if (query->commandType == CMD_UTILITY)
1814  {
1815  /* Ignore utility statements, unless they contain a Query */
1816  query = UtilityContainsQuery(query->utilityStmt);
1817  if (query)
1818  ScanQueryForLocks(query, acquire);
1819  continue;
1820  }
1821 
1822  ScanQueryForLocks(query, acquire);
1823  }
1824 }
CmdType commandType
Definition: parsenodes.h:127
Node * utilityStmt
Definition: parsenodes.h:142

References CMD_UTILITY, Query::commandType, lfirst_node, ScanQueryForLocks(), UtilityContainsQuery(), and Query::utilityStmt.

Referenced by RevalidateCachedQuery().

◆ BuildCachedPlan()

static CachedPlan * BuildCachedPlan ( CachedPlanSource plansource,
List qlist,
ParamListInfo  boundParams,
QueryEnvironment queryEnv 
)
static

Definition at line 883 of file plancache.c.

885 {
886  CachedPlan *plan;
887  List *plist;
888  bool snapshot_set;
889  bool is_transient;
890  MemoryContext plan_context;
892  ListCell *lc;
893 
894  /*
895  * Normally the querytree should be valid already, but if it's not,
896  * rebuild it.
897  *
898  * NOTE: GetCachedPlan should have called RevalidateCachedQuery first, so
899  * we ought to be holding sufficient locks to prevent any invalidation.
900  * However, if we're building a custom plan after having built and
901  * rejected a generic plan, it's possible to reach here with is_valid
902  * false due to an invalidation while making the generic plan. In theory
903  * the invalidation must be a false positive, perhaps a consequence of an
904  * sinval reset event or the debug_discard_caches code. But for safety,
905  * let's treat it as real and redo the RevalidateCachedQuery call.
906  */
907  if (!plansource->is_valid)
908  qlist = RevalidateCachedQuery(plansource, queryEnv);
909 
910  /*
911  * If we don't already have a copy of the querytree list that can be
912  * scribbled on by the planner, make one. For a one-shot plan, we assume
913  * it's okay to scribble on the original query_list.
914  */
915  if (qlist == NIL)
916  {
917  if (!plansource->is_oneshot)
918  qlist = copyObject(plansource->query_list);
919  else
920  qlist = plansource->query_list;
921  }
922 
923  /*
924  * If a snapshot is already set (the normal case), we can just use that
925  * for planning. But if it isn't, and we need one, install one.
926  */
927  snapshot_set = false;
928  if (!ActiveSnapshotSet() &&
929  plansource->raw_parse_tree &&
931  {
933  snapshot_set = true;
934  }
935 
936  /*
937  * Generate the plan.
938  */
939  plist = pg_plan_queries(qlist, plansource->query_string,
940  plansource->cursor_options, boundParams);
941 
942  /* Release snapshot if we got one */
943  if (snapshot_set)
945 
946  /*
947  * Normally we make a dedicated memory context for the CachedPlan and its
948  * subsidiary data. (It's probably not going to be large, but just in
949  * case, allow it to grow large. It's transient for the moment.) But for
950  * a one-shot plan, we just leave it in the caller's memory context.
951  */
952  if (!plansource->is_oneshot)
953  {
955  "CachedPlan",
957  MemoryContextCopyAndSetIdentifier(plan_context, plansource->query_string);
958 
959  /*
960  * Copy plan into the new context.
961  */
962  MemoryContextSwitchTo(plan_context);
963 
964  plist = copyObject(plist);
965  }
966  else
967  plan_context = CurrentMemoryContext;
968 
969  /*
970  * Create and fill the CachedPlan struct within the new context.
971  */
972  plan = (CachedPlan *) palloc(sizeof(CachedPlan));
973  plan->magic = CACHEDPLAN_MAGIC;
974  plan->stmt_list = plist;
975 
976  /*
977  * CachedPlan is dependent on role either if RLS affected the rewrite
978  * phase or if a role dependency was injected during planning. And it's
979  * transient if any plan is marked so.
980  */
981  plan->planRoleId = GetUserId();
982  plan->dependsOnRole = plansource->dependsOnRLS;
983  is_transient = false;
984  foreach(lc, plist)
985  {
986  PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
987 
988  if (plannedstmt->commandType == CMD_UTILITY)
989  continue; /* Ignore utility statements */
990 
991  if (plannedstmt->transientPlan)
992  is_transient = true;
993  if (plannedstmt->dependsOnRole)
994  plan->dependsOnRole = true;
995  }
996  if (is_transient)
997  {
999  plan->saved_xmin = TransactionXmin;
1000  }
1001  else
1002  plan->saved_xmin = InvalidTransactionId;
1003  plan->refcount = 0;
1004  plan->context = plan_context;
1005  plan->is_oneshot = plansource->is_oneshot;
1006  plan->is_saved = false;
1007  plan->is_valid = true;
1008 
1009  /* assign generation number to new plan */
1010  plan->generation = ++(plansource->generation);
1011 
1012  MemoryContextSwitchTo(oldcxt);
1013 
1014  return plan;
1015 }
Assert(fmt[strlen(fmt) - 1] !='\n')
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
void * palloc(Size size)
Definition: mcxt.c:1226
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:170
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:101
Oid GetUserId(void)
Definition: miscinit.c:509
#define copyObject(obj)
Definition: nodes.h:244
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
bool analyze_requires_snapshot(RawStmt *parseTree)
Definition: analyze.c:488
#define NIL
Definition: pg_list.h:68
#define plan(x)
Definition: pg_regress.c:154
static List * RevalidateCachedQuery(CachedPlanSource *plansource, QueryEnvironment *queryEnv)
Definition: plancache.c:559
#define CACHEDPLAN_MAGIC
Definition: plancache.h:41
List * pg_plan_queries(List *querytrees, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:970
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:197
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:629
TransactionId TransactionXmin
Definition: snapmgr.c:104
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:763
void PopActiveSnapshot(void)
Definition: snapmgr.c:724
const char * query_string
Definition: plancache.h:100
struct RawStmt * raw_parse_tree
Definition: plancache.h:99
List * query_list
Definition: plancache.h:111
Definition: pg_list.h:54
bool transientPlan
Definition: plannodes.h:63
bool dependsOnRole
Definition: plannodes.h:65
#define InvalidTransactionId
Definition: transam.h:31
#define TransactionIdIsNormal(xid)
Definition: transam.h:42

References ActiveSnapshotSet(), ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, analyze_requires_snapshot(), Assert(), CACHEDPLAN_MAGIC, CMD_UTILITY, PlannedStmt::commandType, copyObject, CurrentMemoryContext, CachedPlanSource::cursor_options, CachedPlanSource::dependsOnRLS, PlannedStmt::dependsOnRole, CachedPlanSource::generation, GetTransactionSnapshot(), GetUserId(), InvalidTransactionId, CachedPlanSource::is_oneshot, CachedPlanSource::is_valid, lfirst_node, MemoryContextCopyAndSetIdentifier, MemoryContextSwitchTo(), NIL, palloc(), pg_plan_queries(), plan, PopActiveSnapshot(), PushActiveSnapshot(), CachedPlanSource::query_list, CachedPlanSource::query_string, CachedPlanSource::raw_parse_tree, RevalidateCachedQuery(), TransactionIdIsNormal, TransactionXmin, and PlannedStmt::transientPlan.

Referenced by GetCachedPlan().

◆ cached_plan_cost()

static double cached_plan_cost ( CachedPlan plan,
bool  include_planner 
)
static

Definition at line 1080 of file plancache.c.

1081 {
1082  double result = 0;
1083  ListCell *lc;
1084 
1085  foreach(lc, plan->stmt_list)
1086  {
1087  PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1088 
1089  if (plannedstmt->commandType == CMD_UTILITY)
1090  continue; /* Ignore utility statements */
1091 
1092  result += plannedstmt->planTree->total_cost;
1093 
1094  if (include_planner)
1095  {
1096  /*
1097  * Currently we use a very crude estimate of planning effort based
1098  * on the number of relations in the finished plan's rangetable.
1099  * Join planning effort actually scales much worse than linearly
1100  * in the number of relations --- but only until the join collapse
1101  * limits kick in. Also, while inheritance child relations surely
1102  * add to planning effort, they don't make the join situation
1103  * worse. So the actual shape of the planning cost curve versus
1104  * number of relations isn't all that obvious. It will take
1105  * considerable work to arrive at a less crude estimate, and for
1106  * now it's not clear that's worth doing.
1107  *
1108  * The other big difficulty here is that we don't have any very
1109  * good model of how planning cost compares to execution costs.
1110  * The current multiplier of 1000 * cpu_operator_cost is probably
1111  * on the low side, but we'll try this for awhile before making a
1112  * more aggressive correction.
1113  *
1114  * If we ever do write a more complicated estimator, it should
1115  * probably live in src/backend/optimizer/ not here.
1116  */
1117  int nrelations = list_length(plannedstmt->rtable);
1118 
1119  result += 1000.0 * cpu_operator_cost * (nrelations + 1);
1120  }
1121  }
1122 
1123  return result;
1124 }
double cpu_operator_cost
Definition: costsize.c:124
static int list_length(const List *l)
Definition: pg_list.h:152
Cost total_cost
Definition: plannodes.h:130
struct Plan * planTree
Definition: plannodes.h:71

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

Referenced by GetCachedPlan().

◆ CachedPlanAllowsSimpleValidityCheck()

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

Definition at line 1313 of file plancache.c.

1315 {
1316  ListCell *lc;
1317 
1318  /*
1319  * Sanity-check that the caller gave us a validated generic plan. Notice
1320  * that we *don't* assert plansource->is_valid as you might expect; that's
1321  * because it's possible that that's already false when GetCachedPlan
1322  * returns, e.g. because ResetPlanCache happened partway through. We
1323  * should accept the plan as long as plan->is_valid is true, and expect to
1324  * replan after the next CachedPlanIsSimplyValid call.
1325  */
1326  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1327  Assert(plan->magic == CACHEDPLAN_MAGIC);
1328  Assert(plan->is_valid);
1329  Assert(plan == plansource->gplan);
1330  Assert(plansource->search_path != NULL);
1332 
1333  /* We don't support oneshot plans here. */
1334  if (plansource->is_oneshot)
1335  return false;
1336  Assert(!plan->is_oneshot);
1337 
1338  /*
1339  * If the plan is dependent on RLS considerations, or it's transient,
1340  * reject. These things probably can't ever happen for table-free
1341  * queries, but for safety's sake let's check.
1342  */
1343  if (plansource->dependsOnRLS)
1344  return false;
1345  if (plan->dependsOnRole)
1346  return false;
1347  if (TransactionIdIsValid(plan->saved_xmin))
1348  return false;
1349 
1350  /*
1351  * Reject if AcquirePlannerLocks would have anything to do. This is
1352  * simplistic, but there's no need to inquire any more carefully; indeed,
1353  * for current callers it shouldn't even be possible to hit any of these
1354  * checks.
1355  */
1356  foreach(lc, plansource->query_list)
1357  {
1358  Query *query = lfirst_node(Query, lc);
1359 
1360  if (query->commandType == CMD_UTILITY)
1361  return false;
1362  if (query->rtable || query->cteList || query->hasSubLinks)
1363  return false;
1364  }
1365 
1366  /*
1367  * Reject if AcquireExecutorLocks would have anything to do. This is
1368  * probably unnecessary given the previous check, but let's be safe.
1369  */
1370  foreach(lc, plan->stmt_list)
1371  {
1372  PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1373  ListCell *lc2;
1374 
1375  if (plannedstmt->commandType == CMD_UTILITY)
1376  return false;
1377 
1378  /*
1379  * We have to grovel through the rtable because it's likely to contain
1380  * an RTE_RESULT relation, rather than being totally empty.
1381  */
1382  foreach(lc2, plannedstmt->rtable)
1383  {
1384  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1385 
1386  if (rte->rtekind == RTE_RELATION)
1387  return false;
1388  }
1389  }
1390 
1391  /*
1392  * Okay, it's simple. Note that what we've primarily established here is
1393  * that no locks need be taken before checking the plan's is_valid flag.
1394  */
1395 
1396  /* Bump refcount if requested. */
1397  if (owner)
1398  {
1400  plan->refcount++;
1402  }
1403 
1404  return true;
1405 }
bool SearchPathMatchesCurrentEnvironment(SearchPathMatcher *path)
Definition: namespace.c:3443
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:40
void ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
Definition: resowner.c:1225
void ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner)
Definition: resowner.c:1214
struct CachedPlan * gplan
Definition: plancache.h:121
struct SearchPathMatcher * search_path
Definition: plancache.h:114
List * cteList
Definition: parsenodes.h:172
List * rtable
Definition: parsenodes.h:174
#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, ResourceOwnerEnlargePlanCacheRefs(), 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 1617 of file plancache.c.

1619 {
1620  Query *pstmt;
1621 
1622  /* Assert caller is doing things in a sane order */
1623  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1624  Assert(plansource->is_complete);
1625 
1626  /*
1627  * No work needed if statement doesn't return tuples (we assume this
1628  * feature cannot be changed by an invalidation)
1629  */
1630  if (plansource->resultDesc == NULL)
1631  return NIL;
1632 
1633  /* Make sure the querytree list is valid and we have parse-time locks */
1634  RevalidateCachedQuery(plansource, queryEnv);
1635 
1636  /* Get the primary statement and find out what it returns */
1637  pstmt = QueryListGetPrimaryStmt(plansource->query_list);
1638 
1639  return FetchStatementTargetList((Node *) pstmt);
1640 }
static Query * QueryListGetPrimaryStmt(List *stmts)
Definition: plancache.c:1730
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 1428 of file plancache.c.

1430 {
1431  /*
1432  * Careful here: since the caller doesn't necessarily hold a refcount on
1433  * the plan to start with, it's possible that "plan" is a dangling
1434  * pointer. Don't dereference it until we've verified that it still
1435  * matches the plansource's gplan (which is either valid or NULL).
1436  */
1437  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1438 
1439  /*
1440  * Has cache invalidation fired on this plan? We can check this right
1441  * away since there are no locks that we'd need to acquire first. Note
1442  * that here we *do* check plansource->is_valid, so as to force plan
1443  * rebuild if that's become false.
1444  */
1445  if (!plansource->is_valid ||
1446  plan == NULL || plan != plansource->gplan ||
1447  !plan->is_valid)
1448  return false;
1449 
1450  Assert(plan->magic == CACHEDPLAN_MAGIC);
1451 
1452  /* Is the search_path still the same as when we made it? */
1453  Assert(plansource->search_path != NULL);
1455  return false;
1456 
1457  /* It's still good. Bump refcount if requested. */
1458  if (owner)
1459  {
1461  plan->refcount++;
1463  }
1464 
1465  return true;
1466 }

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

Referenced by exec_eval_simple_expr().

◆ CachedPlanIsValid()

bool CachedPlanIsValid ( CachedPlanSource plansource)

Definition at line 1604 of file plancache.c.

1605 {
1606  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1607  return plansource->is_valid;
1608 }

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

1477 {
1478  /* Assert caller is doing things in a sane order */
1479  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1480  Assert(plansource->is_complete);
1481 
1482  /* These seem worth real tests, though */
1483  if (plansource->is_saved)
1484  elog(ERROR, "cannot move a saved cached plan to another context");
1485  if (plansource->is_oneshot)
1486  elog(ERROR, "cannot move a one-shot cached plan to another context");
1487 
1488  /* OK, let the caller keep the plan where he wishes */
1489  MemoryContextSetParent(plansource->context, newcontext);
1490 
1491  /*
1492  * The query_context needs no special handling, since it's a child of
1493  * plansource->context. But if there's a generic plan, it should be
1494  * maintained as a sibling of plansource->context.
1495  */
1496  if (plansource->gplan)
1497  {
1498  Assert(plansource->gplan->magic == CACHEDPLAN_MAGIC);
1499  MemoryContextSetParent(plansource->gplan->context, newcontext);
1500  }
1501 }
#define ERROR
Definition: elog.h:39
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:546
MemoryContext context
Definition: plancache.h:109
MemoryContext context
Definition: plancache.h:160

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

Referenced by _SPI_make_plan_non_temp().

◆ CheckCachedPlan()

static bool CheckCachedPlan ( CachedPlanSource plansource)
static

Definition at line 799 of file plancache.c.

800 {
801  CachedPlan *plan = plansource->gplan;
802 
803  /* Assert that caller checked the querytree */
804  Assert(plansource->is_valid);
805 
806  /* If there's no generic plan, just say "false" */
807  if (!plan)
808  return false;
809 
810  Assert(plan->magic == CACHEDPLAN_MAGIC);
811  /* Generic plans are never one-shot */
812  Assert(!plan->is_oneshot);
813 
814  /*
815  * If plan isn't valid for current role, we can't use it.
816  */
817  if (plan->is_valid && plan->dependsOnRole &&
818  plan->planRoleId != GetUserId())
819  plan->is_valid = false;
820 
821  /*
822  * If it appears valid, acquire locks and recheck; this is much the same
823  * logic as in RevalidateCachedQuery, but for a plan.
824  */
825  if (plan->is_valid)
826  {
827  /*
828  * Plan must have positive refcount because it is referenced by
829  * plansource; so no need to fear it disappears under us here.
830  */
831  Assert(plan->refcount > 0);
832 
833  AcquireExecutorLocks(plan->stmt_list, true);
834 
835  /*
836  * If plan was transient, check to see if TransactionXmin has
837  * advanced, and if so invalidate it.
838  */
839  if (plan->is_valid &&
840  TransactionIdIsValid(plan->saved_xmin) &&
842  plan->is_valid = false;
843 
844  /*
845  * By now, if any invalidation has happened, the inval callback
846  * functions will have marked the plan invalid.
847  */
848  if (plan->is_valid)
849  {
850  /* Successfully revalidated and locked the query. */
851  return true;
852  }
853 
854  /* Oops, the race case happened. Release useless locks. */
855  AcquireExecutorLocks(plan->stmt_list, false);
856  }
857 
858  /*
859  * Plan has been invalidated, so unlink it from the parent and release it.
860  */
861  ReleaseGenericPlan(plansource);
862 
863  return false;
864 }
static void ReleaseGenericPlan(CachedPlanSource *plansource)
Definition: plancache.c:531
static void AcquireExecutorLocks(List *stmt_list, bool acquire)
Definition: plancache.c:1749
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43

References AcquireExecutorLocks(), Assert(), CACHEDPLAN_MAGIC, GetUserId(), CachedPlanSource::gplan, CachedPlanSource::is_valid, plan, ReleaseGenericPlan(), TransactionIdEquals, TransactionIdIsValid, and TransactionXmin.

Referenced by GetCachedPlan().

◆ choose_custom_plan()

static bool choose_custom_plan ( CachedPlanSource plansource,
ParamListInfo  boundParams 
)
static

Definition at line 1023 of file plancache.c.

1024 {
1025  double avg_custom_cost;
1026 
1027  /* One-shot plans will always be considered custom */
1028  if (plansource->is_oneshot)
1029  return true;
1030 
1031  /* Otherwise, never any point in a custom plan if there's no parameters */
1032  if (boundParams == NULL)
1033  return false;
1034  /* ... nor when planning would be a no-op */
1035  if (!StmtPlanRequiresRevalidation(plansource))
1036  return false;
1037 
1038  /* Let settings force the decision */
1040  return false;
1042  return true;
1043 
1044  /* See if caller wants to force the decision */
1045  if (plansource->cursor_options & CURSOR_OPT_GENERIC_PLAN)
1046  return false;
1047  if (plansource->cursor_options & CURSOR_OPT_CUSTOM_PLAN)
1048  return true;
1049 
1050  /* Generate custom plans until we have done at least 5 (arbitrary) */
1051  if (plansource->num_custom_plans < 5)
1052  return true;
1053 
1054  avg_custom_cost = plansource->total_custom_cost / plansource->num_custom_plans;
1055 
1056  /*
1057  * Prefer generic plan if it's less expensive than the average custom
1058  * plan. (Because we include a charge for cost of planning in the
1059  * custom-plan costs, this means the generic plan only has to be less
1060  * expensive than the execution cost plus replan cost of the custom
1061  * plans.)
1062  *
1063  * Note that if generic_cost is -1 (indicating we've not yet determined
1064  * the generic plan cost), we'll always prefer generic at this point.
1065  */
1066  if (plansource->generic_cost < avg_custom_cost)
1067  return false;
1068 
1069  return true;
1070 }
#define CURSOR_OPT_GENERIC_PLAN
Definition: parsenodes.h:3163
#define CURSOR_OPT_CUSTOM_PLAN
Definition: parsenodes.h:3164
int plan_cache_mode
Definition: plancache.c:123
#define StmtPlanRequiresRevalidation(plansource)
Definition: plancache.c:86
@ PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN
Definition: plancache.h:34
@ PLAN_CACHE_MODE_FORCE_GENERIC_PLAN
Definition: plancache.h:33
double total_custom_cost
Definition: plancache.h:132
int64 num_custom_plans
Definition: plancache.h:133
double generic_cost
Definition: plancache.h:131

References CURSOR_OPT_CUSTOM_PLAN, CURSOR_OPT_GENERIC_PLAN, CachedPlanSource::cursor_options, CachedPlanSource::generic_cost, CachedPlanSource::is_oneshot, CachedPlanSource::num_custom_plans, plan_cache_mode, PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN, PLAN_CACHE_MODE_FORCE_GENERIC_PLAN, StmtPlanRequiresRevalidation, and CachedPlanSource::total_custom_cost.

Referenced by GetCachedPlan().

◆ CompleteCachedPlan()

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

Definition at line 342 of file plancache.c.

351 {
352  MemoryContext source_context = plansource->context;
354 
355  /* Assert caller is doing things in a sane order */
356  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
357  Assert(!plansource->is_complete);
358 
359  /*
360  * If caller supplied a querytree_context, reparent it underneath the
361  * CachedPlanSource's context; otherwise, create a suitable context and
362  * copy the querytree_list into it. But no data copying should be done
363  * for one-shot plans; for those, assume the passed querytree_list is
364  * sufficiently long-lived.
365  */
366  if (plansource->is_oneshot)
367  {
368  querytree_context = CurrentMemoryContext;
369  }
370  else if (querytree_context != NULL)
371  {
372  MemoryContextSetParent(querytree_context, source_context);
373  MemoryContextSwitchTo(querytree_context);
374  }
375  else
376  {
377  /* Again, it's a good bet the querytree_context can be small */
378  querytree_context = AllocSetContextCreate(source_context,
379  "CachedPlanQuery",
381  MemoryContextSwitchTo(querytree_context);
382  querytree_list = copyObject(querytree_list);
383  }
384 
385  plansource->query_context = querytree_context;
386  plansource->query_list = querytree_list;
387 
388  if (!plansource->is_oneshot && StmtPlanRequiresRevalidation(plansource))
389  {
390  /*
391  * Use the planner machinery to extract dependencies. Data is saved
392  * in query_context. (We assume that not a lot of extra cruft is
393  * created by this call.) We can skip this for one-shot plans, and
394  * plans not needing revalidation have no such dependencies anyway.
395  */
396  extract_query_dependencies((Node *) querytree_list,
397  &plansource->relationOids,
398  &plansource->invalItems,
399  &plansource->dependsOnRLS);
400 
401  /* Update RLS info as well. */
402  plansource->rewriteRoleId = GetUserId();
403  plansource->rewriteRowSecurity = row_security;
404 
405  /*
406  * Also save the current search_path in the query_context. (This
407  * should not generate much extra cruft either, since almost certainly
408  * the path is already valid.) Again, we don't really need this for
409  * one-shot plans; and we *must* skip this for transaction control
410  * commands, because this could result in catalog accesses.
411  */
412  plansource->search_path = GetSearchPathMatcher(querytree_context);
413  }
414 
415  /*
416  * Save the final parameter types (or other parameter specification data)
417  * into the source_context, as well as our other parameters. Also save
418  * the result tuple descriptor.
419  */
420  MemoryContextSwitchTo(source_context);
421 
422  if (num_params > 0)
423  {
424  plansource->param_types = (Oid *) palloc(num_params * sizeof(Oid));
425  memcpy(plansource->param_types, param_types, num_params * sizeof(Oid));
426  }
427  else
428  plansource->param_types = NULL;
429  plansource->num_params = num_params;
430  plansource->parserSetup = parserSetup;
431  plansource->parserSetupArg = parserSetupArg;
432  plansource->cursor_options = cursor_options;
433  plansource->fixed_result = fixed_result;
434  plansource->resultDesc = PlanCacheComputeResultDesc(querytree_list);
435 
436  MemoryContextSwitchTo(oldcxt);
437 
438  plansource->is_complete = true;
439  plansource->is_valid = true;
440 }
bool row_security
Definition: guc_tables.c:507
SearchPathMatcher * GetSearchPathMatcher(MemoryContext context)
Definition: namespace.c:3384
static TupleDesc PlanCacheComputeResultDesc(List *stmt_list)
Definition: plancache.c:1926
unsigned int Oid
Definition: postgres_ext.h:31
void extract_query_dependencies(Node *query, List **relationOids, List **invalItems, bool *hasRowSecurity)
Definition: setrefs.c:3519
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 1513 of file plancache.c.

1514 {
1515  CachedPlanSource *newsource;
1516  MemoryContext source_context;
1517  MemoryContext querytree_context;
1518  MemoryContext oldcxt;
1519 
1520  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1521  Assert(plansource->is_complete);
1522 
1523  /*
1524  * One-shot plans can't be copied, because we haven't taken care that
1525  * parsing/planning didn't scribble on the raw parse tree or querytrees.
1526  */
1527  if (plansource->is_oneshot)
1528  elog(ERROR, "cannot copy a one-shot cached plan");
1529 
1531  "CachedPlanSource",
1533 
1534  oldcxt = MemoryContextSwitchTo(source_context);
1535 
1536  newsource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
1537  newsource->magic = CACHEDPLANSOURCE_MAGIC;
1538  newsource->raw_parse_tree = copyObject(plansource->raw_parse_tree);
1539  newsource->query_string = pstrdup(plansource->query_string);
1540  MemoryContextSetIdentifier(source_context, newsource->query_string);
1541  newsource->commandTag = plansource->commandTag;
1542  if (plansource->num_params > 0)
1543  {
1544  newsource->param_types = (Oid *)
1545  palloc(plansource->num_params * sizeof(Oid));
1546  memcpy(newsource->param_types, plansource->param_types,
1547  plansource->num_params * sizeof(Oid));
1548  }
1549  else
1550  newsource->param_types = NULL;
1551  newsource->num_params = plansource->num_params;
1552  newsource->parserSetup = plansource->parserSetup;
1553  newsource->parserSetupArg = plansource->parserSetupArg;
1554  newsource->cursor_options = plansource->cursor_options;
1555  newsource->fixed_result = plansource->fixed_result;
1556  if (plansource->resultDesc)
1557  newsource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
1558  else
1559  newsource->resultDesc = NULL;
1560  newsource->context = source_context;
1561 
1562  querytree_context = AllocSetContextCreate(source_context,
1563  "CachedPlanQuery",
1565  MemoryContextSwitchTo(querytree_context);
1566  newsource->query_list = copyObject(plansource->query_list);
1567  newsource->relationOids = copyObject(plansource->relationOids);
1568  newsource->invalItems = copyObject(plansource->invalItems);
1569  if (plansource->search_path)
1570  newsource->search_path = CopySearchPathMatcher(plansource->search_path);
1571  newsource->query_context = querytree_context;
1572  newsource->rewriteRoleId = plansource->rewriteRoleId;
1573  newsource->rewriteRowSecurity = plansource->rewriteRowSecurity;
1574  newsource->dependsOnRLS = plansource->dependsOnRLS;
1575 
1576  newsource->gplan = NULL;
1577 
1578  newsource->is_oneshot = false;
1579  newsource->is_complete = true;
1580  newsource->is_saved = false;
1581  newsource->is_valid = plansource->is_valid;
1582  newsource->generation = plansource->generation;
1583 
1584  /* We may as well copy any acquired cost knowledge */
1585  newsource->generic_cost = plansource->generic_cost;
1586  newsource->total_custom_cost = plansource->total_custom_cost;
1587  newsource->num_generic_plans = plansource->num_generic_plans;
1588  newsource->num_custom_plans = plansource->num_custom_plans;
1589 
1590  MemoryContextSwitchTo(oldcxt);
1591 
1592  return newsource;
1593 }
char * pstrdup(const char *in)
Definition: mcxt.c:1644
void * palloc0(Size size)
Definition: mcxt.c:1257
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:521
SearchPathMatcher * CopySearchPathMatcher(SearchPathMatcher *path)
Definition: namespace.c:3421
CommandTag commandTag
Definition: plancache.h:101
int64 num_generic_plans
Definition: plancache.h:134
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:111

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 ( RawStmt raw_parse_tree,
const char *  query_string,
CommandTag  commandTag 
)

Definition at line 168 of file plancache.c.

171 {
172  CachedPlanSource *plansource;
173  MemoryContext source_context;
174  MemoryContext oldcxt;
175 
176  Assert(query_string != NULL); /* required as of 8.4 */
177 
178  /*
179  * Make a dedicated memory context for the CachedPlanSource and its
180  * permanent subsidiary data. It's probably not going to be large, but
181  * just in case, allow it to grow large. Initially it's a child of the
182  * caller's context (which we assume to be transient), so that it will be
183  * cleaned up on error.
184  */
186  "CachedPlanSource",
188 
189  /*
190  * Create and fill the CachedPlanSource struct within the new context.
191  * Most fields are just left empty for the moment.
192  */
193  oldcxt = MemoryContextSwitchTo(source_context);
194 
195  plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
196  plansource->magic = CACHEDPLANSOURCE_MAGIC;
197  plansource->raw_parse_tree = copyObject(raw_parse_tree);
198  plansource->query_string = pstrdup(query_string);
199  MemoryContextSetIdentifier(source_context, plansource->query_string);
200  plansource->commandTag = commandTag;
201  plansource->param_types = NULL;
202  plansource->num_params = 0;
203  plansource->parserSetup = NULL;
204  plansource->parserSetupArg = NULL;
205  plansource->cursor_options = 0;
206  plansource->fixed_result = false;
207  plansource->resultDesc = NULL;
208  plansource->context = source_context;
209  plansource->query_list = NIL;
210  plansource->relationOids = NIL;
211  plansource->invalItems = NIL;
212  plansource->search_path = NULL;
213  plansource->query_context = NULL;
214  plansource->rewriteRoleId = InvalidOid;
215  plansource->rewriteRowSecurity = false;
216  plansource->dependsOnRLS = false;
217  plansource->gplan = NULL;
218  plansource->is_oneshot = false;
219  plansource->is_complete = false;
220  plansource->is_saved = false;
221  plansource->is_valid = false;
222  plansource->generation = 0;
223  plansource->generic_cost = -1;
224  plansource->total_custom_cost = 0;
225  plansource->num_generic_plans = 0;
226  plansource->num_custom_plans = 0;
227 
228  MemoryContextSwitchTo(oldcxt);
229 
230  return plansource;
231 }
#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 ( RawStmt raw_parse_tree,
const char *  query_string,
CommandTag  commandTag 
)

Definition at line 252 of file plancache.c.

255 {
256  CachedPlanSource *plansource;
257 
258  Assert(query_string != NULL); /* required as of 8.4 */
259 
260  /*
261  * Create and fill the CachedPlanSource struct within the caller's memory
262  * context. Most fields are just left empty for the moment.
263  */
264  plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
265  plansource->magic = CACHEDPLANSOURCE_MAGIC;
266  plansource->raw_parse_tree = raw_parse_tree;
267  plansource->query_string = query_string;
268  plansource->commandTag = commandTag;
269  plansource->param_types = NULL;
270  plansource->num_params = 0;
271  plansource->parserSetup = NULL;
272  plansource->parserSetupArg = NULL;
273  plansource->cursor_options = 0;
274  plansource->fixed_result = false;
275  plansource->resultDesc = NULL;
276  plansource->context = CurrentMemoryContext;
277  plansource->query_list = NIL;
278  plansource->relationOids = NIL;
279  plansource->invalItems = NIL;
280  plansource->search_path = NULL;
281  plansource->query_context = NULL;
282  plansource->rewriteRoleId = InvalidOid;
283  plansource->rewriteRowSecurity = false;
284  plansource->dependsOnRLS = false;
285  plansource->gplan = NULL;
286  plansource->is_oneshot = true;
287  plansource->is_complete = false;
288  plansource->is_saved = false;
289  plansource->is_valid = false;
290  plansource->generation = 0;
291  plansource->generic_cost = -1;
292  plansource->total_custom_cost = 0;
293  plansource->num_generic_plans = 0;
294  plansource->num_custom_plans = 0;
295 
296  return plansource;
297 }

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

503 {
504  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
505 
506  /* If it's been saved, remove it from the list */
507  if (plansource->is_saved)
508  {
509  dlist_delete(&plansource->node);
510  plansource->is_saved = false;
511  }
512 
513  /* Decrement generic CachedPlan's refcount and drop if no longer needed */
514  ReleaseGenericPlan(plansource);
515 
516  /* Mark it no longer valid */
517  plansource->magic = 0;
518 
519  /*
520  * Remove the CachedPlanSource and all subsidiary data (including the
521  * query_context if any). But if it's a one-shot we can't free anything.
522  */
523  if (!plansource->is_oneshot)
524  MemoryContextDelete(plansource->context);
525 }
static void dlist_delete(dlist_node *node)
Definition: ilist.h:405
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:403
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 1711 of file plancache.c.

1712 {
1713  /* Sanity check */
1714  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
1715  /* Unlink from global list */
1716  dlist_delete(&cexpr->node);
1717  /* Free all storage associated with CachedExpression */
1718  MemoryContextDelete(cexpr->context);
1719 }
#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 1654 of file plancache.c.

1655 {
1656  CachedExpression *cexpr;
1657  List *relationOids;
1658  List *invalItems;
1659  MemoryContext cexpr_context;
1660  MemoryContext oldcxt;
1661 
1662  /*
1663  * Pass the expression through the planner, and collect dependencies.
1664  * Everything built here is leaked in the caller's context; that's
1665  * intentional to minimize the size of the permanent data structure.
1666  */
1667  expr = (Node *) expression_planner_with_deps((Expr *) expr,
1668  &relationOids,
1669  &invalItems);
1670 
1671  /*
1672  * Make a private memory context, and copy what we need into that. To
1673  * avoid leaking a long-lived context if we fail while copying data, we
1674  * initially make the context under the caller's context.
1675  */
1677  "CachedExpression",
1679 
1680  oldcxt = MemoryContextSwitchTo(cexpr_context);
1681 
1682  cexpr = (CachedExpression *) palloc(sizeof(CachedExpression));
1683  cexpr->magic = CACHEDEXPR_MAGIC;
1684  cexpr->expr = copyObject(expr);
1685  cexpr->is_valid = true;
1686  cexpr->relationOids = copyObject(relationOids);
1687  cexpr->invalItems = copyObject(invalItems);
1688  cexpr->context = cexpr_context;
1689 
1690  MemoryContextSwitchTo(oldcxt);
1691 
1692  /*
1693  * Reparent the expr's memory context under CacheMemoryContext so that it
1694  * will live indefinitely.
1695  */
1697 
1698  /*
1699  * Add the entry to the global list of cached expressions.
1700  */
1702 
1703  return cexpr;
1704 }
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:364
MemoryContext CacheMemoryContext
Definition: mcxt.c:144
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:163
static dlist_head cached_expression_list
Definition: plancache.c:101
Expr * expression_planner_with_deps(Expr *expr, List **relationOids, List **invalItems)
Definition: planner.c:6515
List * relationOids
Definition: plancache.h:181
List * invalItems
Definition: plancache.h:182

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

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

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(), ResourceOwnerEnlargePlanCacheRefs(), 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 131 of file plancache.c.

132 {
141 }
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition: inval.c:1561
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1519
static void PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:2155
static void PlanCacheObjectCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:2046
static void PlanCacheRelCallback(Datum arg, Oid relid)
Definition: plancache.c:1962
uintptr_t Datum
Definition: postgres.h:64
@ FOREIGNSERVEROID
Definition: syscache.h:64
@ TYPEOID
Definition: syscache.h:114
@ OPEROID
Definition: syscache.h:72
@ PROCOID
Definition: syscache.h:79
@ FOREIGNDATAWRAPPEROID
Definition: syscache.h:62
@ AMOPOPID
Definition: syscache.h:37
@ NAMESPACEOID
Definition: syscache.h:70

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

Referenced by InitPostgres().

◆ PlanCacheComputeResultDesc()

static TupleDesc PlanCacheComputeResultDesc ( List stmt_list)
static

Definition at line 1926 of file plancache.c.

1927 {
1928  Query *query;
1929 
1930  switch (ChoosePortalStrategy(stmt_list))
1931  {
1932  case PORTAL_ONE_SELECT:
1933  case PORTAL_ONE_MOD_WITH:
1934  query = linitial_node(Query, stmt_list);
1935  return ExecCleanTypeFromTL(query->targetList);
1936 
1937  case PORTAL_ONE_RETURNING:
1938  query = QueryListGetPrimaryStmt(stmt_list);
1939  Assert(query->returningList);
1940  return ExecCleanTypeFromTL(query->returningList);
1941 
1942  case PORTAL_UTIL_SELECT:
1943  query = linitial_node(Query, stmt_list);
1944  Assert(query->utilityStmt);
1945  return UtilityTupleDescriptor(query->utilityStmt);
1946 
1947  case PORTAL_MULTI_QUERY:
1948  /* will not return tuples */
1949  break;
1950  }
1951  return NULL;
1952 }
TupleDesc ExecCleanTypeFromTL(List *targetList)
Definition: execTuples.c:1951
#define linitial_node(type, l)
Definition: pg_list.h:181
@ PORTAL_ONE_RETURNING
Definition: portal.h:92
@ PORTAL_MULTI_QUERY
Definition: portal.h:95
@ PORTAL_ONE_SELECT
Definition: portal.h:91
@ PORTAL_ONE_MOD_WITH
Definition: portal.h:93
@ PORTAL_UTIL_SELECT
Definition: portal.h:94
PortalStrategy ChoosePortalStrategy(List *stmts)
Definition: pquery.c:209
List * returningList
Definition: parsenodes.h:195
List * targetList
Definition: parsenodes.h:188
TupleDesc UtilityTupleDescriptor(Node *parsetree)
Definition: utility.c:2085

References Assert(), ChoosePortalStrategy(), ExecCleanTypeFromTL(), linitial_node, PORTAL_MULTI_QUERY, PORTAL_ONE_MOD_WITH, PORTAL_ONE_RETURNING, PORTAL_ONE_SELECT, PORTAL_UTIL_SELECT, QueryListGetPrimaryStmt(), Query::returningList, Query::targetList, Query::utilityStmt, and UtilityTupleDescriptor().

Referenced by CompleteCachedPlan(), and RevalidateCachedQuery().

◆ PlanCacheObjectCallback()

static void PlanCacheObjectCallback ( Datum  arg,
int  cacheid,
uint32  hashvalue 
)
static

Definition at line 2046 of file plancache.c.

2047 {
2048  dlist_iter iter;
2049 
2051  {
2053  node, iter.cur);
2054  ListCell *lc;
2055 
2056  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2057 
2058  /* No work if it's already invalidated */
2059  if (!plansource->is_valid)
2060  continue;
2061 
2062  /* Never invalidate if parse/plan would be a no-op anyway */
2063  if (!StmtPlanRequiresRevalidation(plansource))
2064  continue;
2065 
2066  /*
2067  * Check the dependency list for the rewritten querytree.
2068  */
2069  foreach(lc, plansource->invalItems)
2070  {
2071  PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2072 
2073  if (item->cacheId != cacheid)
2074  continue;
2075  if (hashvalue == 0 ||
2076  item->hashValue == hashvalue)
2077  {
2078  /* Invalidate the querytree and generic plan */
2079  plansource->is_valid = false;
2080  if (plansource->gplan)
2081  plansource->gplan->is_valid = false;
2082  break;
2083  }
2084  }
2085 
2086  /*
2087  * The generic plan, if any, could have more dependencies than the
2088  * querytree does, so we have to check it too.
2089  */
2090  if (plansource->gplan && plansource->gplan->is_valid)
2091  {
2092  foreach(lc, plansource->gplan->stmt_list)
2093  {
2094  PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2095  ListCell *lc3;
2096 
2097  if (plannedstmt->commandType == CMD_UTILITY)
2098  continue; /* Ignore utility statements */
2099  foreach(lc3, plannedstmt->invalItems)
2100  {
2101  PlanInvalItem *item = (PlanInvalItem *) lfirst(lc3);
2102 
2103  if (item->cacheId != cacheid)
2104  continue;
2105  if (hashvalue == 0 ||
2106  item->hashValue == hashvalue)
2107  {
2108  /* Invalidate the generic plan only */
2109  plansource->gplan->is_valid = false;
2110  break; /* out of invalItems scan */
2111  }
2112  }
2113  if (!plansource->gplan->is_valid)
2114  break; /* out of stmt_list scan */
2115  }
2116  }
2117  }
2118 
2119  /* Likewise check cached expressions */
2121  {
2123  node, iter.cur);
2124  ListCell *lc;
2125 
2126  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2127 
2128  /* No work if it's already invalidated */
2129  if (!cexpr->is_valid)
2130  continue;
2131 
2132  foreach(lc, cexpr->invalItems)
2133  {
2134  PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2135 
2136  if (item->cacheId != cacheid)
2137  continue;
2138  if (hashvalue == 0 ||
2139  item->hashValue == hashvalue)
2140  {
2141  cexpr->is_valid = false;
2142  break;
2143  }
2144  }
2145  }
2146 }
#define dlist_foreach(iter, lhead)
Definition: ilist.h:623
#define dlist_container(type, membername, ptr)
Definition: ilist.h:593
static dlist_head saved_plan_list
Definition: plancache.c:96
bool is_valid
Definition: plancache.h:153
List * stmt_list
Definition: plancache.h:150
uint32 hashValue
Definition: plannodes.h:1571
List * invalItems
Definition: plannodes.h:92
dlist_node * cur
Definition: ilist.h:179

References Assert(), cached_expression_list, CACHEDEXPR_MAGIC, CACHEDPLANSOURCE_MAGIC, PlanInvalItem::cacheId, CMD_UTILITY, PlannedStmt::commandType, dlist_iter::cur, dlist_container, dlist_foreach, CachedPlanSource::gplan, PlanInvalItem::hashValue, PlannedStmt::invalItems, CachedPlanSource::invalItems, CachedExpression::invalItems, CachedPlanSource::is_valid, CachedPlan::is_valid, CachedExpression::is_valid, lfirst, lfirst_node, CachedPlanSource::magic, CachedExpression::magic, saved_plan_list, CachedPlan::stmt_list, and StmtPlanRequiresRevalidation.

Referenced by InitPlanCache().

◆ PlanCacheRelCallback()

static void PlanCacheRelCallback ( Datum  arg,
Oid  relid 
)
static

Definition at line 1962 of file plancache.c.

1963 {
1964  dlist_iter iter;
1965 
1967  {
1969  node, iter.cur);
1970 
1971  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1972 
1973  /* No work if it's already invalidated */
1974  if (!plansource->is_valid)
1975  continue;
1976 
1977  /* Never invalidate if parse/plan would be a no-op anyway */
1978  if (!StmtPlanRequiresRevalidation(plansource))
1979  continue;
1980 
1981  /*
1982  * Check the dependency list for the rewritten querytree.
1983  */
1984  if ((relid == InvalidOid) ? plansource->relationOids != NIL :
1985  list_member_oid(plansource->relationOids, relid))
1986  {
1987  /* Invalidate the querytree and generic plan */
1988  plansource->is_valid = false;
1989  if (plansource->gplan)
1990  plansource->gplan->is_valid = false;
1991  }
1992 
1993  /*
1994  * The generic plan, if any, could have more dependencies than the
1995  * querytree does, so we have to check it too.
1996  */
1997  if (plansource->gplan && plansource->gplan->is_valid)
1998  {
1999  ListCell *lc;
2000 
2001  foreach(lc, plansource->gplan->stmt_list)
2002  {
2003  PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2004 
2005  if (plannedstmt->commandType == CMD_UTILITY)
2006  continue; /* Ignore utility statements */
2007  if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
2008  list_member_oid(plannedstmt->relationOids, relid))
2009  {
2010  /* Invalidate the generic plan only */
2011  plansource->gplan->is_valid = false;
2012  break; /* out of stmt_list scan */
2013  }
2014  }
2015  }
2016  }
2017 
2018  /* Likewise check cached expressions */
2020  {
2022  node, iter.cur);
2023 
2024  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2025 
2026  /* No work if it's already invalidated */
2027  if (!cexpr->is_valid)
2028  continue;
2029 
2030  if ((relid == InvalidOid) ? cexpr->relationOids != NIL :
2031  list_member_oid(cexpr->relationOids, relid))
2032  {
2033  cexpr->is_valid = false;
2034  }
2035  }
2036 }
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:721
List * relationOids
Definition: plannodes.h:90

References Assert(), cached_expression_list, CACHEDEXPR_MAGIC, CACHEDPLANSOURCE_MAGIC, CMD_UTILITY, PlannedStmt::commandType, dlist_iter::cur, dlist_container, dlist_foreach, CachedPlanSource::gplan, InvalidOid, CachedPlanSource::is_valid, CachedPlan::is_valid, CachedExpression::is_valid, lfirst_node, list_member_oid(), CachedPlanSource::magic, CachedExpression::magic, NIL, PlannedStmt::relationOids, CachedPlanSource::relationOids, CachedExpression::relationOids, saved_plan_list, CachedPlan::stmt_list, and StmtPlanRequiresRevalidation.

Referenced by InitPlanCache().

◆ PlanCacheSysCallback()

static void PlanCacheSysCallback ( Datum  arg,
int  cacheid,
uint32  hashvalue 
)
static

Definition at line 2155 of file plancache.c.

2156 {
2157  ResetPlanCache();
2158 }
void ResetPlanCache(void)
Definition: plancache.c:2164

References ResetPlanCache().

Referenced by InitPlanCache().

◆ QueryListGetPrimaryStmt()

static Query * QueryListGetPrimaryStmt ( List stmts)
static

Definition at line 1730 of file plancache.c.

1731 {
1732  ListCell *lc;
1733 
1734  foreach(lc, stmts)
1735  {
1736  Query *stmt = lfirst_node(Query, lc);
1737 
1738  if (stmt->canSetTag)
1739  return stmt;
1740  }
1741  return NULL;
1742 }
#define stmt
Definition: indent_codes.h:59

References lfirst_node, and stmt.

Referenced by CachedPlanGetTargetList(), and PlanCacheComputeResultDesc().

◆ ReleaseCachedPlan()

void ReleaseCachedPlan ( CachedPlan plan,
ResourceOwner  owner 
)

Definition at line 1268 of file plancache.c.

1269 {
1270  Assert(plan->magic == CACHEDPLAN_MAGIC);
1271  if (owner)
1272  {
1273  Assert(plan->is_saved);
1275  }
1276  Assert(plan->refcount > 0);
1277  plan->refcount--;
1278  if (plan->refcount == 0)
1279  {
1280  /* Mark it no longer valid */
1281  plan->magic = 0;
1282 
1283  /* One-shot plans do not own their context, so we can't free them */
1284  if (!plan->is_oneshot)
1285  MemoryContextDelete(plan->context);
1286  }
1287 }
void ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
Definition: resowner.c:1234

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

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

◆ ReleaseGenericPlan()

static void ReleaseGenericPlan ( CachedPlanSource plansource)
static

Definition at line 531 of file plancache.c.

532 {
533  /* Be paranoid about the possibility that ReleaseCachedPlan fails */
534  if (plansource->gplan)
535  {
536  CachedPlan *plan = plansource->gplan;
537 
538  Assert(plan->magic == CACHEDPLAN_MAGIC);
539  plansource->gplan = NULL;
540  ReleaseCachedPlan(plan, NULL);
541  }
542 }
void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1268

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

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

◆ ResetPlanCache()

void ResetPlanCache ( void  )

Definition at line 2164 of file plancache.c.

2165 {
2166  dlist_iter iter;
2167 
2169  {
2171  node, iter.cur);
2172 
2173  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2174 
2175  /* No work if it's already invalidated */
2176  if (!plansource->is_valid)
2177  continue;
2178 
2179  /*
2180  * We *must not* mark transaction control statements as invalid,
2181  * particularly not ROLLBACK, because they may need to be executed in
2182  * aborted transactions when we can't revalidate them (cf bug #5269).
2183  * In general there's no point in invalidating statements for which a
2184  * new parse analysis/rewrite/plan cycle would certainly give the same
2185  * results.
2186  */
2187  if (!StmtPlanRequiresRevalidation(plansource))
2188  continue;
2189 
2190  plansource->is_valid = false;
2191  if (plansource->gplan)
2192  plansource->gplan->is_valid = false;
2193  }
2194 
2195  /* Likewise invalidate cached expressions */
2197  {
2199  node, iter.cur);
2200 
2201  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2202 
2203  cexpr->is_valid = false;
2204  }
2205 }

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

◆ RevalidateCachedQuery()

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

Definition at line 559 of file plancache.c.

561 {
562  bool snapshot_set;
563  RawStmt *rawtree;
564  List *tlist; /* transient query-tree list */
565  List *qlist; /* permanent query-tree list */
566  TupleDesc resultDesc;
567  MemoryContext querytree_context;
568  MemoryContext oldcxt;
569 
570  /*
571  * For one-shot plans, we do not support revalidation checking; it's
572  * assumed the query is parsed, planned, and executed in one transaction,
573  * so that no lock re-acquisition is necessary. Also, if the statement
574  * type can't require revalidation, we needn't do anything (and we mustn't
575  * risk catalog accesses when handling, eg, transaction control commands).
576  */
577  if (plansource->is_oneshot || !StmtPlanRequiresRevalidation(plansource))
578  {
579  Assert(plansource->is_valid);
580  return NIL;
581  }
582 
583  /*
584  * If the query is currently valid, we should have a saved search_path ---
585  * check to see if that matches the current environment. If not, we want
586  * to force replan.
587  */
588  if (plansource->is_valid)
589  {
590  Assert(plansource->search_path != NULL);
592  {
593  /* Invalidate the querytree and generic plan */
594  plansource->is_valid = false;
595  if (plansource->gplan)
596  plansource->gplan->is_valid = false;
597  }
598  }
599 
600  /*
601  * If the query rewrite phase had a possible RLS dependency, we must redo
602  * it if either the role or the row_security setting has changed.
603  */
604  if (plansource->is_valid && plansource->dependsOnRLS &&
605  (plansource->rewriteRoleId != GetUserId() ||
606  plansource->rewriteRowSecurity != row_security))
607  plansource->is_valid = false;
608 
609  /*
610  * If the query is currently valid, acquire locks on the referenced
611  * objects; then check again. We need to do it this way to cover the race
612  * condition that an invalidation message arrives before we get the locks.
613  */
614  if (plansource->is_valid)
615  {
616  AcquirePlannerLocks(plansource->query_list, true);
617 
618  /*
619  * By now, if any invalidation has happened, the inval callback
620  * functions will have marked the query invalid.
621  */
622  if (plansource->is_valid)
623  {
624  /* Successfully revalidated and locked the query. */
625  return NIL;
626  }
627 
628  /* Oops, the race case happened. Release useless locks. */
629  AcquirePlannerLocks(plansource->query_list, false);
630  }
631 
632  /*
633  * Discard the no-longer-useful query tree. (Note: we don't want to do
634  * this any earlier, else we'd not have been able to release locks
635  * correctly in the race condition case.)
636  */
637  plansource->is_valid = false;
638  plansource->query_list = NIL;
639  plansource->relationOids = NIL;
640  plansource->invalItems = NIL;
641  plansource->search_path = NULL;
642 
643  /*
644  * Free the query_context. We don't really expect MemoryContextDelete to
645  * fail, but just in case, make sure the CachedPlanSource is left in a
646  * reasonably sane state. (The generic plan won't get unlinked yet, but
647  * that's acceptable.)
648  */
649  if (plansource->query_context)
650  {
651  MemoryContext qcxt = plansource->query_context;
652 
653  plansource->query_context = NULL;
654  MemoryContextDelete(qcxt);
655  }
656 
657  /* Drop the generic plan reference if any */
658  ReleaseGenericPlan(plansource);
659 
660  /*
661  * Now re-do parse analysis and rewrite. This not incidentally acquires
662  * the locks we need to do planning safely.
663  */
664  Assert(plansource->is_complete);
665 
666  /*
667  * If a snapshot is already set (the normal case), we can just use that
668  * for parsing/planning. But if it isn't, install one. Note: no point in
669  * checking whether parse analysis requires a snapshot; utility commands
670  * don't have invalidatable plans, so we'd not get here for such a
671  * command.
672  */
673  snapshot_set = false;
674  if (!ActiveSnapshotSet())
675  {
677  snapshot_set = true;
678  }
679 
680  /*
681  * Run parse analysis and rule rewriting. The parser tends to scribble on
682  * its input, so we must copy the raw parse tree to prevent corruption of
683  * the cache.
684  */
685  rawtree = copyObject(plansource->raw_parse_tree);
686  if (rawtree == NULL)
687  tlist = NIL;
688  else if (plansource->parserSetup != NULL)
689  tlist = pg_analyze_and_rewrite_withcb(rawtree,
690  plansource->query_string,
691  plansource->parserSetup,
692  plansource->parserSetupArg,
693  queryEnv);
694  else
695  tlist = pg_analyze_and_rewrite_fixedparams(rawtree,
696  plansource->query_string,
697  plansource->param_types,
698  plansource->num_params,
699  queryEnv);
700 
701  /* Release snapshot if we got one */
702  if (snapshot_set)
704 
705  /*
706  * Check or update the result tupdesc. XXX should we use a weaker
707  * condition than equalTupleDescs() here?
708  *
709  * We assume the parameter types didn't change from the first time, so no
710  * need to update that.
711  */
712  resultDesc = PlanCacheComputeResultDesc(tlist);
713  if (resultDesc == NULL && plansource->resultDesc == NULL)
714  {
715  /* OK, doesn't return tuples */
716  }
717  else if (resultDesc == NULL || plansource->resultDesc == NULL ||
718  !equalTupleDescs(resultDesc, plansource->resultDesc))
719  {
720  /* can we give a better error message? */
721  if (plansource->fixed_result)
722  ereport(ERROR,
723  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
724  errmsg("cached plan must not change result type")));
725  oldcxt = MemoryContextSwitchTo(plansource->context);
726  if (resultDesc)
727  resultDesc = CreateTupleDescCopy(resultDesc);
728  if (plansource->resultDesc)
729  FreeTupleDesc(plansource->resultDesc);
730  plansource->resultDesc = resultDesc;
731  MemoryContextSwitchTo(oldcxt);
732  }
733 
734  /*
735  * Allocate new query_context and copy the completed querytree into it.
736  * It's transient until we complete the copying and dependency extraction.
737  */
738  querytree_context = AllocSetContextCreate(CurrentMemoryContext,
739  "CachedPlanQuery",
741  oldcxt = MemoryContextSwitchTo(querytree_context);
742 
743  qlist = copyObject(tlist);
744 
745  /*
746  * Use the planner machinery to extract dependencies. Data is saved in
747  * query_context. (We assume that not a lot of extra cruft is created by
748  * this call.)
749  */
751  &plansource->relationOids,
752  &plansource->invalItems,
753  &plansource->dependsOnRLS);
754 
755  /* Update RLS info as well. */
756  plansource->rewriteRoleId = GetUserId();
757  plansource->rewriteRowSecurity = row_security;
758 
759  /*
760  * Also save the current search_path in the query_context. (This should
761  * not generate much extra cruft either, since almost certainly the path
762  * is already valid.)
763  */
764  plansource->search_path = GetSearchPathMatcher(querytree_context);
765 
766  MemoryContextSwitchTo(oldcxt);
767 
768  /* Now reparent the finished query_context and save the links */
769  MemoryContextSetParent(querytree_context, plansource->context);
770 
771  plansource->query_context = querytree_context;
772  plansource->query_list = qlist;
773 
774  /*
775  * Note: we do not reset generic_cost or total_custom_cost, although we
776  * could choose to do so. If the DDL or statistics change that prompted
777  * the invalidation meant a significant change in the cost estimates, it
778  * would be better to reset those variables and start fresh; but often it
779  * doesn't, and we're better retaining our hard-won knowledge about the
780  * relative costs.
781  */
782 
783  plansource->is_valid = true;
784 
785  /* Return transient copy of querytrees for possible use in planning */
786  return tlist;
787 }
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ereport(elevel,...)
Definition: elog.h:149
static void AcquirePlannerLocks(List *stmt_list, bool acquire)
Definition: plancache.c:1805
List * pg_analyze_and_rewrite_withcb(RawStmt *parsetree, const char *query_string, ParserSetupHook parserSetup, void *parserSetupArg, QueryEnvironment *queryEnv)
Definition: postgres.c:762
List * pg_analyze_and_rewrite_fixedparams(RawStmt *parsetree, const char *query_string, const Oid *paramTypes, int numParams, QueryEnvironment *queryEnv)
Definition: postgres.c:669
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:309
bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:402

References AcquirePlannerLocks(), ActiveSnapshotSet(), ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, Assert(), CachedPlanSource::context, copyObject, CreateTupleDescCopy(), CurrentMemoryContext, CachedPlanSource::dependsOnRLS, equalTupleDescs(), ereport, errcode(), errmsg(), ERROR, extract_query_dependencies(), CachedPlanSource::fixed_result, FreeTupleDesc(), GetSearchPathMatcher(), GetTransactionSnapshot(), GetUserId(), CachedPlanSource::gplan, CachedPlanSource::invalItems, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_valid, CachedPlan::is_valid, MemoryContextDelete(), MemoryContextSetParent(), MemoryContextSwitchTo(), NIL, CachedPlanSource::num_params, CachedPlanSource::param_types, CachedPlanSource::parserSetup, CachedPlanSource::parserSetupArg, pg_analyze_and_rewrite_fixedparams(), pg_analyze_and_rewrite_withcb(), PlanCacheComputeResultDesc(), PopActiveSnapshot(), PushActiveSnapshot(), CachedPlanSource::query_context, CachedPlanSource::query_list, CachedPlanSource::query_string, CachedPlanSource::raw_parse_tree, CachedPlanSource::relationOids, ReleaseGenericPlan(), CachedPlanSource::resultDesc, CachedPlanSource::rewriteRoleId, CachedPlanSource::rewriteRowSecurity, row_security, CachedPlanSource::search_path, SearchPathMatchesCurrentEnvironment(), and StmtPlanRequiresRevalidation.

Referenced by BuildCachedPlan(), CachedPlanGetTargetList(), and GetCachedPlan().

◆ SaveCachedPlan()

void SaveCachedPlan ( CachedPlanSource plansource)

Definition at line 458 of file plancache.c.

459 {
460  /* Assert caller is doing things in a sane order */
461  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
462  Assert(plansource->is_complete);
463  Assert(!plansource->is_saved);
464 
465  /* This seems worth a real test, though */
466  if (plansource->is_oneshot)
467  elog(ERROR, "cannot save one-shot cached plan");
468 
469  /*
470  * In typical use, this function would be called before generating any
471  * plans from the CachedPlanSource. If there is a generic plan, moving it
472  * into CacheMemoryContext would be pretty risky since it's unclear
473  * whether the caller has taken suitable care with making references
474  * long-lived. Best thing to do seems to be to discard the plan.
475  */
476  ReleaseGenericPlan(plansource);
477 
478  /*
479  * Reparent the source memory context under CacheMemoryContext so that it
480  * will live indefinitely. The query_context follows along since it's
481  * already a child of the other one.
482  */
484 
485  /*
486  * Add the entry to the global list of cached plans.
487  */
488  dlist_push_tail(&saved_plan_list, &plansource->node);
489 
490  plansource->is_saved = true;
491 }

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

◆ ScanQueryForLocks()

static void ScanQueryForLocks ( Query parsetree,
bool  acquire 
)
static

Definition at line 1830 of file plancache.c.

1831 {
1832  ListCell *lc;
1833 
1834  /* Shouldn't get called on utility commands */
1835  Assert(parsetree->commandType != CMD_UTILITY);
1836 
1837  /*
1838  * First, process RTEs of the current query level.
1839  */
1840  foreach(lc, parsetree->rtable)
1841  {
1842  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
1843 
1844  switch (rte->rtekind)
1845  {
1846  case RTE_RELATION:
1847  /* Acquire or release the appropriate type of lock */
1848  if (acquire)
1849  LockRelationOid(rte->relid, rte->rellockmode);
1850  else
1851  UnlockRelationOid(rte->relid, rte->rellockmode);
1852  break;
1853 
1854  case RTE_SUBQUERY:
1855  /* If this was a view, must lock/unlock the view */
1856  if (OidIsValid(rte->relid))
1857  {
1858  if (acquire)
1859  LockRelationOid(rte->relid, rte->rellockmode);
1860  else
1861  UnlockRelationOid(rte->relid, rte->rellockmode);
1862  }
1863  /* Recurse into subquery-in-FROM */
1864  ScanQueryForLocks(rte->subquery, acquire);
1865  break;
1866 
1867  default:
1868  /* ignore other types of RTEs */
1869  break;
1870  }
1871  }
1872 
1873  /* Recurse into subquery-in-WITH */
1874  foreach(lc, parsetree->cteList)
1875  {
1877 
1878  ScanQueryForLocks(castNode(Query, cte->ctequery), acquire);
1879  }
1880 
1881  /*
1882  * Recurse into sublink subqueries, too. But we already did the ones in
1883  * the rtable and cteList.
1884  */
1885  if (parsetree->hasSubLinks)
1886  {
1888  (void *) &acquire,
1890  }
1891 }
#define query_tree_walker(q, w, c, f)
Definition: nodeFuncs.h:156
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:24
#define castNode(_type_, nodeptr)
Definition: nodes.h:197
static bool ScanQueryWalker(Node *node, bool *acquire)
Definition: plancache.c:1897
Query * subquery
Definition: parsenodes.h:1080

References Assert(), castNode, CMD_UTILITY, Query::commandType, Query::cteList, CommonTableExpr::ctequery, lfirst, lfirst_node, LockRelationOid(), OidIsValid, QTW_IGNORE_RC_SUBQUERIES, query_tree_walker, RangeTblEntry::relid, RangeTblEntry::rellockmode, Query::rtable, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, ScanQueryWalker(), RangeTblEntry::subquery, and UnlockRelationOid().

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

◆ ScanQueryWalker()

static bool ScanQueryWalker ( Node node,
bool acquire 
)
static

Definition at line 1897 of file plancache.c.

1898 {
1899  if (node == NULL)
1900  return false;
1901  if (IsA(node, SubLink))
1902  {
1903  SubLink *sub = (SubLink *) node;
1904 
1905  /* Do what we came for */
1906  ScanQueryForLocks(castNode(Query, sub->subselect), *acquire);
1907  /* Fall through to process lefthand args of SubLink */
1908  }
1909 
1910  /*
1911  * Do NOT recurse into Query nodes, because ScanQueryForLocks already
1912  * processed subselects of subselects for us.
1913  */
1915  (void *) acquire);
1916 }
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:151
#define IsA(nodeptr, _type_)
Definition: nodes.h:179

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

Referenced by ScanQueryForLocks().

Variable Documentation

◆ cached_expression_list

dlist_head cached_expression_list = DLIST_STATIC_INIT(cached_expression_list)
static

◆ plan_cache_mode

int plan_cache_mode = PLAN_CACHE_MODE_AUTO

Definition at line 123 of file plancache.c.

Referenced by choose_custom_plan().

◆ saved_plan_list

dlist_head saved_plan_list = DLIST_STATIC_INIT(saved_plan_list)
static