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)
 
static bool CheckCachedPlan (CachedPlanSource *plansource)
 
static CachedPlanBuildCachedPlan (CachedPlanSource *plansource, List *qlist, ParamListInfo boundParams)
 
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)
 
void ReleaseCachedPlan (CachedPlan *plan, bool useResOwner)
 
void CachedPlanSetParentContext (CachedPlanSource *plansource, MemoryContext newcontext)
 
CachedPlanSourceCopyCachedPlan (CachedPlanSource *plansource)
 
bool CachedPlanIsValid (CachedPlanSource *plansource)
 
ListCachedPlanGetTargetList (CachedPlanSource *plansource)
 
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:573
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 1473 of file plancache.c.

References AccessShareLock, castNode, CMD_UTILITY, PlannedStmt::commandType, get_plan_rowmark(), lfirst, 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().

1474 {
1475  ListCell *lc1;
1476 
1477  foreach(lc1, stmt_list)
1478  {
1479  PlannedStmt *plannedstmt = castNode(PlannedStmt, lfirst(lc1));
1480  int rt_index;
1481  ListCell *lc2;
1482 
1483  if (plannedstmt->commandType == CMD_UTILITY)
1484  {
1485  /*
1486  * Ignore utility statements, except those (such as EXPLAIN) that
1487  * contain a parsed-but-not-planned query. Note: it's okay to use
1488  * ScanQueryForLocks, even though the query hasn't been through
1489  * rule rewriting, because rewriting doesn't change the query
1490  * representation.
1491  */
1492  Query *query = UtilityContainsQuery(plannedstmt->utilityStmt);
1493 
1494  if (query)
1495  ScanQueryForLocks(query, acquire);
1496  continue;
1497  }
1498 
1499  rt_index = 0;
1500  foreach(lc2, plannedstmt->rtable)
1501  {
1502  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1503  LOCKMODE lockmode;
1504  PlanRowMark *rc;
1505 
1506  rt_index++;
1507 
1508  if (rte->rtekind != RTE_RELATION)
1509  continue;
1510 
1511  /*
1512  * Acquire the appropriate type of lock on each relation OID. Note
1513  * that we don't actually try to open the rel, and hence will not
1514  * fail if it's been dropped entirely --- we'll just transiently
1515  * acquire a non-conflicting lock.
1516  */
1517  if (list_member_int(plannedstmt->resultRelations, rt_index) ||
1518  list_member_int(plannedstmt->nonleafResultRelations, rt_index))
1519  lockmode = RowExclusiveLock;
1520  else if ((rc = get_plan_rowmark(plannedstmt->rowMarks, rt_index)) != NULL &&
1522  lockmode = RowShareLock;
1523  else
1524  lockmode = AccessShareLock;
1525 
1526  if (acquire)
1527  LockRelationOid(rte->relid, lockmode);
1528  else
1529  UnlockRelationOid(rte->relid, lockmode);
1530  }
1531  }
1532 }
RowMarkType markType
Definition: plannodes.h:981
int LOCKMODE
Definition: lockdefs.h:26
List * nonleafResultRelations
Definition: plannodes.h:69
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:182
#define castNode(_type_, nodeptr)
Definition: nodes.h:591
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition: plancache.c:1568
#define AccessShareLock
Definition: lockdefs.h:36
#define RowMarkRequiresRowShareLock(marktype)
Definition: plannodes.h:934
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:1844
bool list_member_int(const List *list, int datum)
Definition: list.c:485
#define RowExclusiveLock
Definition: lockdefs.h:38
Node * utilityStmt
Definition: plannodes.h:83
#define RowShareLock
Definition: lockdefs.h:37
CmdType commandType
Definition: plannodes.h:45
List * rowMarks
Definition: plannodes.h:75
#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:916
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 1543 of file plancache.c.

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

Referenced by RevalidateCachedQuery().

1544 {
1545  ListCell *lc;
1546 
1547  foreach(lc, stmt_list)
1548  {
1549  Query *query = castNode(Query, lfirst(lc));
1550 
1551  if (query->commandType == CMD_UTILITY)
1552  {
1553  /* Ignore utility statements, unless they contain a Query */
1554  query = UtilityContainsQuery(query->utilityStmt);
1555  if (query)
1556  ScanQueryForLocks(query, acquire);
1557  continue;
1558  }
1559 
1560  ScanQueryForLocks(query, acquire);
1561  }
1562 }
#define castNode(_type_, nodeptr)
Definition: nodes.h:591
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition: plancache.c:1568
Node * utilityStmt
Definition: parsenodes.h:111
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:1844
CmdType commandType
Definition: parsenodes.h:103
#define lfirst(lc)
Definition: pg_list.h:106
static CachedPlan * BuildCachedPlan ( CachedPlanSource plansource,
List qlist,
ParamListInfo  boundParams 
)
static

Definition at line 877 of file plancache.c.

References ActiveSnapshotSet(), ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate(), analyze_requires_snapshot(), Assert, CACHEDPLAN_MAGIC, castNode, 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, 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().

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);
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 = (List *) 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 
951  /*
952  * Copy plan into the new context.
953  */
954  MemoryContextSwitchTo(plan_context);
955 
956  plist = (List *) copyObject(plist);
957  }
958  else
959  plan_context = CurrentMemoryContext;
960 
961  /*
962  * Create and fill the CachedPlan struct within the new context.
963  */
964  plan = (CachedPlan *) palloc(sizeof(CachedPlan));
965  plan->magic = CACHEDPLAN_MAGIC;
966  plan->stmt_list = plist;
967 
968  /*
969  * CachedPlan is dependent on role either if RLS affected the rewrite
970  * phase or if a role dependency was injected during planning. And it's
971  * transient if any plan is marked so.
972  */
973  plan->planRoleId = GetUserId();
974  plan->dependsOnRole = plansource->dependsOnRLS;
975  is_transient = false;
976  foreach(lc, plist)
977  {
978  PlannedStmt *plannedstmt = castNode(PlannedStmt, lfirst(lc));
979 
980  if (plannedstmt->commandType == CMD_UTILITY)
981  continue; /* Ignore utility statements */
982 
983  if (plannedstmt->transientPlan)
984  is_transient = true;
985  if (plannedstmt->dependsOnRole)
986  plan->dependsOnRole = true;
987  }
988  if (is_transient)
989  {
991  plan->saved_xmin = TransactionXmin;
992  }
993  else
995  plan->refcount = 0;
996  plan->context = plan_context;
997  plan->is_oneshot = plansource->is_oneshot;
998  plan->is_saved = false;
999  plan->is_valid = true;
1000 
1001  /* assign generation number to new plan */
1002  plan->generation = ++(plansource->generation);
1003 
1004  MemoryContextSwitchTo(oldcxt);
1005 
1006  return plan;
1007 }
Oid planRoleId
Definition: plancache.h:136
#define CACHEDPLAN_MAGIC
Definition: plancache.h:25
bool dependsOnRole
Definition: plannodes.h:57
#define NIL
Definition: pg_list.h:69
bool analyze_requires_snapshot(RawStmt *parseTree)
Definition: analyze.c:345
bool is_valid
Definition: plancache.h:135
Oid GetUserId(void)
Definition: miscinit.c:283
#define castNode(_type_, nodeptr)
Definition: nodes.h:591
int refcount
Definition: plancache.h:141
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
bool dependsOnRole
Definition: plancache.h:137
void PopActiveSnapshot(void)
Definition: snapmgr.c:807
MemoryContext context
Definition: plancache.h:142
bool transientPlan
Definition: plannodes.h:55
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:300
TransactionId TransactionXmin
Definition: snapmgr.c:164
void * copyObject(const void *from)
Definition: copyfuncs.c:4619
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:728
#define InvalidTransactionId
Definition: transam.h:31
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:846
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
bool is_saved
Definition: plancache.h:134
CmdType commandType
Definition: plannodes.h:45
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
int generation
Definition: plancache.h:140
struct RawStmt * raw_parse_tree
Definition: plancache.h:82
bool is_oneshot
Definition: plancache.h:133
void * palloc(Size size)
Definition: mcxt.c:849
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:182
List * query_list
Definition: plancache.h:94
List * stmt_list
Definition: plancache.h:132
static List * RevalidateCachedQuery(CachedPlanSource *plansource)
Definition: plancache.c:556
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
TransactionId saved_xmin
Definition: plancache.h:138
Definition: pg_list.h:45
List * pg_plan_queries(List *querytrees, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:842
static double cached_plan_cost ( CachedPlan plan,
bool  include_planner 
)
static

Definition at line 1066 of file plancache.c.

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

Referenced by GetCachedPlan().

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

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

1422 {
1423  Query *pstmt;
1424 
1425  /* Assert caller is doing things in a sane order */
1426  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1427  Assert(plansource->is_complete);
1428 
1429  /*
1430  * No work needed if statement doesn't return tuples (we assume this
1431  * feature cannot be changed by an invalidation)
1432  */
1433  if (plansource->resultDesc == NULL)
1434  return NIL;
1435 
1436  /* Make sure the querytree list is valid and we have parse-time locks */
1437  RevalidateCachedQuery(plansource);
1438 
1439  /* Get the primary statement and find out what it returns */
1440  pstmt = QueryListGetPrimaryStmt(plansource->query_list);
1441 
1442  return FetchStatementTargetList((Node *) pstmt);
1443 }
#define NIL
Definition: pg_list.h:69
Definition: nodes.h:522
TupleDesc resultDesc
Definition: plancache.h:91
List * FetchStatementTargetList(Node *stmt)
Definition: pquery.c:357
static Query * QueryListGetPrimaryStmt(List *stmts)
Definition: plancache.c:1454
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
List * query_list
Definition: plancache.h:94
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:24
static List * RevalidateCachedQuery(CachedPlanSource *plansource)
Definition: plancache.c:556
bool CachedPlanIsValid ( CachedPlanSource plansource)

Definition at line 1408 of file plancache.c.

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

Referenced by SPI_plan_is_valid().

1409 {
1410  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1411  return plansource->is_valid;
1412 }
#define Assert(condition)
Definition: c.h:675
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:24
void CachedPlanSetParentContext ( CachedPlanSource plansource,
MemoryContext  newcontext 
)

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

1282 {
1283  /* Assert caller is doing things in a sane order */
1284  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1285  Assert(plansource->is_complete);
1286 
1287  /* These seem worth real tests, though */
1288  if (plansource->is_saved)
1289  elog(ERROR, "cannot move a saved cached plan to another context");
1290  if (plansource->is_oneshot)
1291  elog(ERROR, "cannot move a one-shot cached plan to another context");
1292 
1293  /* OK, let the caller keep the plan where he wishes */
1294  MemoryContextSetParent(plansource->context, newcontext);
1295 
1296  /*
1297  * The query_context needs no special handling, since it's a child of
1298  * plansource->context. But if there's a generic plan, it should be
1299  * maintained as a sibling of plansource->context.
1300  */
1301  if (plansource->gplan)
1302  {
1303  Assert(plansource->gplan->magic == CACHEDPLAN_MAGIC);
1304  MemoryContextSetParent(plansource->gplan->context, newcontext);
1305  }
1306 }
#define CACHEDPLAN_MAGIC
Definition: plancache.h:25
MemoryContext context
Definition: plancache.h:92
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:317
MemoryContext context
Definition: plancache.h:142
struct CachedPlan * gplan
Definition: plancache.h:104
#define ERROR
Definition: elog.h:43
#define Assert(condition)
Definition: c.h:675
#define elog
Definition: elog.h:219
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:24
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:136
#define CACHEDPLAN_MAGIC
Definition: plancache.h:25
static void AcquireExecutorLocks(List *stmt_list, bool acquire)
Definition: plancache.c:1473
bool is_valid
Definition: plancache.h:135
static void ReleaseGenericPlan(CachedPlanSource *plansource)
Definition: plancache.c:528
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
Oid GetUserId(void)
Definition: miscinit.c:283
int refcount
Definition: plancache.h:141
bool dependsOnRole
Definition: plancache.h:137
struct CachedPlan * gplan
Definition: plancache.h:104
TransactionId TransactionXmin
Definition: snapmgr.c:164
#define Assert(condition)
Definition: c.h:675
bool is_oneshot
Definition: plancache.h:133
List * stmt_list
Definition: plancache.h:132
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TransactionId saved_xmin
Definition: plancache.h:138
static bool choose_custom_plan ( CachedPlanSource plansource,
ParamListInfo  boundParams 
)
static

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

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

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

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

1319 {
1320  CachedPlanSource *newsource;
1321  MemoryContext source_context;
1322  MemoryContext querytree_context;
1323  MemoryContext oldcxt;
1324 
1325  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1326  Assert(plansource->is_complete);
1327 
1328  /*
1329  * One-shot plans can't be copied, because we haven't taken care that
1330  * parsing/planning didn't scribble on the raw parse tree or querytrees.
1331  */
1332  if (plansource->is_oneshot)
1333  elog(ERROR, "cannot copy a one-shot cached plan");
1334 
1336  "CachedPlanSource",
1338 
1339  oldcxt = MemoryContextSwitchTo(source_context);
1340 
1341  newsource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
1342  newsource->magic = CACHEDPLANSOURCE_MAGIC;
1343  newsource->raw_parse_tree = copyObject(plansource->raw_parse_tree);
1344  newsource->query_string = pstrdup(plansource->query_string);
1345  newsource->commandTag = plansource->commandTag;
1346  if (plansource->num_params > 0)
1347  {
1348  newsource->param_types = (Oid *)
1349  palloc(plansource->num_params * sizeof(Oid));
1350  memcpy(newsource->param_types, plansource->param_types,
1351  plansource->num_params * sizeof(Oid));
1352  }
1353  else
1354  newsource->param_types = NULL;
1355  newsource->num_params = plansource->num_params;
1356  newsource->parserSetup = plansource->parserSetup;
1357  newsource->parserSetupArg = plansource->parserSetupArg;
1358  newsource->cursor_options = plansource->cursor_options;
1359  newsource->fixed_result = plansource->fixed_result;
1360  if (plansource->resultDesc)
1361  newsource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
1362  else
1363  newsource->resultDesc = NULL;
1364  newsource->context = source_context;
1365 
1366  querytree_context = AllocSetContextCreate(source_context,
1367  "CachedPlanQuery",
1369  MemoryContextSwitchTo(querytree_context);
1370  newsource->query_list = (List *) copyObject(plansource->query_list);
1371  newsource->relationOids = (List *) copyObject(plansource->relationOids);
1372  newsource->invalItems = (List *) copyObject(plansource->invalItems);
1373  if (plansource->search_path)
1374  newsource->search_path = CopyOverrideSearchPath(plansource->search_path);
1375  newsource->query_context = querytree_context;
1376  newsource->rewriteRoleId = plansource->rewriteRoleId;
1377  newsource->rewriteRowSecurity = plansource->rewriteRowSecurity;
1378  newsource->dependsOnRLS = plansource->dependsOnRLS;
1379 
1380  newsource->gplan = NULL;
1381 
1382  newsource->is_oneshot = false;
1383  newsource->is_complete = true;
1384  newsource->is_saved = false;
1385  newsource->is_valid = plansource->is_valid;
1386  newsource->generation = plansource->generation;
1387  newsource->next_saved = NULL;
1388 
1389  /* We may as well copy any acquired cost knowledge */
1390  newsource->generic_cost = plansource->generic_cost;
1391  newsource->total_custom_cost = plansource->total_custom_cost;
1392  newsource->num_custom_plans = plansource->num_custom_plans;
1393 
1394  MemoryContextSwitchTo(oldcxt);
1395 
1396  return newsource;
1397 }
MemoryContext context
Definition: plancache.h:92
bool rewriteRowSecurity
Definition: plancache.h:101
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:141
const char * commandTag
Definition: plancache.h:84
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:115
struct CachedPlan * gplan
Definition: plancache.h:104
TupleDesc resultDesc
Definition: plancache.h:91
void * copyObject(const void *from)
Definition: copyfuncs.c:4619
struct CachedPlanSource * next_saved
Definition: plancache.h:112
#define ERROR
Definition: elog.h:43
OverrideSearchPath * CopyOverrideSearchPath(OverrideSearchPath *path)
Definition: namespace.c:3207
List * invalItems
Definition: plancache.h:96
Oid * param_types
Definition: plancache.h:85
List * relationOids
Definition: plancache.h:95
void * parserSetupArg
Definition: plancache.h:88
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
ParserSetupHook parserSetup
Definition: plancache.h:87
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:114
#define Assert(condition)
Definition: c.h:675
const char * query_string
Definition: plancache.h:83
struct RawStmt * raw_parse_tree
Definition: plancache.h:82
void * palloc(Size size)
Definition: mcxt.c:849
MemoryContext query_context
Definition: plancache.h:99
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:182
List * query_list
Definition: plancache.h:94
#define elog
Definition: elog.h:219
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:24
Definition: pg_list.h:45
struct OverrideSearchPath * search_path
Definition: plancache.h:97
CachedPlanSource* CreateCachedPlan ( RawStmt raw_parse_tree,
const char *  query_string,
const char *  commandTag 
)

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

154 {
155  CachedPlanSource *plansource;
156  MemoryContext source_context;
157  MemoryContext oldcxt;
158 
159  Assert(query_string != NULL); /* required as of 8.4 */
160 
161  /*
162  * Make a dedicated memory context for the CachedPlanSource and its
163  * permanent subsidiary data. It's probably not going to be large, but
164  * just in case, allow it to grow large. Initially it's a child of the
165  * caller's context (which we assume to be transient), so that it will be
166  * cleaned up on error.
167  */
169  "CachedPlanSource",
171 
172  /*
173  * Create and fill the CachedPlanSource struct within the new context.
174  * Most fields are just left empty for the moment.
175  */
176  oldcxt = MemoryContextSwitchTo(source_context);
177 
178  plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
179  plansource->magic = CACHEDPLANSOURCE_MAGIC;
180  plansource->raw_parse_tree = copyObject(raw_parse_tree);
181  plansource->query_string = pstrdup(query_string);
182  plansource->commandTag = commandTag;
183  plansource->param_types = NULL;
184  plansource->num_params = 0;
185  plansource->parserSetup = NULL;
186  plansource->parserSetupArg = NULL;
187  plansource->cursor_options = 0;
188  plansource->fixed_result = false;
189  plansource->resultDesc = NULL;
190  plansource->context = source_context;
191  plansource->query_list = NIL;
192  plansource->relationOids = NIL;
193  plansource->invalItems = NIL;
194  plansource->search_path = NULL;
195  plansource->query_context = NULL;
196  plansource->rewriteRoleId = InvalidOid;
197  plansource->rewriteRowSecurity = false;
198  plansource->dependsOnRLS = false;
199  plansource->gplan = NULL;
200  plansource->is_oneshot = false;
201  plansource->is_complete = false;
202  plansource->is_saved = false;
203  plansource->is_valid = false;
204  plansource->generation = 0;
205  plansource->next_saved = NULL;
206  plansource->generic_cost = -1;
207  plansource->total_custom_cost = 0;
208  plansource->num_custom_plans = 0;
209 
210  MemoryContextSwitchTo(oldcxt);
211 
212  return plansource;
213 }
MemoryContext context
Definition: plancache.h:92
#define NIL
Definition: pg_list.h:69
bool rewriteRowSecurity
Definition: plancache.h:101
const char * commandTag
Definition: plancache.h:84
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:115
struct CachedPlan * gplan
Definition: plancache.h:104
TupleDesc resultDesc
Definition: plancache.h:91
void * copyObject(const void *from)
Definition: copyfuncs.c:4619
struct CachedPlanSource * next_saved
Definition: plancache.h:112
List * invalItems
Definition: plancache.h:96
Oid * param_types
Definition: plancache.h:85
List * relationOids
Definition: plancache.h:95
void * parserSetupArg
Definition: plancache.h:88
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
ParserSetupHook parserSetup
Definition: plancache.h:87
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:114
#define Assert(condition)
Definition: c.h:675
const char * query_string
Definition: plancache.h:83
struct RawStmt * raw_parse_tree
Definition: plancache.h:82
MemoryContext query_context
Definition: plancache.h:99
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:182
List * query_list
Definition: plancache.h:94
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:24
struct OverrideSearchPath * search_path
Definition: plancache.h:97
CachedPlanSource* CreateOneShotCachedPlan ( RawStmt raw_parse_tree,
const char *  query_string,
const char *  commandTag 
)

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

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

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

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

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

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

Definition at line 115 of file plancache.c.

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

Referenced by InitPostgres().

116 {
124 }
static void PlanCacheFuncCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:1767
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition: inval.c:1405
static void PlanCacheRelCallback(Datum arg, Oid relid)
Definition: plancache.c:1702
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1381
uintptr_t Datum
Definition: postgres.h:372
static void PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:1846
static TupleDesc PlanCacheComputeResultDesc ( List stmt_list)
static

Definition at line 1666 of file plancache.c.

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

1667 {
1668  Query *query;
1669 
1670  switch (ChoosePortalStrategy(stmt_list))
1671  {
1672  case PORTAL_ONE_SELECT:
1673  case PORTAL_ONE_MOD_WITH:
1674  query = castNode(Query, linitial(stmt_list));
1675  return ExecCleanTypeFromTL(query->targetList, false);
1676 
1677  case PORTAL_ONE_RETURNING:
1678  query = QueryListGetPrimaryStmt(stmt_list);
1679  Assert(query->returningList);
1680  return ExecCleanTypeFromTL(query->returningList, false);
1681 
1682  case PORTAL_UTIL_SELECT:
1683  query = castNode(Query, linitial(stmt_list));
1684  Assert(query->utilityStmt);
1685  return UtilityTupleDescriptor(query->utilityStmt);
1686 
1687  case PORTAL_MULTI_QUERY:
1688  /* will not return tuples */
1689  break;
1690  }
1691  return NULL;
1692 }
#define castNode(_type_, nodeptr)
Definition: nodes.h:591
Node * utilityStmt
Definition: parsenodes.h:111
List * targetList
Definition: parsenodes.h:131
#define linitial(l)
Definition: pg_list.h:110
static Query * QueryListGetPrimaryStmt(List *stmts)
Definition: plancache.c:1454
List * returningList
Definition: parsenodes.h:135
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
PortalStrategy ChoosePortalStrategy(List *stmts)
Definition: pquery.c:218
TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid)
Definition: execTuples.c:900
TupleDesc UtilityTupleDescriptor(Node *parsetree)
Definition: utility.c:1753
static void PlanCacheFuncCallback ( Datum  arg,
int  cacheid,
uint32  hashvalue 
)
static

Definition at line 1767 of file plancache.c.

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

Referenced by InitPlanCache().

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

Definition at line 1702 of file plancache.c.

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

Referenced by InitPlanCache().

1703 {
1704  CachedPlanSource *plansource;
1705 
1706  for (plansource = first_saved_plan; plansource; plansource = plansource->next_saved)
1707  {
1708  Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1709 
1710  /* No work if it's already invalidated */
1711  if (!plansource->is_valid)
1712  continue;
1713 
1714  /* Never invalidate transaction control commands */
1715  if (IsTransactionStmtPlan(plansource))
1716  continue;
1717 
1718  /*
1719  * Check the dependency list for the rewritten querytree.
1720  */
1721  if ((relid == InvalidOid) ? plansource->relationOids != NIL :
1722  list_member_oid(plansource->relationOids, relid))
1723  {
1724  /* Invalidate the querytree and generic plan */
1725  plansource->is_valid = false;
1726  if (plansource->gplan)
1727  plansource->gplan->is_valid = false;
1728  }
1729 
1730  /*
1731  * The generic plan, if any, could have more dependencies than the
1732  * querytree does, so we have to check it too.
1733  */
1734  if (plansource->gplan && plansource->gplan->is_valid)
1735  {
1736  ListCell *lc;
1737 
1738  foreach(lc, plansource->gplan->stmt_list)
1739  {
1740  PlannedStmt *plannedstmt = castNode(PlannedStmt, lfirst(lc));
1741 
1742  if (plannedstmt->commandType == CMD_UTILITY)
1743  continue; /* Ignore utility statements */
1744  if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
1745  list_member_oid(plannedstmt->relationOids, relid))
1746  {
1747  /* Invalidate the generic plan only */
1748  plansource->gplan->is_valid = false;
1749  break; /* out of stmt_list scan */
1750  }
1751  }
1752  }
1753  }
1754 }
#define NIL
Definition: pg_list.h:69
bool is_valid
Definition: plancache.h:135
#define castNode(_type_, nodeptr)
Definition: nodes.h:591
List * relationOids
Definition: plannodes.h:77
struct CachedPlan * gplan
Definition: plancache.h:104
struct CachedPlanSource * next_saved
Definition: plancache.h:112
static CachedPlanSource * first_saved_plan
Definition: plancache.c:88
List * relationOids
Definition: plancache.h:95
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:675
#define lfirst(lc)
Definition: pg_list.h:106
List * stmt_list
Definition: plancache.h:132
#define IsTransactionStmtPlan(plansource)
Definition: plancache.c:78
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:24
static void PlanCacheSysCallback ( Datum  arg,
int  cacheid,
uint32  hashvalue 
)
static

Definition at line 1846 of file plancache.c.

References ResetPlanCache().

Referenced by InitPlanCache().

1847 {
1848  ResetPlanCache();
1849 }
void ResetPlanCache(void)
Definition: plancache.c:1855
static Query * QueryListGetPrimaryStmt ( List stmts)
static

Definition at line 1454 of file plancache.c.

References Query::canSetTag, castNode, lfirst, and NULL.

Referenced by CachedPlanGetTargetList(), and PlanCacheComputeResultDesc().

1455 {
1456  ListCell *lc;
1457 
1458  foreach(lc, stmts)
1459  {
1460  Query *stmt = castNode(Query, lfirst(lc));
1461 
1462  if (stmt->canSetTag)
1463  return stmt;
1464  }
1465  return NULL;
1466 }
#define castNode(_type_, nodeptr)
Definition: nodes.h:591
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
bool canSetTag
Definition: parsenodes.h:109
void ReleaseCachedPlan ( CachedPlan plan,
bool  useResOwner 
)

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

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

Definition at line 528 of file plancache.c.

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

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

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

Definition at line 1855 of file plancache.c.

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

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

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

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

557 {
558  bool snapshot_set;
559  RawStmt *rawtree;
560  List *tlist; /* transient query-tree list */
561  List *qlist; /* permanent query-tree list */
562  TupleDesc resultDesc;
563  MemoryContext querytree_context;
564  MemoryContext oldcxt;
565 
566  /*
567  * For one-shot plans, we do not support revalidation checking; it's
568  * assumed the query is parsed, planned, and executed in one transaction,
569  * so that no lock re-acquisition is necessary. Also, there is never any
570  * need to revalidate plans for transaction control commands (and we
571  * mustn't risk any catalog accesses when handling those).
572  */
573  if (plansource->is_oneshot || IsTransactionStmtPlan(plansource))
574  {
575  Assert(plansource->is_valid);
576  return NIL;
577  }
578 
579  /*
580  * If the query is currently valid, we should have a saved search_path ---
581  * check to see if that matches the current environment. If not, we want
582  * to force replan.
583  */
584  if (plansource->is_valid)
585  {
586  Assert(plansource->search_path != NULL);
588  {
589  /* Invalidate the querytree and generic plan */
590  plansource->is_valid = false;
591  if (plansource->gplan)
592  plansource->gplan->is_valid = false;
593  }
594  }
595 
596  /*
597  * If the query rewrite phase had a possible RLS dependency, we must redo
598  * it if either the role or the row_security setting has changed.
599  */
600  if (plansource->is_valid && plansource->dependsOnRLS &&
601  (plansource->rewriteRoleId != GetUserId() ||
602  plansource->rewriteRowSecurity != row_security))
603  plansource->is_valid = false;
604 
605  /*
606  * If the query is currently valid, acquire locks on the referenced
607  * objects; then check again. We need to do it this way to cover the race
608  * condition that an invalidation message arrives before we get the locks.
609  */
610  if (plansource->is_valid)
611  {
612  AcquirePlannerLocks(plansource->query_list, true);
613 
614  /*
615  * By now, if any invalidation has happened, the inval callback
616  * functions will have marked the query invalid.
617  */
618  if (plansource->is_valid)
619  {
620  /* Successfully revalidated and locked the query. */
621  return NIL;
622  }
623 
624  /* Oops, the race case happened. Release useless locks. */
625  AcquirePlannerLocks(plansource->query_list, false);
626  }
627 
628  /*
629  * Discard the no-longer-useful query tree. (Note: we don't want to do
630  * this any earlier, else we'd not have been able to release locks
631  * correctly in the race condition case.)
632  */
633  plansource->is_valid = false;
634  plansource->query_list = NIL;
635  plansource->relationOids = NIL;
636  plansource->invalItems = NIL;
637  plansource->search_path = NULL;
638 
639  /*
640  * Free the query_context. We don't really expect MemoryContextDelete to
641  * fail, but just in case, make sure the CachedPlanSource is left in a
642  * reasonably sane state. (The generic plan won't get unlinked yet, but
643  * that's acceptable.)
644  */
645  if (plansource->query_context)
646  {
647  MemoryContext qcxt = plansource->query_context;
648 
649  plansource->query_context = NULL;
650  MemoryContextDelete(qcxt);
651  }
652 
653  /* Drop the generic plan reference if any */
654  ReleaseGenericPlan(plansource);
655 
656  /*
657  * Now re-do parse analysis and rewrite. This not incidentally acquires
658  * the locks we need to do planning safely.
659  */
660  Assert(plansource->is_complete);
661 
662  /*
663  * If a snapshot is already set (the normal case), we can just use that
664  * for parsing/planning. But if it isn't, install one. Note: no point in
665  * checking whether parse analysis requires a snapshot; utility commands
666  * don't have invalidatable plans, so we'd not get here for such a
667  * command.
668  */
669  snapshot_set = false;
670  if (!ActiveSnapshotSet())
671  {
673  snapshot_set = true;
674  }
675 
676  /*
677  * Run parse analysis and rule rewriting. The parser tends to scribble on
678  * its input, so we must copy the raw parse tree to prevent corruption of
679  * the cache.
680  */
681  rawtree = copyObject(plansource->raw_parse_tree);
682  if (rawtree == NULL)
683  tlist = NIL;
684  else if (plansource->parserSetup != NULL)
685  tlist = pg_analyze_and_rewrite_params(rawtree,
686  plansource->query_string,
687  plansource->parserSetup,
688  plansource->parserSetupArg);
689  else
690  tlist = pg_analyze_and_rewrite(rawtree,
691  plansource->query_string,
692  plansource->param_types,
693  plansource->num_params);
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 = (List *) 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:92
#define NIL
Definition: pg_list.h:69
bool rewriteRowSecurity
Definition: plancache.h:101
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:141
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
bool is_valid
Definition: plancache.h:135
static void ReleaseGenericPlan(CachedPlanSource *plansource)
Definition: plancache.c:528
Oid GetUserId(void)
Definition: miscinit.c:283
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:317
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Definition: nodes.h:522
int errcode(int sqlerrcode)
Definition: elog.c:575
void PopActiveSnapshot(void)
Definition: snapmgr.c:807
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:300
struct CachedPlan * gplan
Definition: plancache.h:104
TupleDesc resultDesc
Definition: plancache.h:91
void * copyObject(const void *from)
Definition: copyfuncs.c:4619
List * pg_analyze_and_rewrite(RawStmt *parsetree, const char *query_string, Oid *paramTypes, int numParams)
Definition: postgres.c:644
#define ERROR
Definition: elog.h:43
List * invalItems
Definition: plancache.h:96
OverrideSearchPath * GetOverrideSearchPath(MemoryContext context)
Definition: namespace.c:3171
Oid * param_types
Definition: plancache.h:85
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:728
List * relationOids
Definition: plancache.h:95
void * parserSetupArg
Definition: plancache.h:88
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:846
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
ParserSetupHook parserSetup
Definition: plancache.h:87
#define ereport(elevel, rest)
Definition: elog.h:122
List * pg_analyze_and_rewrite_params(RawStmt *parsetree, const char *query_string, ParserSetupHook parserSetup, void *parserSetupArg)
Definition: postgres.c:679
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
bool OverrideSearchPathMatchesCurrent(OverrideSearchPath *path)
Definition: namespace.c:3223
#define NULL
Definition: c.h:229
bool row_security
Definition: guc.c:449
#define Assert(condition)
Definition: c.h:675
void extract_query_dependencies(Node *query, List **relationOids, List **invalItems, bool *hasRowSecurity)
Definition: setrefs.c:2511
const char * query_string
Definition: plancache.h:83
struct RawStmt * raw_parse_tree
Definition: plancache.h:82
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:266
int errmsg(const char *fmt,...)
Definition: elog.c:797
static void AcquirePlannerLocks(List *stmt_list, bool acquire)
Definition: plancache.c:1543
MemoryContext query_context
Definition: plancache.h:99
bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:352
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:182
List * query_list
Definition: plancache.h:94
#define IsTransactionStmtPlan(plansource)
Definition: plancache.c:78
Definition: pg_list.h:45
static TupleDesc PlanCacheComputeResultDesc(List *stmt_list)
Definition: plancache.c:1666
struct OverrideSearchPath * search_path
Definition: plancache.h:97
void SaveCachedPlan ( CachedPlanSource plansource)

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

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

Definition at line 1568 of file plancache.c.

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

1569 {
1570  ListCell *lc;
1571  int rt_index;
1572 
1573  /* Shouldn't get called on utility commands */
1574  Assert(parsetree->commandType != CMD_UTILITY);
1575 
1576  /*
1577  * First, process RTEs of the current query level.
1578  */
1579  rt_index = 0;
1580  foreach(lc, parsetree->rtable)
1581  {
1582  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
1583  LOCKMODE lockmode;
1584 
1585  rt_index++;
1586  switch (rte->rtekind)
1587  {
1588  case RTE_RELATION:
1589  /* Acquire or release the appropriate type of lock */
1590  if (rt_index == parsetree->resultRelation)
1591  lockmode = RowExclusiveLock;
1592  else if (get_parse_rowmark(parsetree, rt_index) != NULL)
1593  lockmode = RowShareLock;
1594  else
1595  lockmode = AccessShareLock;
1596  if (acquire)
1597  LockRelationOid(rte->relid, lockmode);
1598  else
1599  UnlockRelationOid(rte->relid, lockmode);
1600  break;
1601 
1602  case RTE_SUBQUERY:
1603  /* Recurse into subquery-in-FROM */
1604  ScanQueryForLocks(rte->subquery, acquire);
1605  break;
1606 
1607  default:
1608  /* ignore other types of RTEs */
1609  break;
1610  }
1611  }
1612 
1613  /* Recurse into subquery-in-WITH */
1614  foreach(lc, parsetree->cteList)
1615  {
1617 
1618  ScanQueryForLocks(castNode(Query, cte->ctequery), acquire);
1619  }
1620 
1621  /*
1622  * Recurse into sublink subqueries, too. But we already did the ones in
1623  * the rtable and cteList.
1624  */
1625  if (parsetree->hasSubLinks)
1626  {
1628  (void *) &acquire,
1630  }
1631 }
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2257
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:591
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition: plancache.c:1568
int resultRelation
Definition: parsenodes.h:113
#define AccessShareLock
Definition: lockdefs.h:36
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:22
List * rtable
Definition: parsenodes.h:128
#define RowExclusiveLock
Definition: lockdefs.h:38
static bool ScanQueryWalker(Node *node, bool *acquire)
Definition: plancache.c:1637
#define RowShareLock
Definition: lockdefs.h:37
CmdType commandType
Definition: parsenodes.h:103
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
RTEKind rtekind
Definition: parsenodes.h:916
List * cteList
Definition: parsenodes.h:126
Query * subquery
Definition: parsenodes.h:934
bool hasSubLinks
Definition: parsenodes.h:119
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105
static bool ScanQueryWalker ( Node node,
bool acquire 
)
static

Definition at line 1637 of file plancache.c.

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

Referenced by ScanQueryForLocks().

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

Variable Documentation

CachedPlanSource* first_saved_plan = NULL
static

Definition at line 88 of file plancache.c.

Referenced by SaveCachedPlan().