PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
plancache.h File Reference
#include "access/tupdesc.h"
#include "lib/ilist.h"
#include "nodes/params.h"
#include "tcop/cmdtag.h"
#include "utils/queryenvironment.h"
#include "utils/resowner.h"
Include dependency graph for plancache.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  CachedPlanSource
 
struct  CachedPlan
 
struct  CachedExpression
 

Macros

#define CACHEDPLANSOURCE_MAGIC   195726186
 
#define CACHEDPLAN_MAGIC   953717834
 
#define CACHEDEXPR_MAGIC   838275847
 

Typedefs

typedef struct CachedPlanSource CachedPlanSource
 
typedef struct CachedPlan CachedPlan
 
typedef struct CachedExpression CachedExpression
 

Enumerations

enum  PlanCacheMode { PLAN_CACHE_MODE_AUTO , PLAN_CACHE_MODE_FORCE_GENERIC_PLAN , PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN }
 

Functions

void InitPlanCache (void)
 
void ResetPlanCache (void)
 
void ReleaseAllPlanCacheRefsInOwner (ResourceOwner owner)
 
CachedPlanSourceCreateCachedPlan (struct RawStmt *raw_parse_tree, const char *query_string, CommandTag commandTag)
 
CachedPlanSourceCreateOneShotCachedPlan (struct 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)
 
void CachedPlanSetParentContext (CachedPlanSource *plansource, MemoryContext newcontext)
 
CachedPlanSourceCopyCachedPlan (CachedPlanSource *plansource)
 
bool CachedPlanIsValid (CachedPlanSource *plansource)
 
ListCachedPlanGetTargetList (CachedPlanSource *plansource, QueryEnvironment *queryEnv)
 
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)
 
CachedExpressionGetCachedExpression (Node *expr)
 
void FreeCachedExpression (CachedExpression *cexpr)
 

Variables

PGDLLIMPORT int plan_cache_mode
 

Macro Definition Documentation

◆ CACHEDEXPR_MAGIC

#define CACHEDEXPR_MAGIC   838275847

Definition at line 42 of file plancache.h.

◆ CACHEDPLAN_MAGIC

#define CACHEDPLAN_MAGIC   953717834

Definition at line 41 of file plancache.h.

◆ CACHEDPLANSOURCE_MAGIC

#define CACHEDPLANSOURCE_MAGIC   195726186

Definition at line 40 of file plancache.h.

Typedef Documentation

◆ CachedExpression

◆ CachedPlan

typedef struct CachedPlan CachedPlan

◆ CachedPlanSource

Enumeration Type Documentation

◆ PlanCacheMode

Enumerator
PLAN_CACHE_MODE_AUTO 
PLAN_CACHE_MODE_FORCE_GENERIC_PLAN 
PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN 

Definition at line 30 of file plancache.h.

31{
PlanCacheMode
Definition: plancache.h:31
@ PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN
Definition: plancache.h:34
@ PLAN_CACHE_MODE_FORCE_GENERIC_PLAN
Definition: plancache.h:33
@ PLAN_CACHE_MODE_AUTO
Definition: plancache.h:32

Function Documentation

◆ 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}
#define Assert(condition)
Definition: c.h:812
bool SearchPathMatchesCurrentEnvironment(SearchPathMatcher *path)
Definition: namespace.c:3911
@ CMD_UTILITY
Definition: nodes.h:270
@ RTE_RELATION
Definition: parsenodes.h:1017
#define lfirst(lc)
Definition: pg_list.h:172
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define plan(x)
Definition: pg_regress.c:161
static void ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
Definition: plancache.c:135
#define CACHEDPLAN_MAGIC
Definition: plancache.h:41
#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 * query_list
Definition: plancache.h:111
CmdType commandType
Definition: plannodes.h:52
List * rtable
Definition: plannodes.h:72
List * cteList
Definition: parsenodes.h:168
List * rtable
Definition: parsenodes.h:170
CmdType commandType
Definition: parsenodes.h:121
RTEKind rtekind
Definition: parsenodes.h:1047
#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}
#define NIL
Definition: pg_list.h:68
static List * RevalidateCachedQuery(CachedPlanSource *plansource, QueryEnvironment *queryEnv)
Definition: plancache.c:583
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().

◆ 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
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
Oid GetUserId(void)
Definition: miscinit.c:517
SearchPathMatcher * GetSearchPathMatcher(MemoryContext context)
Definition: namespace.c:3852
#define copyObject(obj)
Definition: nodes.h:224
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
static TupleDesc PlanCacheComputeResultDesc(List *stmt_list)
Definition: plancache.c:1947
#define StmtPlanRequiresRevalidation(plansource)
Definition: plancache.c:85
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
double total_custom_cost
Definition: plancache.h:132
const char * query_string
Definition: plancache.h:100
struct RawStmt * raw_parse_tree
Definition: plancache.h:99
int64 num_custom_plans
Definition: plancache.h:133
int64 num_generic_plans
Definition: plancache.h:134
double generic_cost
Definition: plancache.h:131
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 ( struct 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 ( struct 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
static void ReleaseGenericPlan(CachedPlanSource *plansource)
Definition: plancache.c:555
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
Definition: pg_list.h:54

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

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

◆ 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}
#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
dlist_node * cur
Definition: ilist.h:179

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

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

Variable Documentation

◆ plan_cache_mode

PGDLLIMPORT int plan_cache_mode
extern

Definition at line 147 of file plancache.c.

Referenced by choose_custom_plan().