1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-31 22:04:40 +03:00

Introduce field tracking cached plan type in PlannedStmt

PlannedStmt gains a new field, called CachedPlanType, able to track if a
given plan tree originates from the cache and if we are dealing with a
generic or custom cached plan.

This field can be used for monitoring or statistical purposes, in the
executor hooks, for example, based on the planned statement attached to
a QueryDesc.  A patch is under discussion for pg_stat_statements to
provide an equivalent of the counters in pg_prepared_statements for
custom and generic plans, to provide a more global view of such data, as
this data is now restricted to the current session.

The concept introduced in this commit is useful on its own, and has been
extracted from a larger patch by the same author.

Author: Sami Imseih <samimseih@gmail.com>
Reviewed-by: Andrei Lepikhov <lepihov@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/CAA5RZ0uFw8Y9GCFvafhC=OA8NnMqVZyzXPfv_EePOt+iv1T-qQ@mail.gmail.com
This commit is contained in:
Michael Paquier
2025-07-24 15:41:18 +09:00
parent df335618ed
commit 719dcf3c42
9 changed files with 33 additions and 0 deletions

View File

@ -1588,6 +1588,7 @@ ImportForeignSchema(ImportForeignSchemaStmt *stmt)
pstmt->utilityStmt = (Node *) cstmt;
pstmt->stmt_location = rs->stmt_location;
pstmt->stmt_len = rs->stmt_len;
pstmt->cached_plan_type = PLAN_CACHE_NONE;
/* Execute statement */
ProcessUtility(pstmt, cmd, false,

View File

@ -215,6 +215,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString,
wrapper->utilityStmt = stmt;
wrapper->stmt_location = stmt_location;
wrapper->stmt_len = stmt_len;
wrapper->cached_plan_type = PLAN_CACHE_NONE;
/* do this step */
ProcessUtility(wrapper,

View File

@ -189,6 +189,7 @@ ExecSerializePlan(Plan *plan, EState *estate)
pstmt->permInfos = estate->es_rteperminfos;
pstmt->resultRelations = NIL;
pstmt->appendRelations = NIL;
pstmt->cached_plan_type = PLAN_CACHE_NONE;
/*
* Transfer only parallel-safe subplans, leaving a NULL "hole" in the list

View File

@ -582,6 +582,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
result->utilityStmt = parse->utilityStmt;
result->stmt_location = parse->stmt_location;
result->stmt_len = parse->stmt_len;
result->cached_plan_type = PLAN_CACHE_NONE;
result->jitFlags = PGJIT_NONE;
if (jit_enabled && jit_above_cost >= 0 &&

View File

@ -988,6 +988,7 @@ pg_plan_queries(List *querytrees, const char *query_string, int cursorOptions,
stmt->stmt_location = query->stmt_location;
stmt->stmt_len = query->stmt_len;
stmt->queryId = query->queryId;
stmt->cached_plan_type = PLAN_CACHE_NONE;
}
else
{

View File

@ -1234,6 +1234,7 @@ ProcessUtilitySlow(ParseState *pstate,
wrapper->utilityStmt = stmt;
wrapper->stmt_location = pstmt->stmt_location;
wrapper->stmt_len = pstmt->stmt_len;
wrapper->cached_plan_type = PLAN_CACHE_NONE;
ProcessUtility(wrapper,
queryString,
@ -1964,6 +1965,7 @@ ProcessUtilityForAlterTable(Node *stmt, AlterTableUtilityContext *context)
wrapper->utilityStmt = stmt;
wrapper->stmt_location = context->pstmt->stmt_location;
wrapper->stmt_len = context->pstmt->stmt_len;
wrapper->cached_plan_type = PLAN_CACHE_NONE;
ProcessUtility(wrapper,
context->queryString,

View File

@ -1283,6 +1283,7 @@ GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams,
CachedPlan *plan = NULL;
List *qlist;
bool customplan;
ListCell *lc;
/* Assert caller is doing things in a sane order */
Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
@ -1385,6 +1386,13 @@ GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams,
plan->is_saved = true;
}
foreach(lc, plan->stmt_list)
{
PlannedStmt *pstmt = (PlannedStmt *) lfirst(lc);
pstmt->cached_plan_type = customplan ? PLAN_CACHE_CUSTOM : PLAN_CACHE_GENERIC;
}
return plan;
}

View File

@ -28,6 +28,20 @@
* ----------------------------------------------------------------
*/
/* ----------------
* CachedPlanType
*
* CachedPlanType identifies whether a PlannedStmt is a cached plan, and if
* so, whether it is generic or custom.
* ----------------
*/
typedef enum CachedPlanType
{
PLAN_CACHE_NONE = 0, /* Not a cached plan */
PLAN_CACHE_GENERIC, /* Generic cached plan */
PLAN_CACHE_CUSTOM, /* Custom cached plan */
} CachedPlanType;
/* ----------------
* PlannedStmt node
*
@ -58,6 +72,9 @@ typedef struct PlannedStmt
/* plan identifier (can be set by plugins) */
int64 planId;
/* type of cached plan */
CachedPlanType cached_plan_type;
/* is it insert|update|delete|merge RETURNING? */
bool hasReturning;

View File

@ -391,6 +391,7 @@ CachedFunctionHashEntry
CachedFunctionHashKey
CachedPlan
CachedPlanSource
CachedPlanType
CallContext
CallStmt
CancelRequestPacket