From 336124160b13cecdfa3824d7a3df8143bf93081e Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <akorotkov@postgresql.org>
Date: Tue, 1 Sep 2026 22:55:13 +0300
Subject: [PATCH v1] postgres_fdw: Fix "may be used uninitialized" warning in
 foreign_join_ok()

Commit 0ee83dd4a99 detected the mixed foreign x function-RTE cases in one
if/else chain that only set a pair of bool flags, then acted on those flags in
a second chain.  fpinfo_o and fpinfo_i are each assigned in one chain and read
in the other, so proving them initialized requires correlating the flags with
the assignments.  gcc 13 with -Og does not manage that and reports fpinfo_i as
possibly uninitialized; clang's -Wconditional-uninitialized likewise reports
both variables.

The flags served no purpose beyond deferring the work, so merge the two chains
and read both fdw_private pointers up front, unconditionally.  A function rel
never has an fdw_private of its own, so the pointer is simply NULL until the
stub replaces it, and each branch now assigns and uses the two variables in one
place.

Reported-by: Karina Litskevich <litskevichkarina@gmail.com>
Reported-by: Marina Polyakova <m.polyakova@postgrespro.ru>
Discussion: https://postgr.es/m/CACiT8iamoL-%3D792e6JK2uCVvwDhfCg7DXHhvqN0P33jhGg2-8A%40mail.gmail.com
---
 contrib/postgres_fdw/postgres_fdw.c | 53 +++++++++++------------------
 1 file changed, 19 insertions(+), 34 deletions(-)

diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 9269418a074..47197a733ff 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -7044,8 +7044,6 @@ foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype,
 	PgFdwRelationInfo *fpinfo_i;
 	ListCell   *lc;
 	List	   *joinclauses;
-	bool		outer_is_function = false;
-	bool		inner_is_function = false;
 
 	/*
 	 * We support pushing down INNER, LEFT, RIGHT, FULL OUTER and SEMI joins.
@@ -7069,40 +7067,22 @@ foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype,
 	 * function RTE can be absorbed into joins on multiple foreign servers
 	 * (each call gets its own stub fpinfo and rechecks shippability for the
 	 * specific server).
+	 *
+	 * A function rel has no fdw_private of its own, so when one side is a
+	 * function RTE we replace its NULL fpinfo with a stub, and the rest of
+	 * this function and the cost estimator can then treat both sides
+	 * uniformly.  We hand the stub to the joinrel's deparser via the same
+	 * path the foreign side uses, but we never permanently attach it to the
+	 * function rel's fdw_private (different joinrels may pair the same
+	 * function RTE with different foreign servers).
 	 */
 	fpinfo = (PgFdwRelationInfo *) joinrel->fdw_private;
+	fpinfo_o = (PgFdwRelationInfo *) outerrel->fdw_private;
+	fpinfo_i = (PgFdwRelationInfo *) innerrel->fdw_private;
+
 	if (jointype == JOIN_INNER && innerrel->rtekind == RTE_FUNCTION &&
-		(fpinfo_o = (PgFdwRelationInfo *) outerrel->fdw_private) &&
-		fpinfo_o->pushdown_safe &&
+		fpinfo_o && fpinfo_o->pushdown_safe &&
 		function_rte_pushdown_ok(root, innerrel, outerrel))
-	{
-		inner_is_function = true;
-	}
-	else if (jointype == JOIN_INNER && outerrel->rtekind == RTE_FUNCTION &&
-			 (fpinfo_i = (PgFdwRelationInfo *) innerrel->fdw_private) &&
-			 fpinfo_i->pushdown_safe &&
-			 function_rte_pushdown_ok(root, outerrel, innerrel))
-	{
-		outer_is_function = true;
-	}
-	else
-	{
-		fpinfo_o = (PgFdwRelationInfo *) outerrel->fdw_private;
-		fpinfo_i = (PgFdwRelationInfo *) innerrel->fdw_private;
-		if (!fpinfo_o || !fpinfo_o->pushdown_safe ||
-			!fpinfo_i || !fpinfo_i->pushdown_safe)
-			return false;
-	}
-
-	/*
-	 * If one side is a function RTE, allocate a stub fpinfo so the rest of
-	 * this function and the cost estimator can treat it uniformly.  We hand
-	 * the stub to the joinrel's deparser via the same path the foreign side
-	 * uses, but we never permanently attach it to the function rel's
-	 * fdw_private (different joinrels may pair the same function RTE with
-	 * different foreign servers).
-	 */
-	if (inner_is_function)
 	{
 		fpinfo_i = init_func_stub_fpinfo(fpinfo_o, innerrel);
 
@@ -7117,15 +7097,20 @@ foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype,
 						   &fpinfo_i->remote_conds, &fpinfo_i->local_conds);
 		fpinfo->inner_func_fpinfo = fpinfo_i;
 	}
-	else if (outer_is_function)
+	else if (jointype == JOIN_INNER && outerrel->rtekind == RTE_FUNCTION &&
+			 fpinfo_i && fpinfo_i->pushdown_safe &&
+			 function_rte_pushdown_ok(root, outerrel, innerrel))
 	{
 		fpinfo_o = init_func_stub_fpinfo(fpinfo_i, outerrel);
 
-		/* See the comment in the inner_is_function branch above. */
+		/* See the comment in the branch above. */
 		classifyConditions(root, outerrel, fpinfo_o, outerrel->baserestrictinfo,
 						   &fpinfo_o->remote_conds, &fpinfo_o->local_conds);
 		fpinfo->outer_func_fpinfo = fpinfo_o;
 	}
+	else if (!fpinfo_o || !fpinfo_o->pushdown_safe ||
+			 !fpinfo_i || !fpinfo_i->pushdown_safe)
+		return false;
 
 	/*
 	 * If joining relations have local conditions, those conditions are
-- 
2.55.0

