PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
plancache.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/transam.h"
#include "catalog/namespace.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "parser/analyze.h"
#include "storage/lmgr.h"
#include "tcop/pquery.h"
#include "tcop/utility.h"
#include "utils/inval.h"
#include "utils/memutils.h"
#include "utils/resowner.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 StmtPlanRequiresRevalidation(plansource)
 

Functions

static void ReleaseGenericPlan (CachedPlanSource *plansource)
 
static ListRevalidateCachedQuery (CachedPlanSource *plansource, QueryEnvironment *queryEnv)
 
static bool CheckCachedPlan (CachedPlanSource *plansource)
 
static CachedPlanBuildCachedPlan (CachedPlanSource *plansource, List *qlist, ParamListInfo boundParams, QueryEnvironment *queryEnv)
 
static bool choose_custom_plan (CachedPlanSource *plansource, ParamListInfo boundParams)
 
static double cached_plan_cost (CachedPlan *plan, bool include_planner)
 
static QueryQueryListGetPrimaryStmt (List *stmts)
 
static void AcquireExecutorLocks (List *stmt_list, bool acquire)
 
static void AcquirePlannerLocks (List *stmt_list, bool acquire)
 
static void ScanQueryForLocks (Query *parsetree, bool acquire)
 
static bool ScanQueryWalker (Node *node, bool *acquire)
 
static TupleDesc PlanCacheComputeResultDesc (List *stmt_list)
 
static void PlanCacheRelCallback (Datum arg, Oid relid)
 
static void PlanCacheObjectCallback (Datum arg, int cacheid, uint32 hashvalue)
 
static void PlanCacheSysCallback (Datum arg, int cacheid, uint32 hashvalue)
 
static void ResOwnerReleaseCachedPlan (Datum res)
 
static void ResourceOwnerRememberPlanCacheRef (ResourceOwner owner, CachedPlan *plan)
 
static void ResourceOwnerForgetPlanCacheRef (ResourceOwner owner, CachedPlan *plan)
 
void InitPlanCache (void)
 
CachedPlanSourceCreateCachedPlan (RawStmt *raw_parse_tree, const char *query_string, CommandTag commandTag)
 
CachedPlanSourceCreateOneShotCachedPlan (RawStmt *raw_parse_tree, const char *query_string, CommandTag commandTag)
 
void CompleteCachedPlan (CachedPlanSource *plansource, List *querytree_list, MemoryContext querytree_context, Oid *param_types, int num_params, ParserSetupHook parserSetup, void *parserSetupArg, int cursor_options, bool fixed_result)
 
void SaveCachedPlan (CachedPlanSource *plansource)
 
void DropCachedPlan (CachedPlanSource *plansource)
 
CachedPlanGetCachedPlan (CachedPlanSource *plansource, ParamListInfo boundParams, ResourceOwner owner, QueryEnvironment *queryEnv)
 
void ReleaseCachedPlan (CachedPlan *plan, ResourceOwner owner)
 
bool CachedPlanAllowsSimpleValidityCheck (CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
 
bool CachedPlanIsSimplyValid (CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
 
void CachedPlanSetParentContext (CachedPlanSource *plansource, MemoryContext newcontext)
 
CachedPlanSourceCopyCachedPlan (CachedPlanSource *plansource)
 
bool CachedPlanIsValid (CachedPlanSource *plansource)
 
ListCachedPlanGetTargetList (CachedPlanSource *plansource, QueryEnvironment *queryEnv)
 
CachedExpressionGetCachedExpression (Node *expr)
 
void FreeCachedExpression (CachedExpression *cexpr)
 
void ResetPlanCache (void)
 
void ReleaseAllPlanCacheRefsInOwner (ResourceOwner owner)
 

Variables

static dlist_head saved_plan_list = DLIST_STATIC_INIT(saved_plan_list)
 
static dlist_head cached_expression_list = DLIST_STATIC_INIT(cached_expression_list)
 
static const ResourceOwnerDesc planref_resowner_desc
 
int plan_cache_mode = PLAN_CACHE_MODE_AUTO
 

Macro Definition Documentation

◆ StmtPlanRequiresRevalidation

#define StmtPlanRequiresRevalidation (   plansource)
Value:
((plansource)->raw_parse_tree != NULL && \
stmt_requires_parse_analysis((plansource)->raw_parse_tree))
bool stmt_requires_parse_analysis(RawStmt *parseTree)
Definition: analyze.c:532

Definition at line 85 of file plancache.c.

Function Documentation

◆ AcquireExecutorLocks()

static void AcquireExecutorLocks ( List stmt_list,
bool  acquire 
)
static

Definition at line 1772 of file plancache.c.

1773{
1774 ListCell *lc1;
1775
1776 foreach(lc1, stmt_list)
1777 {
1778 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
1779 ListCell *lc2;
1780
1781 if (plannedstmt->commandType == CMD_UTILITY)
1782 {
1783 /*
1784 * Ignore utility statements, except those (such as EXPLAIN) that
1785 * contain a parsed-but-not-planned query. Note: it's okay to use
1786 * ScanQueryForLocks, even though the query hasn't been through
1787 * rule rewriting, because rewriting doesn't change the query
1788 * representation.
1789 */
1790 Query *query = UtilityContainsQuery(plannedstmt->utilityStmt);
1791
1792 if (query)
1793 ScanQueryForLocks(query, acquire);
1794 continue;
1795 }
1796
1797 foreach(lc2, plannedstmt->rtable)
1798 {
1799 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1800
1801 if (!(rte->rtekind == RTE_RELATION ||
1802 (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid))))
1803 continue;
1804
1805 /*
1806 * Acquire the appropriate type of lock on each relation OID. Note
1807 * that we don't actually try to open the rel, and hence will not
1808 * fail if it's been dropped entirely --- we'll just transiently
1809 * acquire a non-conflicting lock.
1810 */
1811 if (acquire)
1812 LockRelationOid(rte->relid, rte->rellockmode);
1813 else
1814 UnlockRelationOid(rte->relid, rte->rellockmode);
1815 }
1816 }
1817}
#define OidIsValid(objectId)
Definition: c.h:729
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:226
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:107
@ CMD_UTILITY
Definition: nodes.h:270
@ RTE_SUBQUERY
Definition: parsenodes.h:1018
@ RTE_RELATION
Definition: parsenodes.h:1017
#define lfirst(lc)
Definition: pg_list.h:172
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static void ScanQueryForLocks(Query *parsetree, bool acquire)
Definition: plancache.c:1853
CmdType commandType
Definition: plannodes.h:52
Node * utilityStmt
Definition: plannodes.h:95
List * rtable
Definition: plannodes.h:72
RTEKind rtekind
Definition: parsenodes.h:1047
Query * UtilityContainsQuery(Node *parsetree)
Definition: utility.c:2179

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

Referenced by CheckCachedPlan().

◆ AcquirePlannerLocks()

static void AcquirePlannerLocks ( List stmt_list,
bool  acquire 
)
static

Definition at line 1828 of file plancache.c.

1829{
1830 ListCell *lc;
1831
1832 foreach(lc, stmt_list)
1833 {
1834 Query *query = lfirst_node(Query, lc);
1835
1836 if (query->commandType == CMD_UTILITY)
1837 {
1838 /* Ignore utility statements, unless they contain a Query */
1839 query = UtilityContainsQuery(query->utilityStmt);
1840 if (query)
1841 ScanQueryForLocks(query, acquire);
1842 continue;
1843 }
1844
1845 ScanQueryForLocks(query, acquire);
1846 }
1847}
CmdType commandType
Definition: parsenodes.h:121
Node * utilityStmt
Definition: parsenodes.h:136

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

Referenced by RevalidateCachedQuery().

◆ BuildCachedPlan()

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

Definition at line 906 of file plancache.c.

908{
910 List *plist;
911 bool snapshot_set;
912 bool is_transient;
913 MemoryContext plan_context;
915 ListCell *lc;
916
917 /*
918 * Normally the querytree should be valid already, but if it's not,
919 * rebuild it.
920 *
921 * NOTE: GetCachedPlan should have called RevalidateCachedQuery first, so
922 * we ought to be holding sufficient locks to prevent any invalidation.
923 * However, if we're building a custom plan after having built and
924 * rejected a generic plan, it's possible to reach here with is_valid
925 * false due to an invalidation while making the generic plan. In theory
926 * the invalidation must be a false positive, perhaps a consequence of an
927 * sinval reset event or the debug_discard_caches code. But for safety,
928 * let's treat it as real and redo the RevalidateCachedQuery call.
929 */
930 if (!plansource->is_valid)
931 qlist = RevalidateCachedQuery(plansource, queryEnv);
932
933 /*
934 * If we don't already have a copy of the querytree list that can be
935 * scribbled on by the planner, make one. For a one-shot plan, we assume
936 * it's okay to scribble on the original query_list.
937 */
938 if (qlist == NIL)
939 {
940 if (!plansource->is_oneshot)
941 qlist = copyObject(plansource->query_list);
942 else
943 qlist = plansource->query_list;
944 }
945
946 /*
947 * If a snapshot is already set (the normal case), we can just use that
948 * for planning. But if it isn't, and we need one, install one.
949 */
950 snapshot_set = false;
951 if (!ActiveSnapshotSet() &&
952 plansource->raw_parse_tree &&
954 {
956 snapshot_set = true;
957 }
958
959 /*
960 * Generate the plan.
961 */
962 plist = pg_plan_queries(qlist, plansource->query_string,
963 plansource->cursor_options, boundParams);
964
965 /* Release snapshot if we got one */
966 if (snapshot_set)
968
969 /*
970 * Normally we make a dedicated memory context for the CachedPlan and its
971 * subsidiary data. (It's probably not going to be large, but just in
972 * case, allow it to grow large. It's transient for the moment.) But for
973 * a one-shot plan, we just leave it in the caller's memory context.
974 */
975 if (!plansource->is_oneshot)
976 {
978 "CachedPlan",
980 MemoryContextCopyAndSetIdentifier(plan_context, plansource->query_string);
981
982 /*
983 * Copy plan into the new context.
984 */
985 MemoryContextSwitchTo(plan_context);
986
987 plist = copyObject(plist);
988 }
989 else
990 plan_context = CurrentMemoryContext;
991
992 /*
993 * Create and fill the CachedPlan struct within the new context.
994 */
995 plan = (CachedPlan *) palloc(sizeof(CachedPlan));
996 plan->magic = CACHEDPLAN_MAGIC;
997 plan->stmt_list = plist;
998
999 /*
1000 * CachedPlan is dependent on role either if RLS affected the rewrite
1001 * phase or if a role dependency was injected during planning. And it's
1002 * transient if any plan is marked so.
1003 */
1004 plan->planRoleId = GetUserId();
1005 plan->dependsOnRole = plansource->dependsOnRLS;
1006 is_transient = false;
1007 foreach(lc, plist)
1008 {
1009 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1010
1011 if (plannedstmt->commandType == CMD_UTILITY)
1012 continue; /* Ignore utility statements */
1013
1014 if (plannedstmt->transientPlan)
1015 is_transient = true;
1016 if (plannedstmt->dependsOnRole)
1017 plan->dependsOnRole = true;
1018 }
1019 if (is_transient)
1020 {
1022 plan->saved_xmin = TransactionXmin;
1023 }
1024 else
1025 plan->saved_xmin = InvalidTransactionId;
1026 plan->refcount = 0;
1027 plan->context = plan_context;
1028 plan->is_oneshot = plansource->is_oneshot;
1029 plan->is_saved = false;
1030 plan->is_valid = true;
1031
1032 /* assign generation number to new plan */
1033 plan->generation = ++(plansource->generation);
1034
1035 MemoryContextSwitchTo(oldcxt);
1036
1037 return plan;
1038}
#define Assert(condition)
Definition: c.h:812
void * palloc(Size size)
Definition: mcxt.c:1317
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:177
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:101
Oid GetUserId(void)
Definition: miscinit.c:517
#define copyObject(obj)
Definition: nodes.h:224
bool analyze_requires_snapshot(RawStmt *parseTree)
Definition: analyze.c:576
#define NIL
Definition: pg_list.h:68
#define plan(x)
Definition: pg_regress.c:161
static List * RevalidateCachedQuery(CachedPlanSource *plansource, QueryEnvironment *queryEnv)
Definition: plancache.c:583
#define CACHEDPLAN_MAGIC
Definition: plancache.h:41
List * pg_plan_queries(List *querytrees, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:969
MemoryContextSwitchTo(old_ctx)
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:212
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:610
TransactionId TransactionXmin
Definition: snapmgr.c:99
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:740
void PopActiveSnapshot(void)
Definition: snapmgr.c:703
const char * query_string
Definition: plancache.h:100
struct RawStmt * raw_parse_tree
Definition: plancache.h:99
List * query_list
Definition: plancache.h:111
Definition: pg_list.h:54
bool transientPlan
Definition: plannodes.h:62
bool dependsOnRole
Definition: plannodes.h:64
#define InvalidTransactionId
Definition: transam.h:31
#define TransactionIdIsNormal(xid)
Definition: transam.h:42

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

Referenced by GetCachedPlan().

◆ cached_plan_cost()

static double cached_plan_cost ( CachedPlan plan,
bool  include_planner 
)
static

Definition at line 1103 of file plancache.c.

1104{
1105 double result = 0;
1106 ListCell *lc;
1107
1108 foreach(lc, plan->stmt_list)
1109 {
1110 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1111
1112 if (plannedstmt->commandType == CMD_UTILITY)
1113 continue; /* Ignore utility statements */
1114
1115 result += plannedstmt->planTree->total_cost;
1116
1117 if (include_planner)
1118 {
1119 /*
1120 * Currently we use a very crude estimate of planning effort based
1121 * on the number of relations in the finished plan's rangetable.
1122 * Join planning effort actually scales much worse than linearly
1123 * in the number of relations --- but only until the join collapse
1124 * limits kick in. Also, while inheritance child relations surely
1125 * add to planning effort, they don't make the join situation
1126 * worse. So the actual shape of the planning cost curve versus
1127 * number of relations isn't all that obvious. It will take
1128 * considerable work to arrive at a less crude estimate, and for
1129 * now it's not clear that's worth doing.
1130 *
1131 * The other big difficulty here is that we don't have any very
1132 * good model of how planning cost compares to execution costs.
1133 * The current multiplier of 1000 * cpu_operator_cost is probably
1134 * on the low side, but we'll try this for awhile before making a
1135 * more aggressive correction.
1136 *
1137 * If we ever do write a more complicated estimator, it should
1138 * probably live in src/backend/optimizer/ not here.
1139 */
1140 int nrelations = list_length(plannedstmt->rtable);
1141
1142 result += 1000.0 * cpu_operator_cost * (nrelations + 1);
1143 }
1144 }
1145
1146 return result;
1147}
double cpu_operator_cost
Definition: costsize.c:134
static int list_length(const List *l)
Definition: pg_list.h:152
Cost total_cost
Definition: plannodes.h:130
struct Plan * planTree
Definition: plannodes.h:70

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

Referenced by GetCachedPlan().

◆ CachedPlanAllowsSimpleValidityCheck()

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

Definition at line 1336 of file plancache.c.

1338{
1339 ListCell *lc;
1340
1341 /*
1342 * Sanity-check that the caller gave us a validated generic plan. Notice
1343 * that we *don't* assert plansource->is_valid as you might expect; that's
1344 * because it's possible that that's already false when GetCachedPlan
1345 * returns, e.g. because ResetPlanCache happened partway through. We
1346 * should accept the plan as long as plan->is_valid is true, and expect to
1347 * replan after the next CachedPlanIsSimplyValid call.
1348 */
1349 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1350 Assert(plan->magic == CACHEDPLAN_MAGIC);
1351 Assert(plan->is_valid);
1352 Assert(plan == plansource->gplan);
1353 Assert(plansource->search_path != NULL);
1355
1356 /* We don't support oneshot plans here. */
1357 if (plansource->is_oneshot)
1358 return false;
1359 Assert(!plan->is_oneshot);
1360
1361 /*
1362 * If the plan is dependent on RLS considerations, or it's transient,
1363 * reject. These things probably can't ever happen for table-free
1364 * queries, but for safety's sake let's check.
1365 */
1366 if (plansource->dependsOnRLS)
1367 return false;
1368 if (plan->dependsOnRole)
1369 return false;
1370 if (TransactionIdIsValid(plan->saved_xmin))
1371 return false;
1372
1373 /*
1374 * Reject if AcquirePlannerLocks would have anything to do. This is
1375 * simplistic, but there's no need to inquire any more carefully; indeed,
1376 * for current callers it shouldn't even be possible to hit any of these
1377 * checks.
1378 */
1379 foreach(lc, plansource->query_list)
1380 {
1381 Query *query = lfirst_node(Query, lc);
1382
1383 if (query->commandType == CMD_UTILITY)
1384 return false;
1385 if (query->rtable || query->cteList || query->hasSubLinks)
1386 return false;
1387 }
1388
1389 /*
1390 * Reject if AcquireExecutorLocks would have anything to do. This is
1391 * probably unnecessary given the previous check, but let's be safe.
1392 */
1393 foreach(lc, plan->stmt_list)
1394 {
1395 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1396 ListCell *lc2;
1397
1398 if (plannedstmt->commandType == CMD_UTILITY)
1399 return false;
1400
1401 /*
1402 * We have to grovel through the rtable because it's likely to contain
1403 * an RTE_RESULT relation, rather than being totally empty.
1404 */
1405 foreach(lc2, plannedstmt->rtable)
1406 {
1407 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1408
1409 if (rte->rtekind == RTE_RELATION)
1410 return false;
1411 }
1412 }
1413
1414 /*
1415 * Okay, it's simple. Note that what we've primarily established here is
1416 * that no locks need be taken before checking the plan's is_valid flag.
1417 */
1418
1419 /* Bump refcount if requested. */
1420 if (owner)
1421 {
1422 ResourceOwnerEnlarge(owner);
1423 plan->refcount++;
1425 }
1426
1427 return true;
1428}
bool SearchPathMatchesCurrentEnvironment(SearchPathMatcher *path)
Definition: namespace.c:3911
static void ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
Definition: plancache.c:135
#define CACHEDPLANSOURCE_MAGIC
Definition: plancache.h:40
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition: resowner.c:442
struct CachedPlan * gplan
Definition: plancache.h:121
struct SearchPathMatcher * search_path
Definition: plancache.h:114
List * cteList
Definition: parsenodes.h:168
List * rtable
Definition: parsenodes.h:170
#define TransactionIdIsValid(xid)
Definition: transam.h:41

References Assert, CACHEDPLAN_MAGIC, CACHEDPLANSOURCE_MAGIC, CMD_UTILITY, Query::commandType, PlannedStmt::commandType, Query::cteList, CachedPlanSource::dependsOnRLS, CachedPlanSource::gplan, CachedPlanSource::is_oneshot, lfirst, lfirst_node, CachedPlanSource::magic, plan, CachedPlanSource::query_list, ResourceOwnerEnlarge(), ResourceOwnerRememberPlanCacheRef(), Query::rtable, PlannedStmt::rtable, RTE_RELATION, RangeTblEntry::rtekind, CachedPlanSource::search_path, SearchPathMatchesCurrentEnvironment(), and TransactionIdIsValid.

Referenced by exec_eval_simple_expr(), and exec_simple_check_plan().

◆ CachedPlanGetTargetList()

List * CachedPlanGetTargetList ( CachedPlanSource plansource,
QueryEnvironment queryEnv 
)

Definition at line 1640 of file plancache.c.

1642{
1643 Query *pstmt;
1644
1645 /* Assert caller is doing things in a sane order */
1646 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1647 Assert(plansource->is_complete);
1648
1649 /*
1650 * No work needed if statement doesn't return tuples (we assume this
1651 * feature cannot be changed by an invalidation)
1652 */
1653 if (plansource->resultDesc == NULL)
1654 return NIL;
1655
1656 /* Make sure the querytree list is valid and we have parse-time locks */
1657 RevalidateCachedQuery(plansource, queryEnv);
1658
1659 /* Get the primary statement and find out what it returns */
1660 pstmt = QueryListGetPrimaryStmt(plansource->query_list);
1661
1662 return FetchStatementTargetList((Node *) pstmt);
1663}
static Query * QueryListGetPrimaryStmt(List *stmts)
Definition: plancache.c:1753
List * FetchStatementTargetList(Node *stmt)
Definition: pquery.c:348
TupleDesc resultDesc
Definition: plancache.h:108
Definition: nodes.h:129

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

Referenced by exec_describe_statement_message(), and FetchPreparedStatementTargetList().

◆ CachedPlanIsSimplyValid()

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

Definition at line 1451 of file plancache.c.

1453{
1454 /*
1455 * Careful here: since the caller doesn't necessarily hold a refcount on
1456 * the plan to start with, it's possible that "plan" is a dangling
1457 * pointer. Don't dereference it until we've verified that it still
1458 * matches the plansource's gplan (which is either valid or NULL).
1459 */
1460 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1461
1462 /*
1463 * Has cache invalidation fired on this plan? We can check this right
1464 * away since there are no locks that we'd need to acquire first. Note
1465 * that here we *do* check plansource->is_valid, so as to force plan
1466 * rebuild if that's become false.
1467 */
1468 if (!plansource->is_valid ||
1469 plan == NULL || plan != plansource->gplan ||
1470 !plan->is_valid)
1471 return false;
1472
1473 Assert(plan->magic == CACHEDPLAN_MAGIC);
1474
1475 /* Is the search_path still the same as when we made it? */
1476 Assert(plansource->search_path != NULL);
1478 return false;
1479
1480 /* It's still good. Bump refcount if requested. */
1481 if (owner)
1482 {
1483 ResourceOwnerEnlarge(owner);
1484 plan->refcount++;
1486 }
1487
1488 return true;
1489}

References Assert, CACHEDPLAN_MAGIC, CACHEDPLANSOURCE_MAGIC, CachedPlanSource::gplan, CachedPlanSource::is_valid, CachedPlanSource::magic, plan, ResourceOwnerEnlarge(), ResourceOwnerRememberPlanCacheRef(), CachedPlanSource::search_path, and SearchPathMatchesCurrentEnvironment().

Referenced by exec_eval_simple_expr().

◆ CachedPlanIsValid()

bool CachedPlanIsValid ( CachedPlanSource plansource)

Definition at line 1627 of file plancache.c.

1628{
1629 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1630 return plansource->is_valid;
1631}

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

Referenced by SPI_plan_is_valid().

◆ CachedPlanSetParentContext()

void CachedPlanSetParentContext ( CachedPlanSource plansource,
MemoryContext  newcontext 
)

Definition at line 1498 of file plancache.c.

1500{
1501 /* Assert caller is doing things in a sane order */
1502 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1503 Assert(plansource->is_complete);
1504
1505 /* These seem worth real tests, though */
1506 if (plansource->is_saved)
1507 elog(ERROR, "cannot move a saved cached plan to another context");
1508 if (plansource->is_oneshot)
1509 elog(ERROR, "cannot move a one-shot cached plan to another context");
1510
1511 /* OK, let the caller keep the plan where he wishes */
1512 MemoryContextSetParent(plansource->context, newcontext);
1513
1514 /*
1515 * The query_context needs no special handling, since it's a child of
1516 * plansource->context. But if there's a generic plan, it should be
1517 * maintained as a sibling of plansource->context.
1518 */
1519 if (plansource->gplan)
1520 {
1521 Assert(plansource->gplan->magic == CACHEDPLAN_MAGIC);
1522 MemoryContextSetParent(plansource->gplan->context, newcontext);
1523 }
1524}
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:637
MemoryContext context
Definition: plancache.h:109
MemoryContext context
Definition: plancache.h:160

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

◆ CheckCachedPlan()

static bool CheckCachedPlan ( CachedPlanSource plansource)
static

Definition at line 822 of file plancache.c.

823{
824 CachedPlan *plan = plansource->gplan;
825
826 /* Assert that caller checked the querytree */
827 Assert(plansource->is_valid);
828
829 /* If there's no generic plan, just say "false" */
830 if (!plan)
831 return false;
832
833 Assert(plan->magic == CACHEDPLAN_MAGIC);
834 /* Generic plans are never one-shot */
835 Assert(!plan->is_oneshot);
836
837 /*
838 * If plan isn't valid for current role, we can't use it.
839 */
840 if (plan->is_valid && plan->dependsOnRole &&
841 plan->planRoleId != GetUserId())
842 plan->is_valid = false;
843
844 /*
845 * If it appears valid, acquire locks and recheck; this is much the same
846 * logic as in RevalidateCachedQuery, but for a plan.
847 */
848 if (plan->is_valid)
849 {
850 /*
851 * Plan must have positive refcount because it is referenced by
852 * plansource; so no need to fear it disappears under us here.
853 */
854 Assert(plan->refcount > 0);
855
856 AcquireExecutorLocks(plan->stmt_list, true);
857
858 /*
859 * If plan was transient, check to see if TransactionXmin has
860 * advanced, and if so invalidate it.
861 */
862 if (plan->is_valid &&
863 TransactionIdIsValid(plan->saved_xmin) &&
865 plan->is_valid = false;
866
867 /*
868 * By now, if any invalidation has happened, the inval callback
869 * functions will have marked the plan invalid.
870 */
871 if (plan->is_valid)
872 {
873 /* Successfully revalidated and locked the query. */
874 return true;
875 }
876
877 /* Oops, the race case happened. Release useless locks. */
878 AcquireExecutorLocks(plan->stmt_list, false);
879 }
880
881 /*
882 * Plan has been invalidated, so unlink it from the parent and release it.
883 */
884 ReleaseGenericPlan(plansource);
885
886 return false;
887}
static void ReleaseGenericPlan(CachedPlanSource *plansource)
Definition: plancache.c:555
static void AcquireExecutorLocks(List *stmt_list, bool acquire)
Definition: plancache.c:1772
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43

References AcquireExecutorLocks(), Assert, CACHEDPLAN_MAGIC, GetUserId(), CachedPlanSource::gplan, CachedPlanSource::is_valid, plan, ReleaseGenericPlan(), TransactionIdEquals, TransactionIdIsValid, and TransactionXmin.

Referenced by GetCachedPlan().

◆ choose_custom_plan()

static bool choose_custom_plan ( CachedPlanSource plansource,
ParamListInfo  boundParams 
)
static

Definition at line 1046 of file plancache.c.

1047{
1048 double avg_custom_cost;
1049
1050 /* One-shot plans will always be considered custom */
1051 if (plansource->is_oneshot)
1052 return true;
1053
1054 /* Otherwise, never any point in a custom plan if there's no parameters */
1055 if (boundParams == NULL)
1056 return false;
1057 /* ... nor when planning would be a no-op */
1058 if (!StmtPlanRequiresRevalidation(plansource))
1059 return false;
1060
1061 /* Let settings force the decision */
1063 return false;
1065 return true;
1066
1067 /* See if caller wants to force the decision */
1068 if (plansource->cursor_options & CURSOR_OPT_GENERIC_PLAN)
1069 return false;
1070 if (plansource->cursor_options & CURSOR_OPT_CUSTOM_PLAN)
1071 return true;
1072
1073 /* Generate custom plans until we have done at least 5 (arbitrary) */
1074 if (plansource->num_custom_plans < 5)
1075 return true;
1076
1077 avg_custom_cost = plansource->total_custom_cost / plansource->num_custom_plans;
1078
1079 /*
1080 * Prefer generic plan if it's less expensive than the average custom
1081 * plan. (Because we include a charge for cost of planning in the
1082 * custom-plan costs, this means the generic plan only has to be less
1083 * expensive than the execution cost plus replan cost of the custom
1084 * plans.)
1085 *
1086 * Note that if generic_cost is -1 (indicating we've not yet determined
1087 * the generic plan cost), we'll always prefer generic at this point.
1088 */
1089 if (plansource->generic_cost < avg_custom_cost)
1090 return false;
1091
1092 return true;
1093}
#define CURSOR_OPT_GENERIC_PLAN
Definition: parsenodes.h:3315
#define CURSOR_OPT_CUSTOM_PLAN
Definition: parsenodes.h:3316
int plan_cache_mode
Definition: plancache.c:147
#define StmtPlanRequiresRevalidation(plansource)
Definition: plancache.c:85
@ PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN
Definition: plancache.h:34
@ PLAN_CACHE_MODE_FORCE_GENERIC_PLAN
Definition: plancache.h:33
double total_custom_cost
Definition: plancache.h:132
int64 num_custom_plans
Definition: plancache.h:133
double generic_cost
Definition: plancache.h:131

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

Referenced by GetCachedPlan().

◆ CompleteCachedPlan()

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

Definition at line 366 of file plancache.c.

375{
376 MemoryContext source_context = plansource->context;
378
379 /* Assert caller is doing things in a sane order */
380 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
381 Assert(!plansource->is_complete);
382
383 /*
384 * If caller supplied a querytree_context, reparent it underneath the
385 * CachedPlanSource's context; otherwise, create a suitable context and
386 * copy the querytree_list into it. But no data copying should be done
387 * for one-shot plans; for those, assume the passed querytree_list is
388 * sufficiently long-lived.
389 */
390 if (plansource->is_oneshot)
391 {
392 querytree_context = CurrentMemoryContext;
393 }
394 else if (querytree_context != NULL)
395 {
396 MemoryContextSetParent(querytree_context, source_context);
397 MemoryContextSwitchTo(querytree_context);
398 }
399 else
400 {
401 /* Again, it's a good bet the querytree_context can be small */
402 querytree_context = AllocSetContextCreate(source_context,
403 "CachedPlanQuery",
405 MemoryContextSwitchTo(querytree_context);
406 querytree_list = copyObject(querytree_list);
407 }
408
409 plansource->query_context = querytree_context;
410 plansource->query_list = querytree_list;
411
412 if (!plansource->is_oneshot && StmtPlanRequiresRevalidation(plansource))
413 {
414 /*
415 * Use the planner machinery to extract dependencies. Data is saved
416 * in query_context. (We assume that not a lot of extra cruft is
417 * created by this call.) We can skip this for one-shot plans, and
418 * plans not needing revalidation have no such dependencies anyway.
419 */
420 extract_query_dependencies((Node *) querytree_list,
421 &plansource->relationOids,
422 &plansource->invalItems,
423 &plansource->dependsOnRLS);
424
425 /* Update RLS info as well. */
426 plansource->rewriteRoleId = GetUserId();
427 plansource->rewriteRowSecurity = row_security;
428
429 /*
430 * Also save the current search_path in the query_context. (This
431 * should not generate much extra cruft either, since almost certainly
432 * the path is already valid.) Again, we don't really need this for
433 * one-shot plans; and we *must* skip this for transaction control
434 * commands, because this could result in catalog accesses.
435 */
436 plansource->search_path = GetSearchPathMatcher(querytree_context);
437 }
438
439 /*
440 * Save the final parameter types (or other parameter specification data)
441 * into the source_context, as well as our other parameters. Also save
442 * the result tuple descriptor.
443 */
444 MemoryContextSwitchTo(source_context);
445
446 if (num_params > 0)
447 {
448 plansource->param_types = (Oid *) palloc(num_params * sizeof(Oid));
449 memcpy(plansource->param_types, param_types, num_params * sizeof(Oid));
450 }
451 else
452 plansource->param_types = NULL;
453 plansource->num_params = num_params;
454 plansource->parserSetup = parserSetup;
455 plansource->parserSetupArg = parserSetupArg;
456 plansource->cursor_options = cursor_options;
457 plansource->fixed_result = fixed_result;
458 plansource->resultDesc = PlanCacheComputeResultDesc(querytree_list);
459
460 MemoryContextSwitchTo(oldcxt);
461
462 plansource->is_complete = true;
463 plansource->is_valid = true;
464}
bool row_security
Definition: guc_tables.c:510
SearchPathMatcher * GetSearchPathMatcher(MemoryContext context)
Definition: namespace.c:3852
static TupleDesc PlanCacheComputeResultDesc(List *stmt_list)
Definition: plancache.c:1947
unsigned int Oid
Definition: postgres_ext.h:31
void extract_query_dependencies(Node *query, List **relationOids, List **invalItems, bool *hasRowSecurity)
Definition: setrefs.c:3557
MemoryContext query_context
Definition: plancache.h:116
List * invalItems
Definition: plancache.h:113
ParserSetupHook parserSetup
Definition: plancache.h:104
bool rewriteRowSecurity
Definition: plancache.h:118
List * relationOids
Definition: plancache.h:112
void * parserSetupArg
Definition: plancache.h:105

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

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

◆ CopyCachedPlan()

CachedPlanSource * CopyCachedPlan ( CachedPlanSource plansource)

Definition at line 1536 of file plancache.c.

1537{
1538 CachedPlanSource *newsource;
1539 MemoryContext source_context;
1540 MemoryContext querytree_context;
1541 MemoryContext oldcxt;
1542
1543 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1544 Assert(plansource->is_complete);
1545
1546 /*
1547 * One-shot plans can't be copied, because we haven't taken care that
1548 * parsing/planning didn't scribble on the raw parse tree or querytrees.
1549 */
1550 if (plansource->is_oneshot)
1551 elog(ERROR, "cannot copy a one-shot cached plan");
1552
1554 "CachedPlanSource",
1556
1557 oldcxt = MemoryContextSwitchTo(source_context);
1558
1559 newsource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
1560 newsource->magic = CACHEDPLANSOURCE_MAGIC;
1561 newsource->raw_parse_tree = copyObject(plansource->raw_parse_tree);
1562 newsource->query_string = pstrdup(plansource->query_string);
1563 MemoryContextSetIdentifier(source_context, newsource->query_string);
1564 newsource->commandTag = plansource->commandTag;
1565 if (plansource->num_params > 0)
1566 {
1567 newsource->param_types = (Oid *)
1568 palloc(plansource->num_params * sizeof(Oid));
1569 memcpy(newsource->param_types, plansource->param_types,
1570 plansource->num_params * sizeof(Oid));
1571 }
1572 else
1573 newsource->param_types = NULL;
1574 newsource->num_params = plansource->num_params;
1575 newsource->parserSetup = plansource->parserSetup;
1576 newsource->parserSetupArg = plansource->parserSetupArg;
1577 newsource->cursor_options = plansource->cursor_options;
1578 newsource->fixed_result = plansource->fixed_result;
1579 if (plansource->resultDesc)
1580 newsource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
1581 else
1582 newsource->resultDesc = NULL;
1583 newsource->context = source_context;
1584
1585 querytree_context = AllocSetContextCreate(source_context,
1586 "CachedPlanQuery",
1588 MemoryContextSwitchTo(querytree_context);
1589 newsource->query_list = copyObject(plansource->query_list);
1590 newsource->relationOids = copyObject(plansource->relationOids);
1591 newsource->invalItems = copyObject(plansource->invalItems);
1592 if (plansource->search_path)
1593 newsource->search_path = CopySearchPathMatcher(plansource->search_path);
1594 newsource->query_context = querytree_context;
1595 newsource->rewriteRoleId = plansource->rewriteRoleId;
1596 newsource->rewriteRowSecurity = plansource->rewriteRowSecurity;
1597 newsource->dependsOnRLS = plansource->dependsOnRLS;
1598
1599 newsource->gplan = NULL;
1600
1601 newsource->is_oneshot = false;
1602 newsource->is_complete = true;
1603 newsource->is_saved = false;
1604 newsource->is_valid = plansource->is_valid;
1605 newsource->generation = plansource->generation;
1606
1607 /* We may as well copy any acquired cost knowledge */
1608 newsource->generic_cost = plansource->generic_cost;
1609 newsource->total_custom_cost = plansource->total_custom_cost;
1610 newsource->num_generic_plans = plansource->num_generic_plans;
1611 newsource->num_custom_plans = plansource->num_custom_plans;
1612
1613 MemoryContextSwitchTo(oldcxt);
1614
1615 return newsource;
1616}
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void * palloc0(Size size)
Definition: mcxt.c:1347
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:612
SearchPathMatcher * CopySearchPathMatcher(SearchPathMatcher *path)
Definition: namespace.c:3889
CommandTag commandTag
Definition: plancache.h:101
int64 num_generic_plans
Definition: plancache.h:134
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:235

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

Referenced by _SPI_save_plan().

◆ CreateCachedPlan()

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

Definition at line 192 of file plancache.c.

195{
196 CachedPlanSource *plansource;
197 MemoryContext source_context;
198 MemoryContext oldcxt;
199
200 Assert(query_string != NULL); /* required as of 8.4 */
201
202 /*
203 * Make a dedicated memory context for the CachedPlanSource and its
204 * permanent subsidiary data. It's probably not going to be large, but
205 * just in case, allow it to grow large. Initially it's a child of the
206 * caller's context (which we assume to be transient), so that it will be
207 * cleaned up on error.
208 */
210 "CachedPlanSource",
212
213 /*
214 * Create and fill the CachedPlanSource struct within the new context.
215 * Most fields are just left empty for the moment.
216 */
217 oldcxt = MemoryContextSwitchTo(source_context);
218
219 plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
220 plansource->magic = CACHEDPLANSOURCE_MAGIC;
221 plansource->raw_parse_tree = copyObject(raw_parse_tree);
222 plansource->query_string = pstrdup(query_string);
223 MemoryContextSetIdentifier(source_context, plansource->query_string);
224 plansource->commandTag = commandTag;
225 plansource->param_types = NULL;
226 plansource->num_params = 0;
227 plansource->parserSetup = NULL;
228 plansource->parserSetupArg = NULL;
229 plansource->cursor_options = 0;
230 plansource->fixed_result = false;
231 plansource->resultDesc = NULL;
232 plansource->context = source_context;
233 plansource->query_list = NIL;
234 plansource->relationOids = NIL;
235 plansource->invalItems = NIL;
236 plansource->search_path = NULL;
237 plansource->query_context = NULL;
238 plansource->rewriteRoleId = InvalidOid;
239 plansource->rewriteRowSecurity = false;
240 plansource->dependsOnRLS = false;
241 plansource->gplan = NULL;
242 plansource->is_oneshot = false;
243 plansource->is_complete = false;
244 plansource->is_saved = false;
245 plansource->is_valid = false;
246 plansource->generation = 0;
247 plansource->generic_cost = -1;
248 plansource->total_custom_cost = 0;
249 plansource->num_generic_plans = 0;
250 plansource->num_custom_plans = 0;
251
252 MemoryContextSwitchTo(oldcxt);
253
254 return plansource;
255}
#define InvalidOid
Definition: postgres_ext.h:36

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

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

◆ CreateOneShotCachedPlan()

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

Definition at line 276 of file plancache.c.

279{
280 CachedPlanSource *plansource;
281
282 Assert(query_string != NULL); /* required as of 8.4 */
283
284 /*
285 * Create and fill the CachedPlanSource struct within the caller's memory
286 * context. Most fields are just left empty for the moment.
287 */
288 plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
289 plansource->magic = CACHEDPLANSOURCE_MAGIC;
290 plansource->raw_parse_tree = raw_parse_tree;
291 plansource->query_string = query_string;
292 plansource->commandTag = commandTag;
293 plansource->param_types = NULL;
294 plansource->num_params = 0;
295 plansource->parserSetup = NULL;
296 plansource->parserSetupArg = NULL;
297 plansource->cursor_options = 0;
298 plansource->fixed_result = false;
299 plansource->resultDesc = NULL;
300 plansource->context = CurrentMemoryContext;
301 plansource->query_list = NIL;
302 plansource->relationOids = NIL;
303 plansource->invalItems = NIL;
304 plansource->search_path = NULL;
305 plansource->query_context = NULL;
306 plansource->rewriteRoleId = InvalidOid;
307 plansource->rewriteRowSecurity = false;
308 plansource->dependsOnRLS = false;
309 plansource->gplan = NULL;
310 plansource->is_oneshot = true;
311 plansource->is_complete = false;
312 plansource->is_saved = false;
313 plansource->is_valid = false;
314 plansource->generation = 0;
315 plansource->generic_cost = -1;
316 plansource->total_custom_cost = 0;
317 plansource->num_generic_plans = 0;
318 plansource->num_custom_plans = 0;
319
320 return plansource;
321}

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

Referenced by _SPI_prepare_oneshot_plan().

◆ DropCachedPlan()

void DropCachedPlan ( CachedPlanSource plansource)

Definition at line 526 of file plancache.c.

527{
528 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
529
530 /* If it's been saved, remove it from the list */
531 if (plansource->is_saved)
532 {
533 dlist_delete(&plansource->node);
534 plansource->is_saved = false;
535 }
536
537 /* Decrement generic CachedPlan's refcount and drop if no longer needed */
538 ReleaseGenericPlan(plansource);
539
540 /* Mark it no longer valid */
541 plansource->magic = 0;
542
543 /*
544 * Remove the CachedPlanSource and all subsidiary data (including the
545 * query_context if any). But if it's a one-shot we can't free anything.
546 */
547 if (!plansource->is_oneshot)
548 MemoryContextDelete(plansource->context);
549}
static void dlist_delete(dlist_node *node)
Definition: ilist.h:405
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
dlist_node node
Definition: plancache.h:129

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

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

◆ FreeCachedExpression()

void FreeCachedExpression ( CachedExpression cexpr)

Definition at line 1734 of file plancache.c.

1735{
1736 /* Sanity check */
1737 Assert(cexpr->magic == CACHEDEXPR_MAGIC);
1738 /* Unlink from global list */
1739 dlist_delete(&cexpr->node);
1740 /* Free all storage associated with CachedExpression */
1742}
#define CACHEDEXPR_MAGIC
Definition: plancache.h:42
MemoryContext context
Definition: plancache.h:183
dlist_node node
Definition: plancache.h:184

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

Referenced by get_cast_hashentry().

◆ GetCachedExpression()

CachedExpression * GetCachedExpression ( Node expr)

Definition at line 1677 of file plancache.c.

1678{
1679 CachedExpression *cexpr;
1680 List *relationOids;
1681 List *invalItems;
1682 MemoryContext cexpr_context;
1683 MemoryContext oldcxt;
1684
1685 /*
1686 * Pass the expression through the planner, and collect dependencies.
1687 * Everything built here is leaked in the caller's context; that's
1688 * intentional to minimize the size of the permanent data structure.
1689 */
1690 expr = (Node *) expression_planner_with_deps((Expr *) expr,
1691 &relationOids,
1692 &invalItems);
1693
1694 /*
1695 * Make a private memory context, and copy what we need into that. To
1696 * avoid leaking a long-lived context if we fail while copying data, we
1697 * initially make the context under the caller's context.
1698 */
1700 "CachedExpression",
1702
1703 oldcxt = MemoryContextSwitchTo(cexpr_context);
1704
1705 cexpr = (CachedExpression *) palloc(sizeof(CachedExpression));
1706 cexpr->magic = CACHEDEXPR_MAGIC;
1707 cexpr->expr = copyObject(expr);
1708 cexpr->is_valid = true;
1709 cexpr->relationOids = copyObject(relationOids);
1710 cexpr->invalItems = copyObject(invalItems);
1711 cexpr->context = cexpr_context;
1712
1713 MemoryContextSwitchTo(oldcxt);
1714
1715 /*
1716 * Reparent the expr's memory context under CacheMemoryContext so that it
1717 * will live indefinitely.
1718 */
1720
1721 /*
1722 * Add the entry to the global list of cached expressions.
1723 */
1725
1726 return cexpr;
1727}
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:364
MemoryContext CacheMemoryContext
Definition: mcxt.c:152
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:170
static dlist_head cached_expression_list
Definition: plancache.c:100
Expr * expression_planner_with_deps(Expr *expr, List **relationOids, List **invalItems)
Definition: planner.c:6597
List * relationOids
Definition: plancache.h:181
List * invalItems
Definition: plancache.h:182

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, cached_expression_list, CACHEDEXPR_MAGIC, CacheMemoryContext, CachedExpression::context, copyObject, CurrentMemoryContext, dlist_push_tail(), CachedExpression::expr, expression_planner_with_deps(), CachedExpression::invalItems, CachedExpression::is_valid, CachedExpression::magic, MemoryContextSetParent(), MemoryContextSwitchTo(), CachedExpression::node, palloc(), and CachedExpression::relationOids.

Referenced by get_cast_hashentry().

◆ GetCachedPlan()

CachedPlan * GetCachedPlan ( CachedPlanSource plansource,
ParamListInfo  boundParams,
ResourceOwner  owner,
QueryEnvironment queryEnv 
)

Definition at line 1168 of file plancache.c.

1170{
1171 CachedPlan *plan = NULL;
1172 List *qlist;
1173 bool customplan;
1174
1175 /* Assert caller is doing things in a sane order */
1176 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1177 Assert(plansource->is_complete);
1178 /* This seems worth a real test, though */
1179 if (owner && !plansource->is_saved)
1180 elog(ERROR, "cannot apply ResourceOwner to non-saved cached plan");
1181
1182 /* Make sure the querytree list is valid and we have parse-time locks */
1183 qlist = RevalidateCachedQuery(plansource, queryEnv);
1184
1185 /* Decide whether to use a custom plan */
1186 customplan = choose_custom_plan(plansource, boundParams);
1187
1188 if (!customplan)
1189 {
1190 if (CheckCachedPlan(plansource))
1191 {
1192 /* We want a generic plan, and we already have a valid one */
1193 plan = plansource->gplan;
1194 Assert(plan->magic == CACHEDPLAN_MAGIC);
1195 }
1196 else
1197 {
1198 /* Build a new generic plan */
1199 plan = BuildCachedPlan(plansource, qlist, NULL, queryEnv);
1200 /* Just make real sure plansource->gplan is clear */
1201 ReleaseGenericPlan(plansource);
1202 /* Link the new generic plan into the plansource */
1203 plansource->gplan = plan;
1204 plan->refcount++;
1205 /* Immediately reparent into appropriate context */
1206 if (plansource->is_saved)
1207 {
1208 /* saved plans all live under CacheMemoryContext */
1210 plan->is_saved = true;
1211 }
1212 else
1213 {
1214 /* otherwise, it should be a sibling of the plansource */
1216 MemoryContextGetParent(plansource->context));
1217 }
1218 /* Update generic_cost whenever we make a new generic plan */
1219 plansource->generic_cost = cached_plan_cost(plan, false);
1220
1221 /*
1222 * If, based on the now-known value of generic_cost, we'd not have
1223 * chosen to use a generic plan, then forget it and make a custom
1224 * plan. This is a bit of a wart but is necessary to avoid a
1225 * glitch in behavior when the custom plans are consistently big
1226 * winners; at some point we'll experiment with a generic plan and
1227 * find it's a loser, but we don't want to actually execute that
1228 * plan.
1229 */
1230 customplan = choose_custom_plan(plansource, boundParams);
1231
1232 /*
1233 * If we choose to plan again, we need to re-copy the query_list,
1234 * since the planner probably scribbled on it. We can force
1235 * BuildCachedPlan to do that by passing NIL.
1236 */
1237 qlist = NIL;
1238 }
1239 }
1240
1241 if (customplan)
1242 {
1243 /* Build a custom plan */
1244 plan = BuildCachedPlan(plansource, qlist, boundParams, queryEnv);
1245 /* Accumulate total costs of custom plans */
1246 plansource->total_custom_cost += cached_plan_cost(plan, true);
1247
1248 plansource->num_custom_plans++;
1249 }
1250 else
1251 {
1252 plansource->num_generic_plans++;
1253 }
1254
1255 Assert(plan != NULL);
1256
1257 /* Flag the plan as in use by caller */
1258 if (owner)
1259 ResourceOwnerEnlarge(owner);
1260 plan->refcount++;
1261 if (owner)
1263
1264 /*
1265 * Saved plans should be under CacheMemoryContext so they will not go away
1266 * until their reference count goes to zero. In the generic-plan cases we
1267 * already took care of that, but for a custom plan, do it as soon as we
1268 * have created a reference-counted link.
1269 */
1270 if (customplan && plansource->is_saved)
1271 {
1273 plan->is_saved = true;
1274 }
1275
1276 return plan;
1277}
MemoryContext MemoryContextGetParent(MemoryContext context)
Definition: mcxt.c:731
static bool choose_custom_plan(CachedPlanSource *plansource, ParamListInfo boundParams)
Definition: plancache.c:1046
static CachedPlan * BuildCachedPlan(CachedPlanSource *plansource, List *qlist, ParamListInfo boundParams, QueryEnvironment *queryEnv)
Definition: plancache.c:906
static bool CheckCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:822
static double cached_plan_cost(CachedPlan *plan, bool include_planner)
Definition: plancache.c:1103

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

◆ InitPlanCache()

void InitPlanCache ( void  )

Definition at line 155 of file plancache.c.

156{
164 CacheRegisterSyscacheCallback(FOREIGNDATAWRAPPEROID, PlanCacheSysCallback, (Datum) 0);
165}
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition: inval.c:1746
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1704
static void PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:2176
static void PlanCacheObjectCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: plancache.c:2067
static void PlanCacheRelCallback(Datum arg, Oid relid)
Definition: plancache.c:1983
uintptr_t Datum
Definition: postgres.h:64

References CacheRegisterRelcacheCallback(), CacheRegisterSyscacheCallback(), PlanCacheObjectCallback(), PlanCacheRelCallback(), and PlanCacheSysCallback().

Referenced by InitPostgres().

◆ PlanCacheComputeResultDesc()

static TupleDesc PlanCacheComputeResultDesc ( List stmt_list)
static

Definition at line 1947 of file plancache.c.

1948{
1949 Query *query;
1950
1951 switch (ChoosePortalStrategy(stmt_list))
1952 {
1953 case PORTAL_ONE_SELECT:
1955 query = linitial_node(Query, stmt_list);
1956 return ExecCleanTypeFromTL(query->targetList);
1957
1959 query = QueryListGetPrimaryStmt(stmt_list);
1960 Assert(query->returningList);
1961 return ExecCleanTypeFromTL(query->returningList);
1962
1963 case PORTAL_UTIL_SELECT:
1964 query = linitial_node(Query, stmt_list);
1965 Assert(query->utilityStmt);
1966 return UtilityTupleDescriptor(query->utilityStmt);
1967
1968 case PORTAL_MULTI_QUERY:
1969 /* will not return tuples */
1970 break;
1971 }
1972 return NULL;
1973}
TupleDesc ExecCleanTypeFromTL(List *targetList)
Definition: execTuples.c:2137
#define linitial_node(type, l)
Definition: pg_list.h:181
@ PORTAL_ONE_RETURNING
Definition: portal.h:92
@ PORTAL_MULTI_QUERY
Definition: portal.h:95
@ PORTAL_ONE_SELECT
Definition: portal.h:91
@ PORTAL_ONE_MOD_WITH
Definition: portal.h:93
@ PORTAL_UTIL_SELECT
Definition: portal.h:94
PortalStrategy ChoosePortalStrategy(List *stmts)
Definition: pquery.c:209
List * returningList
Definition: parsenodes.h:200
List * targetList
Definition: parsenodes.h:193
TupleDesc UtilityTupleDescriptor(Node *parsetree)
Definition: utility.c:2084

References Assert, ChoosePortalStrategy(), ExecCleanTypeFromTL(), linitial_node, PORTAL_MULTI_QUERY, PORTAL_ONE_MOD_WITH, PORTAL_ONE_RETURNING, PORTAL_ONE_SELECT, PORTAL_UTIL_SELECT, QueryListGetPrimaryStmt(), Query::returningList, Query::targetList, Query::utilityStmt, and UtilityTupleDescriptor().

Referenced by CompleteCachedPlan(), and RevalidateCachedQuery().

◆ PlanCacheObjectCallback()

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

Definition at line 2067 of file plancache.c.

2068{
2069 dlist_iter iter;
2070
2072 {
2074 node, iter.cur);
2075 ListCell *lc;
2076
2077 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2078
2079 /* No work if it's already invalidated */
2080 if (!plansource->is_valid)
2081 continue;
2082
2083 /* Never invalidate if parse/plan would be a no-op anyway */
2084 if (!StmtPlanRequiresRevalidation(plansource))
2085 continue;
2086
2087 /*
2088 * Check the dependency list for the rewritten querytree.
2089 */
2090 foreach(lc, plansource->invalItems)
2091 {
2092 PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2093
2094 if (item->cacheId != cacheid)
2095 continue;
2096 if (hashvalue == 0 ||
2097 item->hashValue == hashvalue)
2098 {
2099 /* Invalidate the querytree and generic plan */
2100 plansource->is_valid = false;
2101 if (plansource->gplan)
2102 plansource->gplan->is_valid = false;
2103 break;
2104 }
2105 }
2106
2107 /*
2108 * The generic plan, if any, could have more dependencies than the
2109 * querytree does, so we have to check it too.
2110 */
2111 if (plansource->gplan && plansource->gplan->is_valid)
2112 {
2113 foreach(lc, plansource->gplan->stmt_list)
2114 {
2115 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2116 ListCell *lc3;
2117
2118 if (plannedstmt->commandType == CMD_UTILITY)
2119 continue; /* Ignore utility statements */
2120 foreach(lc3, plannedstmt->invalItems)
2121 {
2122 PlanInvalItem *item = (PlanInvalItem *) lfirst(lc3);
2123
2124 if (item->cacheId != cacheid)
2125 continue;
2126 if (hashvalue == 0 ||
2127 item->hashValue == hashvalue)
2128 {
2129 /* Invalidate the generic plan only */
2130 plansource->gplan->is_valid = false;
2131 break; /* out of invalItems scan */
2132 }
2133 }
2134 if (!plansource->gplan->is_valid)
2135 break; /* out of stmt_list scan */
2136 }
2137 }
2138 }
2139
2140 /* Likewise check cached expressions */
2142 {
2144 node, iter.cur);
2145 ListCell *lc;
2146
2147 Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2148
2149 /* No work if it's already invalidated */
2150 if (!cexpr->is_valid)
2151 continue;
2152
2153 foreach(lc, cexpr->invalItems)
2154 {
2155 PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2156
2157 if (item->cacheId != cacheid)
2158 continue;
2159 if (hashvalue == 0 ||
2160 item->hashValue == hashvalue)
2161 {
2162 cexpr->is_valid = false;
2163 break;
2164 }
2165 }
2166 }
2167}
#define dlist_foreach(iter, lhead)
Definition: ilist.h:623
#define dlist_container(type, membername, ptr)
Definition: ilist.h:593
static dlist_head saved_plan_list
Definition: plancache.c:95
bool is_valid
Definition: plancache.h:153
List * stmt_list
Definition: plancache.h:150
uint32 hashValue
Definition: plannodes.h:1571
List * invalItems
Definition: plannodes.h:91
dlist_node * cur
Definition: ilist.h:179

References Assert, cached_expression_list, CACHEDEXPR_MAGIC, CACHEDPLANSOURCE_MAGIC, PlanInvalItem::cacheId, CMD_UTILITY, PlannedStmt::commandType, dlist_iter::cur, dlist_container, dlist_foreach, CachedPlanSource::gplan, PlanInvalItem::hashValue, PlannedStmt::invalItems, CachedPlanSource::invalItems, CachedExpression::invalItems, CachedPlanSource::is_valid, CachedPlan::is_valid, CachedExpression::is_valid, lfirst, lfirst_node, CachedPlanSource::magic, CachedExpression::magic, saved_plan_list, CachedPlan::stmt_list, and StmtPlanRequiresRevalidation.

Referenced by InitPlanCache().

◆ PlanCacheRelCallback()

static void PlanCacheRelCallback ( Datum  arg,
Oid  relid 
)
static

Definition at line 1983 of file plancache.c.

1984{
1985 dlist_iter iter;
1986
1988 {
1990 node, iter.cur);
1991
1992 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1993
1994 /* No work if it's already invalidated */
1995 if (!plansource->is_valid)
1996 continue;
1997
1998 /* Never invalidate if parse/plan would be a no-op anyway */
1999 if (!StmtPlanRequiresRevalidation(plansource))
2000 continue;
2001
2002 /*
2003 * Check the dependency list for the rewritten querytree.
2004 */
2005 if ((relid == InvalidOid) ? plansource->relationOids != NIL :
2006 list_member_oid(plansource->relationOids, relid))
2007 {
2008 /* Invalidate the querytree and generic plan */
2009 plansource->is_valid = false;
2010 if (plansource->gplan)
2011 plansource->gplan->is_valid = false;
2012 }
2013
2014 /*
2015 * The generic plan, if any, could have more dependencies than the
2016 * querytree does, so we have to check it too.
2017 */
2018 if (plansource->gplan && plansource->gplan->is_valid)
2019 {
2020 ListCell *lc;
2021
2022 foreach(lc, plansource->gplan->stmt_list)
2023 {
2024 PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2025
2026 if (plannedstmt->commandType == CMD_UTILITY)
2027 continue; /* Ignore utility statements */
2028 if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
2029 list_member_oid(plannedstmt->relationOids, relid))
2030 {
2031 /* Invalidate the generic plan only */
2032 plansource->gplan->is_valid = false;
2033 break; /* out of stmt_list scan */
2034 }
2035 }
2036 }
2037 }
2038
2039 /* Likewise check cached expressions */
2041 {
2043 node, iter.cur);
2044
2045 Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2046
2047 /* No work if it's already invalidated */
2048 if (!cexpr->is_valid)
2049 continue;
2050
2051 if ((relid == InvalidOid) ? cexpr->relationOids != NIL :
2052 list_member_oid(cexpr->relationOids, relid))
2053 {
2054 cexpr->is_valid = false;
2055 }
2056 }
2057}
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:722
List * relationOids
Definition: plannodes.h:89

References Assert, cached_expression_list, CACHEDEXPR_MAGIC, CACHEDPLANSOURCE_MAGIC, CMD_UTILITY, PlannedStmt::commandType, dlist_iter::cur, dlist_container, dlist_foreach, CachedPlanSource::gplan, InvalidOid, CachedPlanSource::is_valid, CachedPlan::is_valid, CachedExpression::is_valid, lfirst_node, list_member_oid(), CachedPlanSource::magic, CachedExpression::magic, NIL, PlannedStmt::relationOids, CachedPlanSource::relationOids, CachedExpression::relationOids, saved_plan_list, CachedPlan::stmt_list, and StmtPlanRequiresRevalidation.

Referenced by InitPlanCache().

◆ PlanCacheSysCallback()

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

Definition at line 2176 of file plancache.c.

2177{
2179}
void ResetPlanCache(void)
Definition: plancache.c:2185

References ResetPlanCache().

Referenced by InitPlanCache().

◆ QueryListGetPrimaryStmt()

static Query * QueryListGetPrimaryStmt ( List stmts)
static

Definition at line 1753 of file plancache.c.

1754{
1755 ListCell *lc;
1756
1757 foreach(lc, stmts)
1758 {
1759 Query *stmt = lfirst_node(Query, lc);
1760
1761 if (stmt->canSetTag)
1762 return stmt;
1763 }
1764 return NULL;
1765}
#define stmt
Definition: indent_codes.h:59

References lfirst_node, and stmt.

Referenced by CachedPlanGetTargetList(), and PlanCacheComputeResultDesc().

◆ ReleaseAllPlanCacheRefsInOwner()

void ReleaseAllPlanCacheRefsInOwner ( ResourceOwner  owner)

Definition at line 2232 of file plancache.c.

2233{
2235}
static const ResourceOwnerDesc planref_resowner_desc
Definition: plancache.c:124
void ResourceOwnerReleaseAllOfKind(ResourceOwner owner, const ResourceOwnerDesc *kind)
Definition: resowner.c:801

References planref_resowner_desc, and ResourceOwnerReleaseAllOfKind().

Referenced by plpgsql_call_handler(), plpgsql_inline_handler(), and plpgsql_xact_cb().

◆ ReleaseCachedPlan()

void ReleaseCachedPlan ( CachedPlan plan,
ResourceOwner  owner 
)

Definition at line 1291 of file plancache.c.

1292{
1293 Assert(plan->magic == CACHEDPLAN_MAGIC);
1294 if (owner)
1295 {
1296 Assert(plan->is_saved);
1298 }
1299 Assert(plan->refcount > 0);
1300 plan->refcount--;
1301 if (plan->refcount == 0)
1302 {
1303 /* Mark it no longer valid */
1304 plan->magic = 0;
1305
1306 /* One-shot plans do not own their context, so we can't free them */
1307 if (!plan->is_oneshot)
1308 MemoryContextDelete(plan->context);
1309 }
1310}
static void ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
Definition: plancache.c:140

References Assert, CACHEDPLAN_MAGIC, MemoryContextDelete(), plan, and ResourceOwnerForgetPlanCacheRef().

Referenced by _SPI_execute_plan(), exec_eval_simple_expr(), exec_simple_check_plan(), ExplainExecuteQuery(), make_callstmt_target(), PortalReleaseCachedPlan(), ReleaseGenericPlan(), ResOwnerReleaseCachedPlan(), and SPI_cursor_open_internal().

◆ ReleaseGenericPlan()

static void ReleaseGenericPlan ( CachedPlanSource plansource)
static

Definition at line 555 of file plancache.c.

556{
557 /* Be paranoid about the possibility that ReleaseCachedPlan fails */
558 if (plansource->gplan)
559 {
560 CachedPlan *plan = plansource->gplan;
561
562 Assert(plan->magic == CACHEDPLAN_MAGIC);
563 plansource->gplan = NULL;
564 ReleaseCachedPlan(plan, NULL);
565 }
566}
void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1291

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

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

◆ ResetPlanCache()

void ResetPlanCache ( void  )

Definition at line 2185 of file plancache.c.

2186{
2187 dlist_iter iter;
2188
2190 {
2192 node, iter.cur);
2193
2194 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2195
2196 /* No work if it's already invalidated */
2197 if (!plansource->is_valid)
2198 continue;
2199
2200 /*
2201 * We *must not* mark transaction control statements as invalid,
2202 * particularly not ROLLBACK, because they may need to be executed in
2203 * aborted transactions when we can't revalidate them (cf bug #5269).
2204 * In general there's no point in invalidating statements for which a
2205 * new parse analysis/rewrite/plan cycle would certainly give the same
2206 * results.
2207 */
2208 if (!StmtPlanRequiresRevalidation(plansource))
2209 continue;
2210
2211 plansource->is_valid = false;
2212 if (plansource->gplan)
2213 plansource->gplan->is_valid = false;
2214 }
2215
2216 /* Likewise invalidate cached expressions */
2218 {
2220 node, iter.cur);
2221
2222 Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2223
2224 cexpr->is_valid = false;
2225 }
2226}

References Assert, cached_expression_list, CACHEDEXPR_MAGIC, CACHEDPLANSOURCE_MAGIC, dlist_iter::cur, dlist_container, dlist_foreach, CachedPlanSource::gplan, CachedPlanSource::is_valid, CachedPlan::is_valid, CachedExpression::is_valid, CachedPlanSource::magic, CachedExpression::magic, saved_plan_list, and StmtPlanRequiresRevalidation.

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

◆ ResourceOwnerForgetPlanCacheRef()

static void ResourceOwnerForgetPlanCacheRef ( ResourceOwner  owner,
CachedPlan plan 
)
inlinestatic

Definition at line 140 of file plancache.c.

141{
143}
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
void ResourceOwnerForget(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:554

References plan, planref_resowner_desc, PointerGetDatum(), and ResourceOwnerForget().

Referenced by ReleaseCachedPlan().

◆ ResourceOwnerRememberPlanCacheRef()

static void ResourceOwnerRememberPlanCacheRef ( ResourceOwner  owner,
CachedPlan plan 
)
inlinestatic

Definition at line 135 of file plancache.c.

136{
138}
void ResourceOwnerRemember(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:514

References plan, planref_resowner_desc, PointerGetDatum(), and ResourceOwnerRemember().

Referenced by CachedPlanAllowsSimpleValidityCheck(), CachedPlanIsSimplyValid(), and GetCachedPlan().

◆ ResOwnerReleaseCachedPlan()

static void ResOwnerReleaseCachedPlan ( Datum  res)
static

Definition at line 2240 of file plancache.c.

2241{
2243}
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312

References DatumGetPointer(), ReleaseCachedPlan(), and res.

◆ RevalidateCachedQuery()

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

Definition at line 583 of file plancache.c.

585{
586 bool snapshot_set;
587 RawStmt *rawtree;
588 List *tlist; /* transient query-tree list */
589 List *qlist; /* permanent query-tree list */
590 TupleDesc resultDesc;
591 MemoryContext querytree_context;
592 MemoryContext oldcxt;
593
594 /*
595 * For one-shot plans, we do not support revalidation checking; it's
596 * assumed the query is parsed, planned, and executed in one transaction,
597 * so that no lock re-acquisition is necessary. Also, if the statement
598 * type can't require revalidation, we needn't do anything (and we mustn't
599 * risk catalog accesses when handling, eg, transaction control commands).
600 */
601 if (plansource->is_oneshot || !StmtPlanRequiresRevalidation(plansource))
602 {
603 Assert(plansource->is_valid);
604 return NIL;
605 }
606
607 /*
608 * If the query is currently valid, we should have a saved search_path ---
609 * check to see if that matches the current environment. If not, we want
610 * to force replan.
611 */
612 if (plansource->is_valid)
613 {
614 Assert(plansource->search_path != NULL);
616 {
617 /* Invalidate the querytree and generic plan */
618 plansource->is_valid = false;
619 if (plansource->gplan)
620 plansource->gplan->is_valid = false;
621 }
622 }
623
624 /*
625 * If the query rewrite phase had a possible RLS dependency, we must redo
626 * it if either the role or the row_security setting has changed.
627 */
628 if (plansource->is_valid && plansource->dependsOnRLS &&
629 (plansource->rewriteRoleId != GetUserId() ||
630 plansource->rewriteRowSecurity != row_security))
631 plansource->is_valid = false;
632
633 /*
634 * If the query is currently valid, acquire locks on the referenced
635 * objects; then check again. We need to do it this way to cover the race
636 * condition that an invalidation message arrives before we get the locks.
637 */
638 if (plansource->is_valid)
639 {
640 AcquirePlannerLocks(plansource->query_list, true);
641
642 /*
643 * By now, if any invalidation has happened, the inval callback
644 * functions will have marked the query invalid.
645 */
646 if (plansource->is_valid)
647 {
648 /* Successfully revalidated and locked the query. */
649 return NIL;
650 }
651
652 /* Oops, the race case happened. Release useless locks. */
653 AcquirePlannerLocks(plansource->query_list, false);
654 }
655
656 /*
657 * Discard the no-longer-useful query tree. (Note: we don't want to do
658 * this any earlier, else we'd not have been able to release locks
659 * correctly in the race condition case.)
660 */
661 plansource->is_valid = false;
662 plansource->query_list = NIL;
663 plansource->relationOids = NIL;
664 plansource->invalItems = NIL;
665 plansource->search_path = NULL;
666
667 /*
668 * Free the query_context. We don't really expect MemoryContextDelete to
669 * fail, but just in case, make sure the CachedPlanSource is left in a
670 * reasonably sane state. (The generic plan won't get unlinked yet, but
671 * that's acceptable.)
672 */
673 if (plansource->query_context)
674 {
675 MemoryContext qcxt = plansource->query_context;
676
677 plansource->query_context = NULL;
679 }
680
681 /* Drop the generic plan reference if any */
682 ReleaseGenericPlan(plansource);
683
684 /*
685 * Now re-do parse analysis and rewrite. This not incidentally acquires
686 * the locks we need to do planning safely.
687 */
688 Assert(plansource->is_complete);
689
690 /*
691 * If a snapshot is already set (the normal case), we can just use that
692 * for parsing/planning. But if it isn't, install one. Note: no point in
693 * checking whether parse analysis requires a snapshot; utility commands
694 * don't have invalidatable plans, so we'd not get here for such a
695 * command.
696 */
697 snapshot_set = false;
698 if (!ActiveSnapshotSet())
699 {
701 snapshot_set = true;
702 }
703
704 /*
705 * Run parse analysis and rule rewriting. The parser tends to scribble on
706 * its input, so we must copy the raw parse tree to prevent corruption of
707 * the cache.
708 */
709 rawtree = copyObject(plansource->raw_parse_tree);
710 if (rawtree == NULL)
711 tlist = NIL;
712 else if (plansource->parserSetup != NULL)
713 tlist = pg_analyze_and_rewrite_withcb(rawtree,
714 plansource->query_string,
715 plansource->parserSetup,
716 plansource->parserSetupArg,
717 queryEnv);
718 else
720 plansource->query_string,
721 plansource->param_types,
722 plansource->num_params,
723 queryEnv);
724
725 /* Release snapshot if we got one */
726 if (snapshot_set)
728
729 /*
730 * Check or update the result tupdesc.
731 *
732 * We assume the parameter types didn't change from the first time, so no
733 * need to update that.
734 */
735 resultDesc = PlanCacheComputeResultDesc(tlist);
736 if (resultDesc == NULL && plansource->resultDesc == NULL)
737 {
738 /* OK, doesn't return tuples */
739 }
740 else if (resultDesc == NULL || plansource->resultDesc == NULL ||
741 !equalRowTypes(resultDesc, plansource->resultDesc))
742 {
743 /* can we give a better error message? */
744 if (plansource->fixed_result)
746 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
747 errmsg("cached plan must not change result type")));
748 oldcxt = MemoryContextSwitchTo(plansource->context);
749 if (resultDesc)
750 resultDesc = CreateTupleDescCopy(resultDesc);
751 if (plansource->resultDesc)
752 FreeTupleDesc(plansource->resultDesc);
753 plansource->resultDesc = resultDesc;
754 MemoryContextSwitchTo(oldcxt);
755 }
756
757 /*
758 * Allocate new query_context and copy the completed querytree into it.
759 * It's transient until we complete the copying and dependency extraction.
760 */
762 "CachedPlanQuery",
764 oldcxt = MemoryContextSwitchTo(querytree_context);
765
766 qlist = copyObject(tlist);
767
768 /*
769 * Use the planner machinery to extract dependencies. Data is saved in
770 * query_context. (We assume that not a lot of extra cruft is created by
771 * this call.)
772 */
774 &plansource->relationOids,
775 &plansource->invalItems,
776 &plansource->dependsOnRLS);
777
778 /* Update RLS info as well. */
779 plansource->rewriteRoleId = GetUserId();
780 plansource->rewriteRowSecurity = row_security;
781
782 /*
783 * Also save the current search_path in the query_context. (This should
784 * not generate much extra cruft either, since almost certainly the path
785 * is already valid.)
786 */
787 plansource->search_path = GetSearchPathMatcher(querytree_context);
788
789 MemoryContextSwitchTo(oldcxt);
790
791 /* Now reparent the finished query_context and save the links */
792 MemoryContextSetParent(querytree_context, plansource->context);
793
794 plansource->query_context = querytree_context;
795 plansource->query_list = qlist;
796
797 /*
798 * Note: we do not reset generic_cost or total_custom_cost, although we
799 * could choose to do so. If the DDL or statistics change that prompted
800 * the invalidation meant a significant change in the cost estimates, it
801 * would be better to reset those variables and start fresh; but often it
802 * doesn't, and we're better retaining our hard-won knowledge about the
803 * relative costs.
804 */
805
806 plansource->is_valid = true;
807
808 /* Return transient copy of querytrees for possible use in planning */
809 return tlist;
810}
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ereport(elevel,...)
Definition: elog.h:149
static void AcquirePlannerLocks(List *stmt_list, bool acquire)
Definition: plancache.c:1828
List * pg_analyze_and_rewrite_withcb(RawStmt *parsetree, const char *query_string, ParserSetupHook parserSetup, void *parserSetupArg, QueryEnvironment *queryEnv)
Definition: postgres.c:757
List * pg_analyze_and_rewrite_fixedparams(RawStmt *parsetree, const char *query_string, const Oid *paramTypes, int numParams, QueryEnvironment *queryEnv)
Definition: postgres.c:664
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:478
bool equalRowTypes(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:732

References AcquirePlannerLocks(), ActiveSnapshotSet(), ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, Assert, CachedPlanSource::context, copyObject, CreateTupleDescCopy(), CurrentMemoryContext, CachedPlanSource::dependsOnRLS, equalRowTypes(), ereport, errcode(), errmsg(), ERROR, extract_query_dependencies(), CachedPlanSource::fixed_result, FreeTupleDesc(), GetSearchPathMatcher(), GetTransactionSnapshot(), GetUserId(), CachedPlanSource::gplan, CachedPlanSource::invalItems, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_valid, CachedPlan::is_valid, MemoryContextDelete(), MemoryContextSetParent(), MemoryContextSwitchTo(), NIL, CachedPlanSource::num_params, CachedPlanSource::param_types, CachedPlanSource::parserSetup, CachedPlanSource::parserSetupArg, pg_analyze_and_rewrite_fixedparams(), pg_analyze_and_rewrite_withcb(), 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, CachedPlanSource::search_path, SearchPathMatchesCurrentEnvironment(), and StmtPlanRequiresRevalidation.

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

◆ SaveCachedPlan()

void SaveCachedPlan ( CachedPlanSource plansource)

Definition at line 482 of file plancache.c.

483{
484 /* Assert caller is doing things in a sane order */
485 Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
486 Assert(plansource->is_complete);
487 Assert(!plansource->is_saved);
488
489 /* This seems worth a real test, though */
490 if (plansource->is_oneshot)
491 elog(ERROR, "cannot save one-shot cached plan");
492
493 /*
494 * In typical use, this function would be called before generating any
495 * plans from the CachedPlanSource. If there is a generic plan, moving it
496 * into CacheMemoryContext would be pretty risky since it's unclear
497 * whether the caller has taken suitable care with making references
498 * long-lived. Best thing to do seems to be to discard the plan.
499 */
500 ReleaseGenericPlan(plansource);
501
502 /*
503 * Reparent the source memory context under CacheMemoryContext so that it
504 * will live indefinitely. The query_context follows along since it's
505 * already a child of the other one.
506 */
508
509 /*
510 * Add the entry to the global list of cached plans.
511 */
512 dlist_push_tail(&saved_plan_list, &plansource->node);
513
514 plansource->is_saved = true;
515}

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

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

◆ ScanQueryForLocks()

static void ScanQueryForLocks ( Query parsetree,
bool  acquire 
)
static

Definition at line 1853 of file plancache.c.

1854{
1855 ListCell *lc;
1856
1857 /* Shouldn't get called on utility commands */
1858 Assert(parsetree->commandType != CMD_UTILITY);
1859
1860 /*
1861 * First, process RTEs of the current query level.
1862 */
1863 foreach(lc, parsetree->rtable)
1864 {
1865 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
1866
1867 switch (rte->rtekind)
1868 {
1869 case RTE_RELATION:
1870 /* Acquire or release the appropriate type of lock */
1871 if (acquire)
1872 LockRelationOid(rte->relid, rte->rellockmode);
1873 else
1874 UnlockRelationOid(rte->relid, rte->rellockmode);
1875 break;
1876
1877 case RTE_SUBQUERY:
1878 /* If this was a view, must lock/unlock the view */
1879 if (OidIsValid(rte->relid))
1880 {
1881 if (acquire)
1882 LockRelationOid(rte->relid, rte->rellockmode);
1883 else
1884 UnlockRelationOid(rte->relid, rte->rellockmode);
1885 }
1886 /* Recurse into subquery-in-FROM */
1887 ScanQueryForLocks(rte->subquery, acquire);
1888 break;
1889
1890 default:
1891 /* ignore other types of RTEs */
1892 break;
1893 }
1894 }
1895
1896 /* Recurse into subquery-in-WITH */
1897 foreach(lc, parsetree->cteList)
1898 {
1900
1901 ScanQueryForLocks(castNode(Query, cte->ctequery), acquire);
1902 }
1903
1904 /*
1905 * Recurse into sublink subqueries, too. But we already did the ones in
1906 * the rtable and cteList.
1907 */
1908 if (parsetree->hasSubLinks)
1909 {
1910 query_tree_walker(parsetree, ScanQueryWalker, &acquire,
1912 }
1913}
#define query_tree_walker(q, w, c, f)
Definition: nodeFuncs.h:158
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:24
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
static bool ScanQueryWalker(Node *node, bool *acquire)
Definition: plancache.c:1919
Query * subquery
Definition: parsenodes.h:1104

References Assert, castNode, CMD_UTILITY, Query::commandType, Query::cteList, CommonTableExpr::ctequery, lfirst, lfirst_node, LockRelationOid(), OidIsValid, QTW_IGNORE_RC_SUBQUERIES, query_tree_walker, RangeTblEntry::relid, Query::rtable, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, ScanQueryForLocks(), ScanQueryWalker(), RangeTblEntry::subquery, and UnlockRelationOid().

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

◆ ScanQueryWalker()

static bool ScanQueryWalker ( Node node,
bool *  acquire 
)
static

Definition at line 1919 of file plancache.c.

1920{
1921 if (node == NULL)
1922 return false;
1923 if (IsA(node, SubLink))
1924 {
1925 SubLink *sub = (SubLink *) node;
1926
1927 /* Do what we came for */
1928 ScanQueryForLocks(castNode(Query, sub->subselect), *acquire);
1929 /* Fall through to process lefthand args of SubLink */
1930 }
1931
1932 /*
1933 * Do NOT recurse into Query nodes, because ScanQueryForLocks already
1934 * processed subselects of subselects for us.
1935 */
1936 return expression_tree_walker(node, ScanQueryWalker, acquire);
1937}
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:153
#define IsA(nodeptr, _type_)
Definition: nodes.h:158

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

Referenced by ScanQueryForLocks(), and ScanQueryWalker().

Variable Documentation

◆ cached_expression_list

dlist_head cached_expression_list = DLIST_STATIC_INIT(cached_expression_list)
static

◆ plan_cache_mode

int plan_cache_mode = PLAN_CACHE_MODE_AUTO

Definition at line 147 of file plancache.c.

Referenced by choose_custom_plan().

◆ planref_resowner_desc

const ResourceOwnerDesc planref_resowner_desc
static
Initial value:
=
{
.name = "plancache reference",
.release_phase = RESOURCE_RELEASE_AFTER_LOCKS,
.release_priority = RELEASE_PRIO_PLANCACHE_REFS,
.ReleaseResource = ResOwnerReleaseCachedPlan,
.DebugPrint = NULL
}
static void ResOwnerReleaseCachedPlan(Datum res)
Definition: plancache.c:2240
#define RELEASE_PRIO_PLANCACHE_REFS
Definition: resowner.h:73
@ RESOURCE_RELEASE_AFTER_LOCKS
Definition: resowner.h:56

Definition at line 124 of file plancache.c.

Referenced by ReleaseAllPlanCacheRefsInOwner(), ResourceOwnerForgetPlanCacheRef(), and ResourceOwnerRememberPlanCacheRef().

◆ saved_plan_list

dlist_head saved_plan_list = DLIST_STATIC_INIT(saved_plan_list)
static