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 IsTransactionStmtPlan(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, bool useResOwner, QueryEnvironment *queryEnv)
 
void ReleaseCachedPlan (CachedPlan *plan, bool useResOwner)
 
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
 

Macro Definition Documentation

◆ IsTransactionStmtPlan

#define IsTransactionStmtPlan (   plansource)
Value:
((plansource)->raw_parse_tree && \
IsA((plansource)->raw_parse_tree->stmt, TransactionStmt))
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
struct TransactionStmt TransactionStmt

Definition at line 82 of file plancache.c.

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

Function Documentation

◆ AcquireExecutorLocks()

static void AcquireExecutorLocks ( List stmt_list,
bool  acquire 
)
static

Definition at line 1738 of file plancache.c.

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

Referenced by CheckCachedPlan().

1739 {
1740  ListCell *lc1;
1741 
1742  foreach(lc1, stmt_list)
1743  {
1744  PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
1745  ListCell *lc2;
1746 
1747  if (plannedstmt->commandType == CMD_UTILITY)
1748  {
1749  /*
1750  * Ignore utility statements, except those (such as EXPLAIN) that
1751  * contain a parsed-but-not-planned query. Note: it's okay to use
1752  * ScanQueryForLocks, even though the query hasn't been through
1753  * rule rewriting, because rewriting doesn't change the query
1754  * representation.
1755  */
1756  Query *query = UtilityContainsQuery(plannedstmt->utilityStmt);
1757 
1758  if (query)
1759  ScanQueryForLocks(query, acquire);
1760  continue;
1761  }
1762 
1763  foreach(lc2, plannedstmt->rtable)
1764  {
1765  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1766 
1767  if (rte->rtekind != RTE_RELATION)
1768  continue;
1769 
1770  /*
1771  * Acquire the appropriate type of lock on each relation OID. Note
1772  * that we don't actually try to open the rel, and hence will not
1773  * fail if it's been dropped entirely --- we'll just transiently
1774  * acquire a non-conflicting lock.
1775  */
1776  if (acquire)
1777  LockRelationOid(rte->relid, rte->rellockmode);
1778  else
1779  UnlockRelationOid(rte->relid, rte->rellockmode);
1780  }
1781  }
1782 }
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:199
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition: plancache.c:1818
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:2063
#define lfirst_node(type, lc)
Definition: pg_list.h:193
Node * utilityStmt
Definition: plannodes.h:92
CmdType commandType
Definition: plannodes.h:46
#define lfirst(lc)
Definition: pg_list.h:190
List * rtable
Definition: plannodes.h:66
RTEKind rtekind
Definition: parsenodes.h:976
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108

◆ AcquirePlannerLocks()

static void AcquirePlannerLocks ( List stmt_list,
bool  acquire 
)
static

Definition at line 1793 of file plancache.c.

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

Referenced by RevalidateCachedQuery().

1794 {
1795  ListCell *lc;
1796 
1797  foreach(lc, stmt_list)
1798  {
1799  Query *query = lfirst_node(Query, lc);
1800 
1801  if (query->commandType == CMD_UTILITY)
1802  {
1803  /* Ignore utility statements, unless they contain a Query */
1804  query = UtilityContainsQuery(query->utilityStmt);
1805  if (query)
1806  ScanQueryForLocks(query, acquire);
1807  continue;
1808  }
1809 
1810  ScanQueryForLocks(query, acquire);
1811  }
1812 }
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition: plancache.c:1818
Node * utilityStmt
Definition: parsenodes.h:120
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:2063
#define lfirst_node(type, lc)
Definition: pg_list.h:193
CmdType commandType
Definition: parsenodes.h:112

◆ BuildCachedPlan()

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

Definition at line 877 of file plancache.c.

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

Referenced by GetCachedPlan().

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

◆ cached_plan_cost()

static double cached_plan_cost ( CachedPlan plan,
bool  include_planner 
)
static

Definition at line 1074 of file plancache.c.

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

Referenced by GetCachedPlan().

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

◆ CachedPlanAllowsSimpleValidityCheck()

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

Definition at line 1305 of file plancache.c.

References Assert, CACHEDPLAN_MAGIC, CACHEDPLANSOURCE_MAGIC, CMD_UTILITY, PlannedStmt::commandType, Query::commandType, Query::cteList, CachedPlanSource::dependsOnRLS, CachedPlan::dependsOnRole, CachedPlanSource::gplan, Query::hasSubLinks, CachedPlanSource::is_oneshot, CachedPlan::is_oneshot, CachedPlan::is_valid, lfirst, lfirst_node, CachedPlanSource::magic, CachedPlan::magic, OverrideSearchPathMatchesCurrent(), CachedPlanSource::query_list, CachedPlan::refcount, ResourceOwnerEnlargePlanCacheRefs(), ResourceOwnerRememberPlanCacheRef(), PlannedStmt::rtable, Query::rtable, RTE_RELATION, RangeTblEntry::rtekind, CachedPlan::saved_xmin, CachedPlanSource::search_path, CachedPlan::stmt_list, and TransactionIdIsValid.

Referenced by exec_eval_simple_expr(), and exec_simple_check_plan().

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

◆ CachedPlanGetTargetList()

List* CachedPlanGetTargetList ( CachedPlanSource plansource,
QueryEnvironment queryEnv 
)

Definition at line 1606 of file plancache.c.

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

1608 {
1609  Query *pstmt;
1610 
1611  /* Assert caller is doing things in a sane order */
1612  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1613  Assert(plansource->is_complete);
1614 
1615  /*
1616  * No work needed if statement doesn't return tuples (we assume this
1617  * feature cannot be changed by an invalidation)
1618  */
1619  if (plansource->resultDesc == NULL)
1620  return NIL;
1621 
1622  /* Make sure the querytree list is valid and we have parse-time locks */
1623  RevalidateCachedQuery(plansource, queryEnv);
1624 
1625  /* Get the primary statement and find out what it returns */
1626  pstmt = QueryListGetPrimaryStmt(plansource->query_list);
1627 
1628  return FetchStatementTargetList((Node *) pstmt);
1629 }
#define NIL
Definition: pg_list.h:65
Definition: nodes.h:529
TupleDesc resultDesc
Definition: plancache.h:108
List * FetchStatementTargetList(Node *stmt)
Definition: pquery.c:345
static Query * QueryListGetPrimaryStmt(List *stmts)
Definition: plancache.c:1719
static List * RevalidateCachedQuery(CachedPlanSource *plansource, QueryEnvironment *queryEnv)
Definition: plancache.c:553
#define Assert(condition)
Definition: c.h:738
List * query_list
Definition: plancache.h:111
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:40

◆ CachedPlanIsSimplyValid()

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

Definition at line 1420 of file plancache.c.

References Assert, CACHEDPLAN_MAGIC, CACHEDPLANSOURCE_MAGIC, CachedPlanSource::gplan, CachedPlanSource::is_valid, CachedPlan::is_valid, CachedPlanSource::magic, CachedPlan::magic, OverrideSearchPathMatchesCurrent(), CachedPlan::refcount, ResourceOwnerEnlargePlanCacheRefs(), ResourceOwnerRememberPlanCacheRef(), and CachedPlanSource::search_path.

Referenced by exec_eval_simple_expr().

1422 {
1423  /*
1424  * Careful here: since the caller doesn't necessarily hold a refcount on
1425  * the plan to start with, it's possible that "plan" is a dangling
1426  * pointer. Don't dereference it until we've verified that it still
1427  * matches the plansource's gplan (which is either valid or NULL).
1428  */
1429  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1430 
1431  /*
1432  * Has cache invalidation fired on this plan? We can check this right
1433  * away since there are no locks that we'd need to acquire first. Note
1434  * that here we *do* check plansource->is_valid, so as to force plan
1435  * rebuild if that's become false.
1436  */
1437  if (!plansource->is_valid || plan != plansource->gplan || !plan->is_valid)
1438  return false;
1439 
1440  Assert(plan->magic == CACHEDPLAN_MAGIC);
1441 
1442  /* Is the search_path still the same as when we made it? */
1443  Assert(plansource->search_path != NULL);
1445  return false;
1446 
1447  /* It's still good. Bump refcount if requested. */
1448  if (owner)
1449  {
1451  plan->refcount++;
1452  ResourceOwnerRememberPlanCacheRef(owner, plan);
1453  }
1454 
1455  return true;
1456 }
#define CACHEDPLAN_MAGIC
Definition: plancache.h:41
bool is_valid
Definition: plancache.h:152
int refcount
Definition: plancache.h:158
void ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
Definition: resowner.c:1132
void ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner)
Definition: resowner.c:1121
struct CachedPlan * gplan
Definition: plancache.h:121
bool OverrideSearchPathMatchesCurrent(OverrideSearchPath *path)
Definition: namespace.c:3419
#define Assert(condition)
Definition: c.h:738
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:40
struct OverrideSearchPath * search_path
Definition: plancache.h:114

◆ CachedPlanIsValid()

bool CachedPlanIsValid ( CachedPlanSource plansource)

Definition at line 1593 of file plancache.c.

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

Referenced by SPI_plan_is_valid().

1594 {
1595  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1596  return plansource->is_valid;
1597 }
#define Assert(condition)
Definition: c.h:738
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:40

◆ CachedPlanSetParentContext()

void CachedPlanSetParentContext ( CachedPlanSource plansource,
MemoryContext  newcontext 
)

Definition at line 1465 of file plancache.c.

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

1467 {
1468  /* Assert caller is doing things in a sane order */
1469  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1470  Assert(plansource->is_complete);
1471 
1472  /* These seem worth real tests, though */
1473  if (plansource->is_saved)
1474  elog(ERROR, "cannot move a saved cached plan to another context");
1475  if (plansource->is_oneshot)
1476  elog(ERROR, "cannot move a one-shot cached plan to another context");
1477 
1478  /* OK, let the caller keep the plan where he wishes */
1479  MemoryContextSetParent(plansource->context, newcontext);
1480 
1481  /*
1482  * The query_context needs no special handling, since it's a child of
1483  * plansource->context. But if there's a generic plan, it should be
1484  * maintained as a sibling of plansource->context.
1485  */
1486  if (plansource->gplan)
1487  {
1488  Assert(plansource->gplan->magic == CACHEDPLAN_MAGIC);
1489  MemoryContextSetParent(plansource->gplan->context, newcontext);
1490  }
1491 }
#define CACHEDPLAN_MAGIC
Definition: plancache.h:41
MemoryContext context
Definition: plancache.h:109
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:354
MemoryContext context
Definition: plancache.h:159
struct CachedPlan * gplan
Definition: plancache.h:121
#define ERROR
Definition: elog.h:43
#define Assert(condition)
Definition: c.h:738
#define elog(elevel,...)
Definition: elog.h:214
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:40

◆ CheckCachedPlan()

static bool CheckCachedPlan ( CachedPlanSource plansource)
static

Definition at line 793 of file plancache.c.

References AcquireExecutorLocks(), Assert, CACHEDPLAN_MAGIC, CachedPlan::dependsOnRole, GetUserId(), CachedPlanSource::gplan, CachedPlan::is_oneshot, CachedPlanSource::is_valid, CachedPlan::is_valid, CachedPlan::magic, CachedPlan::planRoleId, CachedPlan::refcount, ReleaseGenericPlan(), CachedPlan::saved_xmin, CachedPlan::stmt_list, TransactionIdEquals, TransactionIdIsValid, and TransactionXmin.

Referenced by GetCachedPlan().

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

◆ choose_custom_plan()

static bool choose_custom_plan ( CachedPlanSource plansource,
ParamListInfo  boundParams 
)
static

Definition at line 1017 of file plancache.c.

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

Referenced by GetCachedPlan().

1018 {
1019  double avg_custom_cost;
1020 
1021  /* One-shot plans will always be considered custom */
1022  if (plansource->is_oneshot)
1023  return true;
1024 
1025  /* Otherwise, never any point in a custom plan if there's no parameters */
1026  if (boundParams == NULL)
1027  return false;
1028  /* ... nor for transaction control statements */
1029  if (IsTransactionStmtPlan(plansource))
1030  return false;
1031 
1032  /* Let settings force the decision */
1034  return false;
1036  return true;
1037 
1038  /* See if caller wants to force the decision */
1039  if (plansource->cursor_options & CURSOR_OPT_GENERIC_PLAN)
1040  return false;
1041  if (plansource->cursor_options & CURSOR_OPT_CUSTOM_PLAN)
1042  return true;
1043 
1044  /* Generate custom plans until we have done at least 5 (arbitrary) */
1045  if (plansource->num_custom_plans < 5)
1046  return true;
1047 
1048  avg_custom_cost = plansource->total_custom_cost / plansource->num_custom_plans;
1049 
1050  /*
1051  * Prefer generic plan if it's less expensive than the average custom
1052  * plan. (Because we include a charge for cost of planning in the
1053  * custom-plan costs, this means the generic plan only has to be less
1054  * expensive than the execution cost plus replan cost of the custom
1055  * plans.)
1056  *
1057  * Note that if generic_cost is -1 (indicating we've not yet determined
1058  * the generic plan cost), we'll always prefer generic at this point.
1059  */
1060  if (plansource->generic_cost < avg_custom_cost)
1061  return false;
1062 
1063  return true;
1064 }
double total_custom_cost
Definition: plancache.h:132
#define CURSOR_OPT_CUSTOM_PLAN
Definition: parsenodes.h:2714
int plan_cache_mode
Definition: plancache.c:119
double generic_cost
Definition: plancache.h:131
#define CURSOR_OPT_GENERIC_PLAN
Definition: parsenodes.h:2713
#define IsTransactionStmtPlan(plansource)
Definition: plancache.c:82

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

References ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, Assert, CACHEDPLANSOURCE_MAGIC, CachedPlanSource::context, copyObject, CurrentMemoryContext, CachedPlanSource::cursor_options, CachedPlanSource::dependsOnRLS, extract_query_dependencies(), CachedPlanSource::fixed_result, GetOverrideSearchPath(), GetUserId(), CachedPlanSource::invalItems, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_valid, IsTransactionStmtPlan, 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, and CachedPlanSource::search_path.

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

345 {
346  MemoryContext source_context = plansource->context;
348 
349  /* Assert caller is doing things in a sane order */
350  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
351  Assert(!plansource->is_complete);
352 
353  /*
354  * If caller supplied a querytree_context, reparent it underneath the
355  * CachedPlanSource's context; otherwise, create a suitable context and
356  * copy the querytree_list into it. But no data copying should be done
357  * for one-shot plans; for those, assume the passed querytree_list is
358  * sufficiently long-lived.
359  */
360  if (plansource->is_oneshot)
361  {
362  querytree_context = CurrentMemoryContext;
363  }
364  else if (querytree_context != NULL)
365  {
366  MemoryContextSetParent(querytree_context, source_context);
367  MemoryContextSwitchTo(querytree_context);
368  }
369  else
370  {
371  /* Again, it's a good bet the querytree_context can be small */
372  querytree_context = AllocSetContextCreate(source_context,
373  "CachedPlanQuery",
375  MemoryContextSwitchTo(querytree_context);
376  querytree_list = copyObject(querytree_list);
377  }
378 
379  plansource->query_context = querytree_context;
380  plansource->query_list = querytree_list;
381 
382  if (!plansource->is_oneshot && !IsTransactionStmtPlan(plansource))
383  {
384  /*
385  * Use the planner machinery to extract dependencies. Data is saved
386  * in query_context. (We assume that not a lot of extra cruft is
387  * created by this call.) We can skip this for one-shot plans, and
388  * transaction control commands have no such dependencies anyway.
389  */
390  extract_query_dependencies((Node *) querytree_list,
391  &plansource->relationOids,
392  &plansource->invalItems,
393  &plansource->dependsOnRLS);
394 
395  /* Update RLS info as well. */
396  plansource->rewriteRoleId = GetUserId();
397  plansource->rewriteRowSecurity = row_security;
398 
399  /*
400  * Also save the current search_path in the query_context. (This
401  * should not generate much extra cruft either, since almost certainly
402  * the path is already valid.) Again, we don't really need this for
403  * one-shot plans; and we *must* skip this for transaction control
404  * commands, because this could result in catalog accesses.
405  */
406  plansource->search_path = GetOverrideSearchPath(querytree_context);
407  }
408 
409  /*
410  * Save the final parameter types (or other parameter specification data)
411  * into the source_context, as well as our other parameters. Also save
412  * the result tuple descriptor.
413  */
414  MemoryContextSwitchTo(source_context);
415 
416  if (num_params > 0)
417  {
418  plansource->param_types = (Oid *) palloc(num_params * sizeof(Oid));
419  memcpy(plansource->param_types, param_types, num_params * sizeof(Oid));
420  }
421  else
422  plansource->param_types = NULL;
423  plansource->num_params = num_params;
424  plansource->parserSetup = parserSetup;
425  plansource->parserSetupArg = parserSetupArg;
426  plansource->cursor_options = cursor_options;
427  plansource->fixed_result = fixed_result;
428  plansource->resultDesc = PlanCacheComputeResultDesc(querytree_list);
429 
430  MemoryContextSwitchTo(oldcxt);
431 
432  plansource->is_complete = true;
433  plansource->is_valid = true;
434 }
MemoryContext context
Definition: plancache.h:109
bool rewriteRowSecurity
Definition: plancache.h:118
#define AllocSetContextCreate
Definition: memutils.h:170
Oid GetUserId(void)
Definition: miscinit.c:448
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:354
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Definition: nodes.h:529
unsigned int Oid
Definition: postgres_ext.h:31
TupleDesc resultDesc
Definition: plancache.h:108
List * invalItems
Definition: plancache.h:113
OverrideSearchPath * GetOverrideSearchPath(MemoryContext context)
Definition: namespace.c:3360
List * relationOids
Definition: plancache.h:112
void * parserSetupArg
Definition: plancache.h:105
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
ParserSetupHook parserSetup
Definition: plancache.h:104
bool row_security
Definition: guc.c:532
#define Assert(condition)
Definition: c.h:738
void extract_query_dependencies(Node *query, List **relationOids, List **invalItems, bool *hasRowSecurity)
Definition: setrefs.c:2791
void * palloc(Size size)
Definition: mcxt.c:949
MemoryContext query_context
Definition: plancache.h:116
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:209
List * query_list
Definition: plancache.h:111
#define IsTransactionStmtPlan(plansource)
Definition: plancache.c:82
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:40
#define copyObject(obj)
Definition: nodes.h:645
static TupleDesc PlanCacheComputeResultDesc(List *stmt_list)
Definition: plancache.c:1906
struct OverrideSearchPath * search_path
Definition: plancache.h:114

◆ CopyCachedPlan()

CachedPlanSource* CopyCachedPlan ( CachedPlanSource plansource)

Definition at line 1503 of file plancache.c.

References ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, Assert, CACHEDPLANSOURCE_MAGIC, CachedPlanSource::commandTag, CachedPlanSource::context, copyObject, CopyOverrideSearchPath(), 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_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().

1504 {
1505  CachedPlanSource *newsource;
1506  MemoryContext source_context;
1507  MemoryContext querytree_context;
1508  MemoryContext oldcxt;
1509 
1510  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1511  Assert(plansource->is_complete);
1512 
1513  /*
1514  * One-shot plans can't be copied, because we haven't taken care that
1515  * parsing/planning didn't scribble on the raw parse tree or querytrees.
1516  */
1517  if (plansource->is_oneshot)
1518  elog(ERROR, "cannot copy a one-shot cached plan");
1519 
1521  "CachedPlanSource",
1523 
1524  oldcxt = MemoryContextSwitchTo(source_context);
1525 
1526  newsource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
1527  newsource->magic = CACHEDPLANSOURCE_MAGIC;
1528  newsource->raw_parse_tree = copyObject(plansource->raw_parse_tree);
1529  newsource->query_string = pstrdup(plansource->query_string);
1530  MemoryContextSetIdentifier(source_context, newsource->query_string);
1531  newsource->commandTag = plansource->commandTag;
1532  if (plansource->num_params > 0)
1533  {
1534  newsource->param_types = (Oid *)
1535  palloc(plansource->num_params * sizeof(Oid));
1536  memcpy(newsource->param_types, plansource->param_types,
1537  plansource->num_params * sizeof(Oid));
1538  }
1539  else
1540  newsource->param_types = NULL;
1541  newsource->num_params = plansource->num_params;
1542  newsource->parserSetup = plansource->parserSetup;
1543  newsource->parserSetupArg = plansource->parserSetupArg;
1544  newsource->cursor_options = plansource->cursor_options;
1545  newsource->fixed_result = plansource->fixed_result;
1546  if (plansource->resultDesc)
1547  newsource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
1548  else
1549  newsource->resultDesc = NULL;
1550  newsource->context = source_context;
1551 
1552  querytree_context = AllocSetContextCreate(source_context,
1553  "CachedPlanQuery",
1555  MemoryContextSwitchTo(querytree_context);
1556  newsource->query_list = copyObject(plansource->query_list);
1557  newsource->relationOids = copyObject(plansource->relationOids);
1558  newsource->invalItems = copyObject(plansource->invalItems);
1559  if (plansource->search_path)
1560  newsource->search_path = CopyOverrideSearchPath(plansource->search_path);
1561  newsource->query_context = querytree_context;
1562  newsource->rewriteRoleId = plansource->rewriteRoleId;
1563  newsource->rewriteRowSecurity = plansource->rewriteRowSecurity;
1564  newsource->dependsOnRLS = plansource->dependsOnRLS;
1565 
1566  newsource->gplan = NULL;
1567 
1568  newsource->is_oneshot = false;
1569  newsource->is_complete = true;
1570  newsource->is_saved = false;
1571  newsource->is_valid = plansource->is_valid;
1572  newsource->generation = plansource->generation;
1573 
1574  /* We may as well copy any acquired cost knowledge */
1575  newsource->generic_cost = plansource->generic_cost;
1576  newsource->total_custom_cost = plansource->total_custom_cost;
1577  newsource->num_custom_plans = plansource->num_custom_plans;
1578 
1579  MemoryContextSwitchTo(oldcxt);
1580 
1581  return newsource;
1582 }
MemoryContext context
Definition: plancache.h:109
bool rewriteRowSecurity
Definition: plancache.h:118
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:110
#define AllocSetContextCreate
Definition: memutils.h:170
char * pstrdup(const char *in)
Definition: mcxt.c:1186
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
unsigned int Oid
Definition: postgres_ext.h:31
double total_custom_cost
Definition: plancache.h:132
struct CachedPlan * gplan
Definition: plancache.h:121
TupleDesc resultDesc
Definition: plancache.h:108
#define ERROR
Definition: elog.h:43
OverrideSearchPath * CopyOverrideSearchPath(OverrideSearchPath *path)
Definition: namespace.c:3397
List * invalItems
Definition: plancache.h:113
List * relationOids
Definition: plancache.h:112
void * parserSetupArg
Definition: plancache.h:105
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
ParserSetupHook parserSetup
Definition: plancache.h:104
void * palloc0(Size size)
Definition: mcxt.c:980
double generic_cost
Definition: plancache.h:131
#define Assert(condition)
Definition: c.h:738
const char * query_string
Definition: plancache.h:100
CommandTag commandTag
Definition: plancache.h:101
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:329
struct RawStmt * raw_parse_tree
Definition: plancache.h:99
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:214
MemoryContext query_context
Definition: plancache.h:116
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:209
List * query_list
Definition: plancache.h:111
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:40
#define copyObject(obj)
Definition: nodes.h:645
struct OverrideSearchPath * search_path
Definition: plancache.h:114

◆ CreateCachedPlan()

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

Definition at line 164 of file plancache.c.

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

167 {
168  CachedPlanSource *plansource;
169  MemoryContext source_context;
170  MemoryContext oldcxt;
171 
172  Assert(query_string != NULL); /* required as of 8.4 */
173 
174  /*
175  * Make a dedicated memory context for the CachedPlanSource and its
176  * permanent subsidiary data. It's probably not going to be large, but
177  * just in case, allow it to grow large. Initially it's a child of the
178  * caller's context (which we assume to be transient), so that it will be
179  * cleaned up on error.
180  */
182  "CachedPlanSource",
184 
185  /*
186  * Create and fill the CachedPlanSource struct within the new context.
187  * Most fields are just left empty for the moment.
188  */
189  oldcxt = MemoryContextSwitchTo(source_context);
190 
191  plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
192  plansource->magic = CACHEDPLANSOURCE_MAGIC;
193  plansource->raw_parse_tree = copyObject(raw_parse_tree);
194  plansource->query_string = pstrdup(query_string);
195  MemoryContextSetIdentifier(source_context, plansource->query_string);
196  plansource->commandTag = commandTag;
197  plansource->param_types = NULL;
198  plansource->num_params = 0;
199  plansource->parserSetup = NULL;
200  plansource->parserSetupArg = NULL;
201  plansource->cursor_options = 0;
202  plansource->fixed_result = false;
203  plansource->resultDesc = NULL;
204  plansource->context = source_context;
205  plansource->query_list = NIL;
206  plansource->relationOids = NIL;
207  plansource->invalItems = NIL;
208  plansource->search_path = NULL;
209  plansource->query_context = NULL;
210  plansource->rewriteRoleId = InvalidOid;
211  plansource->rewriteRowSecurity = false;
212  plansource->dependsOnRLS = false;
213  plansource->gplan = NULL;
214  plansource->is_oneshot = false;
215  plansource->is_complete = false;
216  plansource->is_saved = false;
217  plansource->is_valid = false;
218  plansource->generation = 0;
219  plansource->generic_cost = -1;
220  plansource->total_custom_cost = 0;
221  plansource->num_custom_plans = 0;
222 
223  MemoryContextSwitchTo(oldcxt);
224 
225  return plansource;
226 }
MemoryContext context
Definition: plancache.h:109
#define NIL
Definition: pg_list.h:65
bool rewriteRowSecurity
Definition: plancache.h:118
#define AllocSetContextCreate
Definition: memutils.h:170
char * pstrdup(const char *in)
Definition: mcxt.c:1186
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
double total_custom_cost
Definition: plancache.h:132
struct CachedPlan * gplan
Definition: plancache.h:121
TupleDesc resultDesc
Definition: plancache.h:108
List * invalItems
Definition: plancache.h:113
List * relationOids
Definition: plancache.h:112
void * parserSetupArg
Definition: plancache.h:105
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
ParserSetupHook parserSetup
Definition: plancache.h:104
void * palloc0(Size size)
Definition: mcxt.c:980
#define InvalidOid
Definition: postgres_ext.h:36
double generic_cost
Definition: plancache.h:131
#define Assert(condition)
Definition: c.h:738
const char * query_string
Definition: plancache.h:100
CommandTag commandTag
Definition: plancache.h:101
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:329
struct RawStmt * raw_parse_tree
Definition: plancache.h:99
MemoryContext query_context
Definition: plancache.h:116
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:209
List * query_list
Definition: plancache.h:111
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:40
#define copyObject(obj)
Definition: nodes.h:645
struct OverrideSearchPath * search_path
Definition: plancache.h:114

◆ CreateOneShotCachedPlan()

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

Definition at line 247 of file plancache.c.

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

250 {
251  CachedPlanSource *plansource;
252 
253  Assert(query_string != NULL); /* required as of 8.4 */
254 
255  /*
256  * Create and fill the CachedPlanSource struct within the caller's memory
257  * context. Most fields are just left empty for the moment.
258  */
259  plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
260  plansource->magic = CACHEDPLANSOURCE_MAGIC;
261  plansource->raw_parse_tree = raw_parse_tree;
262  plansource->query_string = query_string;
263  plansource->commandTag = commandTag;
264  plansource->param_types = NULL;
265  plansource->num_params = 0;
266  plansource->parserSetup = NULL;
267  plansource->parserSetupArg = NULL;
268  plansource->cursor_options = 0;
269  plansource->fixed_result = false;
270  plansource->resultDesc = NULL;
271  plansource->context = CurrentMemoryContext;
272  plansource->query_list = NIL;
273  plansource->relationOids = NIL;
274  plansource->invalItems = NIL;
275  plansource->search_path = NULL;
276  plansource->query_context = NULL;
277  plansource->rewriteRoleId = InvalidOid;
278  plansource->rewriteRowSecurity = false;
279  plansource->dependsOnRLS = false;
280  plansource->gplan = NULL;
281  plansource->is_oneshot = true;
282  plansource->is_complete = false;
283  plansource->is_saved = false;
284  plansource->is_valid = false;
285  plansource->generation = 0;
286  plansource->generic_cost = -1;
287  plansource->total_custom_cost = 0;
288  plansource->num_custom_plans = 0;
289 
290  return plansource;
291 }
MemoryContext context
Definition: plancache.h:109
#define NIL
Definition: pg_list.h:65
bool rewriteRowSecurity
Definition: plancache.h:118
double total_custom_cost
Definition: plancache.h:132
struct CachedPlan * gplan
Definition: plancache.h:121
TupleDesc resultDesc
Definition: plancache.h:108
List * invalItems
Definition: plancache.h:113
List * relationOids
Definition: plancache.h:112
void * parserSetupArg
Definition: plancache.h:105
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
ParserSetupHook parserSetup
Definition: plancache.h:104
void * palloc0(Size size)
Definition: mcxt.c:980
#define InvalidOid
Definition: postgres_ext.h:36
double generic_cost
Definition: plancache.h:131
#define Assert(condition)
Definition: c.h:738
const char * query_string
Definition: plancache.h:100
CommandTag commandTag
Definition: plancache.h:101
struct RawStmt * raw_parse_tree
Definition: plancache.h:99
MemoryContext query_context
Definition: plancache.h:116
List * query_list
Definition: plancache.h:111
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:40
struct OverrideSearchPath * search_path
Definition: plancache.h:114

◆ DropCachedPlan()

void DropCachedPlan ( CachedPlanSource plansource)

Definition at line 496 of file plancache.c.

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

497 {
498  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
499 
500  /* If it's been saved, remove it from the list */
501  if (plansource->is_saved)
502  {
503  dlist_delete(&plansource->node);
504  plansource->is_saved = false;
505  }
506 
507  /* Decrement generic CachedPlan's refcount and drop if no longer needed */
508  ReleaseGenericPlan(plansource);
509 
510  /* Mark it no longer valid */
511  plansource->magic = 0;
512 
513  /*
514  * Remove the CachedPlanSource and all subsidiary data (including the
515  * query_context if any). But if it's a one-shot we can't free anything.
516  */
517  if (!plansource->is_oneshot)
518  MemoryContextDelete(plansource->context);
519 }
MemoryContext context
Definition: plancache.h:109
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
static void ReleaseGenericPlan(CachedPlanSource *plansource)
Definition: plancache.c:525
static void dlist_delete(dlist_node *node)
Definition: ilist.h:358
#define Assert(condition)
Definition: c.h:738
dlist_node node
Definition: plancache.h:129
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:40

◆ FreeCachedExpression()

void FreeCachedExpression ( CachedExpression cexpr)

Definition at line 1700 of file plancache.c.

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

Referenced by get_cast_hashentry().

1701 {
1702  /* Sanity check */
1703  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
1704  /* Unlink from global list */
1705  dlist_delete(&cexpr->node);
1706  /* Free all storage associated with CachedExpression */
1707  MemoryContextDelete(cexpr->context);
1708 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
MemoryContext context
Definition: plancache.h:182
#define CACHEDEXPR_MAGIC
Definition: plancache.h:42
static void dlist_delete(dlist_node *node)
Definition: ilist.h:358
#define Assert(condition)
Definition: c.h:738
dlist_node node
Definition: plancache.h:183

◆ GetCachedExpression()

CachedExpression* GetCachedExpression ( Node expr)

Definition at line 1643 of file plancache.c.

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, 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().

1644 {
1645  CachedExpression *cexpr;
1646  List *relationOids;
1647  List *invalItems;
1648  MemoryContext cexpr_context;
1649  MemoryContext oldcxt;
1650 
1651  /*
1652  * Pass the expression through the planner, and collect dependencies.
1653  * Everything built here is leaked in the caller's context; that's
1654  * intentional to minimize the size of the permanent data structure.
1655  */
1656  expr = (Node *) expression_planner_with_deps((Expr *) expr,
1657  &relationOids,
1658  &invalItems);
1659 
1660  /*
1661  * Make a private memory context, and copy what we need into that. To
1662  * avoid leaking a long-lived context if we fail while copying data, we
1663  * initially make the context under the caller's context.
1664  */
1666  "CachedExpression",
1668 
1669  oldcxt = MemoryContextSwitchTo(cexpr_context);
1670 
1671  cexpr = (CachedExpression *) palloc(sizeof(CachedExpression));
1672  cexpr->magic = CACHEDEXPR_MAGIC;
1673  cexpr->expr = copyObject(expr);
1674  cexpr->is_valid = true;
1675  cexpr->relationOids = copyObject(relationOids);
1676  cexpr->invalItems = copyObject(invalItems);
1677  cexpr->context = cexpr_context;
1678 
1679  MemoryContextSwitchTo(oldcxt);
1680 
1681  /*
1682  * Reparent the expr's memory context under CacheMemoryContext so that it
1683  * will live indefinitely.
1684  */
1686 
1687  /*
1688  * Add the entry to the global list of cached expressions.
1689  */
1691 
1692  return cexpr;
1693 }
#define AllocSetContextCreate
Definition: memutils.h:170
MemoryContext context
Definition: plancache.h:182
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:354
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:317
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Definition: nodes.h:529
static dlist_head cached_expression_list
Definition: plancache.c:97
List * relationOids
Definition: plancache.h:180
List * invalItems
Definition: plancache.h:181
#define CACHEDEXPR_MAGIC
Definition: plancache.h:42
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
dlist_node node
Definition: plancache.h:183
Expr * expression_planner_with_deps(Expr *expr, List **relationOids, List **invalItems)
Definition: planner.c:6184
void * palloc(Size size)
Definition: mcxt.c:949
#define copyObject(obj)
Definition: nodes.h:645
Definition: pg_list.h:50
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ GetCachedPlan()

CachedPlan* GetCachedPlan ( CachedPlanSource plansource,
ParamListInfo  boundParams,
bool  useResOwner,
QueryEnvironment queryEnv 
)

Definition at line 1139 of file plancache.c.

References Assert, BuildCachedPlan(), cached_plan_cost(), CACHEDPLAN_MAGIC, CACHEDPLANSOURCE_MAGIC, CacheMemoryContext, CheckCachedPlan(), choose_custom_plan(), CachedPlanSource::context, CachedPlan::context, CurrentResourceOwner, elog, ERROR, CachedPlanSource::generic_cost, CachedPlanSource::gplan, CachedPlanSource::is_complete, CachedPlanSource::is_saved, CachedPlan::is_saved, CachedPlanSource::magic, CachedPlan::magic, MemoryContextGetParent(), MemoryContextSetParent(), NIL, CachedPlanSource::num_custom_plans, CachedPlan::refcount, 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().

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

◆ InitPlanCache()

void InitPlanCache ( void  )

Definition at line 127 of file plancache.c.

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

Referenced by InitPostgres().

128 {
137 }
static void PlanCacheObjectCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:2026
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition: inval.c:1468
static void PlanCacheRelCallback(Datum arg, Oid relid)
Definition: plancache.c:1942
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1426
uintptr_t Datum
Definition: postgres.h:367
static void PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:2135

◆ PlanCacheComputeResultDesc()

static TupleDesc PlanCacheComputeResultDesc ( List stmt_list)
static

Definition at line 1906 of file plancache.c.

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

1907 {
1908  Query *query;
1909 
1910  switch (ChoosePortalStrategy(stmt_list))
1911  {
1912  case PORTAL_ONE_SELECT:
1913  case PORTAL_ONE_MOD_WITH:
1914  query = linitial_node(Query, stmt_list);
1915  return ExecCleanTypeFromTL(query->targetList);
1916 
1917  case PORTAL_ONE_RETURNING:
1918  query = QueryListGetPrimaryStmt(stmt_list);
1919  Assert(query->returningList);
1920  return ExecCleanTypeFromTL(query->returningList);
1921 
1922  case PORTAL_UTIL_SELECT:
1923  query = linitial_node(Query, stmt_list);
1924  Assert(query->utilityStmt);
1925  return UtilityTupleDescriptor(query->utilityStmt);
1926 
1927  case PORTAL_MULTI_QUERY:
1928  /* will not return tuples */
1929  break;
1930  }
1931  return NULL;
1932 }
TupleDesc ExecCleanTypeFromTL(List *targetList)
Definition: execTuples.c:1920
Node * utilityStmt
Definition: parsenodes.h:120
#define linitial_node(type, l)
Definition: pg_list.h:198
List * targetList
Definition: parsenodes.h:140
static Query * QueryListGetPrimaryStmt(List *stmts)
Definition: plancache.c:1719
List * returningList
Definition: parsenodes.h:146
#define Assert(condition)
Definition: c.h:738
PortalStrategy ChoosePortalStrategy(List *stmts)
Definition: pquery.c:206
TupleDesc UtilityTupleDescriptor(Node *parsetree)
Definition: utility.c:1969

◆ PlanCacheObjectCallback()

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

Definition at line 2026 of file plancache.c.

References Assert, 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, IsTransactionStmtPlan, lfirst, lfirst_node, CachedPlanSource::magic, CachedExpression::magic, and CachedPlan::stmt_list.

Referenced by InitPlanCache().

2027 {
2028  dlist_iter iter;
2029 
2031  {
2033  node, iter.cur);
2034  ListCell *lc;
2035 
2036  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2037 
2038  /* No work if it's already invalidated */
2039  if (!plansource->is_valid)
2040  continue;
2041 
2042  /* Never invalidate transaction control commands */
2043  if (IsTransactionStmtPlan(plansource))
2044  continue;
2045 
2046  /*
2047  * Check the dependency list for the rewritten querytree.
2048  */
2049  foreach(lc, plansource->invalItems)
2050  {
2051  PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2052 
2053  if (item->cacheId != cacheid)
2054  continue;
2055  if (hashvalue == 0 ||
2056  item->hashValue == hashvalue)
2057  {
2058  /* Invalidate the querytree and generic plan */
2059  plansource->is_valid = false;
2060  if (plansource->gplan)
2061  plansource->gplan->is_valid = false;
2062  break;
2063  }
2064  }
2065 
2066  /*
2067  * The generic plan, if any, could have more dependencies than the
2068  * querytree does, so we have to check it too.
2069  */
2070  if (plansource->gplan && plansource->gplan->is_valid)
2071  {
2072  foreach(lc, plansource->gplan->stmt_list)
2073  {
2074  PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2075  ListCell *lc3;
2076 
2077  if (plannedstmt->commandType == CMD_UTILITY)
2078  continue; /* Ignore utility statements */
2079  foreach(lc3, plannedstmt->invalItems)
2080  {
2081  PlanInvalItem *item = (PlanInvalItem *) lfirst(lc3);
2082 
2083  if (item->cacheId != cacheid)
2084  continue;
2085  if (hashvalue == 0 ||
2086  item->hashValue == hashvalue)
2087  {
2088  /* Invalidate the generic plan only */
2089  plansource->gplan->is_valid = false;
2090  break; /* out of invalItems scan */
2091  }
2092  }
2093  if (!plansource->gplan->is_valid)
2094  break; /* out of stmt_list scan */
2095  }
2096  }
2097  }
2098 
2099  /* Likewise check cached expressions */
2101  {
2103  node, iter.cur);
2104  ListCell *lc;
2105 
2106  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2107 
2108  /* No work if it's already invalidated */
2109  if (!cexpr->is_valid)
2110  continue;
2111 
2112  foreach(lc, cexpr->invalItems)
2113  {
2114  PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2115 
2116  if (item->cacheId != cacheid)
2117  continue;
2118  if (hashvalue == 0 ||
2119  item->hashValue == hashvalue)
2120  {
2121  cexpr->is_valid = false;
2122  break;
2123  }
2124  }
2125  }
2126 }
bool is_valid
Definition: plancache.h:152
#define dlist_foreach(iter, lhead)
Definition: ilist.h:507
static dlist_head cached_expression_list
Definition: plancache.c:97
struct CachedPlan * gplan
Definition: plancache.h:121
List * invalItems
Definition: plannodes.h:88
List * invalItems
Definition: plancache.h:181
#define dlist_container(type, membername, ptr)
Definition: ilist.h:477
List * invalItems
Definition: plancache.h:113
#define lfirst_node(type, lc)
Definition: pg_list.h:193
#define CACHEDEXPR_MAGIC
Definition: plancache.h:42
static dlist_head saved_plan_list
Definition: plancache.c:92
CmdType commandType
Definition: plannodes.h:46
dlist_node * cur
Definition: ilist.h:161
uint32 hashValue
Definition: plannodes.h:1248
#define Assert(condition)
Definition: c.h:738
#define lfirst(lc)
Definition: pg_list.h:190
List * stmt_list
Definition: plancache.h:149
#define IsTransactionStmtPlan(plansource)
Definition: plancache.c:82
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:40

◆ PlanCacheRelCallback()

static void PlanCacheRelCallback ( Datum  arg,
Oid  relid 
)
static

Definition at line 1942 of file plancache.c.

References Assert, 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, IsTransactionStmtPlan, lfirst_node, list_member_oid(), CachedPlanSource::magic, CachedExpression::magic, NIL, PlannedStmt::relationOids, CachedPlanSource::relationOids, CachedExpression::relationOids, and CachedPlan::stmt_list.

Referenced by InitPlanCache().

1943 {
1944  dlist_iter iter;
1945 
1947  {
1949  node, iter.cur);
1950 
1951  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1952 
1953  /* No work if it's already invalidated */
1954  if (!plansource->is_valid)
1955  continue;
1956 
1957  /* Never invalidate transaction control commands */
1958  if (IsTransactionStmtPlan(plansource))
1959  continue;
1960 
1961  /*
1962  * Check the dependency list for the rewritten querytree.
1963  */
1964  if ((relid == InvalidOid) ? plansource->relationOids != NIL :
1965  list_member_oid(plansource->relationOids, relid))
1966  {
1967  /* Invalidate the querytree and generic plan */
1968  plansource->is_valid = false;
1969  if (plansource->gplan)
1970  plansource->gplan->is_valid = false;
1971  }
1972 
1973  /*
1974  * The generic plan, if any, could have more dependencies than the
1975  * querytree does, so we have to check it too.
1976  */
1977  if (plansource->gplan && plansource->gplan->is_valid)
1978  {
1979  ListCell *lc;
1980 
1981  foreach(lc, plansource->gplan->stmt_list)
1982  {
1983  PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1984 
1985  if (plannedstmt->commandType == CMD_UTILITY)
1986  continue; /* Ignore utility statements */
1987  if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
1988  list_member_oid(plannedstmt->relationOids, relid))
1989  {
1990  /* Invalidate the generic plan only */
1991  plansource->gplan->is_valid = false;
1992  break; /* out of stmt_list scan */
1993  }
1994  }
1995  }
1996  }
1997 
1998  /* Likewise check cached expressions */
2000  {
2002  node, iter.cur);
2003 
2004  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2005 
2006  /* No work if it's already invalidated */
2007  if (!cexpr->is_valid)
2008  continue;
2009 
2010  if ((relid == InvalidOid) ? cexpr->relationOids != NIL :
2011  list_member_oid(cexpr->relationOids, relid))
2012  {
2013  cexpr->is_valid = false;
2014  }
2015  }
2016 }
#define NIL
Definition: pg_list.h:65
bool is_valid
Definition: plancache.h:152
#define dlist_foreach(iter, lhead)
Definition: ilist.h:507
List * relationOids
Definition: plannodes.h:86
static dlist_head cached_expression_list
Definition: plancache.c:97
List * relationOids
Definition: plancache.h:180
struct CachedPlan * gplan
Definition: plancache.h:121
#define dlist_container(type, membername, ptr)
Definition: ilist.h:477
#define lfirst_node(type, lc)
Definition: pg_list.h:193
#define CACHEDEXPR_MAGIC
Definition: plancache.h:42
List * relationOids
Definition: plancache.h:112
static dlist_head saved_plan_list
Definition: plancache.c:92
CmdType commandType
Definition: plannodes.h:46
dlist_node * cur
Definition: ilist.h:161
#define InvalidOid
Definition: postgres_ext.h:36
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:674
#define Assert(condition)
Definition: c.h:738
List * stmt_list
Definition: plancache.h:149
#define IsTransactionStmtPlan(plansource)
Definition: plancache.c:82
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:40

◆ PlanCacheSysCallback()

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

Definition at line 2135 of file plancache.c.

References ResetPlanCache().

Referenced by InitPlanCache().

2136 {
2137  ResetPlanCache();
2138 }
void ResetPlanCache(void)
Definition: plancache.c:2144

◆ QueryListGetPrimaryStmt()

static Query * QueryListGetPrimaryStmt ( List stmts)
static

Definition at line 1719 of file plancache.c.

References Query::canSetTag, and lfirst_node.

Referenced by CachedPlanGetTargetList(), and PlanCacheComputeResultDesc().

1720 {
1721  ListCell *lc;
1722 
1723  foreach(lc, stmts)
1724  {
1725  Query *stmt = lfirst_node(Query, lc);
1726 
1727  if (stmt->canSetTag)
1728  return stmt;
1729  }
1730  return NULL;
1731 }
#define lfirst_node(type, lc)
Definition: pg_list.h:193
bool canSetTag
Definition: parsenodes.h:118

◆ ReleaseCachedPlan()

void ReleaseCachedPlan ( CachedPlan plan,
bool  useResOwner 
)

Definition at line 1260 of file plancache.c.

References Assert, CACHEDPLAN_MAGIC, CachedPlan::context, CurrentResourceOwner, CachedPlan::is_oneshot, CachedPlan::is_saved, CachedPlan::magic, MemoryContextDelete(), CachedPlan::refcount, 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().

1261 {
1262  Assert(plan->magic == CACHEDPLAN_MAGIC);
1263  if (useResOwner)
1264  {
1265  Assert(plan->is_saved);
1267  }
1268  Assert(plan->refcount > 0);
1269  plan->refcount--;
1270  if (plan->refcount == 0)
1271  {
1272  /* Mark it no longer valid */
1273  plan->magic = 0;
1274 
1275  /* One-shot plans do not own their context, so we can't free them */
1276  if (!plan->is_oneshot)
1278  }
1279 }
#define CACHEDPLAN_MAGIC
Definition: plancache.h:41
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
int refcount
Definition: plancache.h:158
MemoryContext context
Definition: plancache.h:159
void ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
Definition: resowner.c:1141
bool is_saved
Definition: plancache.h:151
#define Assert(condition)
Definition: c.h:738
bool is_oneshot
Definition: plancache.h:150

◆ ReleaseGenericPlan()

static void ReleaseGenericPlan ( CachedPlanSource plansource)
static

Definition at line 525 of file plancache.c.

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

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

526 {
527  /* Be paranoid about the possibility that ReleaseCachedPlan fails */
528  if (plansource->gplan)
529  {
530  CachedPlan *plan = plansource->gplan;
531 
532  Assert(plan->magic == CACHEDPLAN_MAGIC);
533  plansource->gplan = NULL;
534  ReleaseCachedPlan(plan, false);
535  }
536 }
#define CACHEDPLAN_MAGIC
Definition: plancache.h:41
struct CachedPlan * gplan
Definition: plancache.h:121
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1260
#define Assert(condition)
Definition: c.h:738

◆ ResetPlanCache()

void ResetPlanCache ( void  )

Definition at line 2144 of file plancache.c.

References Assert, CACHEDEXPR_MAGIC, CACHEDPLANSOURCE_MAGIC, CMD_UTILITY, Query::commandType, dlist_iter::cur, dlist_container, dlist_foreach, CachedPlanSource::gplan, CachedPlanSource::is_valid, CachedPlan::is_valid, CachedExpression::is_valid, IsTransactionStmtPlan, lfirst_node, CachedPlanSource::magic, CachedExpression::magic, CachedPlanSource::query_list, UtilityContainsQuery(), and Query::utilityStmt.

Referenced by assign_session_replication_role(), DiscardAll(), DiscardCommand(), and PlanCacheSysCallback().

2145 {
2146  dlist_iter iter;
2147 
2149  {
2151  node, iter.cur);
2152  ListCell *lc;
2153 
2154  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2155 
2156  /* No work if it's already invalidated */
2157  if (!plansource->is_valid)
2158  continue;
2159 
2160  /*
2161  * We *must not* mark transaction control statements as invalid,
2162  * particularly not ROLLBACK, because they may need to be executed in
2163  * aborted transactions when we can't revalidate them (cf bug #5269).
2164  */
2165  if (IsTransactionStmtPlan(plansource))
2166  continue;
2167 
2168  /*
2169  * In general there is no point in invalidating utility statements
2170  * since they have no plans anyway. So invalidate it only if it
2171  * contains at least one non-utility statement, or contains a utility
2172  * statement that contains a pre-analyzed query (which could have
2173  * dependencies.)
2174  */
2175  foreach(lc, plansource->query_list)
2176  {
2177  Query *query = lfirst_node(Query, lc);
2178 
2179  if (query->commandType != CMD_UTILITY ||
2181  {
2182  /* non-utility statement, so invalidate */
2183  plansource->is_valid = false;
2184  if (plansource->gplan)
2185  plansource->gplan->is_valid = false;
2186  /* no need to look further */
2187  break;
2188  }
2189  }
2190  }
2191 
2192  /* Likewise invalidate cached expressions */
2194  {
2196  node, iter.cur);
2197 
2198  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2199 
2200  cexpr->is_valid = false;
2201  }
2202 }
bool is_valid
Definition: plancache.h:152
#define dlist_foreach(iter, lhead)
Definition: ilist.h:507
Node * utilityStmt
Definition: parsenodes.h:120
static dlist_head cached_expression_list
Definition: plancache.c:97
struct CachedPlan * gplan
Definition: plancache.h:121
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:2063
#define dlist_container(type, membername, ptr)
Definition: ilist.h:477
#define lfirst_node(type, lc)
Definition: pg_list.h:193
#define CACHEDEXPR_MAGIC
Definition: plancache.h:42
static dlist_head saved_plan_list
Definition: plancache.c:92
dlist_node * cur
Definition: ilist.h:161
CmdType commandType
Definition: parsenodes.h:112
#define Assert(condition)
Definition: c.h:738
List * query_list
Definition: plancache.h:111
#define IsTransactionStmtPlan(plansource)
Definition: plancache.c:82
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:40

◆ RevalidateCachedQuery()

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

Definition at line 553 of file plancache.c.

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(), GetOverrideSearchPath(), GetTransactionSnapshot(), GetUserId(), CachedPlanSource::gplan, CachedPlanSource::invalItems, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_valid, CachedPlan::is_valid, IsTransactionStmtPlan, MemoryContextDelete(), MemoryContextSetParent(), MemoryContextSwitchTo(), NIL, CachedPlanSource::num_params, OverrideSearchPathMatchesCurrent(), CachedPlanSource::param_types, CachedPlanSource::parserSetup, CachedPlanSource::parserSetupArg, pg_analyze_and_rewrite(), pg_analyze_and_rewrite_params(), 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, and CachedPlanSource::search_path.

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

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

◆ SaveCachedPlan()

void SaveCachedPlan ( CachedPlanSource plansource)

Definition at line 452 of file plancache.c.

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

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

453 {
454  /* Assert caller is doing things in a sane order */
455  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
456  Assert(plansource->is_complete);
457  Assert(!plansource->is_saved);
458 
459  /* This seems worth a real test, though */
460  if (plansource->is_oneshot)
461  elog(ERROR, "cannot save one-shot cached plan");
462 
463  /*
464  * In typical use, this function would be called before generating any
465  * plans from the CachedPlanSource. If there is a generic plan, moving it
466  * into CacheMemoryContext would be pretty risky since it's unclear
467  * whether the caller has taken suitable care with making references
468  * long-lived. Best thing to do seems to be to discard the plan.
469  */
470  ReleaseGenericPlan(plansource);
471 
472  /*
473  * Reparent the source memory context under CacheMemoryContext so that it
474  * will live indefinitely. The query_context follows along since it's
475  * already a child of the other one.
476  */
478 
479  /*
480  * Add the entry to the global list of cached plans.
481  */
482  dlist_push_tail(&saved_plan_list, &plansource->node);
483 
484  plansource->is_saved = true;
485 }
MemoryContext context
Definition: plancache.h:109
static void ReleaseGenericPlan(CachedPlanSource *plansource)
Definition: plancache.c:525
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:354
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:317
#define ERROR
Definition: elog.h:43
static dlist_head saved_plan_list
Definition: plancache.c:92
#define Assert(condition)
Definition: c.h:738
dlist_node node
Definition: plancache.h:129
#define elog(elevel,...)
Definition: elog.h:214
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:40
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ ScanQueryForLocks()

static void ScanQueryForLocks ( Query parsetree,
bool  acquire 
)
static

Definition at line 1818 of file plancache.c.

References Assert, castNode, CMD_UTILITY, Query::commandType, Query::cteList, CommonTableExpr::ctequery, Query::hasSubLinks, lfirst, lfirst_node, LockRelationOid(), 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().

1819 {
1820  ListCell *lc;
1821 
1822  /* Shouldn't get called on utility commands */
1823  Assert(parsetree->commandType != CMD_UTILITY);
1824 
1825  /*
1826  * First, process RTEs of the current query level.
1827  */
1828  foreach(lc, parsetree->rtable)
1829  {
1830  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
1831 
1832  switch (rte->rtekind)
1833  {
1834  case RTE_RELATION:
1835  /* Acquire or release the appropriate type of lock */
1836  if (acquire)
1837  LockRelationOid(rte->relid, rte->rellockmode);
1838  else
1839  UnlockRelationOid(rte->relid, rte->rellockmode);
1840  break;
1841 
1842  case RTE_SUBQUERY:
1843  /* Recurse into subquery-in-FROM */
1844  ScanQueryForLocks(rte->subquery, acquire);
1845  break;
1846 
1847  default:
1848  /* ignore other types of RTEs */
1849  break;
1850  }
1851  }
1852 
1853  /* Recurse into subquery-in-WITH */
1854  foreach(lc, parsetree->cteList)
1855  {
1857 
1858  ScanQueryForLocks(castNode(Query, cte->ctequery), acquire);
1859  }
1860 
1861  /*
1862  * Recurse into sublink subqueries, too. But we already did the ones in
1863  * the rtable and cteList.
1864  */
1865  if (parsetree->hasSubLinks)
1866  {
1868  (void *) &acquire,
1870  }
1871 }
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2273
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:199
#define castNode(_type_, nodeptr)
Definition: nodes.h:598
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition: plancache.c:1818
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:22
List * rtable
Definition: parsenodes.h:137
#define lfirst_node(type, lc)
Definition: pg_list.h:193
static bool ScanQueryWalker(Node *node, bool *acquire)
Definition: plancache.c:1877
CmdType commandType
Definition: parsenodes.h:112
#define Assert(condition)
Definition: c.h:738
#define lfirst(lc)
Definition: pg_list.h:190
RTEKind rtekind
Definition: parsenodes.h:976
List * cteList
Definition: parsenodes.h:135
Query * subquery
Definition: parsenodes.h:1011
bool hasSubLinks
Definition: parsenodes.h:128
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108

◆ ScanQueryWalker()

static bool ScanQueryWalker ( Node node,
bool acquire 
)
static

Definition at line 1877 of file plancache.c.

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

Referenced by ScanQueryForLocks().

1878 {
1879  if (node == NULL)
1880  return false;
1881  if (IsA(node, SubLink))
1882  {
1883  SubLink *sub = (SubLink *) node;
1884 
1885  /* Do what we came for */
1886  ScanQueryForLocks(castNode(Query, sub->subselect), *acquire);
1887  /* Fall through to process lefthand args of SubLink */
1888  }
1889 
1890  /*
1891  * Do NOT recurse into Query nodes, because ScanQueryForLocks already
1892  * processed subselects of subselects for us.
1893  */
1895  (void *) acquire);
1896 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
#define castNode(_type_, nodeptr)
Definition: nodes.h:598
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition: plancache.c:1818
static bool ScanQueryWalker(Node *node, bool *acquire)
Definition: plancache.c:1877
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1839

Variable Documentation

◆ cached_expression_list

dlist_head cached_expression_list = DLIST_STATIC_INIT(cached_expression_list)
static

Definition at line 97 of file plancache.c.

◆ plan_cache_mode

int plan_cache_mode

Definition at line 119 of file plancache.c.

Referenced by choose_custom_plan().

◆ saved_plan_list

dlist_head saved_plan_list = DLIST_STATIC_INIT(saved_plan_list)
static

Definition at line 92 of file plancache.c.