]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Introduce field tracking cached plan type in PlannedStmt
authorMichael Paquier <michael@paquier.xyz>
Thu, 24 Jul 2025 06:41:18 +0000 (15:41 +0900)
committerMichael Paquier <michael@paquier.xyz>
Thu, 24 Jul 2025 06:41:18 +0000 (15:41 +0900)
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

src/backend/commands/foreigncmds.c
src/backend/commands/schemacmds.c
src/backend/executor/execParallel.c
src/backend/optimizer/plan/planner.c
src/backend/tcop/postgres.c
src/backend/tcop/utility.c
src/backend/utils/cache/plancache.c
src/include/nodes/plannodes.h
src/tools/pgindent/typedefs.list

index 8d2d7431544627ee537a6ba3179b0d6574a7b29a..fcd5fcd8915e3ddf489c62b02f34f5702b722ed9 100644 (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,
index 546160f09410e1e9199dda4a224ee410daa7b8d2..c00f1a11384f10a207dc6ffc8fc9816e909c9e8a 100644 (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,
index f3e77bda279063bd5eed42ddb378e7db370d8340..fc76f22fb8238dc275a176424bd36a3f67cf9572 100644 (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
index c989e72cac5cf462c18090ce41aabb22621578bc..a77b2147e9592851cde1f44f99af059011adcd53 100644 (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 &&
index 2f8c3d5f91822f4e7adbd9e861741fcf0a1e2bd1..a297606cdd7fafb08ea5f8d49aeeece2f646ffb6 100644 (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
                {
index 4c1faf5575c4d203904b3fe987857472840ae934..babc34d0cbe1d8801333838698c106b5be943076 100644 (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,
index 89a1c79e984d104613ea875a66d2f2c860383e25..f4d2b9458a5eada131237721ee333f26f6fe8e33 100644 (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;
 }
 
index 4f59e30d62d5ee538868f904a1b53fd67f52b762..46e2e09ea35be190cc0a8d41af9e419f4131b016 100644 (file)
  * ----------------------------------------------------------------
  */
 
+/* ----------------
+ *             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;
 
index a8656419cb6087d4a6b7aa8c43c8ca884ca7d8a5..4353befab9934468f110b1d229c1897e00da9d9d 100644 (file)
@@ -391,6 +391,7 @@ CachedFunctionHashEntry
 CachedFunctionHashKey
 CachedPlan
 CachedPlanSource
+CachedPlanType
 CallContext
 CallStmt
 CancelRequestPacket