PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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/cost.h"
#include "optimizer/planmain.h"
#include "optimizer/prep.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 PlanCacheFuncCallback (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)
 
void ResetPlanCache (void)
 

Variables

static CachedPlanSourcefirst_saved_plan = NULL
 

Macro Definition Documentation

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

Definition at line 78 of file plancache.c.

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

Function Documentation

static void AcquireExecutorLocks ( List stmt_list,
bool  acquire 
)
static

Definition at line 1478 of file plancache.c.

References AccessShareLock, CMD_UTILITY, PlannedStmt::commandType, get_plan_rowmark(), lfirst, lfirst_node, list_member_int(), LockRelationOid(), PlanRowMark::markType, PlannedStmt::nonleafResultRelations, NULL, RangeTblEntry::relid, PlannedStmt::resultRelations, RowExclusiveLock, RowMarkRequiresRowShareLock, PlannedStmt::rowMarks, RowShareLock, PlannedStmt::rtable, RTE_RELATION, RangeTblEntry::rtekind, ScanQueryForLocks(), UnlockRelationOid(), UtilityContainsQuery(), and PlannedStmt::utilityStmt.

Referenced by CheckCachedPlan().

1479 {
1480  ListCell *lc1;
1481 
1482  foreach(lc1, stmt_list)
1483  {
1484  PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
1485  int rt_index;
1486  ListCell *lc2;
1487 
1488  if (plannedstmt->commandType == CMD_UTILITY)
1489  {
1490  /*
1491  * Ignore utility statements, except those (such as EXPLAIN) that
1492  * contain a parsed-but-not-planned query. Note: it's okay to use
1493  * ScanQueryForLocks, even though the query hasn't been through
1494  * rule rewriting, because rewriting doesn't change the query
1495  * representation.
1496  */
1497  Query *query = UtilityContainsQuery(plannedstmt->utilityStmt);
1498 
1499  if (query)
1500  ScanQueryForLocks(query, acquire);
1501  continue;
1502  }
1503 
1504  rt_index = 0;
1505  foreach(lc2, plannedstmt->rtable)
1506  {
1507  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1508  LOCKMODE lockmode;
1509  PlanRowMark *rc;
1510 
1511  rt_index++;
1512 
1513  if (rte->rtekind != RTE_RELATION)
1514  continue;
1515 
1516  /*
1517  * Acquire the appropriate type of lock on each relation OID. Note
1518  * that we don't actually try to open the rel, and hence will not
1519  * fail if it's been dropped entirely --- we'll just transiently
1520  * acquire a non-conflicting lock.
1521  */
1522  if (list_member_int(plannedstmt->resultRelations, rt_index) ||
1523  list_member_int(plannedstmt->nonleafResultRelations, rt_index))
1524  lockmode = RowExclusiveLock;
1525  else if ((rc = get_plan_rowmark(plannedstmt->rowMarks, rt_index)) != NULL &&
1527  lockmode = RowShareLock;
1528  else
1529  lockmode = AccessShareLock;
1530 
1531  if (acquire)
1532  LockRelationOid(rte->relid, lockmode);
1533  else
1534  UnlockRelationOid(rte->relid, lockmode);
1535  }
1536  }
1537 }
RowMarkType markType
Definition: plannodes.h:1007
int LOCKMODE
Definition: lockdefs.h:26
List * nonleafResultRelations
Definition: plannodes.h:72
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:182
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition: plancache.c:1573
#define AccessShareLock
Definition: lockdefs.h:36
#define RowMarkRequiresRowShareLock(marktype)
Definition: plannodes.h:960
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:1856
#define lfirst_node(type, lc)
Definition: pg_list.h:109
bool list_member_int(const List *list, int datum)
Definition: list.c:485
#define RowExclusiveLock
Definition: lockdefs.h:38
Node * utilityStmt
Definition: plannodes.h:94
#define RowShareLock
Definition: lockdefs.h:37
CmdType commandType
Definition: plannodes.h:45
List * rowMarks
Definition: plannodes.h:86
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
List * rtable
Definition: plannodes.h:63
RTEKind rtekind
Definition: parsenodes.h:944
List * resultRelations
Definition: plannodes.h:66
PlanRowMark * get_plan_rowmark(List *rowmarks, Index rtindex)
Definition: preptlist.c:401
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105
static void AcquirePlannerLocks ( List stmt_list,
bool  acquire 
)
static

Definition at line 1548 of file plancache.c.

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

Referenced by RevalidateCachedQuery().

1549 {
1550  ListCell *lc;
1551 
1552  foreach(lc, stmt_list)
1553  {
1554  Query *query = lfirst_node(Query, lc);
1555 
1556  if (query->commandType == CMD_UTILITY)
1557  {
1558  /* Ignore utility statements, unless they contain a Query */
1559  query = UtilityContainsQuery(query->utilityStmt);
1560  if (query)
1561  ScanQueryForLocks(query, acquire);
1562  continue;
1563  }
1564 
1565  ScanQueryForLocks(query, acquire);
1566  }
1567 }
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition: plancache.c:1573
Node * utilityStmt
Definition: parsenodes.h:118
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:1856
#define lfirst_node(type, lc)
Definition: pg_list.h:109
CmdType commandType
Definition: parsenodes.h:110
static CachedPlan * BuildCachedPlan ( CachedPlanSource plansource,
List qlist,
ParamListInfo  boundParams,
QueryEnvironment queryEnv 
)
static

Definition at line 881 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, MemoryContextSwitchTo(), NIL, palloc(), pg_plan_queries(), CachedPlan::planRoleId, PopActiveSnapshot(), PushActiveSnapshot(), CachedPlanSource::query_list, CachedPlanSource::raw_parse_tree, CachedPlan::refcount, RevalidateCachedQuery(), CachedPlan::saved_xmin, CachedPlan::stmt_list, TransactionIdIsNormal, TransactionXmin, and PlannedStmt::transientPlan.

Referenced by GetCachedPlan().

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

Definition at line 1070 of file plancache.c.

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

Referenced by GetCachedPlan().

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

Definition at line 1425 of file plancache.c.

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

Referenced by exec_describe_statement_message(), and FetchPreparedStatementTargetList().

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

Definition at line 1412 of file plancache.c.

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

Referenced by SPI_plan_is_valid().

1413 {
1414  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1415  return plansource->is_valid;
1416 }
#define Assert(condition)
Definition: c.h:676
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:25
void CachedPlanSetParentContext ( CachedPlanSource plansource,
MemoryContext  newcontext 
)

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

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

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

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

Definition at line 1019 of file plancache.c.

References CURSOR_OPT_CUSTOM_PLAN, CURSOR_OPT_GENERIC_PLAN, CachedPlanSource::cursor_options, CachedPlanSource::generic_cost, CachedPlanSource::is_oneshot, IsTransactionStmtPlan, NULL, CachedPlanSource::num_custom_plans, and CachedPlanSource::total_custom_cost.

Referenced by GetCachedPlan().

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

334 {
335  MemoryContext source_context = plansource->context;
337 
338  /* Assert caller is doing things in a sane order */
339  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
340  Assert(!plansource->is_complete);
341 
342  /*
343  * If caller supplied a querytree_context, reparent it underneath the
344  * CachedPlanSource's context; otherwise, create a suitable context and
345  * copy the querytree_list into it. But no data copying should be done
346  * for one-shot plans; for those, assume the passed querytree_list is
347  * sufficiently long-lived.
348  */
349  if (plansource->is_oneshot)
350  {
351  querytree_context = CurrentMemoryContext;
352  }
353  else if (querytree_context != NULL)
354  {
355  MemoryContextSetParent(querytree_context, source_context);
356  MemoryContextSwitchTo(querytree_context);
357  }
358  else
359  {
360  /* Again, it's a good bet the querytree_context can be small */
361  querytree_context = AllocSetContextCreate(source_context,
362  "CachedPlanQuery",
364  MemoryContextSwitchTo(querytree_context);
365  querytree_list = copyObject(querytree_list);
366  }
367 
368  plansource->query_context = querytree_context;
369  plansource->query_list = querytree_list;
370 
371  if (!plansource->is_oneshot && !IsTransactionStmtPlan(plansource))
372  {
373  /*
374  * Use the planner machinery to extract dependencies. Data is saved
375  * in query_context. (We assume that not a lot of extra cruft is
376  * created by this call.) We can skip this for one-shot plans, and
377  * transaction control commands have no such dependencies anyway.
378  */
379  extract_query_dependencies((Node *) querytree_list,
380  &plansource->relationOids,
381  &plansource->invalItems,
382  &plansource->dependsOnRLS);
383 
384  /* Update RLS info as well. */
385  plansource->rewriteRoleId = GetUserId();
386  plansource->rewriteRowSecurity = row_security;
387 
388  /*
389  * Also save the current search_path in the query_context. (This
390  * should not generate much extra cruft either, since almost certainly
391  * the path is already valid.) Again, we don't really need this for
392  * one-shot plans; and we *must* skip this for transaction control
393  * commands, because this could result in catalog accesses.
394  */
395  plansource->search_path = GetOverrideSearchPath(querytree_context);
396  }
397 
398  /*
399  * Save the final parameter types (or other parameter specification data)
400  * into the source_context, as well as our other parameters. Also save
401  * the result tuple descriptor.
402  */
403  MemoryContextSwitchTo(source_context);
404 
405  if (num_params > 0)
406  {
407  plansource->param_types = (Oid *) palloc(num_params * sizeof(Oid));
408  memcpy(plansource->param_types, param_types, num_params * sizeof(Oid));
409  }
410  else
411  plansource->param_types = NULL;
412  plansource->num_params = num_params;
413  plansource->parserSetup = parserSetup;
414  plansource->parserSetupArg = parserSetupArg;
415  plansource->cursor_options = cursor_options;
416  plansource->fixed_result = fixed_result;
417  plansource->resultDesc = PlanCacheComputeResultDesc(querytree_list);
418 
419  MemoryContextSwitchTo(oldcxt);
420 
421  plansource->is_complete = true;
422  plansource->is_valid = true;
423 }
MemoryContext context
Definition: plancache.h:93
bool rewriteRowSecurity
Definition: plancache.h:102
Oid GetUserId(void)
Definition: miscinit.c:284
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:317
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Definition: nodes.h:509
unsigned int Oid
Definition: postgres_ext.h:31
TupleDesc resultDesc
Definition: plancache.h:92
List * invalItems
Definition: plancache.h:97
OverrideSearchPath * GetOverrideSearchPath(MemoryContext context)
Definition: namespace.c:3281
Oid * param_types
Definition: plancache.h:86
List * relationOids
Definition: plancache.h:96
void * parserSetupArg
Definition: plancache.h:89
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
ParserSetupHook parserSetup
Definition: plancache.h:88
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
#define NULL
Definition: c.h:229
bool row_security
Definition: guc.c:446
#define Assert(condition)
Definition: c.h:676
void extract_query_dependencies(Node *query, List **relationOids, List **invalItems, bool *hasRowSecurity)
Definition: setrefs.c:2534
void * palloc(Size size)
Definition: mcxt.c:849
MemoryContext query_context
Definition: plancache.h:100
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:182
List * query_list
Definition: plancache.h:95
#define IsTransactionStmtPlan(plansource)
Definition: plancache.c:78
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:25
#define copyObject(obj)
Definition: nodes.h:622
static TupleDesc PlanCacheComputeResultDesc(List *stmt_list)
Definition: plancache.c:1671
struct OverrideSearchPath * search_path
Definition: plancache.h:98
CachedPlanSource* CopyCachedPlan ( CachedPlanSource plansource)

Definition at line 1322 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, MemoryContextSwitchTo(), CachedPlanSource::next_saved, NULL, 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().

1323 {
1324  CachedPlanSource *newsource;
1325  MemoryContext source_context;
1326  MemoryContext querytree_context;
1327  MemoryContext oldcxt;
1328 
1329  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1330  Assert(plansource->is_complete);
1331 
1332  /*
1333  * One-shot plans can't be copied, because we haven't taken care that
1334  * parsing/planning didn't scribble on the raw parse tree or querytrees.
1335  */
1336  if (plansource->is_oneshot)
1337  elog(ERROR, "cannot copy a one-shot cached plan");
1338 
1340  "CachedPlanSource",
1342 
1343  oldcxt = MemoryContextSwitchTo(source_context);
1344 
1345  newsource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
1346  newsource->magic = CACHEDPLANSOURCE_MAGIC;
1347  newsource->raw_parse_tree = copyObject(plansource->raw_parse_tree);
1348  newsource->query_string = pstrdup(plansource->query_string);
1349  newsource->commandTag = plansource->commandTag;
1350  if (plansource->num_params > 0)
1351  {
1352  newsource->param_types = (Oid *)
1353  palloc(plansource->num_params * sizeof(Oid));
1354  memcpy(newsource->param_types, plansource->param_types,
1355  plansource->num_params * sizeof(Oid));
1356  }
1357  else
1358  newsource->param_types = NULL;
1359  newsource->num_params = plansource->num_params;
1360  newsource->parserSetup = plansource->parserSetup;
1361  newsource->parserSetupArg = plansource->parserSetupArg;
1362  newsource->cursor_options = plansource->cursor_options;
1363  newsource->fixed_result = plansource->fixed_result;
1364  if (plansource->resultDesc)
1365  newsource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
1366  else
1367  newsource->resultDesc = NULL;
1368  newsource->context = source_context;
1369 
1370  querytree_context = AllocSetContextCreate(source_context,
1371  "CachedPlanQuery",
1373  MemoryContextSwitchTo(querytree_context);
1374  newsource->query_list = copyObject(plansource->query_list);
1375  newsource->relationOids = copyObject(plansource->relationOids);
1376  newsource->invalItems = copyObject(plansource->invalItems);
1377  if (plansource->search_path)
1378  newsource->search_path = CopyOverrideSearchPath(plansource->search_path);
1379  newsource->query_context = querytree_context;
1380  newsource->rewriteRoleId = plansource->rewriteRoleId;
1381  newsource->rewriteRowSecurity = plansource->rewriteRowSecurity;
1382  newsource->dependsOnRLS = plansource->dependsOnRLS;
1383 
1384  newsource->gplan = NULL;
1385 
1386  newsource->is_oneshot = false;
1387  newsource->is_complete = true;
1388  newsource->is_saved = false;
1389  newsource->is_valid = plansource->is_valid;
1390  newsource->generation = plansource->generation;
1391  newsource->next_saved = NULL;
1392 
1393  /* We may as well copy any acquired cost knowledge */
1394  newsource->generic_cost = plansource->generic_cost;
1395  newsource->total_custom_cost = plansource->total_custom_cost;
1396  newsource->num_custom_plans = plansource->num_custom_plans;
1397 
1398  MemoryContextSwitchTo(oldcxt);
1399 
1400  return newsource;
1401 }
MemoryContext context
Definition: plancache.h:93
bool rewriteRowSecurity
Definition: plancache.h:102
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:100
const char * commandTag
Definition: plancache.h:85
char * pstrdup(const char *in)
Definition: mcxt.c:1077
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
unsigned int Oid
Definition: postgres_ext.h:31
double total_custom_cost
Definition: plancache.h:116
struct CachedPlan * gplan
Definition: plancache.h:105
TupleDesc resultDesc
Definition: plancache.h:92
struct CachedPlanSource * next_saved
Definition: plancache.h:113
#define ERROR
Definition: elog.h:43
OverrideSearchPath * CopyOverrideSearchPath(OverrideSearchPath *path)
Definition: namespace.c:3317
List * invalItems
Definition: plancache.h:97
Oid * param_types
Definition: plancache.h:86
List * relationOids
Definition: plancache.h:96
void * parserSetupArg
Definition: plancache.h:89
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
ParserSetupHook parserSetup
Definition: plancache.h:88
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
void * palloc0(Size size)
Definition: mcxt.c:878
#define NULL
Definition: c.h:229
double generic_cost
Definition: plancache.h:115
#define Assert(condition)
Definition: c.h:676
const char * query_string
Definition: plancache.h:84
struct RawStmt * raw_parse_tree
Definition: plancache.h:83
void * palloc(Size size)
Definition: mcxt.c:849
MemoryContext query_context
Definition: plancache.h:100
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:182
List * query_list
Definition: plancache.h:95
#define elog
Definition: elog.h:219
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:25
#define copyObject(obj)
Definition: nodes.h:622
struct OverrideSearchPath * search_path
Definition: plancache.h:98
CachedPlanSource* CreateCachedPlan ( RawStmt raw_parse_tree,
const char *  query_string,
const char *  commandTag 
)

Definition at line 152 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, MemoryContextSwitchTo(), CachedPlanSource::next_saved, NIL, NULL, 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().

155 {
156  CachedPlanSource *plansource;
157  MemoryContext source_context;
158  MemoryContext oldcxt;
159 
160  Assert(query_string != NULL); /* required as of 8.4 */
161 
162  /*
163  * Make a dedicated memory context for the CachedPlanSource and its
164  * permanent subsidiary data. It's probably not going to be large, but
165  * just in case, allow it to grow large. Initially it's a child of the
166  * caller's context (which we assume to be transient), so that it will be
167  * cleaned up on error.
168  */
170  "CachedPlanSource",
172 
173  /*
174  * Create and fill the CachedPlanSource struct within the new context.
175  * Most fields are just left empty for the moment.
176  */
177  oldcxt = MemoryContextSwitchTo(source_context);
178 
179  plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
180  plansource->magic = CACHEDPLANSOURCE_MAGIC;
181  plansource->raw_parse_tree = copyObject(raw_parse_tree);
182  plansource->query_string = pstrdup(query_string);
183  plansource->commandTag = commandTag;
184  plansource->param_types = NULL;
185  plansource->num_params = 0;
186  plansource->parserSetup = NULL;
187  plansource->parserSetupArg = NULL;
188  plansource->cursor_options = 0;
189  plansource->fixed_result = false;
190  plansource->resultDesc = NULL;
191  plansource->context = source_context;
192  plansource->query_list = NIL;
193  plansource->relationOids = NIL;
194  plansource->invalItems = NIL;
195  plansource->search_path = NULL;
196  plansource->query_context = NULL;
197  plansource->rewriteRoleId = InvalidOid;
198  plansource->rewriteRowSecurity = false;
199  plansource->dependsOnRLS = false;
200  plansource->gplan = NULL;
201  plansource->is_oneshot = false;
202  plansource->is_complete = false;
203  plansource->is_saved = false;
204  plansource->is_valid = false;
205  plansource->generation = 0;
206  plansource->next_saved = NULL;
207  plansource->generic_cost = -1;
208  plansource->total_custom_cost = 0;
209  plansource->num_custom_plans = 0;
210 
211  MemoryContextSwitchTo(oldcxt);
212 
213  return plansource;
214 }
MemoryContext context
Definition: plancache.h:93
#define NIL
Definition: pg_list.h:69
bool rewriteRowSecurity
Definition: plancache.h:102
const char * commandTag
Definition: plancache.h:85
char * pstrdup(const char *in)
Definition: mcxt.c:1077
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
double total_custom_cost
Definition: plancache.h:116
struct CachedPlan * gplan
Definition: plancache.h:105
TupleDesc resultDesc
Definition: plancache.h:92
struct CachedPlanSource * next_saved
Definition: plancache.h:113
List * invalItems
Definition: plancache.h:97
Oid * param_types
Definition: plancache.h:86
List * relationOids
Definition: plancache.h:96
void * parserSetupArg
Definition: plancache.h:89
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
ParserSetupHook parserSetup
Definition: plancache.h:88
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
void * palloc0(Size size)
Definition: mcxt.c:878
#define InvalidOid
Definition: postgres_ext.h:36
#define NULL
Definition: c.h:229
double generic_cost
Definition: plancache.h:115
#define Assert(condition)
Definition: c.h:676
const char * query_string
Definition: plancache.h:84
struct RawStmt * raw_parse_tree
Definition: plancache.h:83
MemoryContext query_context
Definition: plancache.h:100
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:182
List * query_list
Definition: plancache.h:95
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:25
#define copyObject(obj)
Definition: nodes.h:622
struct OverrideSearchPath * search_path
Definition: plancache.h:98
CachedPlanSource* CreateOneShotCachedPlan ( RawStmt raw_parse_tree,
const char *  query_string,
const char *  commandTag 
)

Definition at line 235 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, CachedPlanSource::next_saved, NIL, NULL, 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().

238 {
239  CachedPlanSource *plansource;
240 
241  Assert(query_string != NULL); /* required as of 8.4 */
242 
243  /*
244  * Create and fill the CachedPlanSource struct within the caller's memory
245  * context. Most fields are just left empty for the moment.
246  */
247  plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
248  plansource->magic = CACHEDPLANSOURCE_MAGIC;
249  plansource->raw_parse_tree = raw_parse_tree;
250  plansource->query_string = query_string;
251  plansource->commandTag = commandTag;
252  plansource->param_types = NULL;
253  plansource->num_params = 0;
254  plansource->parserSetup = NULL;
255  plansource->parserSetupArg = NULL;
256  plansource->cursor_options = 0;
257  plansource->fixed_result = false;
258  plansource->resultDesc = NULL;
259  plansource->context = CurrentMemoryContext;
260  plansource->query_list = NIL;
261  plansource->relationOids = NIL;
262  plansource->invalItems = NIL;
263  plansource->search_path = NULL;
264  plansource->query_context = NULL;
265  plansource->rewriteRoleId = InvalidOid;
266  plansource->rewriteRowSecurity = false;
267  plansource->dependsOnRLS = false;
268  plansource->gplan = NULL;
269  plansource->is_oneshot = true;
270  plansource->is_complete = false;
271  plansource->is_saved = false;
272  plansource->is_valid = false;
273  plansource->generation = 0;
274  plansource->next_saved = NULL;
275  plansource->generic_cost = -1;
276  plansource->total_custom_cost = 0;
277  plansource->num_custom_plans = 0;
278 
279  return plansource;
280 }
MemoryContext context
Definition: plancache.h:93
#define NIL
Definition: pg_list.h:69
bool rewriteRowSecurity
Definition: plancache.h:102
const char * commandTag
Definition: plancache.h:85
double total_custom_cost
Definition: plancache.h:116
struct CachedPlan * gplan
Definition: plancache.h:105
TupleDesc resultDesc
Definition: plancache.h:92
struct CachedPlanSource * next_saved
Definition: plancache.h:113
List * invalItems
Definition: plancache.h:97
Oid * param_types
Definition: plancache.h:86
List * relationOids
Definition: plancache.h:96
void * parserSetupArg
Definition: plancache.h:89
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
ParserSetupHook parserSetup
Definition: plancache.h:88
void * palloc0(Size size)
Definition: mcxt.c:878
#define InvalidOid
Definition: postgres_ext.h:36
#define NULL
Definition: c.h:229
double generic_cost
Definition: plancache.h:115
#define Assert(condition)
Definition: c.h:676
const char * query_string
Definition: plancache.h:84
struct RawStmt * raw_parse_tree
Definition: plancache.h:83
MemoryContext query_context
Definition: plancache.h:100
List * query_list
Definition: plancache.h:95
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:25
struct OverrideSearchPath * search_path
Definition: plancache.h:98
void DropCachedPlan ( CachedPlanSource plansource)

Definition at line 486 of file plancache.c.

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

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

487 {
488  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
489 
490  /* If it's been saved, remove it from the list */
491  if (plansource->is_saved)
492  {
493  if (first_saved_plan == plansource)
494  first_saved_plan = plansource->next_saved;
495  else
496  {
497  CachedPlanSource *psrc;
498 
499  for (psrc = first_saved_plan; psrc; psrc = psrc->next_saved)
500  {
501  if (psrc->next_saved == plansource)
502  {
503  psrc->next_saved = plansource->next_saved;
504  break;
505  }
506  }
507  }
508  plansource->is_saved = false;
509  }
510 
511  /* Decrement generic CachePlan's refcount and drop if no longer needed */
512  ReleaseGenericPlan(plansource);
513 
514  /* Mark it no longer valid */
515  plansource->magic = 0;
516 
517  /*
518  * Remove the CachedPlanSource and all subsidiary data (including the
519  * query_context if any). But if it's a one-shot we can't free anything.
520  */
521  if (!plansource->is_oneshot)
522  MemoryContextDelete(plansource->context);
523 }
MemoryContext context
Definition: plancache.h:93
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
static void ReleaseGenericPlan(CachedPlanSource *plansource)
Definition: plancache.c:529
struct CachedPlanSource * next_saved
Definition: plancache.h:113
static CachedPlanSource * first_saved_plan
Definition: plancache.c:88
#define Assert(condition)
Definition: c.h:676
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:25
CachedPlan* GetCachedPlan ( CachedPlanSource plansource,
ParamListInfo  boundParams,
bool  useResOwner,
QueryEnvironment queryEnv 
)

Definition at line 1135 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, NULL, 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().

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

Definition at line 116 of file plancache.c.

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

Referenced by InitPostgres().

117 {
125 }
static void PlanCacheFuncCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:1772
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition: inval.c:1431
static void PlanCacheRelCallback(Datum arg, Oid relid)
Definition: plancache.c:1707
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1389
uintptr_t Datum
Definition: postgres.h:372
static void PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:1851
static TupleDesc PlanCacheComputeResultDesc ( List stmt_list)
static

Definition at line 1671 of file plancache.c.

References Assert, ChoosePortalStrategy(), ExecCleanTypeFromTL(), linitial_node, NULL, 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().

1672 {
1673  Query *query;
1674 
1675  switch (ChoosePortalStrategy(stmt_list))
1676  {
1677  case PORTAL_ONE_SELECT:
1678  case PORTAL_ONE_MOD_WITH:
1679  query = linitial_node(Query, stmt_list);
1680  return ExecCleanTypeFromTL(query->targetList, false);
1681 
1682  case PORTAL_ONE_RETURNING:
1683  query = QueryListGetPrimaryStmt(stmt_list);
1684  Assert(query->returningList);
1685  return ExecCleanTypeFromTL(query->returningList, false);
1686 
1687  case PORTAL_UTIL_SELECT:
1688  query = linitial_node(Query, stmt_list);
1689  Assert(query->utilityStmt);
1690  return UtilityTupleDescriptor(query->utilityStmt);
1691 
1692  case PORTAL_MULTI_QUERY:
1693  /* will not return tuples */
1694  break;
1695  }
1696  return NULL;
1697 }
Node * utilityStmt
Definition: parsenodes.h:118
#define linitial_node(type, l)
Definition: pg_list.h:114
List * targetList
Definition: parsenodes.h:138
static Query * QueryListGetPrimaryStmt(List *stmts)
Definition: plancache.c:1459
List * returningList
Definition: parsenodes.h:144
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:676
PortalStrategy ChoosePortalStrategy(List *stmts)
Definition: pquery.c:221
TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid)
Definition: execTuples.c:900
TupleDesc UtilityTupleDescriptor(Node *parsetree)
Definition: utility.c:1765
static void PlanCacheFuncCallback ( Datum  arg,
int  cacheid,
uint32  hashvalue 
)
static

Definition at line 1772 of file plancache.c.

References Assert, CACHEDPLANSOURCE_MAGIC, PlanInvalItem::cacheId, CMD_UTILITY, PlannedStmt::commandType, CachedPlanSource::gplan, PlanInvalItem::hashValue, PlannedStmt::invalItems, CachedPlanSource::invalItems, CachedPlanSource::is_valid, CachedPlan::is_valid, IsTransactionStmtPlan, lfirst, lfirst_node, CachedPlanSource::magic, CachedPlanSource::next_saved, and CachedPlan::stmt_list.

Referenced by InitPlanCache().

1773 {
1774  CachedPlanSource *plansource;
1775 
1776  for (plansource = first_saved_plan; plansource; plansource = plansource->next_saved)
1777  {
1778  ListCell *lc;
1779 
1780  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1781 
1782  /* No work if it's already invalidated */
1783  if (!plansource->is_valid)
1784  continue;
1785 
1786  /* Never invalidate transaction control commands */
1787  if (IsTransactionStmtPlan(plansource))
1788  continue;
1789 
1790  /*
1791  * Check the dependency list for the rewritten querytree.
1792  */
1793  foreach(lc, plansource->invalItems)
1794  {
1795  PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
1796 
1797  if (item->cacheId != cacheid)
1798  continue;
1799  if (hashvalue == 0 ||
1800  item->hashValue == hashvalue)
1801  {
1802  /* Invalidate the querytree and generic plan */
1803  plansource->is_valid = false;
1804  if (plansource->gplan)
1805  plansource->gplan->is_valid = false;
1806  break;
1807  }
1808  }
1809 
1810  /*
1811  * The generic plan, if any, could have more dependencies than the
1812  * querytree does, so we have to check it too.
1813  */
1814  if (plansource->gplan && plansource->gplan->is_valid)
1815  {
1816  foreach(lc, plansource->gplan->stmt_list)
1817  {
1818  PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1819  ListCell *lc3;
1820 
1821  if (plannedstmt->commandType == CMD_UTILITY)
1822  continue; /* Ignore utility statements */
1823  foreach(lc3, plannedstmt->invalItems)
1824  {
1825  PlanInvalItem *item = (PlanInvalItem *) lfirst(lc3);
1826 
1827  if (item->cacheId != cacheid)
1828  continue;
1829  if (hashvalue == 0 ||
1830  item->hashValue == hashvalue)
1831  {
1832  /* Invalidate the generic plan only */
1833  plansource->gplan->is_valid = false;
1834  break; /* out of invalItems scan */
1835  }
1836  }
1837  if (!plansource->gplan->is_valid)
1838  break; /* out of stmt_list scan */
1839  }
1840  }
1841  }
1842 }
bool is_valid
Definition: plancache.h:136
struct CachedPlan * gplan
Definition: plancache.h:105
List * invalItems
Definition: plannodes.h:90
struct CachedPlanSource * next_saved
Definition: plancache.h:113
List * invalItems
Definition: plancache.h:97
#define lfirst_node(type, lc)
Definition: pg_list.h:109
static CachedPlanSource * first_saved_plan
Definition: plancache.c:88
CmdType commandType
Definition: plannodes.h:45
uint32 hashValue
Definition: plannodes.h:1028
#define Assert(condition)
Definition: c.h:676
#define lfirst(lc)
Definition: pg_list.h:106
List * stmt_list
Definition: plancache.h:133
#define IsTransactionStmtPlan(plansource)
Definition: plancache.c:78
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:25
static void PlanCacheRelCallback ( Datum  arg,
Oid  relid 
)
static

Definition at line 1707 of file plancache.c.

References Assert, CACHEDPLANSOURCE_MAGIC, CMD_UTILITY, PlannedStmt::commandType, CachedPlanSource::gplan, InvalidOid, CachedPlanSource::is_valid, CachedPlan::is_valid, IsTransactionStmtPlan, lfirst_node, list_member_oid(), CachedPlanSource::magic, CachedPlanSource::next_saved, NIL, PlannedStmt::relationOids, CachedPlanSource::relationOids, and CachedPlan::stmt_list.

Referenced by InitPlanCache().

1708 {
1709  CachedPlanSource *plansource;
1710 
1711  for (plansource = first_saved_plan; plansource; plansource = plansource->next_saved)
1712  {
1713  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1714 
1715  /* No work if it's already invalidated */
1716  if (!plansource->is_valid)
1717  continue;
1718 
1719  /* Never invalidate transaction control commands */
1720  if (IsTransactionStmtPlan(plansource))
1721  continue;
1722 
1723  /*
1724  * Check the dependency list for the rewritten querytree.
1725  */
1726  if ((relid == InvalidOid) ? plansource->relationOids != NIL :
1727  list_member_oid(plansource->relationOids, relid))
1728  {
1729  /* Invalidate the querytree and generic plan */
1730  plansource->is_valid = false;
1731  if (plansource->gplan)
1732  plansource->gplan->is_valid = false;
1733  }
1734 
1735  /*
1736  * The generic plan, if any, could have more dependencies than the
1737  * querytree does, so we have to check it too.
1738  */
1739  if (plansource->gplan && plansource->gplan->is_valid)
1740  {
1741  ListCell *lc;
1742 
1743  foreach(lc, plansource->gplan->stmt_list)
1744  {
1745  PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1746 
1747  if (plannedstmt->commandType == CMD_UTILITY)
1748  continue; /* Ignore utility statements */
1749  if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
1750  list_member_oid(plannedstmt->relationOids, relid))
1751  {
1752  /* Invalidate the generic plan only */
1753  plansource->gplan->is_valid = false;
1754  break; /* out of stmt_list scan */
1755  }
1756  }
1757  }
1758  }
1759 }
#define NIL
Definition: pg_list.h:69
bool is_valid
Definition: plancache.h:136
List * relationOids
Definition: plannodes.h:88
struct CachedPlan * gplan
Definition: plancache.h:105
struct CachedPlanSource * next_saved
Definition: plancache.h:113
#define lfirst_node(type, lc)
Definition: pg_list.h:109
static CachedPlanSource * first_saved_plan
Definition: plancache.c:88
List * relationOids
Definition: plancache.h:96
CmdType commandType
Definition: plannodes.h:45
#define InvalidOid
Definition: postgres_ext.h:36
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505
#define Assert(condition)
Definition: c.h:676
List * stmt_list
Definition: plancache.h:133
#define IsTransactionStmtPlan(plansource)
Definition: plancache.c:78
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:25
static void PlanCacheSysCallback ( Datum  arg,
int  cacheid,
uint32  hashvalue 
)
static

Definition at line 1851 of file plancache.c.

References ResetPlanCache().

Referenced by InitPlanCache().

1852 {
1853  ResetPlanCache();
1854 }
void ResetPlanCache(void)
Definition: plancache.c:1860
static Query * QueryListGetPrimaryStmt ( List stmts)
static

Definition at line 1459 of file plancache.c.

References Query::canSetTag, lfirst_node, and NULL.

Referenced by CachedPlanGetTargetList(), and PlanCacheComputeResultDesc().

1460 {
1461  ListCell *lc;
1462 
1463  foreach(lc, stmts)
1464  {
1465  Query *stmt = lfirst_node(Query, lc);
1466 
1467  if (stmt->canSetTag)
1468  return stmt;
1469  }
1470  return NULL;
1471 }
#define lfirst_node(type, lc)
Definition: pg_list.h:109
#define NULL
Definition: c.h:229
bool canSetTag
Definition: parsenodes.h:116
void ReleaseCachedPlan ( CachedPlan plan,
bool  useResOwner 
)

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

1257 {
1258  Assert(plan->magic == CACHEDPLAN_MAGIC);
1259  if (useResOwner)
1260  {
1261  Assert(plan->is_saved);
1263  }
1264  Assert(plan->refcount > 0);
1265  plan->refcount--;
1266  if (plan->refcount == 0)
1267  {
1268  /* Mark it no longer valid */
1269  plan->magic = 0;
1270 
1271  /* One-shot plans do not own their context, so we can't free them */
1272  if (!plan->is_oneshot)
1274  }
1275 }
#define CACHEDPLAN_MAGIC
Definition: plancache.h:26
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
int refcount
Definition: plancache.h:142
MemoryContext context
Definition: plancache.h:143
void ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
Definition: resowner.c:1073
bool is_saved
Definition: plancache.h:135
#define Assert(condition)
Definition: c.h:676
bool is_oneshot
Definition: plancache.h:134
static void ReleaseGenericPlan ( CachedPlanSource plansource)
static

Definition at line 529 of file plancache.c.

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

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

530 {
531  /* Be paranoid about the possibility that ReleaseCachedPlan fails */
532  if (plansource->gplan)
533  {
534  CachedPlan *plan = plansource->gplan;
535 
536  Assert(plan->magic == CACHEDPLAN_MAGIC);
537  plansource->gplan = NULL;
538  ReleaseCachedPlan(plan, false);
539  }
540 }
#define CACHEDPLAN_MAGIC
Definition: plancache.h:26
struct CachedPlan * gplan
Definition: plancache.h:105
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1256
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:676
void ResetPlanCache ( void  )

Definition at line 1860 of file plancache.c.

References Assert, CACHEDPLANSOURCE_MAGIC, CMD_UTILITY, Query::commandType, CachedPlanSource::gplan, CachedPlanSource::is_valid, CachedPlan::is_valid, IsTransactionStmtPlan, lfirst_node, CachedPlanSource::magic, CachedPlanSource::next_saved, CachedPlanSource::query_list, UtilityContainsQuery(), and Query::utilityStmt.

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

1861 {
1862  CachedPlanSource *plansource;
1863 
1864  for (plansource = first_saved_plan; plansource; plansource = plansource->next_saved)
1865  {
1866  ListCell *lc;
1867 
1868  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1869 
1870  /* No work if it's already invalidated */
1871  if (!plansource->is_valid)
1872  continue;
1873 
1874  /*
1875  * We *must not* mark transaction control statements as invalid,
1876  * particularly not ROLLBACK, because they may need to be executed in
1877  * aborted transactions when we can't revalidate them (cf bug #5269).
1878  */
1879  if (IsTransactionStmtPlan(plansource))
1880  continue;
1881 
1882  /*
1883  * In general there is no point in invalidating utility statements
1884  * since they have no plans anyway. So invalidate it only if it
1885  * contains at least one non-utility statement, or contains a utility
1886  * statement that contains a pre-analyzed query (which could have
1887  * dependencies.)
1888  */
1889  foreach(lc, plansource->query_list)
1890  {
1891  Query *query = lfirst_node(Query, lc);
1892 
1893  if (query->commandType != CMD_UTILITY ||
1895  {
1896  /* non-utility statement, so invalidate */
1897  plansource->is_valid = false;
1898  if (plansource->gplan)
1899  plansource->gplan->is_valid = false;
1900  /* no need to look further */
1901  break;
1902  }
1903  }
1904  }
1905 }
bool is_valid
Definition: plancache.h:136
Node * utilityStmt
Definition: parsenodes.h:118
struct CachedPlan * gplan
Definition: plancache.h:105
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:1856
struct CachedPlanSource * next_saved
Definition: plancache.h:113
#define lfirst_node(type, lc)
Definition: pg_list.h:109
static CachedPlanSource * first_saved_plan
Definition: plancache.c:88
CmdType commandType
Definition: parsenodes.h:110
#define Assert(condition)
Definition: c.h:676
List * query_list
Definition: plancache.h:95
#define IsTransactionStmtPlan(plansource)
Definition: plancache.c:78
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:25
static List * RevalidateCachedQuery ( CachedPlanSource plansource,
QueryEnvironment queryEnv 
)
static

Definition at line 557 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, NULL, 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().

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

Definition at line 441 of file plancache.c.

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

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

442 {
443  /* Assert caller is doing things in a sane order */
444  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
445  Assert(plansource->is_complete);
446  Assert(!plansource->is_saved);
447 
448  /* This seems worth a real test, though */
449  if (plansource->is_oneshot)
450  elog(ERROR, "cannot save one-shot cached plan");
451 
452  /*
453  * In typical use, this function would be called before generating any
454  * plans from the CachedPlanSource. If there is a generic plan, moving it
455  * into CacheMemoryContext would be pretty risky since it's unclear
456  * whether the caller has taken suitable care with making references
457  * long-lived. Best thing to do seems to be to discard the plan.
458  */
459  ReleaseGenericPlan(plansource);
460 
461  /*
462  * Reparent the source memory context under CacheMemoryContext so that it
463  * will live indefinitely. The query_context follows along since it's
464  * already a child of the other one.
465  */
467 
468  /*
469  * Add the entry to the global list of cached plans.
470  */
471  plansource->next_saved = first_saved_plan;
472  first_saved_plan = plansource;
473 
474  plansource->is_saved = true;
475 }
MemoryContext context
Definition: plancache.h:93
static void ReleaseGenericPlan(CachedPlanSource *plansource)
Definition: plancache.c:529
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:317
struct CachedPlanSource * next_saved
Definition: plancache.h:113
#define ERROR
Definition: elog.h:43
static CachedPlanSource * first_saved_plan
Definition: plancache.c:88
#define Assert(condition)
Definition: c.h:676
#define elog
Definition: elog.h:219
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:25
MemoryContext CacheMemoryContext
Definition: mcxt.c:46
static void ScanQueryForLocks ( Query parsetree,
bool  acquire 
)
static

Definition at line 1573 of file plancache.c.

References AccessShareLock, Assert, castNode, CMD_UTILITY, Query::commandType, Query::cteList, CommonTableExpr::ctequery, get_parse_rowmark(), Query::hasSubLinks, lfirst, lfirst_node, LockRelationOid(), NULL, QTW_IGNORE_RC_SUBQUERIES, query_tree_walker(), RangeTblEntry::relid, Query::resultRelation, RowExclusiveLock, RowShareLock, Query::rtable, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, ScanQueryWalker(), RangeTblEntry::subquery, and UnlockRelationOid().

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

1574 {
1575  ListCell *lc;
1576  int rt_index;
1577 
1578  /* Shouldn't get called on utility commands */
1579  Assert(parsetree->commandType != CMD_UTILITY);
1580 
1581  /*
1582  * First, process RTEs of the current query level.
1583  */
1584  rt_index = 0;
1585  foreach(lc, parsetree->rtable)
1586  {
1587  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
1588  LOCKMODE lockmode;
1589 
1590  rt_index++;
1591  switch (rte->rtekind)
1592  {
1593  case RTE_RELATION:
1594  /* Acquire or release the appropriate type of lock */
1595  if (rt_index == parsetree->resultRelation)
1596  lockmode = RowExclusiveLock;
1597  else if (get_parse_rowmark(parsetree, rt_index) != NULL)
1598  lockmode = RowShareLock;
1599  else
1600  lockmode = AccessShareLock;
1601  if (acquire)
1602  LockRelationOid(rte->relid, lockmode);
1603  else
1604  UnlockRelationOid(rte->relid, lockmode);
1605  break;
1606 
1607  case RTE_SUBQUERY:
1608  /* Recurse into subquery-in-FROM */
1609  ScanQueryForLocks(rte->subquery, acquire);
1610  break;
1611 
1612  default:
1613  /* ignore other types of RTEs */
1614  break;
1615  }
1616  }
1617 
1618  /* Recurse into subquery-in-WITH */
1619  foreach(lc, parsetree->cteList)
1620  {
1622 
1623  ScanQueryForLocks(castNode(Query, cte->ctequery), acquire);
1624  }
1625 
1626  /*
1627  * Recurse into sublink subqueries, too. But we already did the ones in
1628  * the rtable and cteList.
1629  */
1630  if (parsetree->hasSubLinks)
1631  {
1633  (void *) &acquire,
1635  }
1636 }
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2246
RowMarkClause * get_parse_rowmark(Query *qry, Index rtindex)
int LOCKMODE
Definition: lockdefs.h:26
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:182
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition: plancache.c:1573
int resultRelation
Definition: parsenodes.h:120
#define AccessShareLock
Definition: lockdefs.h:36
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:22
List * rtable
Definition: parsenodes.h:135
#define lfirst_node(type, lc)
Definition: pg_list.h:109
#define RowExclusiveLock
Definition: lockdefs.h:38
static bool ScanQueryWalker(Node *node, bool *acquire)
Definition: plancache.c:1642
#define RowShareLock
Definition: lockdefs.h:37
CmdType commandType
Definition: parsenodes.h:110
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:676
#define lfirst(lc)
Definition: pg_list.h:106
RTEKind rtekind
Definition: parsenodes.h:944
List * cteList
Definition: parsenodes.h:133
Query * subquery
Definition: parsenodes.h:967
bool hasSubLinks
Definition: parsenodes.h:126
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105
static bool ScanQueryWalker ( Node node,
bool acquire 
)
static

Definition at line 1642 of file plancache.c.

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

Referenced by ScanQueryForLocks().

1643 {
1644  if (node == NULL)
1645  return false;
1646  if (IsA(node, SubLink))
1647  {
1648  SubLink *sub = (SubLink *) node;
1649 
1650  /* Do what we came for */
1651  ScanQueryForLocks(castNode(Query, sub->subselect), *acquire);
1652  /* Fall through to process lefthand args of SubLink */
1653  }
1654 
1655  /*
1656  * Do NOT recurse into Query nodes, because ScanQueryForLocks already
1657  * processed subselects of subselects for us.
1658  */
1660  (void *) acquire);
1661 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition: plancache.c:1573
static bool ScanQueryWalker(Node *node, bool *acquire)
Definition: plancache.c:1642
#define NULL
Definition: c.h:229
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1843

Variable Documentation

CachedPlanSource* first_saved_plan = NULL
static

Definition at line 88 of file plancache.c.

Referenced by SaveCachedPlan().