Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lnUbt-0002ML-95 for pgsql-bugs@arkaria.postgresql.org; Sun, 30 May 2021 23:12:45 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1lnUbr-0003J2-Hv for pgsql-bugs@arkaria.postgresql.org; Sun, 30 May 2021 23:12:43 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lnUbr-0003Iq-B7 for pgsql-bugs@lists.postgresql.org; Sun, 30 May 2021 23:12:43 +0000 Received: from sss.pgh.pa.us ([66.207.139.130]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lnUbk-0001dJ-HV for pgsql-bugs@lists.postgresql.org; Sun, 30 May 2021 23:12:42 +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 14UNCXuD2433210; Sun, 30 May 2021 19:12:33 -0400 From: Tom Lane To: Dmitry Dolgov <9erthalion6@gmail.com> cc: "Poot, Bas (B.J.)" , "pgsql-bugs@lists.postgresql.org" Subject: Re: XX000: unknown type of jsonb container. In-reply-to: <20210423151505.lxx5ti7ivcza3xqw@localhost> References: <534fca83789c4a378c7de379e9067d4f@politie.nl> <20210407181105.lmi7hgifwzs3eeee@localhost> <20210413161500.kufk4iyrmcmhhbrc@localhost> <20210423151505.lxx5ti7ivcza3xqw@localhost> Comments: In-reply-to Dmitry Dolgov <9erthalion6@gmail.com> message dated "Fri, 23 Apr 2021 17:15:05 +0200" MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0" Content-ID: <2433176.1622416297.0@sss.pgh.pa.us> Date: Sun, 30 May 2021 19:12:33 -0400 Message-ID: <2433209.1622416353@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: <2433176.1622416297.1@sss.pgh.pa.us> Dmitry Dolgov <9erthalion6@gmail.com> writes: > I couldn't find any other feasible explanations, and have come to a > conclusion that this happens when a projection is applied to a > GatherMerge path. As it's a projection capable path, no new projection > is created and target list is changed in place. In the subpath target > list ordering is different because of query ordering, and I don't see > where it all comes together during execution. Funny enough even explain > shows that the final plan passes a wrong values to jsonb_each_text. I dug into this, and found that the proximate problem is that we're generating a Sort node in which the output column order is different from the input. If Sort could project, that'd be fine, but of course it doesn't. (I wonder if there should be some more assertions in setrefs.c to try to catch plans that are broken like that.) Of course, it's not like the planner has never heard of that restriction. The problem occurs because what arrives at createplan.c looks like ProjectionPath ProjectionPath SortPath SeqScanPath that is, we've got *two* redundant ProjectionPaths, and the logic in createplan.c that is supposed to decide whether we can skip generating a projecting Result node for a ProjectionPath gets confused and decides we don't need any Result, rather than deciding we need one Result. Maybe we could work around that, but having two stacked ProjectionPaths is just silly, so the attached patch deals with this problem by making sure we don't do that. The place where that happens in the example reported in this thread is apply_projection_to_path, which somebody kluged up to the point where it'd create this situation just below a Gather/GatherMerge node. So I first tried to fix it there, and for safety added an Assert to create_projection_path saying that its input wasn't a ProjectionPath. The Assert blew up the regression tests. The same thing is happening in other places, and only by luck have we not noticed any bad effects. So the attached fixes it by stripping any input ProjectionPath in create_projection_path, instead. I'm not sure about creating a test case. The case reported here is far too expensive to use in the regression tests. regards, tom lane ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name="remove-redundant-ProjectionPath-1.patch"; charset="us-ascii" Content-ID: <2433176.1622416297.2@sss.pgh.pa.us> Content-Description: remove-redundant-ProjectionPath-1.patch Content-Transfer-Encoding: quoted-printable diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer= /util/pathnode.c index b248b038e0..6c6bde04f6 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -2632,7 +2632,22 @@ create_projection_path(PlannerInfo *root, PathTarget *target) { ProjectionPath *pathnode =3D makeNode(ProjectionPath); - PathTarget *oldtarget =3D subpath->pathtarget; + PathTarget *oldtarget; + + /* + * We mustn't put a ProjectionPath directly above another; it's useless + * and will confuse createplan.c. Rather than making sure all callers + * know that, let's implement it here, by stripping off any ProjectionPa= th + * in what we're given. Given this rule, there won't be more than one. + */ + if (IsA(subpath, ProjectionPath)) + { + ProjectionPath *subpp =3D (ProjectionPath *) subpath; + + Assert(subpp->path.parent =3D=3D rel); + subpath =3D subpp->subpath; + Assert(!IsA(subpath, ProjectionPath)); + } = pathnode->path.pathtype =3D T_Result; pathnode->path.parent =3D rel; @@ -2658,6 +2673,7 @@ create_projection_path(PlannerInfo *root, * Note: in the latter case, create_projection_plan has to recheck our * conclusion; see comments therein. */ + oldtarget =3D subpath->pathtarget; if (is_projection_capable_path(subpath) || equal(oldtarget->exprs, target->exprs)) { ------- =_aaaaaaaaaa0--