Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1usTTl-005j2x-K4 for pgsql-bugs@arkaria.postgresql.org; Sat, 30 Aug 2025 21:51:22 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1usTTk-00H1FM-92 for pgsql-bugs@arkaria.postgresql.org; Sat, 30 Aug 2025 21:51:20 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1usTTk-00H1FD-0W for pgsql-bugs@lists.postgresql.org; Sat, 30 Aug 2025 21:51:20 +0000 Received: from sss.pgh.pa.us ([68.162.161.243]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1usTTh-002aKZ-2A for pgsql-bugs@lists.postgresql.org; Sat, 30 Aug 2025 21:51:19 +0000 Received: from sss1.sss.pgh.pa.us (localhost [127.0.0.1]) by sss.pgh.pa.us (8.15.2/8.15.2) with ESMTP id 57ULpGPW050859; Sat, 30 Aug 2025 17:51:16 -0400 From: Tom Lane To: exclusion@gmail.com cc: pgsql-bugs@lists.postgresql.org Subject: Re: BUG #19037: Planner fails on estimating array length with "no relation entry" error In-reply-to: <19037-3d1c7bb553c7ce84@postgresql.org> References: <19037-3d1c7bb553c7ce84@postgresql.org> Comments: In-reply-to PG Bug reporting form message dated "Sat, 30 Aug 2025 12:00:02 -0000" MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0" Content-ID: <50800.1756590655.0@sss.pgh.pa.us> Date: Sat, 30 Aug 2025 17:51:16 -0400 Message-ID: <50858.1756590676@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk ------- =_aaaaaaaaaa0 Content-Type: text/plain; charset="us-ascii" Content-ID: <50800.1756590655.1@sss.pgh.pa.us> PG Bug reporting form writes: > The following script: > create table t(ia int[]); > select exists (select 1 from (select 1) where case when b then 1 else 0 end > = 1) > from (select 1 = any(ia) as b from t); > triggers: > ERROR: XX000: no relation entry for relid 2 > LOCATION: find_base_rel, relnode.c:426 Thanks for the report. After a bit of experimentation, I can shorten the reproducer to select exists (select 1 where (1 = any(ia))::int = 1) from t; ERROR: no relation entry for relid 1 but it doesn't happen any more if you simplify further to select exists (select 1 where 1 = any(ia)) from t; The reason for the difference seems to be that make_subplan checks to see if the EXISTS can be converted to a hashable ANY subplan (cf. convert_EXISTS_to_ANY), and the form where there's a top-level "=" operator in the sub-select's WHERE clause can be so converted. Then we hit the failure while trying to do cost_qual_eval on the converted ANY expression. So you also get this failure if you manually write out the form that convert_EXISTS_to_ANY is generating: select ((1 = any(ia))::int) = any (select 1) from t; ERROR: no relation entry for relid 1 Anyway that's sort of a sideshow. The real issue here is that we're applying cost_qual_eval before the planner has created any RelOptInfos, which means that examine_variable won't work. I find it surprising that this is the first report of such trouble, because it certainly isn't obvious that cost_qual_eval shouldn't be allowed to consult statistics. The most expedient solution is probably to hack examine_variable so that it doesn't fail if root->simple_rel_array isn't there yet. That seems mighty ugly though. Another low-risk response could be to revert 9391f7152. But I don't care for that because it's not really addressing the underlying problem. We might have the same issue elsewhere in cost estimation already, and even if we don't, it would be quite likely we'd introduce it again in future. In some sense the "right" fix would be to do SubPlan generation later, when we have statistics available for the Vars of the parent query. But that seems like a rather large task, and we'd surely not wish to back-patch the results. So I'm not really seeing another workable answer besides hacking examine_variable, more or less as attached. regards, tom lane ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name="v1-dont-fail-in-early-examine_variable.patch"; charset="us-ascii" Content-ID: <50800.1756590655.2@sss.pgh.pa.us> Content-Description: v1-dont-fail-in-early-examine_variable.patch Content-Transfer-Encoding: quoted-printable diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/self= uncs.c index 1c480cfaaf7..1a6db244c94 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -5309,6 +5309,20 @@ examine_variable(PlannerInfo *root, Node *node, int= varRelid, /* Save the exposed type of the expression */ vardata->vartype =3D exprType(node); = + /* + * It's possible to get here during SubLink planning, before we have + * constructed any RelOptInfos for the parent query level. In that case + * we have to punt by pretending the node is variable-free, since we + * cannot satisfy the API expectation of passing back a RelOptInfo. + */ + if (root->simple_rel_array =3D=3D NULL) + { + vardata->var =3D node; + vardata->atttype =3D vardata->vartype; + vardata->atttypmod =3D exprTypmod(node); + return; + } + /* Look inside any binary-compatible relabeling */ = if (IsA(node, RelabelType)) ------- =_aaaaaaaaaa0--