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, const char *commandTag)
 
CachedPlanSourceCreateOneShotCachedPlan (RawStmt *raw_parse_tree, const char *query_string, const char *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)
 
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:576
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 1560 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().

1561 {
1562  ListCell *lc1;
1563 
1564  foreach(lc1, stmt_list)
1565  {
1566  PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
1567  ListCell *lc2;
1568 
1569  if (plannedstmt->commandType == CMD_UTILITY)
1570  {
1571  /*
1572  * Ignore utility statements, except those (such as EXPLAIN) that
1573  * contain a parsed-but-not-planned query. Note: it's okay to use
1574  * ScanQueryForLocks, even though the query hasn't been through
1575  * rule rewriting, because rewriting doesn't change the query
1576  * representation.
1577  */
1578  Query *query = UtilityContainsQuery(plannedstmt->utilityStmt);
1579 
1580  if (query)
1581  ScanQueryForLocks(query, acquire);
1582  continue;
1583  }
1584 
1585  foreach(lc2, plannedstmt->rtable)
1586  {
1587  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1588 
1589  if (rte->rtekind != RTE_RELATION)
1590  continue;
1591 
1592  /*
1593  * Acquire the appropriate type of lock on each relation OID. Note
1594  * that we don't actually try to open the rel, and hence will not
1595  * fail if it's been dropped entirely --- we'll just transiently
1596  * acquire a non-conflicting lock.
1597  */
1598  if (acquire)
1599  LockRelationOid(rte->relid, rte->rellockmode);
1600  else
1601  UnlockRelationOid(rte->relid, rte->rellockmode);
1602  }
1603  }
1604 }
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:199
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition: plancache.c:1640
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:1918
#define lfirst_node(type, lc)
Definition: pg_list.h:193
Node * utilityStmt
Definition: plannodes.h:90
CmdType commandType
Definition: plannodes.h:46
#define lfirst(lc)
Definition: pg_list.h:190
List * rtable
Definition: plannodes.h:66
RTEKind rtekind
Definition: parsenodes.h:974
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108

◆ AcquirePlannerLocks()

static void AcquirePlannerLocks ( List stmt_list,
bool  acquire 
)
static

Definition at line 1615 of file plancache.c.

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

Referenced by RevalidateCachedQuery().

1616 {
1617  ListCell *lc;
1618 
1619  foreach(lc, stmt_list)
1620  {
1621  Query *query = lfirst_node(Query, lc);
1622 
1623  if (query->commandType == CMD_UTILITY)
1624  {
1625  /* Ignore utility statements, unless they contain a Query */
1626  query = UtilityContainsQuery(query->utilityStmt);
1627  if (query)
1628  ScanQueryForLocks(query, acquire);
1629  continue;
1630  }
1631 
1632  ScanQueryForLocks(query, acquire);
1633  }
1634 }
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition: plancache.c:1640
Node * utilityStmt
Definition: parsenodes.h:120
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:1918
#define lfirst_node(type, lc)
Definition: pg_list.h:193
CmdType commandType
Definition: parsenodes.h:112

◆ BuildCachedPlan()

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

Definition at line 877 of file plancache.c.

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

Referenced by GetCachedPlan().

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

◆ cached_plan_cost()

static double cached_plan_cost ( CachedPlan plan,
bool  include_planner 
)
static

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

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

◆ CachedPlanGetTargetList()

List* CachedPlanGetTargetList ( CachedPlanSource plansource,
QueryEnvironment queryEnv 
)

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

1430 {
1431  Query *pstmt;
1432 
1433  /* Assert caller is doing things in a sane order */
1434  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1435  Assert(plansource->is_complete);
1436 
1437  /*
1438  * No work needed if statement doesn't return tuples (we assume this
1439  * feature cannot be changed by an invalidation)
1440  */
1441  if (plansource->resultDesc == NULL)
1442  return NIL;
1443 
1444  /* Make sure the querytree list is valid and we have parse-time locks */
1445  RevalidateCachedQuery(plansource, queryEnv);
1446 
1447  /* Get the primary statement and find out what it returns */
1448  pstmt = QueryListGetPrimaryStmt(plansource->query_list);
1449 
1450  return FetchStatementTargetList((Node *) pstmt);
1451 }
#define NIL
Definition: pg_list.h:65
Definition: nodes.h:525
TupleDesc resultDesc
Definition: plancache.h:105
List * FetchStatementTargetList(Node *stmt)
Definition: pquery.c:358
static Query * QueryListGetPrimaryStmt(List *stmts)
Definition: plancache.c:1541
static List * RevalidateCachedQuery(CachedPlanSource *plansource, QueryEnvironment *queryEnv)
Definition: plancache.c:553
#define Assert(condition)
Definition: c.h:732
List * query_list
Definition: plancache.h:108
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:37

◆ CachedPlanIsValid()

bool CachedPlanIsValid ( CachedPlanSource plansource)

Definition at line 1415 of file plancache.c.

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

Referenced by SPI_plan_is_valid().

1416 {
1417  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1418  return plansource->is_valid;
1419 }
#define Assert(condition)
Definition: c.h:732
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:37

◆ CachedPlanSetParentContext()

void CachedPlanSetParentContext ( CachedPlanSource plansource,
MemoryContext  newcontext 
)

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

1289 {
1290  /* Assert caller is doing things in a sane order */
1291  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1292  Assert(plansource->is_complete);
1293 
1294  /* These seem worth real tests, though */
1295  if (plansource->is_saved)
1296  elog(ERROR, "cannot move a saved cached plan to another context");
1297  if (plansource->is_oneshot)
1298  elog(ERROR, "cannot move a one-shot cached plan to another context");
1299 
1300  /* OK, let the caller keep the plan where he wishes */
1301  MemoryContextSetParent(plansource->context, newcontext);
1302 
1303  /*
1304  * The query_context needs no special handling, since it's a child of
1305  * plansource->context. But if there's a generic plan, it should be
1306  * maintained as a sibling of plansource->context.
1307  */
1308  if (plansource->gplan)
1309  {
1310  Assert(plansource->gplan->magic == CACHEDPLAN_MAGIC);
1311  MemoryContextSetParent(plansource->gplan->context, newcontext);
1312  }
1313 }
#define CACHEDPLAN_MAGIC
Definition: plancache.h:38
MemoryContext context
Definition: plancache.h:106
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:354
MemoryContext context
Definition: plancache.h:156
struct CachedPlan * gplan
Definition: plancache.h:118
#define ERROR
Definition: elog.h:43
#define Assert(condition)
Definition: c.h:732
#define elog(elevel,...)
Definition: elog.h:226
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:37

◆ CheckCachedPlan()

static bool CheckCachedPlan ( CachedPlanSource plansource)
static

Definition at line 793 of file plancache.c.

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

Referenced by GetCachedPlan().

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

◆ choose_custom_plan()

static bool choose_custom_plan ( CachedPlanSource plansource,
ParamListInfo  boundParams 
)
static

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

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

◆ CompleteCachedPlan()

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

Definition at line 336 of file plancache.c.

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

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

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

◆ CopyCachedPlan()

CachedPlanSource* CopyCachedPlan ( CachedPlanSource plansource)

Definition at line 1325 of file plancache.c.

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

Referenced by _SPI_save_plan().

1326 {
1327  CachedPlanSource *newsource;
1328  MemoryContext source_context;
1329  MemoryContext querytree_context;
1330  MemoryContext oldcxt;
1331 
1332  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1333  Assert(plansource->is_complete);
1334 
1335  /*
1336  * One-shot plans can't be copied, because we haven't taken care that
1337  * parsing/planning didn't scribble on the raw parse tree or querytrees.
1338  */
1339  if (plansource->is_oneshot)
1340  elog(ERROR, "cannot copy a one-shot cached plan");
1341 
1343  "CachedPlanSource",
1345 
1346  oldcxt = MemoryContextSwitchTo(source_context);
1347 
1348  newsource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
1349  newsource->magic = CACHEDPLANSOURCE_MAGIC;
1350  newsource->raw_parse_tree = copyObject(plansource->raw_parse_tree);
1351  newsource->query_string = pstrdup(plansource->query_string);
1352  MemoryContextSetIdentifier(source_context, newsource->query_string);
1353  newsource->commandTag = plansource->commandTag;
1354  if (plansource->num_params > 0)
1355  {
1356  newsource->param_types = (Oid *)
1357  palloc(plansource->num_params * sizeof(Oid));
1358  memcpy(newsource->param_types, plansource->param_types,
1359  plansource->num_params * sizeof(Oid));
1360  }
1361  else
1362  newsource->param_types = NULL;
1363  newsource->num_params = plansource->num_params;
1364  newsource->parserSetup = plansource->parserSetup;
1365  newsource->parserSetupArg = plansource->parserSetupArg;
1366  newsource->cursor_options = plansource->cursor_options;
1367  newsource->fixed_result = plansource->fixed_result;
1368  if (plansource->resultDesc)
1369  newsource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
1370  else
1371  newsource->resultDesc = NULL;
1372  newsource->context = source_context;
1373 
1374  querytree_context = AllocSetContextCreate(source_context,
1375  "CachedPlanQuery",
1377  MemoryContextSwitchTo(querytree_context);
1378  newsource->query_list = copyObject(plansource->query_list);
1379  newsource->relationOids = copyObject(plansource->relationOids);
1380  newsource->invalItems = copyObject(plansource->invalItems);
1381  if (plansource->search_path)
1382  newsource->search_path = CopyOverrideSearchPath(plansource->search_path);
1383  newsource->query_context = querytree_context;
1384  newsource->rewriteRoleId = plansource->rewriteRoleId;
1385  newsource->rewriteRowSecurity = plansource->rewriteRowSecurity;
1386  newsource->dependsOnRLS = plansource->dependsOnRLS;
1387 
1388  newsource->gplan = NULL;
1389 
1390  newsource->is_oneshot = false;
1391  newsource->is_complete = true;
1392  newsource->is_saved = false;
1393  newsource->is_valid = plansource->is_valid;
1394  newsource->generation = plansource->generation;
1395 
1396  /* We may as well copy any acquired cost knowledge */
1397  newsource->generic_cost = plansource->generic_cost;
1398  newsource->total_custom_cost = plansource->total_custom_cost;
1399  newsource->num_custom_plans = plansource->num_custom_plans;
1400 
1401  MemoryContextSwitchTo(oldcxt);
1402 
1403  return newsource;
1404 }
MemoryContext context
Definition: plancache.h:106
bool rewriteRowSecurity
Definition: plancache.h:115
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:110
#define AllocSetContextCreate
Definition: memutils.h:170
const char * commandTag
Definition: plancache.h:98
char * pstrdup(const char *in)
Definition: mcxt.c:1186
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
unsigned int Oid
Definition: postgres_ext.h:31
double total_custom_cost
Definition: plancache.h:129
struct CachedPlan * gplan
Definition: plancache.h:118
TupleDesc resultDesc
Definition: plancache.h:105
#define ERROR
Definition: elog.h:43
OverrideSearchPath * CopyOverrideSearchPath(OverrideSearchPath *path)
Definition: namespace.c:3388
List * invalItems
Definition: plancache.h:110
Oid * param_types
Definition: plancache.h:99
List * relationOids
Definition: plancache.h:109
void * parserSetupArg
Definition: plancache.h:102
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
ParserSetupHook parserSetup
Definition: plancache.h:101
void * palloc0(Size size)
Definition: mcxt.c:980
double generic_cost
Definition: plancache.h:128
#define Assert(condition)
Definition: c.h:732
const char * query_string
Definition: plancache.h:97
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:329
struct RawStmt * raw_parse_tree
Definition: plancache.h:96
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:226
MemoryContext query_context
Definition: plancache.h:113
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:209
List * query_list
Definition: plancache.h:108
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:37
#define copyObject(obj)
Definition: nodes.h:641
struct OverrideSearchPath * search_path
Definition: plancache.h:111

◆ CreateCachedPlan()

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

Definition at line 164 of file plancache.c.

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

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

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

◆ CreateOneShotCachedPlan()

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

Definition at line 247 of file plancache.c.

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

Referenced by _SPI_prepare_oneshot_plan().

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

◆ DropCachedPlan()

void DropCachedPlan ( CachedPlanSource plansource)

Definition at line 496 of file plancache.c.

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

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

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

◆ FreeCachedExpression()

void FreeCachedExpression ( CachedExpression cexpr)

Definition at line 1522 of file plancache.c.

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

Referenced by get_cast_hashentry().

1523 {
1524  /* Sanity check */
1525  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
1526  /* Unlink from global list */
1527  dlist_delete(&cexpr->node);
1528  /* Free all storage associated with CachedExpression */
1529  MemoryContextDelete(cexpr->context);
1530 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
MemoryContext context
Definition: plancache.h:179
#define CACHEDEXPR_MAGIC
Definition: plancache.h:39
static void dlist_delete(dlist_node *node)
Definition: ilist.h:358
#define Assert(condition)
Definition: c.h:732
dlist_node node
Definition: plancache.h:180

◆ GetCachedExpression()

CachedExpression* GetCachedExpression ( Node expr)

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

1466 {
1467  CachedExpression *cexpr;
1468  List *relationOids;
1469  List *invalItems;
1470  MemoryContext cexpr_context;
1471  MemoryContext oldcxt;
1472 
1473  /*
1474  * Pass the expression through the planner, and collect dependencies.
1475  * Everything built here is leaked in the caller's context; that's
1476  * intentional to minimize the size of the permanent data structure.
1477  */
1478  expr = (Node *) expression_planner_with_deps((Expr *) expr,
1479  &relationOids,
1480  &invalItems);
1481 
1482  /*
1483  * Make a private memory context, and copy what we need into that. To
1484  * avoid leaking a long-lived context if we fail while copying data, we
1485  * initially make the context under the caller's context.
1486  */
1488  "CachedExpression",
1490 
1491  oldcxt = MemoryContextSwitchTo(cexpr_context);
1492 
1493  cexpr = (CachedExpression *) palloc(sizeof(CachedExpression));
1494  cexpr->magic = CACHEDEXPR_MAGIC;
1495  cexpr->expr = copyObject(expr);
1496  cexpr->is_valid = true;
1497  cexpr->relationOids = copyObject(relationOids);
1498  cexpr->invalItems = copyObject(invalItems);
1499  cexpr->context = cexpr_context;
1500 
1501  MemoryContextSwitchTo(oldcxt);
1502 
1503  /*
1504  * Reparent the expr's memory context under CacheMemoryContext so that it
1505  * will live indefinitely.
1506  */
1508 
1509  /*
1510  * Add the entry to the global list of cached expressions.
1511  */
1513 
1514  return cexpr;
1515 }
#define AllocSetContextCreate
Definition: memutils.h:170
MemoryContext context
Definition: plancache.h:179
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:354
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:317
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Definition: nodes.h:525
static dlist_head cached_expression_list
Definition: plancache.c:97
List * relationOids
Definition: plancache.h:177
List * invalItems
Definition: plancache.h:178
#define CACHEDEXPR_MAGIC
Definition: plancache.h:39
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
dlist_node node
Definition: plancache.h:180
Expr * expression_planner_with_deps(Expr *expr, List **relationOids, List **invalItems)
Definition: planner.c:6073
void * palloc(Size size)
Definition: mcxt.c:949
#define copyObject(obj)
Definition: nodes.h:641
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 1138 of file plancache.c.

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

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

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

◆ 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:1848
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition: inval.c:1468
static void PlanCacheRelCallback(Datum arg, Oid relid)
Definition: plancache.c:1764
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1426
uintptr_t Datum
Definition: postgres.h:367
static void PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:1957

◆ PlanCacheComputeResultDesc()

static TupleDesc PlanCacheComputeResultDesc ( List stmt_list)
static

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

1729 {
1730  Query *query;
1731 
1732  switch (ChoosePortalStrategy(stmt_list))
1733  {
1734  case PORTAL_ONE_SELECT:
1735  case PORTAL_ONE_MOD_WITH:
1736  query = linitial_node(Query, stmt_list);
1737  return ExecCleanTypeFromTL(query->targetList);
1738 
1739  case PORTAL_ONE_RETURNING:
1740  query = QueryListGetPrimaryStmt(stmt_list);
1741  Assert(query->returningList);
1742  return ExecCleanTypeFromTL(query->returningList);
1743 
1744  case PORTAL_UTIL_SELECT:
1745  query = linitial_node(Query, stmt_list);
1746  Assert(query->utilityStmt);
1747  return UtilityTupleDescriptor(query->utilityStmt);
1748 
1749  case PORTAL_MULTI_QUERY:
1750  /* will not return tuples */
1751  break;
1752  }
1753  return NULL;
1754 }
TupleDesc ExecCleanTypeFromTL(List *targetList)
Definition: execTuples.c:1916
Node * utilityStmt
Definition: parsenodes.h:120
#define linitial_node(type, l)
Definition: pg_list.h:198
List * targetList
Definition: parsenodes.h:140
static Query * QueryListGetPrimaryStmt(List *stmts)
Definition: plancache.c:1541
List * returningList
Definition: parsenodes.h:146
#define Assert(condition)
Definition: c.h:732
PortalStrategy ChoosePortalStrategy(List *stmts)
Definition: pquery.c:219
TupleDesc UtilityTupleDescriptor(Node *parsetree)
Definition: utility.c:1824

◆ PlanCacheObjectCallback()

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

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

1849 {
1850  dlist_iter iter;
1851 
1853  {
1855  node, iter.cur);
1856  ListCell *lc;
1857 
1858  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1859 
1860  /* No work if it's already invalidated */
1861  if (!plansource->is_valid)
1862  continue;
1863 
1864  /* Never invalidate transaction control commands */
1865  if (IsTransactionStmtPlan(plansource))
1866  continue;
1867 
1868  /*
1869  * Check the dependency list for the rewritten querytree.
1870  */
1871  foreach(lc, plansource->invalItems)
1872  {
1873  PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
1874 
1875  if (item->cacheId != cacheid)
1876  continue;
1877  if (hashvalue == 0 ||
1878  item->hashValue == hashvalue)
1879  {
1880  /* Invalidate the querytree and generic plan */
1881  plansource->is_valid = false;
1882  if (plansource->gplan)
1883  plansource->gplan->is_valid = false;
1884  break;
1885  }
1886  }
1887 
1888  /*
1889  * The generic plan, if any, could have more dependencies than the
1890  * querytree does, so we have to check it too.
1891  */
1892  if (plansource->gplan && plansource->gplan->is_valid)
1893  {
1894  foreach(lc, plansource->gplan->stmt_list)
1895  {
1896  PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1897  ListCell *lc3;
1898 
1899  if (plannedstmt->commandType == CMD_UTILITY)
1900  continue; /* Ignore utility statements */
1901  foreach(lc3, plannedstmt->invalItems)
1902  {
1903  PlanInvalItem *item = (PlanInvalItem *) lfirst(lc3);
1904 
1905  if (item->cacheId != cacheid)
1906  continue;
1907  if (hashvalue == 0 ||
1908  item->hashValue == hashvalue)
1909  {
1910  /* Invalidate the generic plan only */
1911  plansource->gplan->is_valid = false;
1912  break; /* out of invalItems scan */
1913  }
1914  }
1915  if (!plansource->gplan->is_valid)
1916  break; /* out of stmt_list scan */
1917  }
1918  }
1919  }
1920 
1921  /* Likewise check cached expressions */
1923  {
1925  node, iter.cur);
1926  ListCell *lc;
1927 
1928  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
1929 
1930  /* No work if it's already invalidated */
1931  if (!cexpr->is_valid)
1932  continue;
1933 
1934  foreach(lc, cexpr->invalItems)
1935  {
1936  PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
1937 
1938  if (item->cacheId != cacheid)
1939  continue;
1940  if (hashvalue == 0 ||
1941  item->hashValue == hashvalue)
1942  {
1943  cexpr->is_valid = false;
1944  break;
1945  }
1946  }
1947  }
1948 }
bool is_valid
Definition: plancache.h:149
#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:118
List * invalItems
Definition: plannodes.h:86
List * invalItems
Definition: plancache.h:178
#define dlist_container(type, membername, ptr)
Definition: ilist.h:477
List * invalItems
Definition: plancache.h:110
#define lfirst_node(type, lc)
Definition: pg_list.h:193
#define CACHEDEXPR_MAGIC
Definition: plancache.h:39
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:1228
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
List * stmt_list
Definition: plancache.h:146
#define IsTransactionStmtPlan(plansource)
Definition: plancache.c:82
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:37

◆ PlanCacheRelCallback()

static void PlanCacheRelCallback ( Datum  arg,
Oid  relid 
)
static

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

1765 {
1766  dlist_iter iter;
1767 
1769  {
1771  node, iter.cur);
1772 
1773  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1774 
1775  /* No work if it's already invalidated */
1776  if (!plansource->is_valid)
1777  continue;
1778 
1779  /* Never invalidate transaction control commands */
1780  if (IsTransactionStmtPlan(plansource))
1781  continue;
1782 
1783  /*
1784  * Check the dependency list for the rewritten querytree.
1785  */
1786  if ((relid == InvalidOid) ? plansource->relationOids != NIL :
1787  list_member_oid(plansource->relationOids, relid))
1788  {
1789  /* Invalidate the querytree and generic plan */
1790  plansource->is_valid = false;
1791  if (plansource->gplan)
1792  plansource->gplan->is_valid = false;
1793  }
1794 
1795  /*
1796  * The generic plan, if any, could have more dependencies than the
1797  * querytree does, so we have to check it too.
1798  */
1799  if (plansource->gplan && plansource->gplan->is_valid)
1800  {
1801  ListCell *lc;
1802 
1803  foreach(lc, plansource->gplan->stmt_list)
1804  {
1805  PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1806 
1807  if (plannedstmt->commandType == CMD_UTILITY)
1808  continue; /* Ignore utility statements */
1809  if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
1810  list_member_oid(plannedstmt->relationOids, relid))
1811  {
1812  /* Invalidate the generic plan only */
1813  plansource->gplan->is_valid = false;
1814  break; /* out of stmt_list scan */
1815  }
1816  }
1817  }
1818  }
1819 
1820  /* Likewise check cached expressions */
1822  {
1824  node, iter.cur);
1825 
1826  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
1827 
1828  /* No work if it's already invalidated */
1829  if (!cexpr->is_valid)
1830  continue;
1831 
1832  if ((relid == InvalidOid) ? cexpr->relationOids != NIL :
1833  list_member_oid(cexpr->relationOids, relid))
1834  {
1835  cexpr->is_valid = false;
1836  }
1837  }
1838 }
#define NIL
Definition: pg_list.h:65
bool is_valid
Definition: plancache.h:149
#define dlist_foreach(iter, lhead)
Definition: ilist.h:507
List * relationOids
Definition: plannodes.h:84
static dlist_head cached_expression_list
Definition: plancache.c:97
List * relationOids
Definition: plancache.h:177
struct CachedPlan * gplan
Definition: plancache.h:118
#define dlist_container(type, membername, ptr)
Definition: ilist.h:477
#define lfirst_node(type, lc)
Definition: pg_list.h:193
#define CACHEDEXPR_MAGIC
Definition: plancache.h:39
List * relationOids
Definition: plancache.h:109
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:675
#define Assert(condition)
Definition: c.h:732
List * stmt_list
Definition: plancache.h:146
#define IsTransactionStmtPlan(plansource)
Definition: plancache.c:82
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:37

◆ PlanCacheSysCallback()

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

Definition at line 1957 of file plancache.c.

References ResetPlanCache().

Referenced by InitPlanCache().

1958 {
1959  ResetPlanCache();
1960 }
void ResetPlanCache(void)
Definition: plancache.c:1966

◆ QueryListGetPrimaryStmt()

static Query * QueryListGetPrimaryStmt ( List stmts)
static

Definition at line 1541 of file plancache.c.

References Query::canSetTag, and lfirst_node.

Referenced by CachedPlanGetTargetList(), and PlanCacheComputeResultDesc().

1542 {
1543  ListCell *lc;
1544 
1545  foreach(lc, stmts)
1546  {
1547  Query *stmt = lfirst_node(Query, lc);
1548 
1549  if (stmt->canSetTag)
1550  return stmt;
1551  }
1552  return NULL;
1553 }
#define lfirst_node(type, lc)
Definition: pg_list.h:193
bool canSetTag
Definition: parsenodes.h:118

◆ ReleaseCachedPlan()

void ReleaseCachedPlan ( CachedPlan plan,
bool  useResOwner 
)

Definition at line 1259 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(), ResourceOwnerReleaseInternal(), and SPI_cursor_open_internal().

1260 {
1261  Assert(plan->magic == CACHEDPLAN_MAGIC);
1262  if (useResOwner)
1263  {
1264  Assert(plan->is_saved);
1266  }
1267  Assert(plan->refcount > 0);
1268  plan->refcount--;
1269  if (plan->refcount == 0)
1270  {
1271  /* Mark it no longer valid */
1272  plan->magic = 0;
1273 
1274  /* One-shot plans do not own their context, so we can't free them */
1275  if (!plan->is_oneshot)
1277  }
1278 }
#define CACHEDPLAN_MAGIC
Definition: plancache.h:38
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
int refcount
Definition: plancache.h:155
MemoryContext context
Definition: plancache.h:156
void ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
Definition: resowner.c:1117
bool is_saved
Definition: plancache.h:148
#define Assert(condition)
Definition: c.h:732
bool is_oneshot
Definition: plancache.h:147

◆ ReleaseGenericPlan()

static void ReleaseGenericPlan ( CachedPlanSource plansource)
static

Definition at line 525 of file plancache.c.

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

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

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

◆ ResetPlanCache()

void ResetPlanCache ( void  )

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

1967 {
1968  dlist_iter iter;
1969 
1971  {
1973  node, iter.cur);
1974  ListCell *lc;
1975 
1976  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1977 
1978  /* No work if it's already invalidated */
1979  if (!plansource->is_valid)
1980  continue;
1981 
1982  /*
1983  * We *must not* mark transaction control statements as invalid,
1984  * particularly not ROLLBACK, because they may need to be executed in
1985  * aborted transactions when we can't revalidate them (cf bug #5269).
1986  */
1987  if (IsTransactionStmtPlan(plansource))
1988  continue;
1989 
1990  /*
1991  * In general there is no point in invalidating utility statements
1992  * since they have no plans anyway. So invalidate it only if it
1993  * contains at least one non-utility statement, or contains a utility
1994  * statement that contains a pre-analyzed query (which could have
1995  * dependencies.)
1996  */
1997  foreach(lc, plansource->query_list)
1998  {
1999  Query *query = lfirst_node(Query, lc);
2000 
2001  if (query->commandType != CMD_UTILITY ||
2003  {
2004  /* non-utility statement, so invalidate */
2005  plansource->is_valid = false;
2006  if (plansource->gplan)
2007  plansource->gplan->is_valid = false;
2008  /* no need to look further */
2009  break;
2010  }
2011  }
2012  }
2013 
2014  /* Likewise invalidate cached expressions */
2016  {
2018  node, iter.cur);
2019 
2020  Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2021 
2022  cexpr->is_valid = false;
2023  }
2024 }
bool is_valid
Definition: plancache.h:149
#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:118
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:1918
#define dlist_container(type, membername, ptr)
Definition: ilist.h:477
#define lfirst_node(type, lc)
Definition: pg_list.h:193
#define CACHEDEXPR_MAGIC
Definition: plancache.h:39
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:732
List * query_list
Definition: plancache.h:108
#define IsTransactionStmtPlan(plansource)
Definition: plancache.c:82
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:37

◆ RevalidateCachedQuery()

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

Definition at line 553 of file plancache.c.

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

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

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

◆ SaveCachedPlan()

void SaveCachedPlan ( CachedPlanSource plansource)

Definition at line 452 of file plancache.c.

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

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

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

◆ ScanQueryForLocks()

static void ScanQueryForLocks ( Query parsetree,
bool  acquire 
)
static

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

1641 {
1642  ListCell *lc;
1643 
1644  /* Shouldn't get called on utility commands */
1645  Assert(parsetree->commandType != CMD_UTILITY);
1646 
1647  /*
1648  * First, process RTEs of the current query level.
1649  */
1650  foreach(lc, parsetree->rtable)
1651  {
1652  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
1653 
1654  switch (rte->rtekind)
1655  {
1656  case RTE_RELATION:
1657  /* Acquire or release the appropriate type of lock */
1658  if (acquire)
1659  LockRelationOid(rte->relid, rte->rellockmode);
1660  else
1661  UnlockRelationOid(rte->relid, rte->rellockmode);
1662  break;
1663 
1664  case RTE_SUBQUERY:
1665  /* Recurse into subquery-in-FROM */
1666  ScanQueryForLocks(rte->subquery, acquire);
1667  break;
1668 
1669  default:
1670  /* ignore other types of RTEs */
1671  break;
1672  }
1673  }
1674 
1675  /* Recurse into subquery-in-WITH */
1676  foreach(lc, parsetree->cteList)
1677  {
1679 
1680  ScanQueryForLocks(castNode(Query, cte->ctequery), acquire);
1681  }
1682 
1683  /*
1684  * Recurse into sublink subqueries, too. But we already did the ones in
1685  * the rtable and cteList.
1686  */
1687  if (parsetree->hasSubLinks)
1688  {
1690  (void *) &acquire,
1692  }
1693 }
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2274
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:199
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition: plancache.c:1640
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:22
List * rtable
Definition: parsenodes.h:137
#define lfirst_node(type, lc)
Definition: pg_list.h:193
static bool ScanQueryWalker(Node *node, bool *acquire)
Definition: plancache.c:1699
CmdType commandType
Definition: parsenodes.h:112
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
RTEKind rtekind
Definition: parsenodes.h:974
List * cteList
Definition: parsenodes.h:135
Query * subquery
Definition: parsenodes.h:1009
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 1699 of file plancache.c.

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

Referenced by ScanQueryForLocks().

1700 {
1701  if (node == NULL)
1702  return false;
1703  if (IsA(node, SubLink))
1704  {
1705  SubLink *sub = (SubLink *) node;
1706 
1707  /* Do what we came for */
1708  ScanQueryForLocks(castNode(Query, sub->subselect), *acquire);
1709  /* Fall through to process lefthand args of SubLink */
1710  }
1711 
1712  /*
1713  * Do NOT recurse into Query nodes, because ScanQueryForLocks already
1714  * processed subselects of subselects for us.
1715  */
1717  (void *) acquire);
1718 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition: plancache.c:1640
static bool ScanQueryWalker(Node *node, bool *acquire)
Definition: plancache.c:1699
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1840

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.