0001-fix-variable-not-found-in-subplan-target-lists.patch

text/x-patch

Filename: 0001-fix-variable-not-found-in-subplan-target-lists.patch
Type: text/x-patch
Part: 3
Message: [BUG] Remove self joins causes 'variable not found in subplan target lists' error

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: format-patch
Series: patch 0001
Subject: fix: variable not found in subplan target lists
File+
src/backend/optimizer/path/equivclass.c 15 6
From 4ebad7d772827fe2f3f34fcf6681d49fe4a829ff Mon Sep 17 00:00:00 2001
From: Sergey Soloviev <sergey.soloviev@tantorlabs.ru>
Date: Fri, 22 Aug 2025 16:37:02 +0300
Subject: [PATCH] fix: variable not found in subplan target lists

When restoring 'attr_needed' after self-join removal we should also
consider EC with constants because some plan nodes can use such constant
attributes.

For example, after converting `EXISTS` to JOIN planner can create
`UniquePath` referencing attribute which is contained in EC with
constant. But because `attr_needed` is NULL then this attribute is not
returned by JOIN, so at `set_plan_references` fails to find this
attribute in targetlist of node below.
---
 src/backend/optimizer/path/equivclass.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index 441f12f6c50..58ca75ab7a8 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -2586,18 +2586,27 @@ rebuild_eclass_attr_needed(PlannerInfo *root)
 		 */
 		Assert(ec->ec_childmembers == NULL);

-		/* Need do anything only for a multi-member, no-const EC. */
-		if (list_length(ec->ec_members) > 1 && !ec->ec_has_const)
+		/*
+		 * Need do anything only for a multi-member. Note that some
+		 * wrapping plan nodes (i.e. UniquePath) can reference attributes
+		 * contained in EC with constants.
+		 */
+		if (list_length(ec->ec_members) > 1)
 		{
 			ListCell   *lc2;

 			foreach(lc2, ec->ec_members)
 			{
 				EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2);
-				List	   *vars = pull_var_clause((Node *) cur_em->em_expr,
-												   PVC_RECURSE_AGGREGATES |
-												   PVC_RECURSE_WINDOWFUNCS |
-												   PVC_INCLUDE_PLACEHOLDERS);
+				List	   *vars;
+
+				if (cur_em->em_is_const)
+					continue;
+
+				vars = pull_var_clause((Node *) cur_em->em_expr,
+										PVC_RECURSE_AGGREGATES |
+										PVC_RECURSE_WINDOWFUNCS |
+										PVC_INCLUDE_PLACEHOLDERS);

 				add_vars_to_attr_needed(root, vars, ec->ec_relids);
 				list_free(vars);
--
2.43.0