0001-pg_plan_advice-Avoid-a-crash-under-GEQO.nocfbot

application/octet-stream

Filename: 0001-pg_plan_advice-Avoid-a-crash-under-GEQO.nocfbot
Type: application/octet-stream
Part: 0
Message: Re: pg_plan_advice
From 798d6df3efbed5dfb6c784aaeaf9982db113d487 Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Mon, 16 Mar 2026 11:50:00 -0400
Subject: [PATCH 1/4] pg_plan_advice: Avoid a crash under GEQO.

The previous code could allocate pgpa_sj_unique_rel objects in a context
that had too short a lifespan. Fix by allocating them (and any
associated List-related allocations) in the same context as the
pgpa_planner_state to which they are attached.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Discussion: http://postgr.es/m/a6e6d603-e847-44dc-acd5-879fb4570062@gmail.com
---
 contrib/pg_plan_advice/pgpa_planner.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/contrib/pg_plan_advice/pgpa_planner.c b/contrib/pg_plan_advice/pgpa_planner.c
index 5508b8af707..08e6ec199b9 100644
--- a/contrib/pg_plan_advice/pgpa_planner.c
+++ b/contrib/pg_plan_advice/pgpa_planner.c
@@ -90,6 +90,7 @@ typedef enum pgpa_jo_outcome
 
 typedef struct pgpa_planner_state
 {
+	MemoryContext	mcxt;
 	bool		generate_advice_feedback;
 	bool		generate_advice_string;
 	pgpa_trove *trove;
@@ -324,10 +325,18 @@ pgpa_planner_setup(PlannerGlobal *glob, Query *parse, const char *query_string,
 	 * some purpose. That could be (1) recording that we will need to generate
 	 * an advice string, (2) storing a trove of supplied advice, or (3)
 	 * facilitating debugging cross-checks when asserts are enabled.
+	 *
+	 * Currently, the active memory context should be one that will last for
+	 * the entire duration of query planning, but if GEQO is in use, it's
+	 * possible that some of our callbacks may be invoked later with
+	 * CurrentMemoryContext set to some shorter-lived context. So, record
+	 * the context that should be used for allocations that need to live
+	 * as long as the pgpa_planner_state itself.
 	 */
 	if (needs_pps)
 	{
 		pps = palloc0_object(pgpa_planner_state);
+		pps->mcxt = CurrentMemoryContext;
 		pps->generate_advice_feedback = generate_advice_feedback;
 		pps->generate_advice_string = generate_advice_string;
 		pps->trove = trove;
@@ -616,11 +625,15 @@ pgpa_join_path_setup(PlannerInfo *root, RelOptInfo *joinrel,
 			/* If not a duplicate, append to the list. */
 			if (!found)
 			{
-				pgpa_sj_unique_rel *ur = palloc_object(pgpa_sj_unique_rel);
+				pgpa_sj_unique_rel *ur;
+				MemoryContext	oldcontext;
 
+				oldcontext = MemoryContextSwitchTo(pps->mcxt);
+				ur = palloc_object(pgpa_sj_unique_rel);
 				ur->plan_name = root->plan_name;
 				ur->relids = uniquerel->relids;
 				pps->sj_unique_rels = lappend(pps->sj_unique_rels, ur);
+				MemoryContextSwitchTo(oldcontext);
 			}
 		}
 	}
-- 
2.51.0