1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-11 10:01:57 +03:00

Suppress unnecessary explicit sorting for EPQ mergejoin path

When building a ForeignPath for a joinrel, if there's a possibility
that EvalPlanQual will be executed, we must identify a suitable path
for EPQ checks.  If the outer or inner path of the chosen path is a
ForeignPath representing a pushed-down join, we replace it with its
fdw_outerpath to ensure that the EPQ check path consists entirely of
local joins.

If the chosen path is a MergePath, and its outer or inner path is a
ForeignPath that is not already well enough ordered, the MergePath
will have non-NIL outersortkeys or innersortkeys indicating the
desired ordering to be created by an explicit Sort node.  If we then
replace the outer or inner path with its corresponding fdw_outerpath,
and that path is already sufficiently ordered, we end up in an
inconsistent state: the MergePath has non-NIL outersortkeys or
innersortkeys, and its input path is already properly ordered.  This
inconsistency can result in an Assert failure or the addition of a
redundant Sort node.

To fix, check if the new outer or inner path of a MergePath is already
properly sorted, and set its outersortkeys or innersortkeys to NIL if
so.

Bug: #18902
Reported-by: Nikita Kalinin <n.kalinin@postgrespro.ru>
Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: Tender Wang <tndrwang@gmail.com>
Discussion: https://postgr.es/m/18902-71c1bed2b9f7c46f@postgresql.org
This commit is contained in:
Richard Guo
2025-05-08 18:20:18 +09:00
parent 9fef27a83b
commit 773db22269
3 changed files with 102 additions and 0 deletions

View File

@ -22,6 +22,7 @@
#include "foreign/foreign.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "optimizer/paths.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
@ -808,7 +809,23 @@ GetExistingLocalJoinPath(RelOptInfo *joinrel)
foreign_path = (ForeignPath *) joinpath->outerjoinpath;
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 the 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;
}
}
}
if (IsA(joinpath->innerjoinpath, ForeignPath))
@ -817,7 +834,23 @@ GetExistingLocalJoinPath(RelOptInfo *joinrel)
foreign_path = (ForeignPath *) joinpath->innerjoinpath;
if (IS_JOIN_REL(foreign_path->path.parent))
{
joinpath->innerjoinpath = foreign_path->fdw_outerpath;
if (joinpath->path.pathtype == T_MergeJoin)
{
MergePath *merge_path = (MergePath *) joinpath;
/*
* If the new inner path is already well enough ordered
* for the mergejoin, we can skip doing an explicit sort.
*/
if (merge_path->innersortkeys &&
pathkeys_contained_in(merge_path->innersortkeys,
joinpath->innerjoinpath->pathkeys))
merge_path->innersortkeys = NIL;
}
}
}
return (Path *) joinpath;