Re: BUG #18902: TRAP:: failed Assert("!is_sorted") in File: "createplan.c" - Mailing list pgsql-bugs

From Richard Guo
Subject Re: BUG #18902: TRAP:: failed Assert("!is_sorted") in File: "createplan.c"
Date
Msg-id CAMbWs4-MB0M8P_WYWCL04yvJtf299N4d6og5rYQbgDXDVqfiRg@mail.gmail.com
Whole thread Raw
In response to Re: BUG #18902: TRAP:: failed Assert("!is_sorted") in File: "createplan.c"  (Richard Guo <guofenglinux@gmail.com>)
Responses Re: BUG #18902: TRAP:: failed Assert("!is_sorted") in File: "createplan.c"
List pgsql-bugs
On Thu, Apr 24, 2025 at 6:20 PM Richard Guo <guofenglinux@gmail.com> wrote:
> On Thu, Apr 24, 2025 at 5:40 PM Richard Guo <guofenglinux@gmail.com> wrote:
> > Yeah.  Quoting the comments for outersortkeys/innersortkeys:
> >
> >  * outersortkeys (resp. innersortkeys) is NIL if the outer path
> >  * (resp. inner path) is already ordered appropriately for the
> >  * mergejoin.  If it is not NIL then it is a PathKeys list describing
> >  * the ordering that must be created by an explicit Sort node.
> >
> > And try_mergejoin_path will detect whether the outer path (resp. inner
> > path) is already well enough ordered, and suppresses an explicit sort
> > step if so by setting outersortkeys (resp. innersortkeys) to NIL.
> >
> > This reflects a basic assumption: if MergePath.outersortkeys is not
> > NIL, it means the outer path is not sufficiently ordered.
> >
> > Therefore, I think the "Assert(!is_sorted)" when outersortkeys is not
> > NIL is reasonable.  And I think some other code is violating this
> > assumption.
> >
> > I tried this repro query on v17 and got a plan with a redundant Sort
> > node.  It seems that this issue existed prior to commit 828e94c9d, and
> > the Assert introduced in that commit makes the issue easier to detect.
>
> It seems the culprit is in GetExistingLocalJoinPath(), which is used
> to get a local path for EPQ checks.  In that function, if the outer or
> inner path of the selected join path is a ForeignScan, it is replaced
> with the fdw_outerpath.
>
> The problem arises when the selected join path is a MergePath, and its
> outer or inner path is a ForeignScan that is not already well enough
> ordered.  In this case, the MergePath will have non-NIL outersortkeys
> or innersortkeys.  If we then replace the outer or inner path with the
> corresponding fdw_outerpath, and that path is already sufficiently
> ordered, we end up in an inconsistent state: the MergePath has non-NIL
> outersortkeys/innersortkeys, and its input path is already properly
> ordered.
>
> This inconsistency leads to a redundant Sort node prior to commit
> 828e94c9d, and triggers an Assert failure after that commit.

To fix, I think we can set outersortkeys/innersortkeys to NIL in
GetExistingLocalJoinPath() if we detect that the new outer/inner path
of the MergePath is already sorted properly, similar to what we do in
try_mergejoin_path().

    if (IS_JOIN_REL(foreign_path->path.parent))
+   {
        joinpath->outerjoinpath = foreign_path->fdw_outerpath;
+
+       if (joinpath->path.pathtype == T_MergeJoin)
+       {
+           MergePath   *merge_path = (MergePath *) joinpath;
+
+           /*
+            * If the new outer path is already well enough ordered for
+            * mergejoin, we can skip doing an explicit sort.
+            */
+           if (merge_path->outersortkeys &&
+               pathkeys_contained_in(merge_path->outersortkeys,
+                                     joinpath->outerjoinpath->pathkeys))
+               merge_path->outersortkeys = NIL;
+       }
+   }

(We need to do the same to innersortkeys.)

One problem with this approach is that the cost of the explicit sort
has already been included in the MergePath.  However, I'm not too
concerned about this, since the resulting plan is only used for EPQ
checks, where cost accuracy is not that important.  After all, we also
don't adjust the join path's cost when replacing its outer or inner
subpath.

Any thoughts?

Thanks
Richard



pgsql-bugs by date:

Previous
From: Richard Guo
Date:
Subject: Re: BUG #18902: TRAP:: failed Assert("!is_sorted") in File: "createplan.c"
Next
From: David Rowley
Date:
Subject: Re: BUG #18902: TRAP:: failed Assert("!is_sorted") in File: "createplan.c"