From 412193b284eeb2a04d8b7f81c4f584e6fab3f2a4 Mon Sep 17 00:00:00 2001
From: 0xPoe <poe.liu@pm.me>
Date: Mon, 5 Oct 2026 09:16:58 +0200
Subject: [PATCH v1] pg_plan_advice: Handle custom scans that replace a join

pgpa_relids() did not know about CustomScan, so a custom scan that
replaces a join (scanrelid = 0) looked like a plan node that scans no
relations.  When such a node was an input of a join, the plan walker
failed with "plan node has no RTIs".  When it was the topmost node,
the relations that it covers were silently left out of the generated
advice.

The plan walker also runs to produce advice feedback, so the error was
not limited to EXPLAIN (PLAN_ADVICE).  With
pg_plan_advice.always_store_advice_details, or with supplied advice
plus pg_plan_advice.feedback_warnings, an ordinary query failed.

Return custom_relids for a CustomScan, as is already done with
fs_relids for a ForeignScan.  The node is then treated as an ordinary
scan of several relations.  It appears in JOIN_ORDER advice as an
unordered sublist, which is what the README says should happen.

Reported-by: Noah Misch <noah@leadboat.com>
Discussion: https://postgr.es/m/20260827171830.68.noahmisch@microsoft.com
---
 contrib/pg_plan_advice/pgpa_walker.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/contrib/pg_plan_advice/pgpa_walker.c b/contrib/pg_plan_advice/pgpa_walker.c
index bfd1a8e3be1..bf252b4be57 100644
--- a/contrib/pg_plan_advice/pgpa_walker.c
+++ b/contrib/pg_plan_advice/pgpa_walker.c
@@ -572,6 +572,8 @@ pgpa_relids(Plan *plan)
 		return ((Result *) plan)->relids;
 	else if (IsA(plan, ForeignScan))
 		return ((ForeignScan *) plan)->fs_relids;
+	else if (IsA(plan, CustomScan))
+		return ((CustomScan *) plan)->custom_relids;
 	else if (IsA(plan, Append))
 		return ((Append *) plan)->apprelids;
 	else if (IsA(plan, MergeAppend))
-- 
2.54.0 (Apple Git-157)

