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:579
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 1743 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().

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

◆ AcquirePlannerLocks()

static void AcquirePlannerLocks ( List stmt_list,
bool  acquire 
)
static

Definition at line 1798 of file plancache.c.

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

Referenced by RevalidateCachedQuery().

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

◆ BuildCachedPlan()

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

Definition at line 879 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().

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

◆ cached_plan_cost()

static double cached_plan_cost ( CachedPlan plan,
bool  include_planner 
)
static

Definition at line 1076 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().

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

◆ CachedPlanAllowsSimpleValidityCheck()

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

Definition at line 1309 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().

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

◆ CachedPlanGetTargetList()

List* CachedPlanGetTargetList ( CachedPlanSource plansource,
QueryEnvironment queryEnv 
)

Definition at line 1611 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().

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

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

◆ CachedPlanIsValid()

bool CachedPlanIsValid ( CachedPlanSource plansource)

Definition at line 1598 of file plancache.c.

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

Referenced by SPI_plan_is_valid().

1599 {
1600  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1601  return plansource->is_valid;
1602 }
#define Assert(condition)
Definition: c.h:746
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:40

◆ CachedPlanSetParentContext()

void CachedPlanSetParentContext ( CachedPlanSource plansource,
MemoryContext  newcontext 
)

Definition at line 1469 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().

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

◆ CheckCachedPlan()

static bool CheckCachedPlan ( CachedPlanSource plansource)
static

Definition at line 795 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().

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

◆ choose_custom_plan()

static bool choose_custom_plan ( CachedPlanSource plansource,
ParamListInfo  boundParams 
)
static

Definition at line 1019 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().

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

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

◆ CopyCachedPlan()

CachedPlanSource* CopyCachedPlan ( CachedPlanSource plansource)

Definition at line 1507 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_generic_plans, CachedPlanSource::num_params, palloc(), palloc0(), CachedPlanSource::param_types, CachedPlanSource::parserSetup, CachedPlanSource::parserSetupArg, pstrdup(), CachedPlanSource::query_context, CachedPlanSource::query_list, CachedPlanSource::query_string, CachedPlanSource::raw_parse_tree, CachedPlanSource::relationOids, CachedPlanSource::resultDesc, CachedPlanSource::rewriteRoleId, CachedPlanSource::rewriteRowSecurity, CachedPlanSource::search_path, and CachedPlanSource::total_custom_cost.

Referenced by _SPI_save_plan().

1508 {
1509  CachedPlanSource *newsource;
1510  MemoryContext source_context;
1511  MemoryContext querytree_context;
1512  MemoryContext oldcxt;
1513 
1514  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1515  Assert(plansource->is_complete);
1516 
1517  /*
1518  * One-shot plans can't be copied, because we haven't taken care that
1519  * parsing/planning didn't scribble on the raw parse tree or querytrees.
1520  */
1521  if (plansource->is_oneshot)
1522  elog(ERROR, "cannot copy a one-shot cached plan");
1523 
1525  "CachedPlanSource",
1527 
1528  oldcxt = MemoryContextSwitchTo(source_context);
1529 
1530  newsource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
1531  newsource->magic = CACHEDPLANSOURCE_MAGIC;
1532  newsource->raw_parse_tree = copyObject(plansource->raw_parse_tree);
1533  newsource->query_string = pstrdup(plansource->query_string);
1534  MemoryContextSetIdentifier(source_context, newsource->query_string);
1535  newsource->commandTag = plansource->commandTag;
1536  if (plansource->num_params > 0)
1537  {
1538  newsource->param_types = (Oid *)
1539  palloc(plansource->num_params * sizeof(Oid));
1540  memcpy(newsource->param_types, plansource->param_types,
1541  plansource->num_params * sizeof(Oid));
1542  }
1543  else
1544  newsource->param_types = NULL;
1545  newsource->num_params = plansource->num_params;
1546  newsource->parserSetup = plansource->parserSetup;
1547  newsource->parserSetupArg = plansource->parserSetupArg;
1548  newsource->cursor_options = plansource->cursor_options;
1549  newsource->fixed_result = plansource->fixed_result;
1550  if (plansource->resultDesc)
1551  newsource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
1552  else
1553  newsource->resultDesc = NULL;
1554  newsource->context = source_context;
1555 
1556  querytree_context = AllocSetContextCreate(source_context,
1557  "CachedPlanQuery",
1559  MemoryContextSwitchTo(querytree_context);
1560  newsource->query_list = copyObject(plansource->query_list);
1561  newsource->relationOids = copyObject(plansource->relationOids);
1562  newsource->invalItems = copyObject(plansource->invalItems);
1563  if (plansource->search_path)
1564  newsource->search_path = CopyOverrideSearchPath(plansource->search_path);
1565  newsource->query_context = querytree_context;
1566  newsource->rewriteRoleId = plansource->rewriteRoleId;
1567  newsource->rewriteRowSecurity = plansource->rewriteRowSecurity;
1568  newsource->dependsOnRLS = plansource->dependsOnRLS;
1569 
1570  newsource->gplan = NULL;
1571 
1572  newsource->is_oneshot = false;
1573  newsource->is_complete = true;
1574  newsource->is_saved = false;
1575  newsource->is_valid = plansource->is_valid;
1576  newsource->generation = plansource->generation;
1577 
1578  /* We may as well copy any acquired cost knowledge */
1579  newsource->generic_cost = plansource->generic_cost;
1580  newsource->total_custom_cost = plansource->total_custom_cost;
1581  newsource->num_generic_plans = plansource->num_generic_plans;
1582  newsource->num_custom_plans = plansource->num_custom_plans;
1583 
1584  MemoryContextSwitchTo(oldcxt);
1585 
1586  return newsource;
1587 }
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:1187
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
int64 num_custom_plans
Definition: plancache.h:133
TupleDesc resultDesc
Definition: plancache.h:108
#define ERROR
Definition: elog.h:43
OverrideSearchPath * CopyOverrideSearchPath(OverrideSearchPath *path)
Definition: namespace.c:3396
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:981
int64 num_generic_plans
Definition: plancache.h:134
double generic_cost
Definition: plancache.h:131
#define Assert(condition)
Definition: c.h:746
const char * query_string
Definition: plancache.h:100
CommandTag commandTag
Definition: plancache.h:101
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:330
struct RawStmt * raw_parse_tree
Definition: plancache.h:99
void * palloc(Size size)
Definition: mcxt.c:950
#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:644
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_generic_plans, CachedPlanSource::num_params, palloc0(), CachedPlanSource::param_types, CachedPlanSource::parserSetup, CachedPlanSource::parserSetupArg, pstrdup(), CachedPlanSource::query_context, CachedPlanSource::query_list, CachedPlanSource::query_string, CachedPlanSource::raw_parse_tree, CachedPlanSource::relationOids, CachedPlanSource::resultDesc, CachedPlanSource::rewriteRoleId, CachedPlanSource::rewriteRowSecurity, CachedPlanSource::search_path, and CachedPlanSource::total_custom_cost.

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

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_generic_plans = 0;
222  plansource->num_custom_plans = 0;
223 
224  MemoryContextSwitchTo(oldcxt);
225 
226  return plansource;
227 }
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:1187
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
double total_custom_cost
Definition: plancache.h:132
struct CachedPlan * gplan
Definition: plancache.h:121
int64 num_custom_plans
Definition: plancache.h:133
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:981
int64 num_generic_plans
Definition: plancache.h:134
#define InvalidOid
Definition: postgres_ext.h:36
double generic_cost
Definition: plancache.h:131
#define Assert(condition)
Definition: c.h:746
const char * query_string
Definition: plancache.h:100
CommandTag commandTag
Definition: plancache.h:101
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:330
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:644
struct OverrideSearchPath * search_path
Definition: plancache.h:114

◆ CreateOneShotCachedPlan()

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

Definition at line 248 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_generic_plans, CachedPlanSource::num_params, palloc0(), CachedPlanSource::param_types, CachedPlanSource::parserSetup, CachedPlanSource::parserSetupArg, CachedPlanSource::query_context, CachedPlanSource::query_list, CachedPlanSource::query_string, CachedPlanSource::raw_parse_tree, CachedPlanSource::relationOids, CachedPlanSource::resultDesc, CachedPlanSource::rewriteRoleId, CachedPlanSource::rewriteRowSecurity, CachedPlanSource::search_path, and CachedPlanSource::total_custom_cost.

Referenced by _SPI_prepare_oneshot_plan().

251 {
252  CachedPlanSource *plansource;
253 
254  Assert(query_string != NULL); /* required as of 8.4 */
255 
256  /*
257  * Create and fill the CachedPlanSource struct within the caller's memory
258  * context. Most fields are just left empty for the moment.
259  */
260  plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
261  plansource->magic = CACHEDPLANSOURCE_MAGIC;
262  plansource->raw_parse_tree = raw_parse_tree;
263  plansource->query_string = query_string;
264  plansource->commandTag = commandTag;
265  plansource->param_types = NULL;
266  plansource->num_params = 0;
267  plansource->parserSetup = NULL;
268  plansource->parserSetupArg = NULL;
269  plansource->cursor_options = 0;
270  plansource->fixed_result = false;
271  plansource->resultDesc = NULL;
272  plansource->context = CurrentMemoryContext;
273  plansource->query_list = NIL;
274  plansource->relationOids = NIL;
275  plansource->invalItems = NIL;
276  plansource->search_path = NULL;
277  plansource->query_context = NULL;
278  plansource->rewriteRoleId = InvalidOid;
279  plansource->rewriteRowSecurity = false;
280  plansource->dependsOnRLS = false;
281  plansource->gplan = NULL;
282  plansource->is_oneshot = true;
283  plansource->is_complete = false;
284  plansource->is_saved = false;
285  plansource->is_valid = false;
286  plansource->generation = 0;
287  plansource->generic_cost = -1;
288  plansource->total_custom_cost = 0;
289  plansource->num_generic_plans = 0;
290  plansource->num_custom_plans = 0;
291 
292  return plansource;
293 }
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
int64 num_custom_plans
Definition: plancache.h:133
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:981
int64 num_generic_plans
Definition: plancache.h:134
#define InvalidOid
Definition: postgres_ext.h:36
double generic_cost
Definition: plancache.h:131
#define Assert(condition)
Definition: c.h:746
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 498 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().

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

◆ FreeCachedExpression()

void FreeCachedExpression ( CachedExpression cexpr)

Definition at line 1705 of file plancache.c.

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

Referenced by get_cast_hashentry().

1706 {
1707  /* Sanity check */
1708  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
1709  /* Unlink from global list */
1710  dlist_delete(&cexpr->node);
1711  /* Free all storage associated with CachedExpression */
1712  MemoryContextDelete(cexpr->context);
1713 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:212
MemoryContext context
Definition: plancache.h:183
#define CACHEDEXPR_MAGIC
Definition: plancache.h:42
static void dlist_delete(dlist_node *node)
Definition: ilist.h:358
#define Assert(condition)
Definition: c.h:746
dlist_node node
Definition: plancache.h:184

◆ GetCachedExpression()

CachedExpression* GetCachedExpression ( Node expr)

Definition at line 1648 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().

1649 {
1650  CachedExpression *cexpr;
1651  List *relationOids;
1652  List *invalItems;
1653  MemoryContext cexpr_context;
1654  MemoryContext oldcxt;
1655 
1656  /*
1657  * Pass the expression through the planner, and collect dependencies.
1658  * Everything built here is leaked in the caller's context; that's
1659  * intentional to minimize the size of the permanent data structure.
1660  */
1661  expr = (Node *) expression_planner_with_deps((Expr *) expr,
1662  &relationOids,
1663  &invalItems);
1664 
1665  /*
1666  * Make a private memory context, and copy what we need into that. To
1667  * avoid leaking a long-lived context if we fail while copying data, we
1668  * initially make the context under the caller's context.
1669  */
1671  "CachedExpression",
1673 
1674  oldcxt = MemoryContextSwitchTo(cexpr_context);
1675 
1676  cexpr = (CachedExpression *) palloc(sizeof(CachedExpression));
1677  cexpr->magic = CACHEDEXPR_MAGIC;
1678  cexpr->expr = copyObject(expr);
1679  cexpr->is_valid = true;
1680  cexpr->relationOids = copyObject(relationOids);
1681  cexpr->invalItems = copyObject(invalItems);
1682  cexpr->context = cexpr_context;
1683 
1684  MemoryContextSwitchTo(oldcxt);
1685 
1686  /*
1687  * Reparent the expr's memory context under CacheMemoryContext so that it
1688  * will live indefinitely.
1689  */
1691 
1692  /*
1693  * Add the entry to the global list of cached expressions.
1694  */
1696 
1697  return cexpr;
1698 }
#define AllocSetContextCreate
Definition: memutils.h:170
MemoryContext context
Definition: plancache.h:183
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:355
#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:528
static dlist_head cached_expression_list
Definition: plancache.c:97
List * relationOids
Definition: plancache.h:181
List * invalItems
Definition: plancache.h:182
#define CACHEDEXPR_MAGIC
Definition: plancache.h:42
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
dlist_node node
Definition: plancache.h:184
Expr * expression_planner_with_deps(Expr *expr, List **relationOids, List **invalItems)
Definition: planner.c:6201
void * palloc(Size size)
Definition: mcxt.c:950
#define copyObject(obj)
Definition: nodes.h:644
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 1141 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, CachedPlanSource::num_generic_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().

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

◆ 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:2031
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition: inval.c:1476
static void PlanCacheRelCallback(Datum arg, Oid relid)
Definition: plancache.c:1947
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1434
uintptr_t Datum
Definition: postgres.h:367
static void PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:2140

◆ PlanCacheComputeResultDesc()

static TupleDesc PlanCacheComputeResultDesc ( List stmt_list)
static

Definition at line 1911 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().

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

◆ PlanCacheObjectCallback()

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

Definition at line 2031 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().

2032 {
2033  dlist_iter iter;
2034 
2036  {
2038  node, iter.cur);
2039  ListCell *lc;
2040 
2041  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2042 
2043  /* No work if it's already invalidated */
2044  if (!plansource->is_valid)
2045  continue;
2046 
2047  /* Never invalidate transaction control commands */
2048  if (IsTransactionStmtPlan(plansource))
2049  continue;
2050 
2051  /*
2052  * Check the dependency list for the rewritten querytree.
2053  */
2054  foreach(lc, plansource->invalItems)
2055  {
2056  PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2057 
2058  if (item->cacheId != cacheid)
2059  continue;
2060  if (hashvalue == 0 ||
2061  item->hashValue == hashvalue)
2062  {
2063  /* Invalidate the querytree and generic plan */
2064  plansource->is_valid = false;
2065  if (plansource->gplan)
2066  plansource->gplan->is_valid = false;
2067  break;
2068  }
2069  }
2070 
2071  /*
2072  * The generic plan, if any, could have more dependencies than the
2073  * querytree does, so we have to check it too.
2074  */
2075  if (plansource->gplan && plansource->gplan->is_valid)
2076  {
2077  foreach(lc, plansource->gplan->stmt_list)
2078  {
2079  PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2080  ListCell *lc3;
2081 
2082  if (plannedstmt->commandType == CMD_UTILITY)
2083  continue; /* Ignore utility statements */
2084  foreach(lc3, plannedstmt->invalItems)
2085  {
2086  PlanInvalItem *item = (PlanInvalItem *) lfirst(lc3);
2087 
2088  if (item->cacheId != cacheid)
2089  continue;
2090  if (hashvalue == 0 ||
2091  item->hashValue == hashvalue)
2092  {
2093  /* Invalidate the generic plan only */
2094  plansource->gplan->is_valid = false;
2095  break; /* out of invalItems scan */
2096  }
2097  }
2098  if (!plansource->gplan->is_valid)
2099  break; /* out of stmt_list scan */
2100  }
2101  }
2102  }
2103 
2104  /* Likewise check cached expressions */
2106  {
2108  node, iter.cur);
2109  ListCell *lc;
2110 
2111  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2112 
2113  /* No work if it's already invalidated */
2114  if (!cexpr->is_valid)
2115  continue;
2116 
2117  foreach(lc, cexpr->invalItems)
2118  {
2119  PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2120 
2121  if (item->cacheId != cacheid)
2122  continue;
2123  if (hashvalue == 0 ||
2124  item->hashValue == hashvalue)
2125  {
2126  cexpr->is_valid = false;
2127  break;
2128  }
2129  }
2130  }
2131 }
bool is_valid
Definition: plancache.h:153
#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:82
List * invalItems
Definition: plancache.h:182
#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:172
#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:746
#define lfirst(lc)
Definition: pg_list.h:169
List * stmt_list
Definition: plancache.h:150
#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 1947 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().

1948 {
1949  dlist_iter iter;
1950 
1952  {
1954  node, iter.cur);
1955 
1956  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1957 
1958  /* No work if it's already invalidated */
1959  if (!plansource->is_valid)
1960  continue;
1961 
1962  /* Never invalidate transaction control commands */
1963  if (IsTransactionStmtPlan(plansource))
1964  continue;
1965 
1966  /*
1967  * Check the dependency list for the rewritten querytree.
1968  */
1969  if ((relid == InvalidOid) ? plansource->relationOids != NIL :
1970  list_member_oid(plansource->relationOids, relid))
1971  {
1972  /* Invalidate the querytree and generic plan */
1973  plansource->is_valid = false;
1974  if (plansource->gplan)
1975  plansource->gplan->is_valid = false;
1976  }
1977 
1978  /*
1979  * The generic plan, if any, could have more dependencies than the
1980  * querytree does, so we have to check it too.
1981  */
1982  if (plansource->gplan && plansource->gplan->is_valid)
1983  {
1984  ListCell *lc;
1985 
1986  foreach(lc, plansource->gplan->stmt_list)
1987  {
1988  PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1989 
1990  if (plannedstmt->commandType == CMD_UTILITY)
1991  continue; /* Ignore utility statements */
1992  if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
1993  list_member_oid(plannedstmt->relationOids, relid))
1994  {
1995  /* Invalidate the generic plan only */
1996  plansource->gplan->is_valid = false;
1997  break; /* out of stmt_list scan */
1998  }
1999  }
2000  }
2001  }
2002 
2003  /* Likewise check cached expressions */
2005  {
2007  node, iter.cur);
2008 
2009  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2010 
2011  /* No work if it's already invalidated */
2012  if (!cexpr->is_valid)
2013  continue;
2014 
2015  if ((relid == InvalidOid) ? cexpr->relationOids != NIL :
2016  list_member_oid(cexpr->relationOids, relid))
2017  {
2018  cexpr->is_valid = false;
2019  }
2020  }
2021 }
#define NIL
Definition: pg_list.h:65
bool is_valid
Definition: plancache.h:153
#define dlist_foreach(iter, lhead)
Definition: ilist.h:507
List * relationOids
Definition: plannodes.h:80
static dlist_head cached_expression_list
Definition: plancache.c:97
List * relationOids
Definition: plancache.h:181
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:172
#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:746
List * stmt_list
Definition: plancache.h:150
#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 2140 of file plancache.c.

References ResetPlanCache().

Referenced by InitPlanCache().

2141 {
2142  ResetPlanCache();
2143 }
void ResetPlanCache(void)
Definition: plancache.c:2149

◆ QueryListGetPrimaryStmt()

static Query * QueryListGetPrimaryStmt ( List stmts)
static

Definition at line 1724 of file plancache.c.

References Query::canSetTag, and lfirst_node.

Referenced by CachedPlanGetTargetList(), and PlanCacheComputeResultDesc().

1725 {
1726  ListCell *lc;
1727 
1728  foreach(lc, stmts)
1729  {
1730  Query *stmt = lfirst_node(Query, lc);
1731 
1732  if (stmt->canSetTag)
1733  return stmt;
1734  }
1735  return NULL;
1736 }
#define lfirst_node(type, lc)
Definition: pg_list.h:172
bool canSetTag
Definition: parsenodes.h:118

◆ ReleaseCachedPlan()

void ReleaseCachedPlan ( CachedPlan plan,
bool  useResOwner 
)

Definition at line 1264 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().

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

◆ ReleaseGenericPlan()

static void ReleaseGenericPlan ( CachedPlanSource plansource)
static

Definition at line 527 of file plancache.c.

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

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

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

◆ ResetPlanCache()

void ResetPlanCache ( void  )

Definition at line 2149 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().

2150 {
2151  dlist_iter iter;
2152 
2154  {
2156  node, iter.cur);
2157  ListCell *lc;
2158 
2159  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2160 
2161  /* No work if it's already invalidated */
2162  if (!plansource->is_valid)
2163  continue;
2164 
2165  /*
2166  * We *must not* mark transaction control statements as invalid,
2167  * particularly not ROLLBACK, because they may need to be executed in
2168  * aborted transactions when we can't revalidate them (cf bug #5269).
2169  */
2170  if (IsTransactionStmtPlan(plansource))
2171  continue;
2172 
2173  /*
2174  * In general there is no point in invalidating utility statements
2175  * since they have no plans anyway. So invalidate it only if it
2176  * contains at least one non-utility statement, or contains a utility
2177  * statement that contains a pre-analyzed query (which could have
2178  * dependencies.)
2179  */
2180  foreach(lc, plansource->query_list)
2181  {
2182  Query *query = lfirst_node(Query, lc);
2183 
2184  if (query->commandType != CMD_UTILITY ||
2186  {
2187  /* non-utility statement, so invalidate */
2188  plansource->is_valid = false;
2189  if (plansource->gplan)
2190  plansource->gplan->is_valid = false;
2191  /* no need to look further */
2192  break;
2193  }
2194  }
2195  }
2196 
2197  /* Likewise invalidate cached expressions */
2199  {
2201  node, iter.cur);
2202 
2203  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2204 
2205  cexpr->is_valid = false;
2206  }
2207 }
bool is_valid
Definition: plancache.h:153
#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:2110
#define dlist_container(type, membername, ptr)
Definition: ilist.h:477
#define lfirst_node(type, lc)
Definition: pg_list.h:172
#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:746
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 555 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().

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

◆ SaveCachedPlan()

void SaveCachedPlan ( CachedPlanSource plansource)

Definition at line 454 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().

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

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

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

Referenced by ScanQueryForLocks().

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

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.